amplify-flutter icon indicating copy to clipboard operation
amplify-flutter copied to clipboard

DataStore Contains Query Operator to support List Type

Open stam0912 opened this issue 2 years ago • 4 comments

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]
}

stam0912 avatar Nov 15 '23 22:11 stam0912

Update: I tested it on my iOS device, it seems to be working. So i guess it's a bug on Android.

stam0912 avatar Nov 16 '23 18:11 stam0912

@stam0912 thanks for reporting this issue, we are investigating it and will provide update here.

NikaHsn avatar Dec 13 '23 01:12 NikaHsn

@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/

NikaHsn avatar Dec 16 '23 00:12 NikaHsn

This issue exists in iOS also, I have mentioned the similar issue in swift SDK #4860.

amritnew avatar May 09 '24 13:05 amritnew