Skip to content

Commit c1806ba

Browse files
author
Ludovic Motte
committed
EmbeddedId management
1 parent df38b86 commit c1806ba

File tree

5 files changed

+186
-105
lines changed

5 files changed

+186
-105
lines changed

graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java

Lines changed: 127 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ public class GraphQLJpaSchemaBuilder implements GraphQLSchemaBuilder {
9292

9393
private Map<Class<?>, GraphQLType> classCache = new HashMap<>();
9494
private Map<EntityType<?>, GraphQLObjectType> entityCache = new HashMap<>();
95-
private Map<EmbeddableType<?>, GraphQLObjectType> embeddableCache = new HashMap<>();
95+
private Map<EmbeddableType<?>, GraphQLObjectType> embeddableOutputCache = new HashMap<>();
96+
private Map<EmbeddableType<?>, GraphQLInputObjectType> embeddableInputCache = new HashMap<>();
9697

9798
private static final Logger log = LoggerFactory.getLogger(GraphQLJpaSchemaBuilder.class);
9899

@@ -289,13 +290,13 @@ private GraphQLInputType getWhereAttributeType(Attribute<?,?> attribute) {
289290
.field(GraphQLInputObjectField.newInputObjectField()
290291
.name(Criteria.EQ.name())
291292
.description("Equals criteria")
292-
.type((GraphQLInputType) getAttributeType(attribute))
293+
.type(getAttributeInputType(attribute))
293294
.build()
294295
)
295296
.field(GraphQLInputObjectField.newInputObjectField()
296297
.name(Criteria.NE.name())
297298
.description("Not Equals criteria")
298-
.type((GraphQLInputType) getAttributeType(attribute))
299+
.type(getAttributeInputType(attribute))
299300
.build()
300301
);
301302

@@ -304,25 +305,25 @@ private GraphQLInputType getWhereAttributeType(Attribute<?,?> attribute) {
304305
builder.field(GraphQLInputObjectField.newInputObjectField()
305306
.name(Criteria.LE.name())
306307
.description("Less then or Equals criteria")
307-
.type((GraphQLInputType) getAttributeType(attribute))
308+
.type(getAttributeInputType(attribute))
308309
.build()
309310
)
310311
.field(GraphQLInputObjectField.newInputObjectField()
311312
.name(Criteria.GE.name())
312313
.description("Greater or Equals criteria")
313-
.type((GraphQLInputType) getAttributeType(attribute))
314+
.type(getAttributeInputType(attribute))
314315
.build()
315316
)
316317
.field(GraphQLInputObjectField.newInputObjectField()
317318
.name(Criteria.GT.name())
318319
.description("Greater Then criteria")
319-
.type((GraphQLInputType) getAttributeType(attribute))
320+
.type(getAttributeInputType(attribute))
320321
.build()
321322
)
322323
.field(GraphQLInputObjectField.newInputObjectField()
323324
.name(Criteria.LT.name())
324325
.description("Less Then criteria")
325-
.type((GraphQLInputType) getAttributeType(attribute))
326+
.type(getAttributeInputType(attribute))
326327
.build()
327328
);
328329
}
@@ -331,25 +332,25 @@ private GraphQLInputType getWhereAttributeType(Attribute<?,?> attribute) {
331332
builder.field(GraphQLInputObjectField.newInputObjectField()
332333
.name(Criteria.LIKE.name())
333334
.description("Like criteria")
334-
.type((GraphQLInputType) getAttributeType(attribute))
335+
.type(getAttributeInputType(attribute))
335336
.build()
336337
)
337338
.field(GraphQLInputObjectField.newInputObjectField()
338339
.name(Criteria.CASE.name())
339340
.description("Case sensitive match criteria")
340-
.type((GraphQLInputType) getAttributeType(attribute))
341+
.type(getAttributeInputType(attribute))
341342
.build()
342343
)
343344
.field(GraphQLInputObjectField.newInputObjectField()
344345
.name(Criteria.STARTS.name())
345346
.description("Starts with criteria")
346-
.type((GraphQLInputType) getAttributeType(attribute))
347+
.type(getAttributeInputType(attribute))
347348
.build()
348349
)
349350
.field(GraphQLInputObjectField.newInputObjectField()
350351
.name(Criteria.ENDS.name())
351352
.description("Ends with criteria")
352-
.type((GraphQLInputType) getAttributeType(attribute))
353+
.type(getAttributeInputType(attribute))
353354
.build()
354355
);
355356
}
@@ -370,13 +371,13 @@ private GraphQLInputType getWhereAttributeType(Attribute<?,?> attribute) {
370371
.field(GraphQLInputObjectField.newInputObjectField()
371372
.name(Criteria.IN.name())
372373
.description("In criteria")
373-
.type(new GraphQLList(getAttributeType(attribute)))
374+
.type(new GraphQLList(getAttributeInputType(attribute)))
374375
.build()
375376
)
376377
.field(GraphQLInputObjectField.newInputObjectField()
377378
.name(Criteria.NIN.name())
378379
.description("Not In criteria")
379-
.type(new GraphQLList(getAttributeType(attribute)))
380+
.type(new GraphQLList(getAttributeInputType(attribute)))
380381
.build()
381382
);
382383

@@ -389,39 +390,52 @@ private GraphQLInputType getWhereAttributeType(Attribute<?,?> attribute) {
389390
}
390391

391392
private GraphQLArgument getArgument(Attribute<?,?> attribute) {
392-
GraphQLType type = getAttributeType(attribute);
393+
GraphQLInputType type = getAttributeInputType(attribute);
393394
String description = getSchemaDescription(attribute.getJavaMember());
394395

395-
if (type instanceof GraphQLInputType) {
396-
return GraphQLArgument.newArgument()
397-
.name(attribute.getName())
398-
.type((GraphQLInputType) type)
399-
.description(description)
400-
.build();
401-
}
402-
403-
throw new IllegalArgumentException("Attribute " + attribute + " cannot be mapped as an Input Argument");
396+
return GraphQLArgument.newArgument()
397+
.name(attribute.getName())
398+
.type((GraphQLInputType) type)
399+
.description(description)
400+
.build();
404401
}
405402

406-
private GraphQLObjectType getEmbeddableType(EmbeddableType<?> embeddableType) {
407-
if (embeddableCache.containsKey(embeddableType))
408-
return embeddableCache.get(embeddableType);
409-
410-
String embeddableTypeName = namingStrategy.singularize(embeddableType.getJavaType().getSimpleName())+"EmbeddableType";
411-
412-
GraphQLObjectType objectType = GraphQLObjectType.newObject()
413-
.name(embeddableTypeName)
414-
.description(getSchemaDescription( embeddableType.getJavaType()))
415-
.fields(embeddableType.getAttributes().stream()
416-
.filter(this::isNotIgnored)
417-
.map(this::getObjectField)
418-
.collect(Collectors.toList())
419-
)
420-
.build();
421-
422-
embeddableCache.putIfAbsent(embeddableType, objectType);
403+
private GraphQLType getEmbeddableType(EmbeddableType<?> embeddableType, boolean input) {
404+
if (input && embeddableInputCache.containsKey(embeddableType))
405+
return embeddableInputCache.get(embeddableType);
406+
407+
if (!input && embeddableOutputCache.containsKey(embeddableType))
408+
return embeddableOutputCache.get(embeddableType);
409+
String embeddableTypeName = namingStrategy.singularize(embeddableType.getJavaType().getSimpleName())+ (input ? "Input" : "") +"EmbeddableType";
410+
GraphQLType graphQLType=null;
411+
if (input) {
412+
graphQLType = GraphQLInputObjectType.newInputObject()
413+
.name(embeddableTypeName)
414+
.description(getSchemaDescription(embeddableType.getJavaType()))
415+
.fields(embeddableType.getAttributes().stream()
416+
.filter(this::isNotIgnored)
417+
.map(this::getInputObjectField)
418+
.collect(Collectors.toList())
419+
)
420+
.build();
421+
} else {
422+
graphQLType = GraphQLObjectType.newObject()
423+
.name(embeddableTypeName)
424+
.description(getSchemaDescription(embeddableType.getJavaType()))
425+
.fields(embeddableType.getAttributes().stream()
426+
.filter(this::isNotIgnored)
427+
.map(this::getObjectField)
428+
.collect(Collectors.toList())
429+
)
430+
.build();
431+
}
432+
if (input) {
433+
embeddableInputCache.putIfAbsent(embeddableType, (GraphQLInputObjectType) graphQLType);
434+
} else{
435+
embeddableOutputCache.putIfAbsent(embeddableType, (GraphQLObjectType) graphQLType);
436+
}
423437

424-
return objectType;
438+
return graphQLType;
425439
}
426440

427441

@@ -447,67 +461,92 @@ private GraphQLObjectType getObjectType(EntityType<?> entityType) {
447461

448462
@SuppressWarnings( { "rawtypes", "unchecked" } )
449463
private GraphQLFieldDefinition getObjectField(Attribute attribute) {
450-
GraphQLType type = getAttributeType(attribute);
451-
452-
if (type instanceof GraphQLOutputType) {
453-
List<GraphQLArgument> arguments = new ArrayList<>();
454-
DataFetcher dataFetcher = PropertyDataFetcher.fetching(attribute.getName());
455-
456-
// Only add the orderBy argument for basic attribute types
457-
if (attribute instanceof SingularAttribute
458-
&& attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC) {
459-
arguments.add(GraphQLArgument.newArgument()
460-
.name(ORDER_BY_PARAM_NAME)
461-
.description("Specifies field sort direction in the query results.")
462-
.type(orderByDirectionEnum)
463-
.build()
464-
);
465-
}
466-
467-
// Get the fields that can be queried on (i.e. Simple Types, no Sub-Objects)
468-
if (attribute instanceof SingularAttribute
469-
&& attribute.getPersistentAttributeType() != Attribute.PersistentAttributeType.BASIC) {
470-
ManagedType foreignType = (ManagedType) ((SingularAttribute) attribute).getType();
471-
472-
// TODO fix page count query
473-
arguments.add(getWhereArgument(foreignType));
474-
475-
} // Get Sub-Objects fields queries via DataFetcher
476-
else if (attribute instanceof PluralAttribute
477-
&& (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ONE_TO_MANY
478-
|| attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.MANY_TO_MANY)) {
479-
EntityType declaringType = (EntityType) ((PluralAttribute) attribute).getDeclaringType();
480-
EntityType elementType = (EntityType) ((PluralAttribute) attribute).getElementType();
481-
482-
arguments.add(getWhereArgument(elementType));
483-
dataFetcher = new GraphQLJpaOneToManyDataFetcher(entityManager, declaringType, (PluralAttribute) attribute);
484-
}
464+
GraphQLOutputType type = getAttributeOutputType(attribute);
465+
466+
List<GraphQLArgument> arguments = new ArrayList<>();
467+
DataFetcher dataFetcher = PropertyDataFetcher.fetching(attribute.getName());
468+
469+
// Only add the orderBy argument for basic attribute types
470+
if (attribute instanceof SingularAttribute
471+
&& attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC) {
472+
arguments.add(GraphQLArgument.newArgument()
473+
.name(ORDER_BY_PARAM_NAME)
474+
.description("Specifies field sort direction in the query results.")
475+
.type(orderByDirectionEnum)
476+
.build()
477+
);
478+
}
485479

486-
return GraphQLFieldDefinition.newFieldDefinition()
487-
.name(attribute.getName())
488-
.description(getSchemaDescription(attribute.getJavaMember()))
489-
.type((GraphQLOutputType) type)
490-
.dataFetcher(dataFetcher)
491-
.argument(arguments)
492-
.build();
480+
// Get the fields that can be queried on (i.e. Simple Types, no Sub-Objects)
481+
if (attribute instanceof SingularAttribute
482+
&& attribute.getPersistentAttributeType() != Attribute.PersistentAttributeType.BASIC) {
483+
ManagedType foreignType = (ManagedType) ((SingularAttribute) attribute).getType();
484+
485+
// TODO fix page count query
486+
arguments.add(getWhereArgument(foreignType));
487+
488+
} // Get Sub-Objects fields queries via DataFetcher
489+
else if (attribute instanceof PluralAttribute
490+
&& (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ONE_TO_MANY
491+
|| attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.MANY_TO_MANY)) {
492+
EntityType declaringType = (EntityType) ((PluralAttribute) attribute).getDeclaringType();
493+
EntityType elementType = (EntityType) ((PluralAttribute) attribute).getElementType();
494+
495+
arguments.add(getWhereArgument(elementType));
496+
dataFetcher = new GraphQLJpaOneToManyDataFetcher(entityManager, declaringType, (PluralAttribute) attribute);
493497
}
494498

495-
throw new IllegalArgumentException("Attribute " + attribute + " cannot be mapped as an Output Argument");
499+
return GraphQLFieldDefinition.newFieldDefinition()
500+
.name(attribute.getName())
501+
.description(getSchemaDescription(attribute.getJavaMember()))
502+
.type(type)
503+
.dataFetcher(dataFetcher)
504+
.argument(arguments)
505+
.build();
506+
}
507+
508+
@SuppressWarnings( { "rawtypes", "unchecked" } )
509+
private GraphQLInputObjectField getInputObjectField(Attribute attribute) {
510+
GraphQLInputType type = getAttributeInputType(attribute);
511+
512+
return GraphQLInputObjectField.newInputObjectField()
513+
.name(attribute.getName())
514+
.description(getSchemaDescription(attribute.getJavaMember()))
515+
.type(type)
516+
.build();
496517
}
497518

498519
private Stream<Attribute<?,?>> findBasicAttributes(Collection<Attribute<?,?>> attributes) {
499520
return attributes.stream().filter(it -> it.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC);
500521
}
501522

502523
@SuppressWarnings( "rawtypes" )
503-
private GraphQLType getAttributeType(Attribute<?,?> attribute) {
524+
private GraphQLInputType getAttributeInputType(Attribute<?,?> attribute) {
525+
try{
526+
return (GraphQLInputType) getAttributeType(attribute, true);
527+
} catch (ClassCastException e){
528+
throw new IllegalArgumentException("Attribute " + attribute + " cannot be mapped as an Input Argument");
529+
}
530+
}
531+
532+
@SuppressWarnings( "rawtypes" )
533+
private GraphQLOutputType getAttributeOutputType(Attribute<?,?> attribute) {
534+
try {
535+
return (GraphQLOutputType) getAttributeType(attribute, false);
536+
} catch (ClassCastException e){
537+
throw new IllegalArgumentException("Attribute " + attribute + " cannot be mapped as an Output Argument");
538+
}
539+
}
540+
541+
@SuppressWarnings( "rawtypes" )
542+
private GraphQLType getAttributeType(Attribute<?,?> attribute, boolean input) {
504543

505544
if (isBasic(attribute)) {
506545
return getGraphQLTypeFromJavaType(attribute.getJavaType());
507546
}
508547
else if (isEmbeddable(attribute)) {
509548
EmbeddableType embeddableType = (EmbeddableType) ((SingularAttribute) attribute).getType();
510-
return getEmbeddableType(embeddableType);
549+
return getEmbeddableType(embeddableType, input);
511550
}
512551
else if (isToMany(attribute)) {
513552
EntityType foreignType = (EntityType) ((PluralAttribute) attribute).getElementType();
@@ -557,7 +596,8 @@ protected final boolean isToOne(Attribute<?,?> attribute) {
557596

558597
protected final boolean isValidInput(Attribute<?,?> attribute) {
559598
return attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC ||
560-
attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ELEMENT_COLLECTION;
599+
attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ELEMENT_COLLECTION ||
600+
attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED;
561601
}
562602

563603
private String getSchemaDescription(Member member) {

graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSimpleDataFetcher.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@
2121
import javax.persistence.NoResultException;
2222
import javax.persistence.metamodel.EntityType;
2323

24+
import graphql.language.Argument;
2425
import graphql.language.Field;
26+
import graphql.language.ObjectValue;
2527
import graphql.schema.DataFetchingEnvironment;
2628

29+
import java.util.List;
30+
import java.util.stream.Collectors;
31+
import java.util.stream.Stream;
32+
2733
class GraphQLJpaSimpleDataFetcher extends QraphQLJpaBaseDataFetcher {
2834

2935
public GraphQLJpaSimpleDataFetcher(EntityManager entityManager, EntityType<?> entityType) {
@@ -32,11 +38,13 @@ public GraphQLJpaSimpleDataFetcher(EntityManager entityManager, EntityType<?> en
3238

3339
@Override
3440
public Object get(DataFetchingEnvironment environment) {
35-
36-
Field field = environment.getFields().iterator().next();
3741

42+
Field field = environment.getFields().iterator().next();
43+
3844
if(!field.getArguments().isEmpty()) {
3945

46+
flattenEmbeddedIdArguments(field);
47+
4048
try {
4149
// Create entity graph from selection
4250
EntityGraph<?> entityGraph = buildEntityGraph(field);
@@ -52,5 +60,24 @@ public Object get(DataFetchingEnvironment environment) {
5260
}
5361

5462
return null;
55-
}
63+
}
64+
65+
private void flattenEmbeddedIdArguments(Field field) {
66+
// manage object arguments (EmbeddedId)
67+
final List<Argument> argumentsWhereObjectsAreFlattened = field.getArguments()
68+
.stream()
69+
.flatMap(argument ->
70+
{
71+
if (!argument.getName().equals("where") && !argument.getName().equals("page") &&
72+
argument.getValue() instanceof ObjectValue) {
73+
return ((ObjectValue) argument.getValue()).getObjectFields()
74+
.stream()
75+
.map(objectField -> new Argument(argument.getName() + "." + objectField.getName(), objectField.getValue()));
76+
} else {
77+
return Stream.of(argument);
78+
}
79+
})
80+
.collect(Collectors.toList());
81+
field.setArguments(argumentsWhereObjectsAreFlattened);
82+
}
5683
}

0 commit comments

Comments
 (0)