Skip to content

support @include/@skip directives #23

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

Merged
merged 2 commits into from
Jan 22, 2020

Conversation

zimuliu
Copy link
Contributor

@zimuliu zimuliu commented Jan 16, 2020

Support these two directives defined in the latest GraphQL standards.

No need to compute the complexity if any of the following is found:

  • @include(if: false)
  • @skip(if: true)

@zimuliu zimuliu requested a review from ivome January 16, 2020 18:24
Copy link
Collaborator

@ivome ivome left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the PR! 👍 This looks good in general, I just found one minor thing that we should fix before merging (See comments).

@@ -183,6 +191,29 @@ export default class QueryComplexity {
(total: number, childNode: FieldNode | FragmentSpreadNode | InlineFragmentNode) => {
let nodeComplexity = 0;

let includeNode = true;
let skipNode = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need one variable to determine if the node should be skipped/included, this avoids contradictory (temporary) values...

Copy link
Contributor Author

@zimuliu zimuliu Jan 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two variables were created for a better alignment with the GraphQL standard:

Neither @Skip nor @include has precedence over the other. In the case that both the @Skip and @include directives are provided in on the same the field or fragment, it must be queried only if the @Skip condition is false and the @include condition is true. Stated conversely, the field or fragment must not be queried if either the @Skip condition is true or the @include condition is false.

from: http://spec.graphql.org/June2018/#sec--include

We can technically use a single variable, but it would be a bit harder to follow.

let includeNode = true;
let skipNode = false;

childNode.directives.forEach((directive: DirectiveNode) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case a server makes excessive use of directives it would iterate over all the directives, extract values, etc. regardless of whether it was already determined if we include or skip the field.

For example:

{
  field @skip(if: true) @otherDirective @otherDirective2 @etc
}

In this case, we could skip the evaluation of the last 3 directives. I'd use Array.find instead and find the directives that result in the exclusion of the field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skip and @include can only be used in queries/mutations from the client, and not in schema definitions on the server side. The chance of multiple directives on a query is really rare. Also, as the directives are not sorted, the big O complexity is the same for both forEach and find. If we use forEach, we just need to scan directives in one pass to get the job done.

Directives from the standard:

directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

@zimuliu zimuliu requested a review from ivome January 20, 2020 15:37
@zimuliu
Copy link
Contributor Author

zimuliu commented Jan 20, 2020

Thanks for reviewing. Responded in the comments to explain the decisions made. Please re-review.

@ivome
Copy link
Collaborator

ivome commented Jan 22, 2020

This makes sense now, thanks for the explanations.

@ivome ivome merged commit 75f5c4c into slicknode:master Jan 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants