aws-amplify / aws-amplify/amplify-android
[DataStore] @hasMany connection to another model returns null inside query and crashes app
- Dominant language
- Java
- Stars
- 287
- Forks
- 132
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 45
Description
### Before opening, please confirm:
- [X] I have [searched for duplicate or closed issues](https://github.com/aws-amplify/amplify-android/issues?q=is%3Aissue+) and [discussions](https://github.com/aws-amplify/amplify-android/discussions).
### Language and Async Model
Kotlin - Coroutines
### Amplify Categories
DataStore
### Gradle script dependencies
```groovy
// Put output below this line
// Amplify core dependency
implementation 'com.amplifyframework:core:1.32.1'
implementation 'com.amplifyframework:core-kotlin:0.16.0'
implementation 'com.amplifyframework:aws-api:1.32.1'
implementation 'com.amplifyframework:aws-datastore:1.32.1'
```
### Environment information
```
# Put output below this line
------------------------------------------------------------
Gradle 7.2
------------------------------------------------------------
Build time: 2021-08-17 09:59:03 UTC
Revision: a773786b58bb28710e3dc96c4d1a7063628952ad
Kotlin: 1.5.21
Groovy: 3.0.8
Ant: Apache Ant(TM) version 1.10.9 compiled on September 27 2020
JVM: 17.0.1 (Oracle Corporation 17.0.1+12-39)
OS: Mac OS X 12.1 aarch64
```
### Please include any relevant guides or documentation you're referencing
https://docs.amplify.aws/lib/datastore/relational/q/platform/android/
### Describe the bug
I am trying to access nested model (Blog & Post in schema) inside DataStore queries similar to how it is possible to access Nested CustomType (which works). In the code, when trying to access the (Mutable)List, I get a null pointer error and my app crashes. I have been facing this issue since amplifyframework version 1.31.3 and now I am on 1.32.x and still facing it.
Any ideas or suggestions?
This seems to be working on other platforms.
On Flutter, https://github.com/aws-amplify/amplify-flutter/issues/260#issuecomment-909679333 mentions that [CustomType] is not supported but that works on my end. Only [AnotherModel] i.e. a @hasMany relationship between tables is not working.
### Reproduction steps (if applicable)
1. Set up env with provided GraphQL Schema
2. Notice that list of CustomType is working fine and is accessible.
3. But, list of AnotherModel is not accessible/returns null and crashes app.
4. This seems to work on iOS, Flutter and JS, but only fails on Native Android (Kotlin)
### Code Snippet
```kotlin
// Put your code below this line.
GlobalScope.launch {
Amplify.DataStore.query(Blog::class, Where.id("1"))
.catch { Log.e("DataStore", "Error", it)}
.collect {
Log.d("DataStore", "${it.id}, ${it.name}, ${it.customs}")
Log.d("DataStore", it.customs[1].children[0].nestedName + ", customs size: ${it.customs.size}")
// the next line returns null and crashes app
Log.d("DataStore", "posts test id: ${it.post[0].id}")
}
}
```
### Log output
```
// Put your logs below this line
E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.example.datastorecrud, PID: 22111
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
at com.example.datastorecrud.MainActivity$onCreate$1$invokeSuspend$$inlined$collect$1.emit(Collect.kt:136)
at kotlinx.coroutines.flow.FlowKt__ErrorsKt$catchImpl$$inlined$collect$1.emit(Collect.kt:134)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt.emitAllImpl$FlowKt__ChannelsKt(Channels.kt:61)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt$emitAllImpl$1.invokeSuspend(Unknown Source:11)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
```
### amplifyconfiguration.json
_No response_
### GraphQL Schema
```graphql
// Put your schema below this line
type Blog @model {
id: ID!
name: String!
customs: [MyCustomModel]
notes: [String]
post: [Post] @hasMany(indexName: "postByBlog", fields: ["id"])
}
type MyCustomModel {
id: ID!
name: String!
desc: String
children: [MyNestedModel]
}
type MyNestedModel {
id: ID!
nestedName: String!
notes: [String]
}
type Post @model {
id:ID!
name:String!
blog_id: ID! @index(name: "postByBlog")
blog: Blog @belongsTo(fields: ["blog_id"])
}
```
### Additional information and screenshots
_No response_
Contributor guide
Research direction
Begin at the Amplify.DataStore.query(Blog::class, Where.id("1")) call and reproduce it with the supplied Blog/Post @hasMany schema and Kotlin snippet. Compare the working custom-type access with the null Post list; done means the relationship can be queried without the reported NullPointerException.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, aws, kotlin
- Domain
- database, mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100