Skip to content

Commit 06cb52c

Browse files
Restructure arguments to calculate function
1 parent ce21964 commit 06cb52c

File tree

1 file changed

+88
-88
lines changed

1 file changed

+88
-88
lines changed

calculate.js

Lines changed: 88 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ module.exports = {queryCalculator, produceResult};
1717
* @private
1818
*/
1919

20-
var _ = require('lodash');
21-
var deleteKey = require('key-del');
22-
var {
20+
const _ = require('lodash');
21+
const deleteKey = require('key-del');
22+
const {
2323
GraphQLError
2424
} = require('graphql');
25-
var {
25+
const {
2626
createNode,
2727
getRootNode,
2828
nodeType
2929
} = require('./functions');
30-
var _execution = require('graphql/execution');
30+
const _execution = require('graphql/execution');
3131

3232
/**
3333
* queryCalculator - calling function for the recursive calculation algorithm.
@@ -42,7 +42,7 @@ var _execution = require('graphql/execution');
4242
* @param {object} options
4343
* @return {object} returns the query result in JSON format
4444
*/
45-
function queryCalculator(db, threshold, validationContext, options, format) {
45+
function queryCalculator(db, threshold, validationContext, options) {
4646
try {
4747
/* Only run for single queries */
4848
if (_.size(validationContext.getDocument().definitions) > 1) {
@@ -53,44 +53,44 @@ function queryCalculator(db, threshold, validationContext, options, format) {
5353
return data;
5454
}
5555

56-
/* Create the three data structures */
57-
var labels = new Map();
58-
var sizeMap = new Map();
59-
var results = new Map();
56+
const documentAST = validationContext.getDocument();
6057

61-
var documentAST = validationContext.getDocument();
62-
/* Parse query to remove location properties */
63-
var query = deleteKey(documentAST.definitions[0].selectionSet.selections, 'loc');
64-
var queryType = validationContext.getSchema().getQueryType();
65-
var rootNode = getRootNode(db, queryType);
6658
/* Set the execution context used for the resolver functions */
67-
var exeContext = _execution.buildExecutionContext(options.schema, documentAST, options.rootValue, db, options.variables, options.operationName, options.fieldResolver);
68-
var fieldNodes = documentAST.definitions[0].selectionSet.selections;
69-
/* Contains the path from the root field to the current field during calculation */
70-
var path;
59+
const exeContext = _execution.buildExecutionContext(options.schema, documentAST, options.rootValue, db, options.variables, options.operationName, options.fieldResolver);
60+
const fieldNodes = documentAST.definitions[0].selectionSet.selections;
61+
62+
/* Additional parameters needed for the calculation */
63+
let calculationContext = {
64+
exeContext : exeContext,
65+
fieldNodes : fieldNodes,
66+
queryType : validationContext.getSchema().getQueryType(),
67+
source : options.rootValue,
68+
path : null
69+
};
7170

72-
var fieldInfo = {
73-
exeContext : exeContext,
74-
fieldNodes : fieldNodes,
75-
queryType : queryType
71+
let structures = {
72+
labels : new Map(),
73+
sizeMap : new Map(),
74+
results : new Map()
7675
};
7776

78-
return calculate(labels, sizeMap, results, rootNode, query, queryType, options.rootValue, path, fieldInfo, validationContext)
77+
/* Parse query to remove location properties */
78+
const query = deleteKey(documentAST.definitions[0].selectionSet.selections, 'loc');
79+
const rootNode = getRootNode(db, calculationContext.queryType);
80+
81+
return calculate(structures, rootNode, query, calculationContext)
7982
.then(() => {
8083
let stringNodeQuery = JSON.stringify([rootNode, query]);
81-
const querySize = arrSum(sizeMap.get(stringNodeQuery));
84+
const querySize = arrSum(structures.sizeMap.get(stringNodeQuery));
8285
console.log('Size of result: ' + querySize);
8386
if (querySize > threshold) {
8487
validationContext.reportError(
8588
new GraphQLError(
8689
`Calculation: Size of query result is ${querySize}, which exceeds maximum size of ${threshold}`)
8790
);
8891
}
89-
if(validationContext.getErrors().length){
90-
return Promise.resolve({ errors: format(validationContext.getErrors()) });
91-
}
9292
let data = {
93-
results : results,
93+
results : structures.results,
9494
validationContext : validationContext,
9595
index : stringNodeQuery
9696
};
@@ -114,57 +114,54 @@ function queryCalculator(db, threshold, validationContext, options, format) {
114114
* underlying data source again. A detailed explanation of this algorithm can be found in the Master's thesis
115115
* "Combining Result Size Estimation and Query Execution for the GraphQL Query Language" by Andreas Lundquist.
116116
*
117-
* @param {object} labels the labels Map
118-
* @param {object} sizeMap the sizeMap Map
119-
* @param {object} results the results Map
120-
* @param {object} u node
121-
* @param {object} query (sub)query to be calculated
122-
* @param {object} parentType type of the parent node
123-
* @param {object} source
124-
* @param {object} current_path
117+
* @param {object} structures contains three map structures: labels, sizeMap and results
118+
* @param {object} u node
119+
* @param {object} query (sub)query to be calculated
120+
* @param {object} calculationContext contains additional information needed for the calculation
121+
* @param {object} path contains the path from the root node to the current node
125122
* @return {promise}
126123
* @private
127124
*/
128-
function calculate(labels, sizeMap, results, u, query, parentType, source, current_path, fieldInfo, validationContext) {
125+
function calculate(structures, u, query, calculationContext, path) {
129126
/* These three strings are used the data structures labels, sizeMap and results */
130127
let stringNodeQuery = JSON.stringify([u, query]);
131128
let stringQuery = JSON.stringify(query);
132129
let stringNode = JSON.stringify(u);
133130
/* Check if query is already in labels for this node [1] */
134-
if (!doQueryExistOnNode(labels, stringNode, stringQuery)) {
131+
if (!doQueryExistOnNode(structures.labels, stringNode, stringQuery)) {
135132
/* Add query to labels [2] and initialize data structures if needed */
136-
addQueryToLabels(labels, stringNode, stringQuery);
137-
initializeDataStructures(sizeMap, results, stringNodeQuery);
133+
addQueryToLabels(structures.labels, stringNode, stringQuery);
134+
initializeDataStructures(structures.sizeMap, structures.results, stringNodeQuery);
138135
if (query.length > 1) {
139136
/* The query consists of multiple subqueries [27] */
140-
return calculateAllSubqueries(labels, sizeMap, results, query, stringNodeQuery, u, parentType, source, current_path, fieldInfo, validationContext);
137+
return calculateAllSubqueries(structures, query, stringNodeQuery, u, calculationContext, path);
141138
} else if (!(query[0].selectionSet)) {
142139
/* The query consists of a single field [3] */
143-
sizeMap.get(stringNodeQuery).push(3);
144-
return getScalarField(results, stringNodeQuery, query, source, parentType, current_path, fieldInfo);
140+
structures.sizeMap.get(stringNodeQuery).push(3);
141+
return getScalarField(structures.results, stringNodeQuery, query, calculationContext, path);
145142
//return Promise.resolve();
146143
} else if (query[0].kind === 'Field') {
147144
/* The query consists of a field with a subselection [9] */
148145
let fieldName = query[0].name.value;
149-
let fieldDef = parentType.getFields()[fieldName];
150-
current_path = addPath(current_path, fieldName);
151-
return getField(query, fieldDef, source, current_path, fieldInfo)
146+
let fieldDef = calculationContext.queryType.getFields()[fieldName];
147+
path = addPath(path, fieldName);
148+
return getField(query, fieldDef, calculationContext, path)
152149
.then(src => {
153-
results.get(stringNodeQuery).push("\"" + fieldName + "\"" + ":");
150+
structures.results.get(stringNodeQuery).push("\"" + fieldName + "\"" + ":");
154151
/* Add to sizeMap depending on the type of the field [15-21] */
155152
if (fieldDef.astNode.type.kind === 'ListType') {
156-
sizeMap.get(stringNodeQuery).push(4);
153+
structures.sizeMap.get(stringNodeQuery).push(4);
157154
} else if (src != null) {
158-
sizeMap.get(stringNodeQuery).push(2);
155+
structures.sizeMap.get(stringNodeQuery).push(2);
159156
} else {
160-
sizeMap.get(stringNodeQuery).push(3);
157+
structures.sizeMap.get(stringNodeQuery).push(3);
161158
}
162159
/* Recursively run the calculate function for every resulting edge [11-14] */
163-
return calculateRelatedNodes(labels, sizeMap, results, src, stringNodeQuery, query, fieldDef, current_path, fieldInfo, validationContext);
160+
return calculateRelatedNodes(structures, src, stringNodeQuery, query, fieldDef, calculationContext, path);
164161
});
165162
} else if (query[0].kind === 'InlineFragment') {
166163
/* The query consists of an inline fragment [22] */
167-
return calculateInlineFragment(labels, sizeMap, results, stringNodeQuery, u, query, source, current_path, fieldInfo, validationContext);
164+
return calculateInlineFragment(structures, stringNodeQuery, u, query, calculationContext, path);
168165
}
169166
} else {
170167
/* The query already exists in labels for this node */
@@ -197,27 +194,27 @@ function initializeDataStructures(sizeMap, results, stringNodeQuery){
197194
}
198195
}
199196

200-
function calculateAllSubqueries(labels, sizeMap, results, query, stringNodeQuery, u, parentType, source, current_path, fieldInfo, validationContext){
197+
function calculateAllSubqueries(structures, query, stringNodeQuery, u, calculationContext, path){
201198
return Promise.all(query.map(function(subquery, index) {
202199
if (index !== 0) {
203-
results.get(stringNodeQuery).push(",");
200+
structures.results.get(stringNodeQuery).push(",");
204201
}
205202
let stringNodeSubquery = JSON.stringify([u, [subquery]]);
206-
results.get(stringNodeQuery).push([stringNodeSubquery]);
207-
return calculate(labels, sizeMap, results, u, [subquery], parentType, source, current_path, fieldInfo, validationContext)
203+
structures.results.get(stringNodeQuery).push([stringNodeSubquery]);
204+
return calculate(structures, u, [subquery], calculationContext, path)
208205
.then(x => {
209-
sizeMap.get(stringNodeQuery).push(sizeMap.get(stringNodeSubquery));
206+
structures.sizeMap.get(stringNodeQuery).push(structures.sizeMap.get(stringNodeSubquery));
210207
return x;
211208
});
212209
}));
213210
}
214211

215212
/* Adds a field with a scalar value (leaf node) to the results structure */
216-
function getScalarField(results, stringNodeQuery, query, source, parentType, current_path, fieldInfo){
213+
function getScalarField(results, stringNodeQuery, query, calculationContext, path){
217214
let fieldName = query[0].name.value;
218-
let fieldDef = parentType.getFields()[fieldName];
219-
current_path = addPath(current_path, fieldName);
220-
return getField(query, fieldDef, source, current_path, fieldInfo)
215+
let fieldDef = calculationContext.queryType.getFields()[fieldName];
216+
path = addPath(path, fieldName);
217+
return getField(query, fieldDef, calculationContext, path)
221218
.then(result => {
222219
let value = formatScalarResult(result, fieldName);
223220
results.get(stringNodeQuery).push("\"" + fieldName + "\"" + ":");
@@ -229,11 +226,11 @@ function getScalarField(results, stringNodeQuery, query, source, parentType, cur
229226
/**
230227
* Builds the resolver info and args, then executes the corresponding resolver function.
231228
*/
232-
function getField(query, fieldDef, source, current_path, fieldInfo){
233-
let resolveFn = fieldDef.resolve || fieldInfo.exeContext.fieldResolver;
234-
let info = _execution.buildResolveInfo(fieldInfo.exeContext, fieldDef, fieldInfo.fieldNodes, fieldInfo.queryType, current_path);
235-
let args = (0, _execution.getArgumentValues(fieldDef, query[0], fieldInfo.exeContext.variableValues));
236-
return Promise.resolve(resolveFn(source, args, fieldInfo.exeContext.contextValue, info));
229+
function getField(query, fieldDef, calculationContext, path){
230+
let resolveFn = fieldDef.resolve || calculationContext.exeContext.fieldResolver;
231+
let info = _execution.buildResolveInfo(calculationContext.exeContext, fieldDef, calculationContext.fieldNodes, calculationContext.queryType, path);
232+
let args = (0, _execution.getArgumentValues(fieldDef, query[0], calculationContext.exeContext.variableValues));
233+
return Promise.resolve(resolveFn(calculationContext.source, args, calculationContext.exeContext.contextValue, info));
237234
}
238235

239236
function formatScalarResult(result, fieldName){
@@ -270,54 +267,57 @@ function formatScalarResult(result, fieldName){
270267
return value;
271268
}
272269

273-
function calculateRelatedNodes(labels, sizeMap, results, src, stringNodeQuery, query, fieldDef, current_path, fieldInfo, validationContext){
274-
let currentType = fieldDef.astNode.type.kind === 'ListType' ? fieldDef.type.ofType : fieldDef.type;
270+
function calculateRelatedNodes(structures, src, stringNodeQuery, query, fieldDef, calculationContext, path){
271+
calculationContext.queryType = fieldDef.astNode.type.kind === 'ListType' ? fieldDef.type.ofType : fieldDef.type;;
275272
/* If multiple related nodes exist */
276273
if (Array.isArray(src)){
277-
results.get(stringNodeQuery).push("[");
274+
structures.results.get(stringNodeQuery).push("[");
278275
return Promise.all(src.map(function(srcItem, index) {
279276
if (index !== 0) {
280-
results.get(stringNodeQuery).push(",");
277+
structures.results.get(stringNodeQuery).push(",");
281278
}
282-
return calculateSingleNode(labels, sizeMap, results, query, srcItem, fieldDef, currentType, stringNodeQuery, current_path, fieldInfo, validationContext);
279+
calculationContext.source = srcItem;
280+
return calculateSingleNode(structures, query, fieldDef, stringNodeQuery, calculationContext, path);
283281
}))
284282
.then(x => {
285-
results.get(stringNodeQuery).push("]");
283+
structures.results.get(stringNodeQuery).push("]");
286284
return x;
287285
});
288286
/* If no related nodes exist */
289287
} else if (src == null){
290-
sizeMap.get(stringNodeQuery).push(2);
291-
results.get(stringNodeQuery).push("null");
288+
structures.sizeMap.get(stringNodeQuery).push(2);
289+
structures.results.get(stringNodeQuery).push("null");
292290
return Promise.resolve();
293291
/* If only a single related node exists */
294292
} else {
295-
return calculateSingleNode(labels, sizeMap, results, query, src, fieldDef, currentType, stringNodeQuery, current_path, fieldInfo, validationContext);
293+
calculationContext.source = src;
294+
return calculateSingleNode(structures, query, fieldDef, stringNodeQuery, calculationContext, path);
296295
}
297296
}
298297

299-
function calculateSingleNode(labels, sizeMap, results, query, source, fieldDef, currentType, stringNodeQuery, current_path, fieldInfo, validationContext){
300-
sizeMap.get(stringNodeQuery).push(2);
301-
let relatedNode = createNode(source, fieldDef);
298+
function calculateSingleNode(structures, query, fieldDef, stringNodeQuery, calculationContext, path){
299+
structures.sizeMap.get(stringNodeQuery).push(2);
300+
let relatedNode = createNode(calculationContext.source, fieldDef);
302301
let stringRelatedNodeSubquery = JSON.stringify([relatedNode, query[0].selectionSet.selections]);
303-
results.get(stringNodeQuery).push("{");
304-
results.get(stringNodeQuery).push([stringRelatedNodeSubquery]);
305-
results.get(stringNodeQuery).push("}");
306-
return calculate(labels, sizeMap, results, relatedNode, query[0].selectionSet.selections, currentType, source, current_path, fieldInfo, validationContext)
302+
structures.results.get(stringNodeQuery).push("{");
303+
structures.results.get(stringNodeQuery).push([stringRelatedNodeSubquery]);
304+
structures.results.get(stringNodeQuery).push("}");
305+
return calculate(structures, relatedNode, query[0].selectionSet.selections, calculationContext, path)
307306
.then(x => {
308-
sizeMap.get(stringNodeQuery).push(sizeMap.get(stringRelatedNodeSubquery));
307+
structures.sizeMap.get(stringNodeQuery).push(structures.sizeMap.get(stringRelatedNodeSubquery));
309308
return x;
310309
});
311310
}
312311

313-
function calculateInlineFragment(labels, sizeMap, results, stringNodeQuery, u, query, source, current_path, fieldInfo, validationContext){
312+
function calculateInlineFragment(structures, stringNodeQuery, u, query, calculationContext, path){
314313
let onType = query[0].typeCondition.name.value;
315314
if (nodeType(u) === onType) {
316315
let stringNodeSubquery = JSON.stringify([u, query[0].selectionSet.selections]);
317-
results.get(stringNodeQuery).push([stringNodeSubquery]);
318-
return calculate(labels, sizeMap, results, u, query[0].selectionSet.selections, validationContext.getSchema().getType(onType), source, current_path, fieldInfo, validationContext)
316+
structures.results.get(stringNodeQuery).push([stringNodeSubquery]);
317+
calculationContext.queryType = fieldInfo.exeContext.schema.getType(onType);
318+
return calculate(structures, u, query[0].selectionSet.selections, calculationContext, path)
319319
.then (x => {
320-
sizeMap.get(stringNodeQuery).push(sizeMap.get(stringNodeSubquery));
320+
structures.sizeMap.get(stringNodeQuery).push(structures.sizeMap.get(stringNodeSubquery));
321321
return x;
322322
});
323323
} else {

0 commit comments

Comments
 (0)