|
15 | 15 |
|
16 | 16 | package com.amplifyframework.api.aws; |
17 | 17 |
|
| 18 | +import androidx.annotation.NonNull; |
| 19 | + |
18 | 20 | import com.amplifyframework.AmplifyException; |
19 | 21 | import com.amplifyframework.api.graphql.GraphQLRequest; |
20 | 22 | import com.amplifyframework.api.graphql.MutationType; |
21 | 23 | import com.amplifyframework.api.graphql.PaginatedResult; |
22 | 24 | import com.amplifyframework.api.graphql.QueryType; |
23 | 25 | import com.amplifyframework.api.graphql.SubscriptionType; |
| 26 | +import com.amplifyframework.core.model.AuthRule; |
| 27 | +import com.amplifyframework.core.model.AuthStrategy; |
24 | 28 | import com.amplifyframework.core.model.Model; |
| 29 | +import com.amplifyframework.core.model.ModelAssociation; |
| 30 | +import com.amplifyframework.core.model.ModelField; |
25 | 31 | import com.amplifyframework.core.model.ModelSchema; |
26 | 32 | import com.amplifyframework.core.model.query.predicate.BeginsWithQueryOperator; |
27 | 33 | import com.amplifyframework.core.model.query.predicate.BetweenQueryOperator; |
|
40 | 46 | import com.amplifyframework.util.Casing; |
41 | 47 | import com.amplifyframework.util.TypeMaker; |
42 | 48 |
|
| 49 | +import java.lang.reflect.Field; |
43 | 50 | import java.lang.reflect.Type; |
44 | 51 | import java.util.ArrayList; |
45 | 52 | import java.util.Arrays; |
46 | 53 | import java.util.Collections; |
| 54 | +import java.util.HashMap; |
47 | 55 | import java.util.List; |
48 | 56 | import java.util.Locale; |
49 | 57 | import java.util.Map; |
| 58 | +import java.util.Objects; |
50 | 59 |
|
51 | 60 | /** |
52 | 61 | * Converts provided model or class type into a request container |
@@ -198,7 +207,7 @@ public static <R, T extends Model> GraphQLRequest<R> buildMutation( |
198 | 207 | if (MutationType.DELETE.equals(type)) { |
199 | 208 | builder.variable("input", inputType, Collections.singletonMap("id", model.getId())); |
200 | 209 | } else { |
201 | | - builder.variable("input", inputType, schema.getMapOfFieldNameAndValues(model)); |
| 210 | + builder.variable("input", inputType, getMapOfFieldNameAndValues(schema, model)); |
202 | 211 | } |
203 | 212 |
|
204 | 213 | if (!QueryPredicates.all().equals(predicate)) { |
@@ -339,4 +348,52 @@ private static Object appSyncOpValue(QueryOperator<?> qOp) { |
339 | 348 | ); |
340 | 349 | } |
341 | 350 | } |
| 351 | + |
| 352 | + private static Map<String, Object> getMapOfFieldNameAndValues( |
| 353 | + @NonNull ModelSchema schema, @NonNull Model instance) throws AmplifyException { |
| 354 | + if (!instance.getClass().getSimpleName().equals(schema.getName())) { |
| 355 | + throw new AmplifyException( |
| 356 | + "The object provided is not an instance of " + schema.getName() + ".", |
| 357 | + "Please provide an instance of " + schema.getName() + " that matches the schema type." |
| 358 | + ); |
| 359 | + } |
| 360 | + final Map<String, Object> result = new HashMap<>(); |
| 361 | + for (ModelField modelField : schema.getFields().values()) { |
| 362 | + String fieldName = modelField.getName(); |
| 363 | + try { |
| 364 | + Field privateField = instance.getClass().getDeclaredField(modelField.getName()); |
| 365 | + privateField.setAccessible(true); |
| 366 | + Object fieldValue = privateField.get(instance); |
| 367 | + final ModelAssociation association = schema.getAssociations().get(fieldName); |
| 368 | + if (association == null) { |
| 369 | + result.put(fieldName, fieldValue); |
| 370 | + } else if (association.isOwner()) { |
| 371 | + Model target = (Model) Objects.requireNonNull(fieldValue); |
| 372 | + result.put(association.getTargetName(), target.getId()); |
| 373 | + } |
| 374 | + // Ignore if field is associated, but is not a "belongsTo" relationship |
| 375 | + } catch (Exception exception) { |
| 376 | + throw new AmplifyException( |
| 377 | + "An invalid field was provided. " + fieldName + " is not present in " + schema.getName(), |
| 378 | + exception, |
| 379 | + "Check if this model schema is a correct representation of the fields in the provided Object"); |
| 380 | + } |
| 381 | + } |
| 382 | + |
| 383 | + /* |
| 384 | + * If the owner field exists on the model, and the value is null, it should be omitted when performing a |
| 385 | + * mutation because the AppSync server will automatically populate it using the authentication token provided |
| 386 | + * in the request header. The logic below filters out the owner field if null for this scenario. |
| 387 | + */ |
| 388 | + for (AuthRule authRule : schema.getAuthRules()) { |
| 389 | + if (AuthStrategy.OWNER.equals(authRule.getAuthStrategy())) { |
| 390 | + String ownerField = authRule.getOwnerFieldOrDefault(); |
| 391 | + if (result.containsKey(ownerField) && result.get(ownerField) == null) { |
| 392 | + result.remove(ownerField); |
| 393 | + } |
| 394 | + } |
| 395 | + } |
| 396 | + |
| 397 | + return result; |
| 398 | + } |
342 | 399 | } |
0 commit comments