From bea5750c7507e0c264676a2583da87d2cf463dad Mon Sep 17 00:00:00 2001 From: Marius Aarsnes Date: Wed, 17 Nov 2021 16:03:10 +0100 Subject: [PATCH 1/2] chore(cycles): avoid cycles in queries Pass along a set of Parents for each field. In the case that the name of the current field exists in the parent set, the method returns to avoid cycles --- index.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 0185a88..9b1214c 100755 --- a/index.js +++ b/index.js @@ -80,6 +80,7 @@ const getVarsToTypesStr = dict => Object.entries(dict) * @param crossReferenceKeyList list of the cross reference * @param curDepth current depth of field * @param fromUnion adds additional depth for unions to avoid empty child + * @param parents a set of previous parent names used to avoid cycles */ const generateQuery = ( curName, @@ -90,6 +91,7 @@ const generateQuery = ( crossReferenceKeyList = [], // [`${curParentName}To${curName}Key`] curDepth = 1, fromUnion = false, + parents = new Set(), ) => { const field = gqlSchema.getType(curParentType).getFields()[curName]; const curTypeName = field.type.inspect().replace(/[[\]!]/g, ''); @@ -97,6 +99,11 @@ const generateQuery = ( let queryStr = ''; let childQuery = ''; + /* Avoid cycles */ + if (parents.has(curName)) { + return {queryStr, argumentsDict} + } + if (curType.getFields) { const crossReferenceKey = `${curParentName}To${curName}Key`; if (crossReferenceKeyList.indexOf(crossReferenceKey) !== -1 || (fromUnion ? curDepth - 2 : curDepth) > depthLimit) return ''; @@ -111,7 +118,7 @@ const generateQuery = ( return includeDeprecatedFields || !fieldSchema.isDeprecated; }) .map(cur => generateQuery(cur, curType, curName, argumentsDict, duplicateArgCounts, - crossReferenceKeyList, curDepth + 1, fromUnion).queryStr) + crossReferenceKeyList, curDepth + 1, fromUnion, new Set([...parents, curName])).queryStr) .filter(cur => Boolean(cur)) .join('\n'); } @@ -141,7 +148,7 @@ const generateQuery = ( const valueType = gqlSchema.getType(valueTypeName); const unionChildQuery = Object.keys(valueType.getFields()) .map(cur => generateQuery(cur, valueType, curName, argumentsDict, duplicateArgCounts, - crossReferenceKeyList, curDepth + 2, true).queryStr) + crossReferenceKeyList, curDepth + 2, true, new Set([...parents, curName])).queryStr) .filter(cur => Boolean(cur)) .join('\n'); From 56f43f2bfad69bff31f381d08ab54b3a1696caca Mon Sep 17 00:00:00 2001 From: Marius Aarsnes Date: Wed, 17 Nov 2021 16:21:09 +0100 Subject: [PATCH 2/2] chore(cycles): make avoid cycles optional --- index.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 9b1214c..5db0907 100755 --- a/index.js +++ b/index.js @@ -11,10 +11,11 @@ program .option('--depthLimit [value]', 'query depth you want to limit(The default is 100)') .option('--ext [value]', 'extension file to use', 'gql') .option('-C, --includeDeprecatedFields [value]', 'Flag to include deprecated fields (The default is to exclude)') + .option('-C, --avoidCycles [value]', 'Flag to avoid cycles in the generated queries (The default is set to false)') .parse(process.argv); const { - schemaFilePath, destDirPath, depthLimit = 100, includeDeprecatedFields = false, ext: fileExtension, + schemaFilePath, destDirPath, depthLimit = 100, includeDeprecatedFields = false, ext: fileExtension, avoidCycles = false } = program; const typeDef = fs.readFileSync(schemaFilePath, 'utf-8'); const source = new Source(typeDef); @@ -100,7 +101,7 @@ const generateQuery = ( let childQuery = ''; /* Avoid cycles */ - if (parents.has(curName)) { + if (avoidCycles && parents.has(curName)) { return {queryStr, argumentsDict} } @@ -117,8 +118,11 @@ const generateQuery = ( const fieldSchema = gqlSchema.getType(curType).getFields()[fieldName]; return includeDeprecatedFields || !fieldSchema.isDeprecated; }) - .map(cur => generateQuery(cur, curType, curName, argumentsDict, duplicateArgCounts, - crossReferenceKeyList, curDepth + 1, fromUnion, new Set([...parents, curName])).queryStr) + .map(cur => + avoidCycles + ? generateQuery(cur, curType, curName, argumentsDict, duplicateArgCounts, crossReferenceKeyList, curDepth + 1, fromUnion, new Set([...parents, curName])).queryStr + : generateQuery(cur, curType, curName, argumentsDict, duplicateArgCounts, crossReferenceKeyList, curDepth + 1, fromUnion).queryStr + ) .filter(cur => Boolean(cur)) .join('\n'); } @@ -147,8 +151,11 @@ const generateQuery = ( const valueTypeName = types[i]; const valueType = gqlSchema.getType(valueTypeName); const unionChildQuery = Object.keys(valueType.getFields()) - .map(cur => generateQuery(cur, valueType, curName, argumentsDict, duplicateArgCounts, - crossReferenceKeyList, curDepth + 2, true, new Set([...parents, curName])).queryStr) + .map(cur => + avoidCycles + ? generateQuery(cur, valueType, curName, argumentsDict, duplicateArgCounts, crossReferenceKeyList, curDepth + 2, true, new Set([...parents, curName])).queryStr + : generateQuery(cur, valueType, curName, argumentsDict, duplicateArgCounts, crossReferenceKeyList, curDepth + 2, true).queryStr + ) .filter(cur => Boolean(cur)) .join('\n');