diff --git a/README.md b/README.md index 504ae12..fa649d5 100644 --- a/README.md +++ b/README.md @@ -389,7 +389,7 @@ The String must contain at least one non-whitespace character, according to Java - Example : `updateAccident( accidentNotes : String @NotBlank) : DriverDetails` -- Applies to : `String`, `ID` +- Applies to : `String`, `ID`, `Lists` - SDL : `directive @NotBlank(message : String = "graphql.validation.NotBlank.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION` diff --git a/src/main/java/graphql/validation/constraints/AbstractDirectiveConstraint.java b/src/main/java/graphql/validation/constraints/AbstractDirectiveConstraint.java index 698d589..d268689 100644 --- a/src/main/java/graphql/validation/constraints/AbstractDirectiveConstraint.java +++ b/src/main/java/graphql/validation/constraints/AbstractDirectiveConstraint.java @@ -307,6 +307,18 @@ protected List mkError(ValidationEnvironment validationEnvironment return singletonList(error); } + /** + * Return true if the type is a String or ID or List type, regardless of non null ness + * + * @param inputType the type to check + * + * @return true if one of the above + */ + protected boolean isStringOrIDOrList(GraphQLInputType inputType) { + return isStringOrID(inputType) || + isList(inputType); + } + /** * Return true if the type is a String or ID or List type or {@link graphql.schema.GraphQLInputObjectType}, regardless of non null ness * diff --git a/src/main/java/graphql/validation/constraints/standard/NotBlankRule.java b/src/main/java/graphql/validation/constraints/standard/NotBlankRule.java index d63da23..0a89894 100644 --- a/src/main/java/graphql/validation/constraints/standard/NotBlankRule.java +++ b/src/main/java/graphql/validation/constraints/standard/NotBlankRule.java @@ -1,5 +1,7 @@ package graphql.validation.constraints.standard; +import static graphql.schema.GraphQLTypeUtil.isList; + import graphql.GraphQLError; import graphql.Scalars; import graphql.schema.GraphQLDirective; @@ -8,6 +10,7 @@ import graphql.validation.constraints.Documentation; import graphql.validation.rules.ValidationEnvironment; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -26,7 +29,7 @@ public Documentation getDocumentation() { .example("updateAccident( accidentNotes : String @NotBlank) : DriverDetails") - .applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName()) + .applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName(), "Lists") .directiveSDL("directive @NotBlank(message : String = \"%s\") " + "on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION", @@ -36,19 +39,38 @@ public Documentation getDocumentation() { @Override public boolean appliesToType(GraphQLInputType inputType) { - return isStringOrID(inputType); + return isStringOrIDOrList(inputType); } @Override protected List runConstraint(ValidationEnvironment validationEnvironment) { Object validatedValue = validationEnvironment.getValidatedValue(); + GraphQLInputType argumentType = validationEnvironment.getValidatedType(); GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class); - if (validatedValue == null || isBlank(validatedValue)) { + if (validatedValue == null) { + return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment)); + } + + List validatedValues; + + if (isList(argumentType)) { + validatedValues = (List)validatedValue; + } else { + validatedValues = Arrays.asList(validatedValue); + } + + if (validatedValues.size() <= 0) { return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment)); + } + for (Object value : validatedValues) { + if (isBlank(value)) { + return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment)); + } } + return Collections.emptyList(); } diff --git a/src/test/groovy/graphql/validation/constraints/standard/NoEmptyBlankConstraintTest.groovy b/src/test/groovy/graphql/validation/constraints/standard/NoEmptyBlankConstraintTest.groovy index e5a82cc..0dd29d2 100644 --- a/src/test/groovy/graphql/validation/constraints/standard/NoEmptyBlankConstraintTest.groovy +++ b/src/test/groovy/graphql/validation/constraints/standard/NoEmptyBlankConstraintTest.groovy @@ -31,6 +31,18 @@ class NoEmptyBlankConstraintTest extends BaseConstraintTestSupport { 'field( arg : ID @NotBlank ) : ID' | "" | 'NotBlank;path=/arg;val:;\t' 'field( arg : ID @NotBlank ) : ID' | "\t\n\r X" | '' 'field( arg : ID @NotBlank ) : ID' | null | '' + + // Lists + 'field( arg : [String] @NotBlank ) : ID' | [] | 'NotBlank;path=/arg;val:[];\t' + 'field( arg : [String] @NotBlank ) : ID' | null | '' + 'field( arg : [String] @NotBlank ) : ID' | ["x"] | '' + 'field( arg : [String] @NotBlank ) : ID' | ["x", "y"] | '' + 'field( arg : [String] @NotBlank ) : ID' | ["x", " "] | 'NotBlank;path=/arg;val:[x, ];\t' + 'field( arg : [ID] @NotBlank ) : ID' | [] | 'NotBlank;path=/arg;val:[];\t' + 'field( arg : [ID] @NotBlank ) : ID' | null | '' + 'field( arg : [ID] @NotBlank ) : ID' | ["x"] | '' + 'field( arg : [ID] @NotBlank ) : ID' | ["x", "y"] | '' + 'field( arg : [String] @NotBlank ) : ID' | ["x", " "] | 'NotBlank;path=/arg;val:[x, ];\t' } @Unroll