Skip to content

Commit 8d594cb

Browse files
authored
Merge pull request #66 from oslabs-beta/em/lists-variables-nesting-refactoring
Refactored Type Weights Object to better handle lists and nesting when calculating query complexity
2 parents 3dc4c6c + e984e15 commit 8d594cb

File tree

7 files changed

+420
-290
lines changed

7 files changed

+420
-290
lines changed

.vscode/launch.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
// Hover to view descriptions of existing attributes.
44
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
55
"version": "0.2.0",
6-
"configurations": [{
6+
"configurations": [
7+
8+
{
79
"type": "node",
810
"request": "launch",
911
"name": "Jest Tests",

src/@types/buildTypeWeights.d.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
export interface Field {
2+
resolveTo?: string;
3+
weight?: FieldWeight;
4+
}
15
export interface Fields {
2-
[index: string]: FieldWeight;
6+
[index: string]: Field;
37
}
4-
export type WeightFunction = (args: ArgumentNode[]) => number;
8+
export type WeightFunction = (args: ArgumentNode[], variables, selectionsCost: number) => number;
59
export type FieldWeight = number | WeightFunction;
610
export interface Type {
711
readonly weight: number;
@@ -17,7 +21,13 @@ export interface TypeWeightConfig {
1721
scalar?: number;
1822
connection?: number;
1923
}
20-
24+
export interface TypeWeightSet {
25+
mutation: number;
26+
query: number;
27+
object: number;
28+
scalar: number;
29+
connection: number;
30+
}
2131
type Variables = {
2232
[index: string]: readonly unknown;
2333
};

src/analysis/ASTnodefunctions.ts

Lines changed: 29 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,9 @@ import {
66
DefinitionNode,
77
Kind,
88
SelectionNode,
9-
ArgumentNode,
9+
isConstValueNode,
1010
} from 'graphql';
1111
import { FieldWeight, TypeWeightObject, Variables } from '../@types/buildTypeWeights';
12-
13-
// TODO: handle variables and arguments
14-
// ! this is not functional
15-
const getArgObj = (args: ArgumentNode[]): { [index: string]: any } => {
16-
const argObj: { [index: string]: any } = {};
17-
for (let i = 0; i < args.length; i + 1) {
18-
const node = args[i];
19-
if (args[i].value.kind !== Kind.VARIABLE) {
20-
if (args[i].value.kind === Kind.INT) {
21-
// FIXME: this does not work
22-
argObj[args[i].name.value] = args[i].value;
23-
}
24-
}
25-
}
26-
return argObj;
27-
};
2812
/**
2913
* The AST node functions call each other following the nested structure below
3014
* Each function handles a specific GraphQL AST node type
@@ -52,34 +36,39 @@ export function fieldNode(
5236
parentName: string
5337
): number {
5438
let complexity = 0;
55-
// console.log('fieldNode', node, parentName);
56-
// check if the field name is in the type weight object.
57-
if (node.name.value.toLocaleLowerCase() in typeWeights) {
58-
// if it is, than the field is an object type, add itss type weight to the total
59-
complexity += typeWeights[node.name.value].weight;
39+
// 'resolvedTypeName' is the name of the Schema Type that this field resolves to
40+
const resolvedTypeName =
41+
node.name.value in typeWeights
42+
? node.name.value
43+
: typeWeights[parentName].fields[node.name.value]?.resolveTo || null;
44+
45+
if (resolvedTypeName) {
46+
// field resolves to an object or a list with possible selections
47+
let selectionsCost = 0;
48+
let calculatedWeight = 0;
49+
const weightFunction = typeWeights[parentName]?.fields[node.name.value]?.weight;
50+
6051
// call the function to handle selection set node with selectionSet property if it is not undefined
6152
if (node.selectionSet) {
62-
complexity += selectionSetNode(
53+
selectionsCost += selectionSetNode(
6354
node.selectionSet,
6455
typeWeights,
6556
variables,
66-
node.name.value
57+
resolvedTypeName
6758
);
6859
}
60+
// if there are arguments and this is a list, call the 'weightFunction' to get the weight of this field. otherwise the weight is static and can be accessed through the typeWeights object
61+
if (node.arguments && typeof weightFunction === 'function') {
62+
calculatedWeight += weightFunction([...node.arguments], variables, selectionsCost);
63+
} else {
64+
calculatedWeight += typeWeights[resolvedTypeName].weight + selectionsCost;
65+
}
66+
complexity += calculatedWeight;
6967
} else {
70-
// otherwise the field is a scalar or a list.
71-
const fieldWeight: FieldWeight = typeWeights[parentName].fields[node.name.value];
72-
if (typeof fieldWeight === 'number') {
73-
// if the feild weight is a number, add the number to the total complexity
74-
complexity += fieldWeight;
75-
} else if (node.arguments) {
76-
// BUG: This code is reached when fieldWeight is undefined, which could result from an invalid query or this type
77-
// missing from the typeWeight object. If left unhandled an error is thrown
78-
// otherwise the the feild weight is a list, invoke the function with variables
79-
// TODO: calculate the complexity for lists with arguments and varibales
80-
// ! this is not functional
81-
// iterate through the arguments to build the object to
82-
complexity += fieldWeight([...node.arguments]);
68+
// field is a scalar and 'weight' is a number
69+
const { weight } = typeWeights[parentName].fields[node.name.value];
70+
if (typeof weight === 'number') {
71+
complexity += weight;
8372
}
8473
}
8574
return complexity;
@@ -92,7 +81,6 @@ export function selectionNode(
9281
parentName: string
9382
): number {
9483
let complexity = 0;
95-
// console.log('selectionNode', node, parentName);
9684
// check the kind property against the set of selection nodes that are possible
9785
if (node.kind === Kind.FIELD) {
9886
// call the function that handle field nodes
@@ -101,7 +89,6 @@ export function selectionNode(
10189
// TODO: add checks for Kind.FRAGMENT_SPREAD and Kind.INLINE_FRAGMENT here
10290
return complexity;
10391
}
104-
10592
export function selectionSetNode(
10693
node: SelectionSetNode,
10794
typeWeights: TypeWeightObject,
@@ -130,14 +117,16 @@ export function definitionNode(
130117
if (node.operation.toLocaleLowerCase() in typeWeights) {
131118
// if it is, it is an object type, add it's type weight to the total
132119
complexity += typeWeights[node.operation].weight;
120+
// console.log(`the weight of ${node.operation} is ${complexity}`);
133121
// call the function to handle selection set node with selectionSet property if it is not undefined
134-
if (node.selectionSet)
122+
if (node.selectionSet) {
135123
complexity += selectionSetNode(
136124
node.selectionSet,
137125
typeWeights,
138126
variables,
139127
node.operation
140128
);
129+
}
141130
}
142131
}
143132
// TODO: add checks for Kind.FRAGMENT_DEFINITION here (there are other type definition nodes that i think we can ignore. see ast.d.ts in 'graphql')

0 commit comments

Comments
 (0)