Skip to content

Commit a276925

Browse files
committed
Can now know what context (field / arg / inputype) is being validated
1 parent 49149ba commit a276925

File tree

1 file changed

+57
-36
lines changed

1 file changed

+57
-36
lines changed

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

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import java.util.Map;
3232

3333
import static graphql.schema.GraphQLTypeUtil.isList;
34+
import static graphql.validation.rules.ValidationEnvironment.ValidatedElement.FIELD;
35+
import static graphql.validation.rules.ValidationEnvironment.ValidatedElement.INPUT_OBJECT_FIELD;
3436
import static java.util.Collections.singletonList;
3537

3638
@SuppressWarnings("UnnecessaryLocalVariable")
@@ -85,48 +87,55 @@ public boolean appliesTo(GraphQLArgument argument, GraphQLFieldDefinition fieldD
8587
return suitable;
8688
}
8789

90+
/**
91+
* A derived class will be called to indicate whether this input type applies to the constraint
92+
*
93+
* @param inputType the input type
94+
*
95+
* @return true if the constraint can handle that type
96+
*/
8897
abstract protected boolean appliesToType(GraphQLInputType inputType);
8998

99+
/**
100+
* This is called to perform the constraint validation
101+
*
102+
* @param validationEnvironment the validation environment
103+
*
104+
* @return a list of errors or an empty one if there are no errors
105+
*/
90106
abstract protected List<GraphQLError> runConstraint(ValidationEnvironment validationEnvironment);
91107

92108

93109
@SuppressWarnings("unchecked")
94110
@Override
95111
public List<GraphQLError> runValidation(ValidationEnvironment validationEnvironment) {
96112

113+
// output fields are special
114+
if (validationEnvironment.getValidatedElement() == FIELD) {
115+
return runFieldValidationImpl(validationEnvironment);
116+
}
117+
97118
GraphQLArgument argument = validationEnvironment.getArgument();
98119
Object validatedValue = validationEnvironment.getValidatedValue();
99-
List<GraphQLDirective> directives = argument.getDirectives();
120+
List<GraphQLDirective> directives = argument == null ? Collections.emptyList() : argument.getDirectives();
100121

101122
//
102123
// all the directives validation code does NOT care for NULL ness since the graphql engine covers that.
103124
// eg a @NonNull validation directive makes no sense in graphql like it might in Java
104125
//
105-
GraphQLInputType inputType = Util.unwrapNonNull(validationEnvironment.getFieldOrArgumentType());
106-
validationEnvironment = validationEnvironment.transform(b -> b.fieldOrArgumentType(inputType));
126+
GraphQLInputType inputType = Util.unwrapNonNull(validationEnvironment.getValidatedType());
127+
validationEnvironment = validationEnvironment.transform(b -> b.validatedType(inputType));
107128

108129
return runValidationImpl(validationEnvironment, inputType, validatedValue, directives);
109130
}
110131

