From 0541d0ef1e17f962bf41eea21217dd22361bdf3e Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 8 Feb 2024 11:15:32 -0500 Subject: [PATCH] - Progress check Signed-off-by: Dave Richer --- client/src/utils/graphQLmodifier.js | 170 +++++++++++++++++++--------- 1 file changed, 118 insertions(+), 52 deletions(-) diff --git a/client/src/utils/graphQLmodifier.js b/client/src/utils/graphQLmodifier.js index c027e7ff1..2e7924e25 100644 --- a/client/src/utils/graphQLmodifier.js +++ b/client/src/utils/graphQLmodifier.js @@ -1,5 +1,7 @@ import {Kind, visit} from "graphql"; +/* eslint-disable no-loop-func */ + /** * Apply sorters to the AST * @param ast @@ -7,31 +9,53 @@ import {Kind, visit} from "graphql"; */ export function applySorters(ast, sorters) { sorters.forEach((sorter) => { - const [table, field] = sorter.field.split('.'); + const fieldPath = sorter.field.split('.'); visit(ast, { OperationDefinition: { enter(node) { - node.selectionSet.selections.forEach((selection) => { - if (selection.name.value === table) { - let orderByArg = selection.arguments.find(arg => arg.name.value === 'order_by'); - if (!orderByArg) { - orderByArg = { - kind: Kind.ARGUMENT, - name: {kind: Kind.NAME, value: 'order_by'}, - value: {kind: Kind.OBJECT, fields: []} - }; - selection.arguments.push(orderByArg); + // Loop through each sorter to apply it + // noinspection DuplicatedCode + + let currentSelection = node; // Start with the root operation + + // Navigate down the field path to the correct location + for (let i = 0; i < fieldPath.length - 1; i++) { + let found = false; + visit(currentSelection, { + Field: { + enter(node) { + if (node.name.value === fieldPath[i]) { + currentSelection = node; // Move down to the next level + found = true; + } + } } + }); + if (!found) break; // Stop if we can't find the next field in the path + } - const sorterField = { - kind: Kind.OBJECT_FIELD, - name: {kind: Kind.NAME, value: field}, - value: {kind: Kind.ENUM, value: sorter.direction} // 'asc' for ascending order, 'desc' for descending order + // Apply the sorter at the correct level + if (currentSelection) { + const targetFieldName = fieldPath[fieldPath.length - 1]; + let orderByArg = currentSelection.arguments.find(arg => arg.name.value === 'order_by'); + if (!orderByArg) { + orderByArg = { + kind: Kind.ARGUMENT, + name: { kind: Kind.NAME, value: 'order_by' }, + value: { kind: Kind.OBJECT, fields: [] }, }; - - orderByArg.value.fields.push(sorterField); + currentSelection.arguments.push(orderByArg); } - }); + + const sorterField = { + kind: Kind.OBJECT_FIELD, + name: { kind: Kind.NAME, value: targetFieldName }, + value: { kind: Kind.ENUM, value: sorter.direction }, // Adjust if your schema uses a different type for sorting directions + }; + + // Add the new sorter condition + orderByArg.value.fields.push(sorterField); + } } } }); @@ -42,49 +66,90 @@ export function applySorters(ast, sorters) { * Apply filters to the AST * @param ast * @param filters - * @param filterFields */ -export function applyFilters(ast, filters, filterFields) { - filters.forEach((filter) => { - const struct = filter.field.split('.'); - visit(ast, { - OperationDefinition: { - enter(node) { - node.selectionSet.selections.forEach((selection) => { - if (selection.name.value === struct[0]) { - let whereArg = selection.arguments.find(arg => arg.name.value === 'where'); +export function applyFilters(ast, filters) { + return visit(ast, { + OperationDefinition: { + enter(node) { + // Loop through each filter to apply it + filters.forEach(filter => { + const fieldPath = filter.field.split('.'); + let currentSelection = node; // Start with the root operation - if (!whereArg) { - whereArg = { - kind: Kind.ARGUMENT, - name: {kind: Kind.NAME, value: 'where'}, - value: {kind: Kind.OBJECT, fields: []} - }; - selection.arguments.push(whereArg); - } - - const filterField = { - kind: Kind.OBJECT_FIELD, - name: {kind: Kind.NAME, value: struct[1]}, - value: { - kind: Kind.OBJECT, - fields: [{ - kind: Kind.OBJECT_FIELD, - name: {kind: Kind.NAME, value: filter.operator}, - value: {kind: Kind.STRING, value: filter.value} - }] + // Navigate down the field path to the correct location + for (let i = 0; i < fieldPath.length - 1; i++) { + let found = false; + visit(currentSelection, { + Field: { + enter(node) { + if (node.name.value === fieldPath[i]) { + currentSelection = node; // Move down to the next level + found = true; + } } - }; + } + }); + if (!found) break; // Stop if we can't find the next field in the path + } - filterFields.push({kind: Kind.OBJECT, fields: [filterField]}); + // Apply the filter at the correct level + if (currentSelection) { + const targetFieldName = fieldPath[fieldPath.length - 1]; + let whereArg = currentSelection.arguments.find(arg => arg.name.value === 'where'); + if (!whereArg) { + whereArg = { + kind: Kind.ARGUMENT, + name: { kind: Kind.NAME, value: 'where' }, + value: { kind: Kind.OBJECT, fields: [] }, + }; + currentSelection.arguments.push(whereArg); } - }); - } + + const filterValue = { + kind: getGraphQLKind(filter.value), + value: filter.value, + }; + + const filterField = { + kind: Kind.OBJECT_FIELD, + name: { kind: Kind.NAME, value: targetFieldName }, + value: { + kind: Kind.OBJECT, + fields: [{ + kind: Kind.OBJECT_FIELD, + name: { kind: Kind.NAME, value: filter.operator }, + value: filterValue, + }], + }, + }; + + // Add the new filter condition + whereArg.value.fields.push(filterField); + } + }); } - }); + } }); } +/** + * Get the GraphQL kind for a value + * @param value + * @returns {Kind|Kind.INT} + */ +function getGraphQLKind(value) { + if (typeof value === 'number') { + return value % 1 === 0 ? Kind.INT : Kind.FLOAT; + } else if (typeof value === 'boolean') { + return Kind.BOOLEAN; + } else if (typeof value === 'string') { + return Kind.STRING; + } + // Extend with more types as needed +} + + + /** * Wrap filters in an 'and' object * @param ast @@ -112,3 +177,4 @@ export function wrapFiltersInAnd(ast, filterFields) { }); } +/* eslint-enable no-loop-func */