Skip to content

Commit 79620c2

Browse files
authored
feat(datastore): Add support for parsing match none predicate in AppSync request builder (#1515)
1 parent 4532bc6 commit 79620c2

File tree

3 files changed

+77
-7
lines changed

3 files changed

+77
-7
lines changed

aws-datastore/src/main/java/com/amplifyframework/datastore/appsync/AppSyncRequestFactory.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ static <T> AppSyncGraphQLRequest<T> buildSyncRequest(
136136
if (!QueryPredicates.all().equals(predicate)) {
137137
String filterType = "Model" + Casing.capitalizeFirst(modelSchema.getName()) + "FilterInput";
138138
QueryPredicate syncPredicate = predicate;
139-
if (syncPredicate instanceof QueryPredicateOperation) {
139+
if (!(syncPredicate instanceof QueryPredicateGroup)) {
140140
// When a filter is provided, wrap it with a predicate group of type AND. By doing this, it enables
141141
// AppSync to optimize the request by performing a DynamoDB query instead of a scan. If the
142142
// provided syncPredicate is already a QueryPredicateGroup, this is not needed. If the provided
@@ -221,6 +221,13 @@ static <M extends Model> AppSyncGraphQLRequest<ModelWithMetadata<M>> buildCreati
221221
}
222222

223223
static Map<String, Object> parsePredicate(QueryPredicate queryPredicate) throws DataStoreException {
224+
if (QueryPredicates.all().equals(queryPredicate)) {
225+
return Collections.singletonMap("id", Collections.singletonMap("ne", null));
226+
}
227+
if (QueryPredicates.none().equals(queryPredicate)) {
228+
// id cannot be null, so match none
229+
return Collections.singletonMap("id", Collections.singletonMap("eq", null));
230+
}
224231
if (queryPredicate instanceof QueryPredicateOperation) {
225232
QueryPredicateOperation<?> qpo = (QueryPredicateOperation<?>) queryPredicate;
226233
QueryOperator<?> op = qpo.operator();

aws-datastore/src/test/java/com/amplifyframework/datastore/appsync/AppSyncRequestFactoryTest.java

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959

6060
import java.util.ArrayList;
6161
import java.util.Arrays;
62+
import java.util.Collections;
6263
import java.util.HashMap;
6364
import java.util.Map;
6465

@@ -181,6 +182,21 @@ public void validatePredicateGroupForSyncExpressionIsNotWrappedWithAnd() throws
181182
true);
182183
}
183184

185+
/**
186+
* If a MatchNoneQueryPredicate is provided, it should be wrapped in an AND group.
187+
* This enables AppSync to optimize by performing an DDB query instead of scan.
188+
* @throws AmplifyException On failure to parse ModelSchema from model class
189+
* @throws JSONException from JSONAssert.assertEquals.
190+
*/
191+
@Test
192+
public void validateMatchNonePredicateForSyncExpressionIsWrappedWithAnd() throws AmplifyException, JSONException {
193+
ModelSchema schema = ModelSchema.fromModelClass(BlogOwner.class);
194+
final GraphQLRequest<Iterable<Post>> request =
195+
AppSyncRequestFactory.buildSyncRequest(schema, null, null, QueryPredicates.none());
196+
JSONAssert.assertEquals(Resources.readAsString("base-sync-request-with-predicate-match-none.txt"),
197+
request.getContent(), true);
198+
}
199+
184200
/**
185201
* Checks that we're getting the expected output for a mutation with predicate.
186202
* @throws DataStoreException If the output does not match.
@@ -279,15 +295,29 @@ public void validateDeleteWithCustomPrimaryKey() throws AmplifyException, JSONEx
279295
*/
280296
@Test
281297
public void validatePredicateGeneration() throws DataStoreException {
282-
Map<String, Object> predicate =
283-
AppSyncRequestFactory.parsePredicate(BlogOwner.NAME.eq("Test Dummy"));
284298
assertEquals(
285-
"{name={eq=Test Dummy}}",
286-
predicate.toString()
299+
Collections.singletonMap("name", Collections.singletonMap("eq", "Test Dummy")),
300+
AppSyncRequestFactory.parsePredicate(BlogOwner.NAME.eq("Test Dummy"))
301+
);
302+
303+
assertEquals(
304+
Collections.singletonMap("and", Arrays.asList(
305+
Collections.singletonMap("name", Collections.singletonMap("beginsWith", "A day in the life of a...")),
306+
Collections.singletonMap("blogOwnerId", Collections.singletonMap("eq", "DUMMY_OWNER_ID"))
307+
)),
308+
AppSyncRequestFactory.parsePredicate(
309+
Blog.NAME.beginsWith("A day in the life of a...").and(Blog.OWNER.eq("DUMMY_OWNER_ID"))
310+
)
287311
);
288312

289-
AppSyncRequestFactory.parsePredicate(
290-
Blog.NAME.beginsWith("A day in the life of a...").and(Blog.OWNER.eq("DUMMY_OWNER_ID"))
313+
assertEquals(
314+
Collections.singletonMap("id", Collections.singletonMap("ne", null)),
315+
AppSyncRequestFactory.parsePredicate(QueryPredicates.all())
316+
);
317+
318+
assertEquals(
319+
Collections.singletonMap("id", Collections.singletonMap("eq", null)),
320+
AppSyncRequestFactory.parsePredicate(QueryPredicates.none())
291321
);
292322
}
293323

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"query": "query SyncBlogOwners($filter: ModelBlogOwnerFilterInput) {
3+
syncBlogOwners(filter: $filter) {
4+
items {
5+
_deleted
6+
_lastChangedAt
7+
_version
8+
blog {
9+
id
10+
}
11+
createdAt
12+
id
13+
name
14+
updatedAt
15+
wea
16+
}
17+
nextToken
18+
startedAt
19+
}
20+
}
21+
",
22+
"variables": {
23+
"filter": {
24+
"and": [
25+
{
26+
"id": {
27+
"eq" : null
28+
}
29+
}
30+
]
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)