DataStore Contains Query Operator to support List Type
Description
I want to selectively sync down a subset of data but the sync expression with contains query operator does not wrok on [String].
I have two models User and Device, below is the schema.
type Device @model @auth(rules: [{allow: public}]) {
id: ID!
iccid: String!
userId: [String]
}
type User @model @auth(rules: [{allow: public}]) {
id: ID!
username: String!
email: String
deviceId: [String]
}
I want to sync down the device only if the userID(List of String) contains the current user ID. I can sync down only the needed data initially when the datastore first started, and then my app crashes every time there is an update event. I got the following error message.
W/amplify:aws-datastore( 5021): Reading subscription events has failed.
W/amplify:aws-datastore( 5021): java.lang.IllegalArgumentException: userId field inside provided object cannot be evaluated by the operator type: CONTAINS
W/amplify:aws-datastore( 5021): at com.amplifyframework.core.model.query.predicate.QueryPredicateOperation.evaluate(QueryPredicateOperation.java:141)
W/amplify:aws-datastore( 5021): at com.amplifyframework.datastore.syncengine.SubscriptionProcessor.lambda$subscriptionObservable$8$com-amplifyframework-datastore-syncengine-SubscriptionProcessor(SubscriptionProcessor.java:241)
W/amplify:aws-datastore( 5021): at com.amplifyframework.datastore.syncengine.SubscriptionProcessor$$ExternalSyntheticLambda18.test(Unknown Source:6)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableFilter$FilterObserver.onNext(ObservableFilter.java:46)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:63)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:201)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:255)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:65)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:56)
W/amplify:aws-datastore( 5021): at java.util.concurrent.FutureTask.run(FutureTask.java:264)
W/amplify:aws-datastore( 5021): at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:307)
W/amplify:aws-datastore( 5021): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
W/amplify:aws-datastore( 5021): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
W/amplify:aws-datastore( 5021): at java.lang.Thread.run(Thread.java:1012)
W/amplify:aws-datastore( 5021): Caused by: java.lang.ClassCastException: java.util.Collections$UnmodifiableRandomAccessList cannot be cast to java.lang.String
W/amplify:aws-datastore( 5021): at com.amplifyframework.core.model.query.predicate.ContainsQueryOperator.evaluate(ContainsQueryOperator.java:23)
W/amplify:aws-datastore( 5021): at com.amplifyframework.core.model.query.predicate.QueryPredicateOperation.evaluate(QueryPredicateOperation.java:137)
W/amplify:aws-datastore( 5021): ... 13 more
W/amplify:aws-datastore( 5021): Reading subscriptions buffer has failed.
W/amplify:aws-datastore( 5021): java.lang.IllegalArgumentException: userId field inside provided object cannot be evaluated by the operator type: CONTAINS
W/amplify:aws-datastore( 5021): at com.amplifyframework.core.model.query.predicate.QueryPredicateOperation.evaluate(QueryPredicateOperation.java:141)
W/amplify:aws-datastore( 5021): at com.amplifyframework.datastore.syncengine.SubscriptionProcessor.lambda$subscriptionObservable$8$com-amplifyframework-datastore-syncengine-SubscriptionProcessor(SubscriptionProcessor.java:241)
W/amplify:aws-datastore( 5021): at com.amplifyframework.datastore.syncengine.SubscriptionProcessor$$ExternalSyntheticLambda18.test(Unknown Source:6)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableFilter$FilterObserver.onNext(ObservableFilter.java:46)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:63)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:201)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:255)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:65)
W/amplify:aws-datastore( 5021): at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:56)
W/amplify:aws-datastore( 5021): at java.util.concurrent.FutureTask.run(FutureTask.java:264)
W/amplify:aws-datastore( 5021): at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:307)
W/amplify:aws-datastore( 5021): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
W/amplify:aws-datastore( 5021): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
W/amplify:aws-datastore( 5021): at java.lang.Thread.run(Thread.java:1012)
W/amplify:aws-datastore( 5021): Caused by: java.lang.ClassCastException: java.util.Collections$UnmodifiableRandomAccessList cannot be cast to java.lang.String
W/amplify:aws-datastore( 5021): at com.amplifyframework.core.model.query.predicate.ContainsQueryOperator.evaluate(ContainsQueryOperator.java:23)
W/amplify:aws-datastore( 5021): at com.amplifyframework.core.model.query.predicate.QueryPredicateOperation.evaluate(QueryPredicateOperation.java:137)
W/amplify:aws-datastore( 5021): ... 13 more
W/System.err( 5021): io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException: The exception was not handled due to missing onError handler in the subscribe() method call. Further reading: https://github.com/ReactiveX/RxJava/wiki/Error-Handling | java.lang.IllegalArgumentException: userId field inside provided object cannot be evaluated by the operator type: CONTAINS
W/System.err( 5021): at io.reactivex.rxjava3.internal.observers.EmptyCompletableObserver.onError(EmptyCompletableObserver.java:50)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.completable.CompletablePeek$CompletableObserverImplementation.onError(CompletablePeek.java:95)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.completable.CompletablePeek$CompletableObserverImplementation.onError(CompletablePeek.java:95)
W/System.err( 5021): at io.reactivex.rxjava3.internal.util.AtomicThrowable.tryTerminateConsumer(AtomicThrowable.java:156)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableFlatMapCompletableCompletable$FlatMapCompletableMainObserver.onError(ObservableFlatMapCompletableCompletable.java:125)
W/System.err( 5021): at io.reactivex.rxjava3.internal.observers.DisposableLambdaObserver.onError(DisposableLambdaObserver.java:65)
W/System.err( 5021): at io.reactivex.rxjava3.subjects.UnicastSubject.errorOrComplete(UnicastSubject.java:434)
W/System.err( 5021): at io.reactivex.rxjava3.subjects.UnicastSubject.drainNormal(UnicastSubject.java:377)
W/System.err( 5021): at io.reactivex.rxjava3.subjects.UnicastSubject.drain(UnicastSubject.java:466)
W/System.err( 5021): at io.reactivex.rxjava3.subjects.UnicastSubject.onError(UnicastSubject.java:334)
W/System.err( 5021): at com.amplifyframework.datastore.syncengine.SubscriptionProcessor.$r8$lambda$2DzBYDskeCFj76tCjx3pAdQcs9Q(Unknown Source:0)
W/System.err( 5021): at com.amplifyframework.datastore.syncengine.SubscriptionProcessor$$ExternalSyntheticLambda12.accept(Unknown Source:4)
W/System.err( 5021): at io.reactivex.rxjava3.internal.observers.LambdaObserver.onError(LambdaObserver.java:77)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onError(ObservableDoOnEach.java:117)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onError(ObservableDoOnEach.java:117)
W/System.err( 5021): at io.reactivex.rxjava3.internal.observers.DisposableLambdaObserver.onError(DisposableLambdaObserver.java:65)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.checkTerminated(ObservableObserveOn.java:281)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:172)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:255)
W/System.err( 5021): at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:65)
W/System.err( 5021): at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:56)
W/System.err( 5021): at java.util.concurrent.FutureTask.run(FutureTask.java:264)
W/System.err( 5021): at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:307)
W/System.err( 5021): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
W/System.err( 5021): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
W/System.err( 5021): at java.lang.Thread.run(Thread.java:1012)
W/System.err( 5021): Caused by: java.lang.IllegalArgumentException: userId field inside provided object cannot be evaluated by the operator type: CONTAINS
W/System.err( 5021): at com.amplifyframework.core.model.query.predicate.QueryPredicateOperation.evaluate(QueryPredicateOperation.java:141)
W/System.err( 5021): at com.amplifyframework.datastore.syncengine.SubscriptionProcessor.lambda$subscriptionObservable$8$com-amplifyframework-datastore-syncengine-SubscriptionProcessor(SubscriptionProcessor.java:241)
W/System.err( 5021): at com.amplifyframework.datastore.syncengine.SubscriptionProcessor$$ExternalSyntheticLambda18.test(Unknown Source:6)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableFilter$FilterObserver.onNext(ObservableFilter.java:46)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:63)
W/System.err( 5021): at io.reactivex.rxjava3.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:201)
W/System.err( 5021): ... 8 more
W/System.err( 5021): Caused by: java.lang.ClassCastException: java.util.Collections$UnmodifiableRandomAccessList cannot be cast to java.lang.String
W/System.err( 5021): at com.amplifyframework.core.model.query.predicate.ContainsQueryOperator.evaluate(ContainsQueryOperator.java:23)
W/System.err( 5021): at com.amplifyframework.core.model.query.predicate.QueryPredicateOperation.evaluate(QueryPredicateOperation.java:137)
W/System.err( 5021): ... 13 more
E/AndroidRuntime( 5021): FATAL EXCEPTION: RxCachedThreadScheduler-2
Categories
- [ ] Analytics
- [ ] API (REST)
- [ ] API (GraphQL)
- [ ] Auth
- [ ] Authenticator
- [X] DataStore
- [ ] Notifications (Push)
- [ ] Storage
Steps to Reproduce
To reproduce the bug, you can use the following two models:
type Device @model @auth(rules: [{allow: public}]) {
id: ID!
iccid: String!
userId: [String]
}
type User @model @auth(rules: [{allow: public}]) {
id: ID!
username: String!
email: String
deviceId: [String]
}
Then configure datastore as below:
Amplify.addPlugin(AmplifyDataStore(
modelProvider: ModelProvider.instance,
syncExpressions: [
DataStoreSyncExpression(User.classType, () => User.ID.eq(userId)),
DataStoreSyncExpression(
Device.classType, () => Device.USERID.contains(userId)),
],
)),
Go to Amplify Studio and edit any field of the device will trigger the error.
Screenshots
No response
Platforms
- [ ] iOS
- [X] Android
- [ ] Web
- [ ] macOS
- [ ] Windows
- [ ] Linux
Flutter Version
3.13.4
Amplify Flutter Version
1.4.0
Deployment Method
Amplify CLI
Schema
type Device @model @auth(rules: [{allow: public}]) {
id: ID!
iccid: String!
userId: [String]
}
type User @model @auth(rules: [{allow: public}]) {
id: ID!
username: String!
email: String
deviceId: [String]
}
Update: I tested it on my iOS device, it seems to be working. So i guess it's a bug on Android.
@stam0912 thanks for reporting this issue, we are investigating it and will provide update here.
@stam0912 DataStoreSyncExpression with contains operation is supported for query fields of String type on Android aws-amplify/amplify-android#1509. I'm working with amplify android team to investigate the app crashing issue and will provide more info as I have them. meanwhile please track the progress on aws-amplify/amplify-android#1509. Given DataStore fetches all the records that user is authorized to access from cloud to the local device, you may find a workaround by using auth rules on your models to selectivly sync subset of data. https://docs.amplify.aws/flutter/build-a-backend/more-features/datastore/authz-rules-setup/
This issue exists in iOS also, I have mentioned the similar issue in swift SDK #4860.