-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(@aws-amplify/datastore): add Selective Sync #7001
Conversation
This pull request fixes 1 alert when merging 462305b into 377acd0 - view on LGTM.com fixed alerts:
|
462305b
to
4c8e9ce
Compare
This pull request fixes 1 alert when merging 4c8e9ce into 377acd0 - view on LGTM.com fixed alerts:
|
Codecov Report
@@ Coverage Diff @@
## main #7001 +/- ##
==========================================
- Coverage 73.28% 72.97% -0.31%
==========================================
Files 213 213
Lines 13197 13295 +98
Branches 2585 2604 +19
==========================================
+ Hits 9671 9702 +31
- Misses 3332 3397 +65
- Partials 194 196 +2
Continue to review full report at Codecov.
|
This pull request fixes 1 alert when merging c237a19 into 7bdb09f - view on LGTM.com fixed alerts:
|
This pull request fixes 1 alert when merging 7375ba7 into 59fdb08 - view on LGTM.com fixed alerts:
|
This pull request fixes 1 alert when merging 9ffe730 into a85c724 - view on LGTM.com fixed alerts:
|
This pull request fixes 1 alert when merging 2bb1d06 into 96fda2a - view on LGTM.com fixed alerts:
|
import { | ||
ModelPredicateCreator, | ||
ModelSortPredicateCreator, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just FYI to reviewers, the sort code is showing up in the diff for AsyncStorageAdapter and IndexedDBAdatper due to a file rename and delete. It's not actually new code, it's just that we had duplicate files (e.g., asyncstorage.ts and AsyncStorageAdapter.ts and the latter was out of date).
I deleted AsyncStorageAdapter.ts and then renamed asyncstorage.ts -> AsyncStorageAdapter.ts. Same for IDB
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! I am very excited for this feature 😄
I added minor comments.
packages/datastore/src/types.ts
Outdated
}; | ||
conflictHandler?: ConflictHandler; // default : retry until client wins up to x times | ||
errorHandler?: (error: SyncError) => void; // default : logger.warn | ||
maxRecordsToSync?: number; // merge | ||
syncPageSize?: number; | ||
fullSyncInterval?: number; | ||
}; | ||
syncExpressions?: SyncExpression<any>[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
packages/datastore/src/types.ts
Outdated
export type SyncExpression<T extends PersistentModel> = Promise<{ | ||
modelConstructor: PersistentModelConstructor<T>; | ||
conditionProducer: | ||
| ProducerModelPredicate<T> | ||
| (() => ProducerModelPredicate<T>) | ||
| (() => Promise<ProducerModelPredicate<T>>); | ||
}>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this type works better (is more flexible for the future) if you drop the Promise
from here and instead add it as needed where you consume it.
packages/datastore/src/sync/utils.ts
Outdated
result[type] = predicates.map(p => { | ||
if (isPredicateObj(p)) { | ||
const { field, operator, operand } = p; | ||
|
||
return { [field]: { [operator]: operand } }; | ||
} else { | ||
result[p.type] = predicateToGraphQLCondition(p); | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This map
operation is confusing, it is only returning a mapped element in one circumstance and modifying an object from the outside scope in the other. This should probably be a forEach
or re-written as something clearer.
This pull request fixes 2 alerts when merging d60587d into abb5e36 - view on LGTM.com fixed alerts:
|
This pull request introduces 1 alert and fixes 2 when merging 5104d0e into abb5e36 - view on LGTM.com new alerts:
fixed alerts:
|
This pull request fixes 2 alerts when merging a2146c0 into 958f61e - view on LGTM.com fixed alerts:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @iartemiev this looks great!
I would double check stop
function to see there is no race condition in case the app invokes start
and stop
repeatedly
This pull request fixes 2 alerts when merging 374d241 into 958f61e - view on LGTM.com fixed alerts:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @iartemiev this is awesome!! 🌮 🎉 🥇
Hey there 👋 I've updated Datastore now adds a
Which results in the following errors in the response.
Now, I understand why this happens: the related AppSync Backend schema does not expect any $filter parameter on this operation and also doesn't know about a type named The way I see it is that this Pull Request has added a change (somewhere around here) that forces me to update my AppSync Backend. How should I proceed with that ? Where is this required Backend change documented ? [Edit] Note that my team has previously decided to work without the Amplify CLI. So we have generated the related AppSync Backend by using a by-AWS-provided CloudFormation Stack template. |
@LaurentEscalier there is no backend change required for those using the CLI - which is the recommended approach for DataStore - as we've always included an optional filter argument in the generated query input type. It was just unused until this change. In your case, you can run |
This pull request has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs. Looking for a help forum? We recommend joining the Amplify Community Discord server |
Works in concert with these CLI changes: aws-amplify/amplify-cli#5586
DataStore - Selective Sync Feature
Enables developers to filter data on the back end before it gets synced down into their users' local stores, as opposed to syncing the entire contents of the associated data source.
Additional details:
DataStore.stop()
method for stopping the sync & subscriptions without clearing out the contents of the local store.Misc.:
Addresses the following feature requests/issues:
Basic usage
Selective Sync is configured by specifying
syncExpressions
, a newly added optional configuration parameter.Developers can choose which model(s) they would like to apply an expression to.
When DataStore starts syncing, only Posts with
rating > 5
and Comments withstatus === 'active'
will be synced down to the user's local store.Developers should only specify a single
syncExpression
per model. Any subsequent expressions for the same model will be ignored.Reevalute expressions at runtime
Sync expressions get evaluated in
DataStore.start()
so it's possible to reevaluate them at runtime.If you want to start syncing down Posts with
rating > 1
, you can do:Upon calling
start()
(or executing a DataStore operation, e.g.,query
,save
,delete
, orobserve
), DataStore will reevaluate thesyncExpressions
.In the above case, the predicate will contain the value
1
, so all Posts withrating > 1
will get synced down.Using async expressions
You can pass a Promise to
syncExpression
:DataStore will wait for the Promise to resolve before applying the expression to sync. Async expressions can also be reevaluated at runtime, just like synchronous expressions (see previous section).
Shorthand
If you don't need to add any logic to your
syncExpression
, you can use the following shorthand (returning the predicate, as opposed to a function or promise that in turn returns a predicate like in the above examples):Advanced use case
You can utilize Selective Sync in order to have your base sync retrieve items from DynamoDB via query against a table, LSI, or GSI. By default, the base sync will perform a scan.
In order to do that, your
syncExpression
should return a predicate that maps to a queryable expression.For example, for the following schema:
This sync expression will produce a query operation:
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.