Skip to content

Commit 75f5c4c

Browse files
authored
Merge pull request #23 from 500px/support-include-skip
support @include/@Skip directives
2 parents 47c4e49 + a974258 commit 75f5c4c

File tree

2 files changed

+118
-2
lines changed

2 files changed

+118
-2
lines changed

src/QueryComplexity.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@
44

55
import {
66
getArgumentValues,
7+
getDirectiveValues,
78
} from 'graphql/execution/values';
89

910
import {
1011
ValidationContext,
1112
FragmentDefinitionNode,
1213
OperationDefinitionNode,
14+
DirectiveNode,
1315
FieldNode,
1416
FragmentSpreadNode,
1517
InlineFragmentNode,
1618
assertCompositeType,
1719
GraphQLField, isCompositeType, GraphQLCompositeType, GraphQLFieldMap,
1820
GraphQLSchema, DocumentNode, TypeInfo,
19-
visit, visitWithTypeInfo
21+
visit, visitWithTypeInfo,
22+
GraphQLDirective,
2023
} from 'graphql';
2124
import {
2225
GraphQLUnionType,
@@ -102,6 +105,8 @@ export default class QueryComplexity {
102105
options: QueryComplexityOptions;
103106
OperationDefinition: Object;
104107
estimators: Array<ComplexityEstimator>;
108+
includeDirectiveDef: GraphQLDirective;
109+
skipDirectiveDef: GraphQLDirective;
105110

106111
constructor(
107112
context: ValidationContext,
@@ -115,6 +120,9 @@ export default class QueryComplexity {
115120
this.complexity = 0;
116121
this.options = options;
117122

123+
this.includeDirectiveDef = this.context.getSchema().getDirective('include');
124+
this.skipDirectiveDef = this.context.getSchema().getDirective('skip');
125+
118126
if (!options.estimators) {
119127
console.warn(
120128
'DEPRECATION WARNING: Estimators should be configured in the queryComplexity options.'
@@ -183,6 +191,29 @@ export default class QueryComplexity {
183191
(total: number, childNode: FieldNode | FragmentSpreadNode | InlineFragmentNode) => {
184192
let nodeComplexity = 0;
185193

194+
let includeNode = true;
195+
let skipNode = false;
196+
197+
childNode.directives.forEach((directive: DirectiveNode) => {
198+
const directiveName = directive.name.value;
199+
switch (directiveName) {
200+
case 'include': {
201+
const values = getDirectiveValues(this.includeDirectiveDef, childNode, this.options.variables || {});
202+
includeNode = values.if;
203+
break;
204+
}
205+
case 'skip': {
206+
const values = getDirectiveValues(this.skipDirectiveDef, childNode, this.options.variables || {});
207+
skipNode = values.if;
208+
break;
209+
}
210+
}
211+
});
212+
213+
if (!includeNode || skipNode) {
214+
return total;
215+
}
216+
186217
switch (childNode.kind) {
187218
case Kind.FIELD: {
188219
const field = fields[childNode.name.value];

src/__tests__/QueryComplexity-test.ts

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,91 @@ describe('QueryComplexity analysis', () => {
4141
expect(complexity).to.equal(1);
4242
});
4343

44+
it('should respect @include(if: false)', () => {
45+
const ast = parse(`
46+
query {
47+
variableScalar(count: 10) @include(if: false)
48+
}
49+
`);
50+
51+
const complexity = getComplexity({
52+
estimators: [
53+
simpleEstimator({defaultComplexity: 1})
54+
],
55+
schema,
56+
query: ast
57+
});
58+
expect(complexity).to.equal(0);
59+
});
60+
61+
it('should respect @include(if: true)', () => {
62+
const ast = parse(`
63+
query {
64+
variableScalar(count: 10) @include(if: true)
65+
}
66+
`);
67+
68+
const complexity = getComplexity({
69+
estimators: [
70+
simpleEstimator({defaultComplexity: 1})
71+
],
72+
schema,
73+
query: ast
74+
});
75+
expect(complexity).to.equal(1);
76+
});
77+
78+
it('should respect @skip(if: true)', () => {
79+
const ast = parse(`
80+
query {
81+
variableScalar(count: 10) @skip(if: true)
82+
}
83+
`);
84+
85+
const complexity = getComplexity({
86+
estimators: [
87+
simpleEstimator({defaultComplexity: 1})
88+
],
89+
schema,
90+
query: ast
91+
});
92+
expect(complexity).to.equal(0);
93+
});
94+
95+
it('should respect @skip(if: false)', () => {
96+
const ast = parse(`
97+
query {
98+
variableScalar(count: 10) @skip(if: false)
99+
}
100+
`);
101+
102+
const complexity = getComplexity({
103+
estimators: [
104+
simpleEstimator({defaultComplexity: 1})
105+
],
106+
schema,
107+
query: ast
108+
});
109+
expect(complexity).to.equal(1);
110+
});
111+
112+
it('should respect @skip(if: false) @include(if: true)', () => {
113+
const ast = parse(`
114+
query {
115+
variableScalar(count: 10) @skip(if: false) @include(if: true)
116+
}
117+
`);
118+
119+
const complexity = getComplexity({
120+
estimators: [
121+
simpleEstimator({defaultComplexity: 1})
122+
],
123+
schema,
124+
query: ast
125+
});
126+
expect(complexity).to.equal(1);
127+
});
128+
44129
it('should calculate complexity with variables', () => {
45130
const ast = parse(`
46131
query Q($count: Int) {
@@ -341,7 +426,7 @@ describe('QueryComplexity analysis', () => {
341426
});
342427
expect(Number.isNaN(complexity)).to.equal(true);
343428
});
344-
429+
345430
it('should skip complexity calculation by directiveEstimator when no astNode available on field', () => {
346431
const ast = parse(`
347432
query {

0 commit comments

Comments
 (0)