132+
private List<GraphQLError> runFieldValidationImpl(ValidationEnvironment validationEnvironment) {
133+
return runConstraintOnDirectives(validationEnvironment, validationEnvironment.getFieldDefinition().getDirectives());
134+
}
135+
111136
@SuppressWarnings("unchecked")
112137
private List<GraphQLError> runValidationImpl(ValidationEnvironment validationEnvironment, GraphQLInputType inputType, Object validatedValue, List<GraphQLDirective> directives) {
113-
List<GraphQLError> errors = new ArrayList<>();
114-
// run them in a stable order
115-
directives = Util.sort(directives, GraphQLDirective::getName);
116-
for (GraphQLDirective directive : directives) {
117-
// we get called for arguments and input field types which can have multiple directive constraints on them and hence no just for this one
118-
boolean isOurDirective = directive.getName().equals(this.getName());
119-
if (!isOurDirective) {
120-
continue;
121-
}
122-
123-
validationEnvironment = validationEnvironment.transform(b -> b.context(GraphQLDirective.class, directive));
124-
//
125-
// now run the directive rule with this directive instance
126-
List<GraphQLError> ruleErrors = this.runConstraint(validationEnvironment);
127-
errors.addAll(ruleErrors);
128-
}
129-
138+
List<GraphQLError> errors = runConstraintOnDirectives(validationEnvironment, directives);
130139
if (validatedValue == null) {
131140
return errors;
132141
}
@@ -151,6 +160,26 @@ private List<GraphQLError> runValidationImpl(ValidationEnvironment validationEnv
151160
return errors;
152161
}
153162

163+
private List<GraphQLError> runConstraintOnDirectives(ValidationEnvironment validationEnvironment, List<GraphQLDirective> directives) {
164+
List<GraphQLError> errors = new ArrayList<>();
165+
directives = Util.sort(directives, GraphQLDirective::getName);
166+
167+
for (GraphQLDirective directive : directives) {
168+
// we get called for arguments and input field and field types which can have multiple directive constraints on them and hence no just for this one
169+
boolean isOurDirective = directive.getName().equals(this.getName());
170+
if (!isOurDirective) {
171+
continue;
172+
}
173+
174+
validationEnvironment = validationEnvironment.transform(b -> b.context(GraphQLDirective.class, directive));
175+
//
176+
// now run the directive rule with this directive instance
177+
List<GraphQLError> ruleErrors = this.runConstraint(validationEnvironment);
178+
errors.addAll(ruleErrors);
179+
}
180+
return errors;
181+
}
182+
154183
private List<GraphQLError> walkObjectArg(ValidationEnvironment validationEnvironment, GraphQLInputObjectType argumentType, Map<String, Object> objectMap) {
155184
List<GraphQLError> errors = new ArrayList<>();
156185

@@ -165,12 +194,13 @@ private List<GraphQLError> walkObjectArg(ValidationEnvironment validationEnviron
165194
continue;
166195
}
167196

168-
ExecutionPath fieldOrArgPath = validationEnvironment.getFieldOrArgumentPath().segment(inputField.getName());
197+
ExecutionPath newPath = validationEnvironment.getValidatedPath().segment(inputField.getName());
169198

170199
ValidationEnvironment newValidationEnvironment = validationEnvironment.transform(builder -> builder
171-
.fieldOrArgumentPath(fieldOrArgPath)
200+
.validatedPath(newPath)
172201
.validatedValue(validatedValue)
173-
.fieldOrArgumentType(fieldType)
202+
.validatedType(fieldType)
203+
.validatedElement(INPUT_OBJECT_FIELD)
174204
);
175205

176206
List<GraphQLError> ruleErrors = runValidationImpl(newValidationEnvironment, fieldType, validatedValue, directives);
@@ -192,12 +222,12 @@ private List<GraphQLError> walkListArg(ValidationEnvironment validationEnvironme
192222
int ix = 0;
193223
for (Object value : objectList) {
194224

195-
ExecutionPath fieldOrArgPath = validationEnvironment.getFieldOrArgumentPath().segment(ix);
225+
ExecutionPath newPath = validationEnvironment.getValidatedPath().segment(ix);
196226

197227
ValidationEnvironment newValidationEnvironment = validationEnvironment.transform(builder -> builder
198-
.fieldOrArgumentPath(fieldOrArgPath)
228+
.validatedPath(newPath)
199229
.validatedValue(value)
200-
.fieldOrArgumentType(listItemType)
230+
.validatedType(listItemType)
201231
);
202232

203233
List<GraphQLError> ruleErrors = runValidationImpl(newValidationEnvironment, listItemType, value, directives);
@@ -331,7 +361,7 @@ protected Map<String, Object> mkMessageParams(Object validatedValue, ValidationE
331361
Map<String, Object> params = new LinkedHashMap<>();
332362
params.put("validatedValue", validatedValue);
333363
params.put("constraint", getName());
334-
params.put("path", mkFieldOrArgPath(validationEnvironment));
364+
params.put("path", validationEnvironment.getValidatedPath());
335365

336366
params.putAll(mkMap(args));
337367
return params;
@@ -357,15 +387,6 @@ protected Map<String, Object> mkMap(Object... args) {
357387
return params;
358388
}
359389

360-
361-
private Object mkFieldOrArgPath(ValidationEnvironment validationEnvironment) {
362-
ExecutionPath executionPath = validationEnvironment.getExecutionPath();
363-
ExecutionPath fieldOrArgumentPath = validationEnvironment.getFieldOrArgumentPath();
364-
365-
executionPath = Util.concatPaths(executionPath, fieldOrArgumentPath);
366-
return executionPath == null ? "/" : executionPath.toString();
367-
}
368-
369390
/**
370391
* Creates a new {@link graphql.GraphQLError}
371392
*

0 commit comments

Comments
 (0)