From 0ace267f370de14eede027bd4957f1bee1df5272 Mon Sep 17 00:00:00 2001 From: Adam Setch <> Date: Tue, 25 Aug 2020 16:13:43 -0400 Subject: [PATCH 1/4] Adding support for @Pattern validation contract against Lists --- .../standard/PatternConstraint.java | 41 ++++++++++++++----- .../standard/PatternConstraintTest.groovy | 2 + 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java b/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java index c4e4631..3783f41 100644 --- a/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java +++ b/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java @@ -4,16 +4,23 @@ import graphql.Scalars; import graphql.schema.GraphQLDirective; import graphql.schema.GraphQLInputType; +import graphql.schema.GraphQLList; +import graphql.schema.GraphQLType; import graphql.validation.constraints.AbstractDirectiveConstraint; import graphql.validation.constraints.Documentation; import graphql.validation.rules.ValidationEnvironment; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static graphql.schema.GraphQLTypeUtil.isList; +import static graphql.schema.GraphQLTypeUtil.isScalar; import static java.util.Collections.emptyList; public class PatternConstraint extends AbstractDirectiveConstraint { @@ -44,32 +51,44 @@ public Documentation getDocumentation() { @Override public boolean appliesToType(GraphQLInputType inputType) { return isOneOfTheseTypes(inputType, - Scalars.GraphQLString - ); + Scalars.GraphQLString) || isList(inputType); } @Override protected List runConstraint(ValidationEnvironment validationEnvironment) { Object validatedValue = validationEnvironment.getValidatedValue(); + if (validatedValue == null) { return emptyList(); } - String strValue = String.valueOf(validatedValue); - GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class); + List validatedValues; + + if (validatedValue instanceof List) { + validatedValues = (ArrayList)validatedValue; + } else { + validatedValues = Arrays.asList(validatedValue); + } + + for (Object value : validatedValues) { + String strValue = String.valueOf(value); - String patternArg = getStrArg(directive, "regexp"); - Pattern pattern = cachedPattern(patternArg); + GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class); - Matcher matcher = pattern.matcher(strValue); - if (!matcher.matches()) { - return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment, - "regexp", patternArg - )); + String patternArg = getStrArg(directive, "regexp"); + Pattern pattern = cachedPattern(patternArg); + + Matcher matcher = pattern.matcher(strValue); + if (!matcher.matches()) { + return mkError(validationEnvironment, directive, + mkMessageParams(validatedValue, validationEnvironment, "regexp", patternArg)); + } } return emptyList(); } + + private Pattern cachedPattern(String patternArg) { return SEEN_PATTERNS.computeIfAbsent(patternArg, Pattern::compile); } diff --git a/src/test/groovy/graphql/validation/constraints/standard/PatternConstraintTest.groovy b/src/test/groovy/graphql/validation/constraints/standard/PatternConstraintTest.groovy index 5291eea..d46d02d 100644 --- a/src/test/groovy/graphql/validation/constraints/standard/PatternConstraintTest.groovy +++ b/src/test/groovy/graphql/validation/constraints/standard/PatternConstraintTest.groovy @@ -22,6 +22,8 @@ class PatternConstraintTest extends BaseConstraintTestSupport { fieldDeclaration | argVal | expectedMessage 'field( arg : String @Pattern(regexp:"[A-Z]*") ) : ID' | "ABCd" | 'Pattern;path=/arg;val:ABCd;\t' 'field( arg : String @Pattern(regexp:"[A-Z]*") ) : ID' | "ABC" | '' + 'field( arg : [String] @Pattern(regexp:"[A-Z]*") ) : ID' | ["ABC"] | '' + 'field( arg : [String] @Pattern(regexp:"[A-Z]*") ) : ID' | ["ABC", "ABCd"] | 'Pattern;path=/arg;val:[ABC, ABCd];\t' // nulls are valid 'field( arg : String @Pattern(regexp:"[A-Z]*") ) : ID' | null | '' From 973e508917de3548a50e1fb4d68ceb397e582256 Mon Sep 17 00:00:00 2001 From: Adam Setch <> Date: Tue, 25 Aug 2020 21:36:05 -0400 Subject: [PATCH 2/4] Updating README.md description --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 90e8502..b959c29 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This library provides extended validation of fields and field arguments for [gra # Status This code is currently under construction. It is fairly complete in providing powerful validation -but as it has NOT be consumed by a production like project then its API usefulness has not been tested +but as it has NOT been consumed by a production like project then its API usefulness has not been tested and battle tested. But the project welcomes all feedback and input on code design and validation requirements. @@ -21,13 +21,13 @@ But the project welcomes all feedback and input on code design and validation re com.graphql-java graphql-java-extended-validation - 0.0.3 + 0.0.4 pom ``` ```groovy -compile 'com.graphql-java:graphql-java-extended-validation:0.0.3' +compile 'com.graphql-java:graphql-java-extended-validation:0.0.4' ``` Its currently available from JCenter repo and Maven central is pending. @@ -409,7 +409,7 @@ The String must match the specified regular expression, which follows the Java r - Example : `updateDriver( licencePlate : String @Patttern(regex : "[A-Z][A-Z][A-Z]-[0-9][0-9][0-9]") : DriverDetails` -- Applies to : `String` +- Applies to : `String`, `Lists` - SDL : `directive @Pattern(regexp : String! =".*", message : String = "graphql.validation.Pattern.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION` From e863c0109e05a42a3a65b2a4c810f9dad3b573eb Mon Sep 17 00:00:00 2001 From: Adam Setch <> Date: Tue, 25 Aug 2020 21:42:42 -0400 Subject: [PATCH 3/4] Tidy up isList check --- .../validation/constraints/standard/PatternConstraint.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java b/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java index 3783f41..62f8589 100644 --- a/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java +++ b/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java @@ -57,6 +57,7 @@ public boolean appliesToType(GraphQLInputType inputType) { @Override protected List runConstraint(ValidationEnvironment validationEnvironment) { Object validatedValue = validationEnvironment.getValidatedValue(); + GraphQLInputType argumentType = validationEnvironment.getValidatedType(); if (validatedValue == null) { return emptyList(); @@ -64,7 +65,7 @@ protected List runConstraint(ValidationEnvironment validationEnvir List validatedValues; - if (validatedValue instanceof List) { + if (isList(argumentType)) { validatedValues = (ArrayList)validatedValue; } else { validatedValues = Arrays.asList(validatedValue); From 692990ff6140fdb185d2c762f36bf031040c53b3 Mon Sep 17 00:00:00 2001 From: Adam Setch <> Date: Wed, 26 Aug 2020 06:13:00 -0400 Subject: [PATCH 4/4] Updating documentation --- .../validation/constraints/standard/PatternConstraint.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java b/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java index 62f8589..3889caf 100644 --- a/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java +++ b/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java @@ -38,9 +38,9 @@ public Documentation getDocumentation() { .description("The String must match the specified regular expression, which follows the Java regular expression conventions.") - .example("updateDriver( licencePlate : String @Patttern(regex : \"[A-Z][A-Z][A-Z]-[0-9][0-9][0-9]\") : DriverDetails") + .example("updateDriver( licencePlate : String @Pattern(regexp : \"[A-Z][A-Z][A-Z]-[0-9][0-9][0-9]\") : DriverDetails") - .applicableTypeNames(Scalars.GraphQLString.getName()) + .applicableTypeNames(Scalars.GraphQLString.getName(), "Lists") .directiveSDL("directive @Pattern(regexp : String! =\".*\", message : String = \"%s\") " + "on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",