-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Update deprecated reason if changed by schema transformer #3787
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| } | ||
|
|
||
| private List<GraphQLAppliedDirective> addDeprecatedDirectiveIfNeeded(GraphQLDirectiveContainer directiveContainer) { | ||
| private List<GraphQLAppliedDirective> addOrUpdateDeprecatedDirectiveIfNeeded(GraphQLDirectiveContainer directiveContainer) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reorganising because the method was getting too long
| return directives.stream().map(d -> { | ||
| if (isDeprecatedDirective(d)) { | ||
| // Don't include reason is deliberately replaced with NOT_SET, for example in Anonymizer | ||
| if (d.getArgument("reason").getArgumentValue() != InputValueWithState.NOT_SET) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very special case. The Anonymizer wipes out deprecated reasons with a special NOT_SET value, which is distinct from null. If this is spotted, we won't add back the deprecated reason.
Test Results 306 files 306 suites 46s ⏱️ Results for commit a54f7b9. |
| if (isDeprecatedDirective(d)) { | ||
| // Don't include reason is deliberately replaced with NOT_SET, for example in Anonymizer | ||
| if (d.getArgument("reason").getArgumentValue() != InputValueWithState.NOT_SET) { | ||
| return d.transform(builder -> builder.argument(newArg)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a subtle change in behaviour: it means the field's reason always takes precedence over the deprecated directive's reason
Do we want this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we do want this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SchemaGenerator (SDL) will generate the field def deprecation reason by default from the directives
graphql.schema.idl.SchemaGeneratorHelper#buildField
builder.deprecate(buildDeprecationReason(fieldDef.getDirectives()));
....
String buildDeprecationReason(List<Directive> directives) {
directives = Optional.ofNullable(directives).orElse(emptyList());
Optional<Directive> directive = directives.stream().filter(d -> "deprecated".equals(d.getName())).findFirst();
if (directive.isPresent()) {
Map<String, String> args = directive.get().getArguments().stream().collect(toMap(
Argument::getName, arg -> ((StringValue) arg.getValue()).getValue()
));
if (args.isEmpty()) {
return NO_LONGER_SUPPORTED; // default value from spec
} else {
// pre flight checks have ensured it's valid
return args.get("reason");
}
}
return null;
}
So the graphql.schema.GraphQLFieldDefinition#getDeprecationReason is the most important part of the deprecation bit.
|
ps in theory I think we still have a bug in introspection. imagine this
This is because But this PR does not have to address this. Its pretty edge case |
Yes agreed it's tricky because there's two places which both "seem" like the source of truth. It's not possible to guess which one is authoritative, for example imagine a wacky case where both the directive's reason and the field definition's reason change. I'd rather make one authoritative and always choose the field definition's reason rather than the directive version. Thanks for the speedy review! |
Fixes #3786
Background
With the schema transformer, it's possible to update the deprecated reason stored on a field definition.
@t2gran reported that the schema printer wasn't printing out the correct deprecated reason when it had been changed by a schema transformer. See #3786 and test in this gist: https://gist.github.com/t2gran/69b149357477870ba25e00375a2626a2. The bug was happening on fields in object types, interface types, and input types. I've recycled the gist object type test and added interface and input type cases.
The root cause was that the schema printer didn't re-check deprecated reason arguments if the deprecated directive already existed. Previously it (incorrectly) assumed that if the deprecated directive already existed, then the reason was fine. This PR fixes that.
I got nerd sniped 😄