From 85d1fd3c393d3de7a0a2389c33189fa24e5c4fd1 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 8 Feb 2024 10:55:35 -0500 Subject: [PATCH] - Progress check Signed-off-by: Dave Richer --- client/src/utils/RenderTemplate.js | 80 ++++++++----------- client/src/utils/graphQLmodifier.js | 114 ++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 50 deletions(-) create mode 100644 client/src/utils/graphQLmodifier.js diff --git a/client/src/utils/RenderTemplate.js b/client/src/utils/RenderTemplate.js index 9125e2434..64b714c69 100644 --- a/client/src/utils/RenderTemplate.js +++ b/client/src/utils/RenderTemplate.js @@ -1,5 +1,5 @@ import {gql} from "@apollo/client"; -import {parse, print, visit, Kind} from "graphql"; +import {parse, print} from "graphql"; import jsreport from "@jsreport/browser-client"; import {notification} from "antd"; import axios from "axios"; @@ -10,6 +10,7 @@ import {store} from "../redux/store"; import client from "../utils/GraphQLClient"; import cleanAxios from "./CleanAxios"; import {TemplateList} from "./TemplateConstants"; +import {applyFilters, applySorters, wrapFiltersInAnd} from "./graphQLmodifier"; const server = process.env.REACT_APP_REPORTS_SERVER_URL; @@ -17,53 +18,6 @@ jsreport.serverUrl = server; const Templates = TemplateList(); - -function applyFilters(ast, filters) { - return filters.reduce((modifiedAst, filter) => { - const struct = filter.field.split('.'); - - return visit(modifiedAst, { - OperationDefinition: { - enter(node) { - // Traverse through the operation definitions to find the correct query and its arguments - node.selectionSet.selections.forEach((selection) => { - if (selection.name.value === struct[0]) { - // Find the existing 'where' argument, if it exists - let whereArg = selection.arguments.find(arg => arg.name.value === 'where'); - - if (!whereArg) { - // If 'where' argument doesn't exist, create it - whereArg = { - kind: Kind.ARGUMENT, - name: { kind: Kind.NAME, value: 'where' }, - value: { kind: Kind.OBJECT, fields: [] } // Initialize an empty object for 'where' clause - }; - selection.arguments.push(whereArg); // Add 'where' argument to the 'jobs' field - } - - // Assuming the filter should be added to the 'where' clause - 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 }, // Assuming equality operator; adjust as necessary - value: { kind: Kind.STRING, value: filter.value } - }] - } - }; - - // Add the filter to the 'where' argument's value - whereArg.value.fields.push(filterField); - } - }); - } - } - }); - }, ast); -} export default async function RenderTemplate( templateObject, bodyshop, @@ -395,7 +349,7 @@ export const fetchFilterData = async ({name}) => { if (generalTemplate) parsedFilterData = atob(generalTemplate.content); } - return { data: JSON.parse(parsedFilterData), useShopSpecificTemplate}; + return {data: JSON.parse(parsedFilterData), useShopSpecificTemplate}; }; const fetchContextData = async (templateObject, jsrAuth) => { @@ -444,7 +398,33 @@ const fetchContextData = async (templateObject, jsrAuth) => { console.dir(templateObject); - const ast = applyFilters(parse(templateQueryToExecute), templateObject.filters); + if ((!templateObject?.filters && !templateObject?.filters?.length && !templateObject?.sorters && !templateObject?.sorters?.length)) { + console.log('No filters or sorters'); + let contextData = {}; + if (templateQueryToExecute) { + const {data} = await client.query({ + query: gql(templateQueryToExecute), + variables: {...templateObject.variables}, + }); + contextData = data; + } + + return {contextData, useShopSpecificTemplate}; + } + + const ast = parse(templateQueryToExecute); + let filterFields = []; + + if (templateObject?.filters && templateObject?.filters?.length) { + console.log('Applying filters') + applyFilters(ast, templateObject.filters, filterFields); + wrapFiltersInAnd(ast, filterFields); + } + if (templateObject?.sorters && templateObject?.sorters?.length) { + console.log('Applying sorters') + applySorters(ast, templateObject.sorters); + } + const finalQuery = print(ast); console.log(finalQuery); diff --git a/client/src/utils/graphQLmodifier.js b/client/src/utils/graphQLmodifier.js new file mode 100644 index 000000000..c027e7ff1 --- /dev/null +++ b/client/src/utils/graphQLmodifier.js @@ -0,0 +1,114 @@ +import {Kind, visit} from "graphql"; + +/** + * Apply sorters to the AST + * @param ast + * @param sorters + */ +export function applySorters(ast, sorters) { + sorters.forEach((sorter) => { + const [table, field] = 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); + } + + 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 + }; + + orderByArg.value.fields.push(sorterField); + } + }); + } + } + }); + }); +} + +/** + * 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'); + + 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} + }] + } + }; + + filterFields.push({kind: Kind.OBJECT, fields: [filterField]}); + } + }); + } + } + }); + }); +} + +/** + * Wrap filters in an 'and' object + * @param ast + * @param filterFields + */ +export function wrapFiltersInAnd(ast, filterFields) { + visit(ast, { + OperationDefinition: { + enter(node) { + node.selectionSet.selections.forEach((selection) => { + let whereArg = selection.arguments.find(arg => arg.name.value === 'where'); + if (filterFields.length > 1) { + const andFilter = { + kind: Kind.OBJECT_FIELD, + name: {kind: Kind.NAME, value: '_and'}, + value: {kind: Kind.LIST, values: filterFields} + }; + whereArg.value.fields.push(andFilter); + } else if (filterFields.length === 1) { + whereArg.value.fields.push(filterFields[0].fields[0]); + } + }); + } + } + }); +} +