2525import com .amplifyframework .core .model .AuthRule ;
2626import com .amplifyframework .core .model .AuthStrategy ;
2727import com .amplifyframework .core .model .Model ;
28+ import com .amplifyframework .core .model .ModelAssociation ;
29+ import com .amplifyframework .core .model .ModelField ;
2830import com .amplifyframework .core .model .ModelSchema ;
31+ import com .amplifyframework .core .model .ModelSchemaRegistry ;
2932import com .amplifyframework .core .model .types .JavaFieldType ;
33+ import com .amplifyframework .datastore .appsync .SerializedModel ;
3034import com .amplifyframework .util .Empty ;
3135import com .amplifyframework .util .FieldFinder ;
3236import com .amplifyframework .util .Wrap ;
3842import java .util .Collections ;
3943import java .util .HashSet ;
4044import java .util .List ;
45+ import java .util .Map ;
4146import java .util .Objects ;
4247import 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}
0 commit comments