-
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
[RFC] DataStore predicate grammar #8901
Comments
This would be such a great addition to datastore to implement so many use cases and especially use cases where you need to do advanced filtering for multitenant applications. Good to see you can query also on the relations of a model. This increases the speed of development. For multi tenant it is key to mix and match AND / OR conditions to sync the right data. I am really looking forward to have this available soon. Is it possible to query lists? So if my id is in a list then query/sync? List |
Btw I prefer option A, because it is more visible what the code is doing. |
Hey @rpostulart,
Hopefully you won't even need to do this! The idea is to empower you to write queries that handle these intermediate "query against list of x" operations internally. For example, whereas you would currently need do things like this: const tasks = await DataStore.query(Task, task => task.owner('eq', 'rpostulart'));
const project_ids = [...new Set(tasks.map(t => t.id))];
const projects = [];
for (let id of project_ids) {
projects.push(await DataStore.query(Project, id))
} You'd now just do something like this: const projects = await DataStore.query(Project, project => project.task.owner.eq('rpostulart')); That said, if you do end up with a list of ID's at some point, the least ambiguous mechanism might just be a DataStore.query(Task, task => task
.or(t => ['a', 'b', 'c', 'x', 'y', 'z'].map(id => t.id.eq(id)))
); I'd be a little concerned that allowing lists of values in the condition methods ( |
Hey @rpostulart, I need to clarify one thing that I read right past on Friday. Nested predicates are only designed to be used against local data. They will not be available for selective sync. Sorry if I set the wrong expectation there! I'll update the issue body to clarify this. |
OK, thanks for the feedback. So how to deal with this use case:
|
I believe this is the same like I needed above: |
does this apply to custom types? like how can I query based on custom type field? |
The new predicate grammar has been released as part of |
Hi @svidgen |
This is a Request For Comments (RFC). RFCs are intended to elicit feedback regarding a proposed change to the Amplify Framework. Please feel free to post comments or questions here.
Summary
This RFC is to gather customer feedback around Amplify DataStore's grammar and handling of the logical operator grouping (
and
,or
,not
) used inquery()
andobserve()
predicates.Selective sync predicates are out of scope.
Motivation
We have begun work to introduce nested predicates for querying against related models. In doing so, we have come to suspect that the existing predicate grammar is laden with ambiguities. It neither mirrors the behavior found in the native platform implementations nor that of other common query languages such as GraphQL. Because we are already changing predicates to add nesting, this is an opportune time to disambiguate this grammar.
Current Logical Operator Behavior
Consider a simple model:
Let's consider a few GraphQL queries and then how we'd perform these operation in iOS vs. JS. Note that iOS also supports an operator-overloaded syntax which JS cannot replicate. And also note that the Java/Android for each of these queries mirrors the iOS nearly exactly, with field-casing being the only difference.
For brevity, only the predicate portion of the
query
operation is shown. Each of these predicates would be the 2nd argument in aDataStore.query(Task, ...)
call.Simple
AND
queryE.g., "Onboarding tasks for a single owner."
GraphQL
iOS
TypeScript/JavaScript
GraphQL and JavaScript have an implicit
AND
grouping. Each newAND
'd condition is simply appended to the expression. This logical grouping must be done explicitly in iOS (and Android) with a wrappingand()
call.Simple OR query
E.g., "Tasks for two particular users plus all 'onboarding' tasks."
GraphQL
iOS
TypeScript/JavaScript
GraphQL's
or
group accepts a list of "full" nested filters. It is not demonstrated here, but the normal implicitAND
logic is applied to the conditions therein. iOS/Android requires explicit, wrappingor()
call for each condition. JavaScript'sor()
method group creates a full new child predicate where all conditions areOR
'd together.More complicated example, mixing AND/OR groups
E.g., "Find onboarding tasks assigned to the wrong user."
GraphQL
iOS
TypeScript/JavaScript
GraphQL implies
AND
grouping at the top level. It'sOR
group applies to the full result of eachAND
-grouped child expression.iOS and Android each require explicit
and()
/or()
grouping for each condition.JavaScript's logical groups are "modal". Each
and()
/or()
call sets the "mode" for the child predicate. This pattern causes predicate structures in TS/JS to be the opposite of the native platforms, almost reversing the expected use ofand()
andor()
.With Nested Predicates
As we consider this logical operator grammar, we must also consider more complicated cases that involve the upcoming nested predicates feature. Nested predicates will allow you to query for a Model against related models.
Lets extend our schema slightly:
A simple query, where we fetch all Tasks where the task's project name contains "[Research]", could look like this:
Under the the existing grammar, we would be able to add intermediate conditions to additionally filter by Task owner for example, like so:
But, what happens if we introduce logical operators under the existing grammar?
What filtering logic do you expect this predicate to perform? Is it Tasks where ...
Or where ...
(Or something else?!)
Under the current grammar, the 2nd interpretation would be correct. But, this is unexpected, disharmonious from other predicate grammars, and possibly too ambiguous as-is.
Proposed Solutions and Options
Let's consider a fairly complicated (albeit contrived) query and and look at some options for representing the same logic as a TS/JS DataStore predicate. We'll start with SQL, because it can unambiguously represent our logic.
Suppose we want all Tasks under "[Research]" projects with "[PDF]" artifacts, plus all "[SPIKE]" Tasks owned by our researchers ("Bob" and "Jane") with "[Report]" or "[REPORT]" artifacts.
Logical Grouping Option A
Condition cannot be chained; hence there is no implicit logical grouping.
Logical Grouping Option B
Conditions can be chained with implicit
AND
grouping.Questions for the community
The text was updated successfully, but these errors were encountered: