@@ -1,5 +1,5 @@
|
|||||||
import {gql} from "@apollo/client";
|
import {gql} from "@apollo/client";
|
||||||
import {parse, print, visit, Kind} from "graphql";
|
import {parse, print} from "graphql";
|
||||||
import jsreport from "@jsreport/browser-client";
|
import jsreport from "@jsreport/browser-client";
|
||||||
import {notification} from "antd";
|
import {notification} from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
@@ -10,6 +10,7 @@ import {store} from "../redux/store";
|
|||||||
import client from "../utils/GraphQLClient";
|
import client from "../utils/GraphQLClient";
|
||||||
import cleanAxios from "./CleanAxios";
|
import cleanAxios from "./CleanAxios";
|
||||||
import {TemplateList} from "./TemplateConstants";
|
import {TemplateList} from "./TemplateConstants";
|
||||||
|
import {applyFilters, applySorters, wrapFiltersInAnd} from "./graphQLmodifier";
|
||||||
|
|
||||||
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
||||||
|
|
||||||
@@ -17,53 +18,6 @@ jsreport.serverUrl = server;
|
|||||||
|
|
||||||
const Templates = TemplateList();
|
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(
|
export default async function RenderTemplate(
|
||||||
templateObject,
|
templateObject,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
@@ -395,7 +349,7 @@ export const fetchFilterData = async ({name}) => {
|
|||||||
if (generalTemplate) parsedFilterData = atob(generalTemplate.content);
|
if (generalTemplate) parsedFilterData = atob(generalTemplate.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { data: JSON.parse(parsedFilterData), useShopSpecificTemplate};
|
return {data: JSON.parse(parsedFilterData), useShopSpecificTemplate};
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchContextData = async (templateObject, jsrAuth) => {
|
const fetchContextData = async (templateObject, jsrAuth) => {
|
||||||
@@ -444,7 +398,33 @@ const fetchContextData = async (templateObject, jsrAuth) => {
|
|||||||
console.dir(templateObject);
|
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);
|
const finalQuery = print(ast);
|
||||||
console.log(finalQuery);
|
console.log(finalQuery);
|
||||||
|
|
||||||
|
|||||||
114
client/src/utils/graphQLmodifier.js
Normal file
114
client/src/utils/graphQLmodifier.js
Normal file
@@ -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]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user