Skip to content

Commit 4d727ff

Browse files
feature(aws-datastore): support for hybrid platforms (#954)
Resolves: #842 Co-authored-by: Praveen Gupta <[email protected]>
1 parent 03e9707 commit 4d727ff

File tree

57 files changed

+2460
-544
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2460
-544
lines changed

aws-api-appsync/src/main/java/com/amplifyframework/api/aws/AppSyncGraphQLRequest.java

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,16 @@ <R> Builder(AppSyncGraphQLRequest<R> request) {
222222
this.variableTypes = new HashMap<>(request.variableTypes);
223223
}
224224

225+
/**
226+
* Sets the {@link ModelSchema} Class and returns this builder.
227+
* @param modelSchema the {@link ModelSchema} Class.
228+
* @return this builder instance.
229+
*/
230+
public Builder modelSchema(@NonNull ModelSchema modelSchema) {
231+
this.modelSchema = Objects.requireNonNull(modelSchema);
232+
return Builder.this;
233+
}
234+
225235
/**
226236
* Sets the {@link Model} Class and returns this builder.
227237
* @param modelClass the {@link Model} Class.
@@ -279,7 +289,6 @@ public Builder variable(@NonNull String key, String type, Object value) {
279289

280290
/**
281291
* Builds an {@link AppSyncGraphQLRequest}.
282-
*
283292
* @param <R> The type of data contained in the GraphQLResponse expected from this request.
284293
* @return the AppSyncGraphQLRequest
285294
* @throws AmplifyException if a ModelSchema cannot be created from the provided model class.
@@ -288,19 +297,29 @@ public <R> AppSyncGraphQLRequest<R> build() throws AmplifyException {
288297
Objects.requireNonNull(this.operation);
289298
Objects.requireNonNull(this.responseType);
290299

291-
if (modelClass != null) {
292-
// Derive modelSchema and selectionSet from modelClass.
300+
// TODO: if the modelClass is contained within the modelSchema,
301+
// why can't we just extract it from the ModelSchema, instead of
302+
// having it as an outside parameter?
303+
if (modelSchema == null) {
304+
if (modelClass == null) {
305+
throw new AmplifyException(
306+
"Both modelSchema and modelClass cannot be null",
307+
AmplifyException.TODO_RECOVERY_SUGGESTION
308+
);
309+
}
310+
// Derive modelSchema from modelClass if not available
293311
modelSchema = ModelSchema.fromModelClass(this.modelClass);
312+
}
313+
314+
// if this Builder was created via newBuilder(),
315+
// selectionSet will already be set, so we can continue on.
316+
if (selectionSet == null) {
294317
selectionSet = SelectionSet.builder()
318+
.modelSchema(this.modelSchema)
295319
.modelClass(this.modelClass)
296320
.operation(this.operation)
297321
.requestOptions(Objects.requireNonNull(this.requestOptions))
298322
.build();
299-
} else {
300-
// If modelClass is null, we can't derive modelSchema and selectionSet. However, if this Builder was
301-
// created via newBuilder(), those fields will already be set, so we can continue on.
302-
Objects.requireNonNull(modelSchema, "modelClass must not be null");
303-
Objects.requireNonNull(selectionSet, "modelClass must not be null");
304323
}
305324
return new AppSyncGraphQLRequest<>(this);
306325
}

aws-api-appsync/src/main/java/com/amplifyframework/api/aws/SelectionSet.java

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@
2525
import com.amplifyframework.core.model.AuthRule;
2626
import com.amplifyframework.core.model.AuthStrategy;
2727
import com.amplifyframework.core.model.Model;
28+
import com.amplifyframework.core.model.ModelAssociation;
29+
import com.amplifyframework.core.model.ModelField;
2830
import com.amplifyframework.core.model.ModelSchema;
31+
import com.amplifyframework.core.model.ModelSchemaRegistry;
2932
import com.amplifyframework.core.model.types.JavaFieldType;
33+
import com.amplifyframework.datastore.appsync.SerializedModel;
3034
import com.amplifyframework.util.Empty;
3135
import com.amplifyframework.util.FieldFinder;
3236
import com.amplifyframework.util.Wrap;
@@ -38,6 +42,7 @@
3842
import java.util.Collections;
3943
import java.util.HashSet;
4044
import java.util.List;
45+
import java.util.Map;
4146
import java.util.Objects;
4247
import java.util.Set;
4348

@@ -167,6 +172,7 @@ static final class Builder {
167172
private Class<? extends Model> modelClass;
168173
private Operation operation;
169174
private GraphQLRequestOptions requestOptions;
175+
private ModelSchema modelSchema;
170176

171177
Builder() { }
172178

@@ -175,6 +181,11 @@ public Builder modelClass(@NonNull Class<? extends Model> modelClass) {
175181
return Builder.this;
176182
}
177183

184+
public Builder modelSchema(@NonNull ModelSchema modelSchema) {
185+
this.modelSchema = Objects.requireNonNull(modelSchema);
186+
return Builder.this;
187+
}
188+
178189
public Builder operation(@NonNull Operation operation) {
179190
this.operation = Objects.requireNonNull(operation);
180191
return Builder.this;
@@ -191,9 +202,15 @@ public Builder requestOptions(@NonNull GraphQLRequestOptions requestOptions) {
191202
* @throws AmplifyException if a ModelSchema cannot be created from the provided model class.
192203
*/
193204
public SelectionSet build() throws AmplifyException {
194-
Objects.requireNonNull(this.modelClass);
205+
if (this.modelClass == null && this.modelSchema == null) {
206+
throw new AmplifyException("Both modelClass and modelSchema cannot be null",
207+
"Provide either a modelClass or a modelSchema to build the selection set");
208+
}
195209
Objects.requireNonNull(this.operation);
196-
SelectionSet node = new SelectionSet(null, getModelFields(modelClass, requestOptions.maxDepth()));
210+
SelectionSet node = new SelectionSet(null,
211+
SerializedModel.class == modelClass
212+
? getModelFields(modelSchema, requestOptions.maxDepth())
213+
: getModelFields(modelClass, requestOptions.maxDepth()));
197214
if (QueryType.LIST.equals(operation) || QueryType.SYNC.equals(operation)) {
198215
node = wrapPagination(node);
199216
}
@@ -222,6 +239,16 @@ private Set<SelectionSet> wrapPagination(Set<SelectionSet> nodes) {
222239
return paginatedSet;
223240
}
224241

242+
/**
243+
* Gets a selection set for the given class.
244+
* TODO: this is mostly duplicative of {@link #getModelFields(ModelSchema, int)}.
245+
* Long-term, we want to remove this current method and rely only on the ModelSchema-based
246+
* version.
247+
* @param clazz Class from which to build selection set
248+
* @param depth Number of children deep to explore
249+
* @return Selection Set
250+
* @throws AmplifyException On faiulre to build selection set
251+
*/
225252
@SuppressWarnings("unchecked") // Cast to Class<Model>
226253
private Set<SelectionSet> getModelFields(Class<? extends Model> clazz, int depth)
227254
throws AmplifyException {
@@ -320,5 +347,40 @@ static Class<?> getClassForField(Field field) {
320347
}
321348
return typeClass;
322349
}
350+
351+
private Set<SelectionSet> getModelFields(ModelSchema modelSchema, int depth) {
352+
if (depth < 0) {
353+
return new HashSet<>();
354+
}
355+
Set<SelectionSet> result = new HashSet<>();
356+
if (depth == 0 && LeafSerializationBehavior.JUST_ID.equals(requestOptions.leafSerializationBehavior())) {
357+
result.add(new SelectionSet("id"));
358+
return result;
359+
}
360+
for (Map.Entry<String, ModelField> entry : modelSchema.getFields().entrySet()) {
361+
String fieldName = entry.getKey();
362+
ModelAssociation association = modelSchema.getAssociations().get(fieldName);
363+
if (association != null) {
364+
if (depth >= 1) {
365+
String associatedModelName = association.getAssociatedType();
366+
ModelSchema associateModelSchema = ModelSchemaRegistry.instance()
367+
.getModelSchemaForModelClass(associatedModelName);
368+
Set<SelectionSet> fields;
369+
if (entry.getValue().isArray()) { // If modelField is an Array
370+
fields = wrapPagination(getModelFields(associateModelSchema, depth - 1));
371+
} else {
372+
fields = getModelFields(associateModelSchema, depth - 1);
373+
}
374+
result.add(new SelectionSet(fieldName, fields));
375+
}
376+
} else {
377+
result.add(new SelectionSet(fieldName));
378+
}
379+
}
380+
for (String fieldName : requestOptions.modelMetaFields()) {
381+
result.add(new SelectionSet(fieldName));
382+
}
383+
return result;
384+
}
323385
}
324386
}

aws-api-appsync/src/main/java/com/amplifyframework/core/model/types/JavaFieldType.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package com.amplifyframework.core.model.types;
1717

1818
import androidx.annotation.NonNull;
19+
import androidx.annotation.Nullable;
1920

2021
import com.amplifyframework.core.model.Model;
2122
import com.amplifyframework.core.model.temporal.Temporal;
@@ -97,9 +98,9 @@ public enum JavaFieldType {
9798
* @param javaFieldType the string representation of the field type.
9899
* @return the enumeration constant.
99100
*/
100-
public static JavaFieldType from(@NonNull Class<?> javaFieldType) {
101+
public static JavaFieldType from(@Nullable Class<?> javaFieldType) {
101102
for (final JavaFieldType type : JavaFieldType.values()) {
102-
if (javaFieldType.equals(type.javaFieldType)) {
103+
if (type.javaFieldType.equals(javaFieldType)) {
103104
return type;
104105
}
105106
}

0 commit comments

Comments
 (0)