1919import static graphql .introspection .Introspection .TypeMetaFieldDef ;
2020import static graphql .introspection .Introspection .TypeNameMetaFieldDef ;
2121
22+ import java .util .AbstractMap .SimpleEntry ;
2223import java .util .ArrayList ;
2324import java .util .Arrays ;
2425import java .util .Collection ;
3031import java .util .NoSuchElementException ;
3132import java .util .Optional ;
3233import java .util .stream .Collectors ;
34+ import java .util .stream .IntStream ;
3335import java .util .stream .Stream ;
3436
3537import javax .persistence .EntityGraph ;
@@ -363,21 +365,157 @@ protected Predicate getArgumentPredicate(CriteriaBuilder cb, From<?,?> path,
363365
364366 whereValue .getObjectFields ().stream ()
365367 .filter (it -> Logical .names ().contains (it .getName ()))
366- .map (it -> getArgumentPredicate (cb , path ,
367- argumentEnvironment (environment , argument .getName ()),
368- new Argument (it .getName (), it .getValue ())))
368+ .map (it -> {
369+ Map <String , Object > arguments = getFieldArguments (environment , it , argument );
370+
371+ if (it .getValue () instanceof ArrayValue ) {
372+ return getArrayArgumentPredicate (cb , path ,
373+ argumentEnvironment (environment , arguments ),
374+ new Argument (it .getName (), it .getValue ()));
375+ }
376+
377+ return getArgumentPredicate (cb , path ,
378+ argumentEnvironment (environment , arguments ),
379+ new Argument (it .getName (), it .getValue ()));
380+ })
369381 .forEach (predicates ::add );
370382
371- whereValue .getObjectFields ().stream ()
372- .filter (it -> !Logical .names ().contains (it .getName ()))
373- .map (it -> getFieldPredicate (it .getName (), cb , path , it ,
374- argumentEnvironment (environment , argument .getName ()),
375- new Argument (it .getName (), it .getValue ())))
376- .filter (predicate -> predicate != null )
377- .forEach (predicates ::add );
383+ whereValue .getObjectFields ()
384+ .stream ()
385+ .filter (it -> !Logical .names ().contains (it .getName ()))
386+ .map (it -> {
387+ Map <String , Object > args = getFieldArguments (environment , it , argument );
388+ Argument arg = new Argument (it .getName (), it .getValue ());
389+
390+ if (isEntityType (environment )) {
391+ Attribute <?,?> attribute = getAttribute (environment , arg );
392+
393+ if (attribute .isAssociation ()) {
394+ GraphQLFieldDefinition fieldDefinition = getFieldDef (environment .getGraphQLSchema (),
395+ this .getObjectType (environment ),
396+ new Field (it .getName ()));
397+ boolean isOptional = false ;
398+
399+ return getArgumentPredicate (cb , reuseJoin (path , it .getName (), isOptional ),
400+ wherePredicateEnvironment (environment , fieldDefinition , args ),
401+ arg );
402+ }
403+ }
404+
405+ return getFieldPredicate (it .getName (),
406+ cb ,
407+ path ,
408+ it ,
409+ argumentEnvironment (environment , args ),
410+ arg );
411+ })
412+ .filter (predicate -> predicate != null )
413+ .forEach (predicates ::add );
378414
379415 return getCompoundPredicate (cb , predicates , logical );
380416 }
417+
418+ protected Predicate getArrayArgumentPredicate (CriteriaBuilder cb ,
419+ From <?, ?> path ,
420+ DataFetchingEnvironment environment ,
421+ Argument argument ) {
422+ ArrayValue whereValue = getValue (argument );
423+
424+ if (whereValue .getValues ().isEmpty ())
425+ return cb .disjunction ();
426+
427+ Logical logical = extractLogical (argument );
428+
429+ List <Predicate > predicates = new ArrayList <>();
430+
431+ List <Map <String ,Object >> arguments = environment .getArgument (logical .name ());
432+ List <ObjectValue > values = whereValue .getValues ()
433+ .stream ()
434+ .map (ObjectValue .class ::cast ).collect (Collectors .toList ());
435+
436+ List <SimpleEntry <ObjectValue , Map <String , Object >>> tuples =
437+ IntStream .range (0 , values .size ())
438+ .mapToObj (i -> new SimpleEntry <ObjectValue , Map <String , Object >>(values .get (i ),
439+ arguments .get (i )))
440+ .collect (Collectors .toList ());
441+
442+ tuples .stream ()
443+ .flatMap (e -> e .getKey ()
444+ .getObjectFields ()
445+ .stream ()
446+ .filter (it -> Logical .names ().contains (it .getName ()))
447+ .map (it -> {
448+ Map <String , Object > args = e .getValue ();
449+ Argument arg = new Argument (it .getName (), it .getValue ());
450+
451+ if (ArrayValue .class .isInstance (it .getValue ())) {
452+ return getArrayArgumentPredicate (cb ,
453+ path ,
454+ argumentEnvironment (environment , args ),
455+ arg );
456+ }
457+
458+ return getArgumentPredicate (cb ,
459+ path ,
460+ argumentEnvironment (environment , args ),
461+ arg );
462+
463+ }))
464+ .forEach (predicates ::add );
465+
466+ tuples .stream ()
467+ .flatMap (e -> e .getKey ()
468+ .getObjectFields ()
469+ .stream ()
470+ .filter (it -> !Logical .names ().contains (it .getName ()))
471+ .map (it -> {
472+ Map <String , Object > args = e .getValue ();
473+ Argument arg = new Argument (it .getName (), it .getValue ());
474+
475+ if (isEntityType (environment )) {
476+ Attribute <?,?> attribute = getAttribute (environment , arg );
477+
478+ if (attribute .isAssociation ()) {
479+ GraphQLFieldDefinition fieldDefinition = getFieldDef (environment .getGraphQLSchema (),
480+ this .getObjectType (environment ),
481+ new Field (it .getName ()));
482+ boolean isOptional = false ;
483+
484+ return getArgumentPredicate (cb , reuseJoin (path , it .getName (), isOptional ),
485+ wherePredicateEnvironment (environment , fieldDefinition , args ),
486+ arg );
487+ }
488+ }
489+
490+ return getFieldPredicate (it .getName (),
491+ cb ,
492+ path ,
493+ it ,
494+ argumentEnvironment (environment , args ),
495+ arg );
496+ }))
497+ .filter (predicate -> predicate != null )
498+ .forEach (predicates ::add );
499+
500+ return getCompoundPredicate (cb , predicates , logical );
501+ }
502+
503+ private Map <String , Object > getFieldArguments (DataFetchingEnvironment environment , ObjectField field , Argument argument ) {
504+ Map <String , Object > arguments ;
505+
506+ if (environment .getArgument (argument .getName ()) instanceof Collection ) {
507+ Collection <Map <String ,Object >> list = environment .getArgument (argument .getName ());
508+
509+ arguments = list .stream ()
510+ .filter (args -> args .get (field .getName ()) != null )
511+ .findFirst ()
512+ .orElse (list .stream ().findFirst ().get ());
513+ } else {
514+ arguments = environment .getArgument (argument .getName ());
515+ }
516+
517+ return arguments ;
518+ }
381519
382520 private Logical extractLogical (Argument argument ) {
383521 return Optional .of (argument .getName ())
@@ -386,6 +524,38 @@ private Logical extractLogical(Argument argument) {
386524 .orElse (Logical .AND );
387525 }
388526
527+ private Predicate getArrayFieldPredicate (String fieldName ,
528+ CriteriaBuilder cb ,
529+ From <?, ?> path ,
530+ ObjectField objectField ,
531+ DataFetchingEnvironment environment ,
532+ Argument argument ) {
533+ ArrayValue value = ArrayValue .class .cast (objectField .getValue ());
534+
535+ Logical logical = extractLogical (argument );
536+
537+ List <Predicate > predicates = new ArrayList <>();
538+
539+ value .getValues ()
540+ .stream ()
541+ .map (ObjectValue .class ::cast )
542+ .flatMap (it -> it .getObjectFields ().stream ())
543+ .map (it -> {
544+ Map <String , Object > args = getFieldArguments (environment , it , argument );
545+ Argument arg = new Argument (it .getName (), it .getValue ());
546+
547+ return getFieldPredicate (it .getName (),
548+ cb ,
549+ path ,
550+ it ,
551+ argumentEnvironment (environment , args ),
552+ arg );
553+ })
554+ .forEach (predicates ::add );
555+
556+ return getCompoundPredicate (cb , predicates , logical );
557+ }
558+
389559 private Predicate getFieldPredicate (String fieldName , CriteriaBuilder cb , From <?,?> path , ObjectField objectField , DataFetchingEnvironment environment , Argument argument ) {
390560 ObjectValue expressionValue ;
391561
@@ -404,10 +574,20 @@ private Predicate getFieldPredicate(String fieldName, CriteriaBuilder cb, From<?
404574 // Let's parse logical expressions, i.e. AND, OR
405575 expressionValue .getObjectFields ().stream ()
406576 .filter (it -> Logical .names ().contains (it .getName ()))
407- .map (it -> getFieldPredicate (fieldName , cb , path , it ,
408- argumentEnvironment (environment , argument .getName ()),
409- new Argument (it .getName (), it .getValue ()))
410- )
577+ .map (it -> {
578+ Map <String , Object > args = getFieldArguments (environment , it , argument );
579+ Argument arg = new Argument (it .getName (), it .getValue ());
580+
581+ if (it .getValue () instanceof ArrayValue ) {
582+ return getArrayFieldPredicate (fieldName , cb , path , it ,
583+ argumentEnvironment (environment , args ),
584+ arg );
585+ }
586+
587+ return getFieldPredicate (fieldName , cb , path , it ,
588+ argumentEnvironment (environment , args ),
589+ arg );
590+ })
411591 .forEach (predicates ::add );
412592
413593 // Let's parse relation criteria expressions if present, i.e. books, author, etc.
@@ -418,20 +598,21 @@ private Predicate getFieldPredicate(String fieldName, CriteriaBuilder cb, From<?
418598 GraphQLFieldDefinition fieldDefinition = getFieldDef (environment .getGraphQLSchema (),
419599 this .getObjectType (environment ),
420600 new Field (fieldName ));
421- Map <String , Object > arguments = new LinkedHashMap <>();
601+ Map <String , Object > args = new LinkedHashMap <>();
602+ Argument arg = new Argument (logical .name (), expressionValue );
422603 boolean isOptional = false ;
423604
424605 if (Logical .names ().contains (argument .getName ())) {
425- arguments .put (logical .name (), environment .getArgument (argument .getName ()));
606+ args .put (logical .name (), environment .getArgument (argument .getName ()));
426607 } else {
427- arguments .put (logical .name (), environment .getArgument (fieldName ));
608+ args .put (logical .name (), environment .getArgument (fieldName ));
428609
429610 isOptional = isOptionalAttribute (getAttribute (environment , argument ));
430611 }
431612
432613 return getArgumentPredicate (cb , reuseJoin (path , fieldName , isOptional ),
433- wherePredicateEnvironment (environment , fieldDefinition , arguments ),
434- new Argument ( logical . name (), expressionValue ) );
614+ wherePredicateEnvironment (environment , fieldDefinition , args ),
615+ arg );
435616 }
436617
437618 // Let's parse simple Criteria expressions, i.e. EQ, LIKE, etc.
@@ -441,7 +622,7 @@ private Predicate getFieldPredicate(String fieldName, CriteriaBuilder cb, From<?
441622 .stream ()
442623 .filter (it -> Criteria .names ().contains (it .getName ()))
443624 .map (it -> getPredicateFilter (new ObjectField (fieldName , it .getValue ()),
444- argumentEnvironment (environment , argument . getName () ),
625+ argumentEnvironment (environment , argument ),
445626 new Argument (it .getName (), it .getValue ())))
446627 .sorted ()
447628 .map (it -> pb .getPredicate (path , path .get (it .getField ()), it ))
@@ -483,9 +664,17 @@ private PredicateFilter getPredicateFilter(ObjectField objectField, DataFetching
483664 return new PredicateFilter (objectField .getName (), filterValue , options );
484665 }
485666
486- protected final DataFetchingEnvironment argumentEnvironment (DataFetchingEnvironment environment , String argumentName ) {
667+ protected final DataFetchingEnvironment argumentEnvironment (DataFetchingEnvironment environment , Map < String , Object > arguments ) {
487668 return DataFetchingEnvironmentBuilder .newDataFetchingEnvironment (environment )
488- .arguments (environment .getArgument (argumentName ))
669+ .arguments (arguments )
670+ .build ();
671+ }
672+
673+ protected final DataFetchingEnvironment argumentEnvironment (DataFetchingEnvironment environment , Argument argument ) {
674+ Map <String , Object > arguments = environment .getArgument (argument .getName ());
675+
676+ return DataFetchingEnvironmentBuilder .newDataFetchingEnvironment (environment )
677+ .arguments (arguments )
489678 .build ();
490679 }
491680
@@ -687,6 +876,13 @@ private EntityType<?> getEntityType(GraphQLObjectType objectType) {
687876 .findFirst ()
688877 .get ();
689878 }
879+
880+ private boolean isEntityType (DataFetchingEnvironment environment ) {
881+ GraphQLObjectType objectType = getObjectType (environment );
882+ return entityManager .getMetamodel ()
883+ .getEntities ().stream ()
884+ .anyMatch (it -> it .getName ().equals (objectType .getName ()));
885+ }
690886
691887 /**
692888 * Resolve GraphQL object type from Argument output type.
0 commit comments