Skip to content

Commit 5eedc2f

Browse files
setchybbakerman
andauthored
Adding support for ID scalar type to Pattern, NotEmpty, NotBlank and Size (#24)
* Adding support for ID scalar type to Pattern, NotEmpty, NotBlank and Size constraints as per #21 * Update README.md (cherry picked from commit 9d6efff) * Update README.md tweaks (cherry picked from commit d8ba27b) Co-authored-by: Brad Baker <[email protected]>
1 parent 00eddb4 commit 5eedc2f

File tree

9 files changed

+66
-33
lines changed

9 files changed

+66
-33
lines changed

README.md

+7-12
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,8 @@
99
This library provides extended validation of fields and field arguments for [graphql-java](https://github.com/graphql-java/graphql-java)
1010

1111

12-
# Status
12+
# Using
1313

14-
This code is currently under construction. It is fairly complete in providing powerful validation
15-
but as it has NOT been consumed by a production like project then its API usefulness has not been tested
16-
and battle tested.
17-
18-
But the project welcomes all feedback and input on code design and validation requirements.
1914

2015
```xml
2116
<dependency>
@@ -37,7 +32,7 @@ compile 'com.graphql-java:graphql-java-extended-validation:14.0.1'
3732
> use 14.0.1 or above for graphql-java 14.x and above
3833
3934

40-
Its currently available from JCenter repo and Maven central is pending.
35+
Its currently available from JCenter repo and Maven central.
4136

4237

4338
# SDL @Directive constraints
@@ -390,7 +385,7 @@ The String must contain at least one non-whitespace character, according to Java
390385

391386
- Example : `updateAccident( accidentNotes : String @NotBlank) : DriverDetails`
392387

393-
- Applies to : `String`
388+
- Applies to : `String`, `ID`
394389

395390
- SDL : `directive @NotBlank(message : String = "graphql.validation.NotBlank.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
396391

@@ -403,7 +398,7 @@ The element must have a non zero size.
403398

404399
- Example : `updateAccident( accidentNotes : [Notes]! @NotEmpty) : DriverDetails`
405400

406-
- Applies to : `String`, `Lists`, `Input Objects`
401+
- Applies to : `String`, `ID`, `Lists`, `Input Objects`
407402

408403
- SDL : `directive @NotEmpty(message : String = "graphql.validation.NotEmpty.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
409404

@@ -414,9 +409,9 @@ The element must have a non zero size.
414409

415410
The String must match the specified regular expression, which follows the Java regular expression conventions.
416411

417-
- Example : `updateDriver( licencePlate : String @Patttern(regex : "[A-Z][A-Z][A-Z]-[0-9][0-9][0-9]") : DriverDetails`
412+
- Example : `updateDriver( licencePlate : String @Pattern(regexp : "[A-Z][A-Z][A-Z]-[0-9][0-9][0-9]") : DriverDetails`
418413

419-
- Applies to : `String`, `Lists`
414+
- Applies to : `String`, `ID`, `Lists`
420415

421416
- SDL : `directive @Pattern(regexp : String! =".*", message : String = "graphql.validation.Pattern.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
422417

@@ -468,7 +463,7 @@ The element size must be between the specified `min` and `max` boundaries (inclu
468463

469464
- Example : `updateDrivingNotes( drivingNote : String @Size( min : 1000, max : 100000)) : DriverDetails`
470465

471-
- Applies to : `String`, `Lists`, `Input Objects`
466+
- Applies to : `String`, `ID`, `Lists`, `Input Objects`
472467

473468
- SDL : `directive @Size(min : Int = 0, max : Int = 2147483647, message : String = "graphql.validation.Size.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
474469

src/main/java/graphql/validation/constraints/AbstractDirectiveConstraint.java

+19-7
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ private List<GraphQLError> runConstraintOnDirectives(ValidationEnvironment valid
160160
* @param inputType the type to check
161161
* @param scalarTypes the array of scalar types
162162
*
163-
* @return true ifits oneof them
163+
* @return true if its one of them
164164
*/
165165
protected boolean isOneOfTheseTypes(GraphQLInputType inputType, GraphQLScalarType... scalarTypes) {
166166
GraphQLInputType type = Util.unwrapNonNull(inputType);
@@ -303,19 +303,31 @@ protected List<GraphQLError> mkError(ValidationEnvironment validationEnvironment
303303
}
304304

305305
/**
306-
* Return true if the type is a String or List type or {@link graphql.schema.GraphQLInputObjectType}, regardless of non null ness
306+
* Return true if the type is a String or ID or List type or {@link graphql.schema.GraphQLInputObjectType}, regardless of non null ness
307307
*
308308
* @param inputType the type to check
309309
*
310310
* @return true if one of the above
311311
*/
312-
protected boolean isStringOrListOrMap(GraphQLInputType inputType) {
312+
protected boolean isStringOrIDOrListOrMap(GraphQLInputType inputType) {
313313
GraphQLInputType unwrappedType = Util.unwrapOneAndAllNonNull(inputType);
314-
return Scalars.GraphQLString.equals(unwrappedType) ||
314+
return isStringOrID(inputType) ||
315315
isList(inputType) ||
316316
(unwrappedType instanceof GraphQLInputObjectType);
317317
}
318318

319+
/**
320+
* Return true if the type is a String or ID
321+
*
322+
* @param inputType the type to check
323+
*
324+
* @return true if one of the above
325+
*/
326+
protected boolean isStringOrID(GraphQLInputType inputType) {
327+
GraphQLInputType unwrappedType = Util.unwrapNonNull(inputType);
328+
return Scalars.GraphQLString.equals(unwrappedType) || Scalars.GraphQLID.equals(unwrappedType);
329+
}
330+
319331
/**
320332
* Casts the object as a Map with an assertion of it is not one
321333
*
@@ -373,18 +385,18 @@ protected boolean asBoolean(Object value) {
373385
}
374386

375387
/**
376-
* Returns the length of a String of the size of a list or size of a Map
388+
* Returns the length of a String, ID, size of a list or size of a Map
377389
*
378390
* @param inputType the input type
379391
* @param value the value
380392
*
381393
* @return the length of a String or Map or List
382394
*/
383-
protected int getStringOrObjectOrMapLength(GraphQLInputType inputType, Object value) {
395+
protected int getStringOrIDOrObjectOrMapLength(GraphQLInputType inputType, Object value) {
384396
int valLen;
385397
if (value == null) {
386398
valLen = 0;
387-
} else if (Scalars.GraphQLString.equals(Util.unwrapNonNull(inputType))) {
399+
} else if (isStringOrID(inputType)) {
388400
valLen = String.valueOf(value).length();
389401
} else if (isList(inputType)) {
390402
valLen = getListLength(value);

src/main/java/graphql/validation/constraints/standard/NotBlankRule.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public Documentation getDocumentation() {
2626

2727
.example("updateAccident( accidentNotes : String @NotBlank) : DriverDetails")
2828

29-
.applicableTypeNames(Scalars.GraphQLString.getName())
29+
.applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName())
3030

3131
.directiveSDL("directive @NotBlank(message : String = \"%s\") " +
3232
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
@@ -36,7 +36,7 @@ public Documentation getDocumentation() {
3636

3737
@Override
3838
public boolean appliesToType(GraphQLInputType inputType) {
39-
return isOneOfTheseTypes(inputType, Scalars.GraphQLString);
39+
return isStringOrID(inputType);
4040
}
4141

4242
@Override

src/main/java/graphql/validation/constraints/standard/NotEmptyRule.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import graphql.validation.constraints.AbstractDirectiveConstraint;
88
import graphql.validation.constraints.Documentation;
99
import graphql.validation.rules.ValidationEnvironment;
10-
1110
import java.util.Collections;
1211
import java.util.List;
1312

@@ -26,7 +25,7 @@ public Documentation getDocumentation() {
2625

2726
.example("updateAccident( accidentNotes : [Notes]! @NotEmpty) : DriverDetails")
2827

29-
.applicableTypeNames(Scalars.GraphQLString.getName(), "Lists", "Input Objects")
28+
.applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName(), "Lists", "Input Objects")
3029

3130
.directiveSDL("directive @NotEmpty(message : String = \"%s\") " +
3231
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
@@ -36,7 +35,7 @@ public Documentation getDocumentation() {
3635

3736
@Override
3837
public boolean appliesToType(GraphQLInputType inputType) {
39-
return isStringOrListOrMap(inputType);
38+
return isStringOrIDOrListOrMap(inputType);
4039
}
4140

4241
@Override
@@ -45,7 +44,7 @@ protected List<GraphQLError> runConstraint(ValidationEnvironment validationEnvir
4544
GraphQLInputType argumentType = validationEnvironment.getValidatedType();
4645

4746
GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class);
48-
int size = getStringOrObjectOrMapLength(argumentType, validatedValue);
47+
int size = getStringOrIDOrObjectOrMapLength(argumentType, validatedValue);
4948

5049
if (size <= 0) {
5150
return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment,

src/main/java/graphql/validation/constraints/standard/PatternConstraint.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public Documentation getDocumentation() {
3535

3636
.example("updateDriver( licencePlate : String @Pattern(regexp : \"[A-Z][A-Z][A-Z]-[0-9][0-9][0-9]\") : DriverDetails")
3737

38-
.applicableTypeNames(Scalars.GraphQLString.getName(), "Lists")
38+
.applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName(), "Lists")
3939

4040
.directiveSDL("directive @Pattern(regexp : String! =\".*\", message : String = \"%s\") " +
4141
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
@@ -45,8 +45,7 @@ public Documentation getDocumentation() {
4545

4646
@Override
4747
public boolean appliesToType(GraphQLInputType inputType) {
48-
return isOneOfTheseTypes(inputType,
49-
Scalars.GraphQLString) || isList(inputType);
48+
return isStringOrID(inputType) || isList(inputType);
5049
}
5150

5251
@Override

src/main/java/graphql/validation/constraints/standard/SizeConstraint.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public Documentation getDocumentation() {
2828

2929
.example("updateDrivingNotes( drivingNote : String @Size( min : 1000, max : 100000)) : DriverDetails")
3030

31-
.applicableTypeNames(Scalars.GraphQLString.getName(), "Lists", "Input Objects")
31+
.applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName(), "Lists", "Input Objects")
3232

3333
.directiveSDL("directive @Size(min : Int = 0, max : Int = %d, message : String = \"%s\") " +
3434
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
@@ -39,7 +39,7 @@ Integer.MAX_VALUE, getMessageTemplate())
3939

4040
@Override
4141
public boolean appliesToType(GraphQLInputType inputType) {
42-
return isStringOrListOrMap(inputType);
42+
return isStringOrIDOrListOrMap(inputType);
4343
}
4444

4545
@Override
@@ -52,7 +52,7 @@ protected List<GraphQLError> runConstraint(ValidationEnvironment validationEnvir
5252
int max = getIntArg(directive, "max");
5353

5454

55-
int size = getStringOrObjectOrMapLength(argType, validatedValue);
55+
int size = getStringOrIDOrObjectOrMapLength(argType, validatedValue);
5656

5757
if (size < min) {
5858
return mkError(validationEnvironment, directive, mkParams(validatedValue, validationEnvironment, min, max, size));

src/test/groovy/graphql/validation/constraints/standard/NoEmptyBlankConstraintTest.groovy

+17-2
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,17 @@ class NoEmptyBlankConstraintTest extends BaseConstraintTestSupport {
2020
where:
2121

2222
fieldDeclaration | argVal | expectedMessage
23+
// strings
2324
'field( arg : String @NotBlank ) : ID' | "\t\n\r " | 'NotBlank;path=/arg;val:\t\n\r ;\t'
2425
'field( arg : String @NotBlank ) : ID' | "" | 'NotBlank;path=/arg;val:;\t'
2526
'field( arg : String @NotBlank ) : ID' | "\t\n\r X" | ''
26-
27-
// nulls are INVALID
2827
'field( arg : String @NotBlank ) : ID' | null | 'NotBlank;path=/arg;val:null;\t'
28+
29+
// IDs
30+
'field( arg : ID @NotBlank ) : ID' | "\t\n\r " | 'NotBlank;path=/arg;val:\t\n\r ;\t'
31+
'field( arg : ID @NotBlank ) : ID' | "" | 'NotBlank;path=/arg;val:;\t'
32+
'field( arg : ID @NotBlank ) : ID' | "\t\n\r X" | ''
33+
'field( arg : ID @NotBlank ) : ID' | null | 'NotBlank;path=/arg;val:null;\t'
2934
}
3035

3136
@Unroll
@@ -47,6 +52,13 @@ class NoEmptyBlankConstraintTest extends BaseConstraintTestSupport {
4752
'field( arg : String @NotEmpty ) : ID' | "\t\n\r" | ''
4853
'field( arg : String @NotEmpty ) : ID' | "ABC" | ''
4954

55+
// IDs
56+
'field( arg : ID @NotEmpty ) : ID' | "" | 'NotEmpty;path=/arg;val:;\t'
57+
'field( arg : ID @NotEmpty ) : ID' | null | 'NotEmpty;path=/arg;val:null;\t'
58+
'field( arg : ID @NotEmpty ) : ID' | "\t\n\r" | ''
59+
'field( arg : ID @NotEmpty ) : ID' | "ABC" | ''
60+
61+
5062
// objects
5163
'field( arg : InputObject @NotEmpty ) : ID' | [:] | 'NotEmpty;path=/arg;val:[:];\t'
5264
'field( arg : InputObject @NotEmpty ) : ID' | null | 'NotEmpty;path=/arg;val:null;\t'
@@ -56,6 +68,9 @@ class NoEmptyBlankConstraintTest extends BaseConstraintTestSupport {
5668
'field( arg : [String] @NotEmpty ) : ID' | [] | 'NotEmpty;path=/arg;val:[];\t'
5769
'field( arg : [String] @NotEmpty ) : ID' | null | 'NotEmpty;path=/arg;val:null;\t'
5870
'field( arg : [String] @NotEmpty ) : ID' | ["x"] | ''
71+
'field( arg : [ID] @NotEmpty ) : ID' | [] | 'NotEmpty;path=/arg;val:[];\t'
72+
'field( arg : [ID] @NotEmpty ) : ID' | null | 'NotEmpty;path=/arg;val:null;\t'
73+
'field( arg : [ID] @NotEmpty ) : ID' | ["x"] | ''
5974

6075
}
6176

src/test/groovy/graphql/validation/constraints/standard/PatternConstraintTest.groovy

+4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ class PatternConstraintTest extends BaseConstraintTestSupport {
2222
fieldDeclaration | argVal | expectedMessage
2323
'field( arg : String @Pattern(regexp:"[A-Z]*") ) : ID' | "ABCd" | 'Pattern;path=/arg;val:ABCd;\t'
2424
'field( arg : String @Pattern(regexp:"[A-Z]*") ) : ID' | "ABC" | ''
25+
'field( arg : ID @Pattern(regexp:"[A-Z]*") ) : ID' | "ABCd" | 'Pattern;path=/arg;val:ABCd;\t'
26+
'field( arg : ID @Pattern(regexp:"[A-Z]*") ) : ID' | "ABC" | ''
2527
'field( arg : [String] @Pattern(regexp:"[A-Z]*") ) : ID' | ["ABC"] | ''
2628
'field( arg : [String] @Pattern(regexp:"[A-Z]*") ) : ID' | ["ABC", "ABCd"] | 'Pattern;path=/arg;val:[ABC, ABCd];\t'
29+
'field( arg : [ID] @Pattern(regexp:"[A-Z]*") ) : ID' | ["ABC"] | ''
30+
'field( arg : [ID] @Pattern(regexp:"[A-Z]*") ) : ID' | ["ABC", "ABCd"] | 'Pattern;path=/arg;val:[ABC, ABCd];\t'
2731

2832
// nulls are valid
2933
'field( arg : String @Pattern(regexp:"[A-Z]*") ) : ID' | null | ''

src/test/groovy/graphql/validation/constraints/standard/SizeConstraintTest.groovy

+9
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,20 @@ class SizeConstraintTest extends BaseConstraintTestSupport {
2020
where:
2121

2222
fieldDeclaration | argVal | expectedMessage
23+
// strings
2324
"field( arg : String @Size(max : 10) ) : ID" | "1234567891011" | "Size;path=/arg;val:1234567891011;\t"
2425
"field( arg : String @Size(max : 100) ) : ID" | "1234567891011" | ""
2526
"field( arg : String @Size(max : 10, min : 5) ) : ID" | "123" | "Size;path=/arg;val:123;\t"
2627

2728
'field( arg : String @Size(min : 5, message : "custom") ) : ID' | "123" | "custom;path=/arg;val:123;\t"
2829
"field( arg : String @Size(min : 5) ) : ID" | null | "Size;path=/arg;val:null;\t"
30+
31+
//IDs
32+
"field( arg : ID @Size(max : 10) ) : ID" | "1234567891011" | "Size;path=/arg;val:1234567891011;\t"
33+
"field( arg : ID @Size(max : 100) ) : ID" | "1234567891011" | ""
34+
"field( arg : ID @Size(max : 10, min : 5) ) : ID" | "123" | "Size;path=/arg;val:123;\t"
35+
36+
'field( arg : ID @Size(min : 5, message : "custom") ) : ID' | "123" | "custom;path=/arg;val:123;\t"
37+
"field( arg : ID @Size(min : 5) ) : ID" | null | "Size;path=/arg;val:null;\t"
2938
}
3039
}

0 commit comments

Comments
 (0)