Skip to content

Commit bdd4b65

Browse files
authored
Merge pull request #17 from BeeHiveJava/master
Calculating query complexity
2 parents 2804b7e + f9e30bf commit bdd4b65

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-1
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,33 @@ type ComplexityEstimatorArgs = {
104104
type ComplexityEstimator = (options: ComplexityEstimatorArgs) => number | void;
105105
```
106106

107+
## Calculate query complexity
108+
```javascript
109+
import { calculateComplexity, simpleEstimator } from "graphql-query-complexity/dist/QueryComplexity";
110+
import { parse } from 'graphql';
111+
112+
// In a resolver the schema can be retrieved from the info argument.
113+
const schema = undefined;
114+
const query = parse(`
115+
query {
116+
some_value
117+
some_list(count: 10) {
118+
some_child_value
119+
}
120+
}
121+
`);
122+
123+
const complexity = calculateComplexity({
124+
estimators: [
125+
simpleEstimator({defaultComplexity: 1})
126+
],
127+
schema,
128+
query
129+
});
130+
131+
console.log(complexity); // Output: 3
132+
```
133+
107134
## Usage with express-graphql
108135

109136
To use the query complexity analysis validation rule with express-graphql, use something like the

src/QueryComplexity.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
InlineFragmentNode,
1616
assertCompositeType,
1717
GraphQLField, isCompositeType, GraphQLCompositeType, GraphQLFieldMap,
18+
GraphQLSchema, DocumentNode, TypeInfo,
19+
visit, visitWithTypeInfo
1820
} from 'graphql';
1921
import {
2022
GraphQLUnionType,
@@ -74,6 +76,26 @@ function queryComplexityMessage(max: number, actual: number): string {
7476
);
7577
}
7678

79+
export function calculateComplexity(options: {
80+
estimators: ComplexityEstimator[],
81+
schema: GraphQLSchema,
82+
query: DocumentNode,
83+
variables?: Object
84+
}): number {
85+
const typeInfo = new TypeInfo(options.schema);
86+
87+
const context = new ValidationContext(options.schema, options.query, typeInfo);
88+
const visitor = new QueryComplexity(context, {
89+
// Maximum complexity does not matter since we're only interested in the calculated complexity.
90+
maximumComplexity: Infinity,
91+
estimators: options.estimators,
92+
variables: options.variables
93+
});
94+
95+
visit(options.query, visitWithTypeInfo(typeInfo, visitor));
96+
return visitor.complexity;
97+
}
98+
7799
export default class QueryComplexity {
78100
context: ValidationContext;
79101
complexity: number;

src/__tests__/QueryComplexity-test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {expect} from 'chai';
1414

1515
import schema from './fixtures/schema';
1616

17-
import ComplexityVisitor from '../QueryComplexity';
17+
import ComplexityVisitor, {calculateComplexity} from '../QueryComplexity';
1818
import {
1919
simpleEstimator,
2020
fieldConfigEstimator,
@@ -23,6 +23,23 @@ import {
2323
describe('QueryComplexity analysis', () => {
2424
const typeInfo = new TypeInfo(schema);
2525

26+
it('should calculate complexity', () => {
27+
const ast = parse(`
28+
query {
29+
variableScalar(count: 10)
30+
}
31+
`);
32+
33+
const complexity = calculateComplexity({
34+
estimators: [
35+
simpleEstimator({defaultComplexity: 1})
36+
],
37+
schema,
38+
query: ast
39+
});
40+
expect(complexity).to.equal(1);
41+
});
42+
2643
it('should not allow negative cost', () => {
2744
const ast = parse(`
2845
query {

0 commit comments

Comments
 (0)