@@ -1,5 +1,7 @@
|
|||||||
import {Kind, visit} from "graphql";
|
import {Kind, visit} from "graphql";
|
||||||
|
|
||||||
|
/* eslint-disable no-loop-func */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply sorters to the AST
|
* Apply sorters to the AST
|
||||||
* @param ast
|
* @param ast
|
||||||
@@ -7,31 +9,53 @@ import {Kind, visit} from "graphql";
|
|||||||
*/
|
*/
|
||||||
export function applySorters(ast, sorters) {
|
export function applySorters(ast, sorters) {
|
||||||
sorters.forEach((sorter) => {
|
sorters.forEach((sorter) => {
|
||||||
const [table, field] = sorter.field.split('.');
|
const fieldPath = sorter.field.split('.');
|
||||||
visit(ast, {
|
visit(ast, {
|
||||||
OperationDefinition: {
|
OperationDefinition: {
|
||||||
enter(node) {
|
enter(node) {
|
||||||
node.selectionSet.selections.forEach((selection) => {
|
// Loop through each sorter to apply it
|
||||||
if (selection.name.value === table) {
|
// noinspection DuplicatedCode
|
||||||
let orderByArg = selection.arguments.find(arg => arg.name.value === 'order_by');
|
|
||||||
if (!orderByArg) {
|
let currentSelection = node; // Start with the root operation
|
||||||
orderByArg = {
|
|
||||||
kind: Kind.ARGUMENT,
|
// Navigate down the field path to the correct location
|
||||||
name: {kind: Kind.NAME, value: 'order_by'},
|
for (let i = 0; i < fieldPath.length - 1; i++) {
|
||||||
value: {kind: Kind.OBJECT, fields: []}
|
let found = false;
|
||||||
};
|
visit(currentSelection, {
|
||||||
selection.arguments.push(orderByArg);
|
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 = {
|
// Apply the sorter at the correct level
|
||||||
kind: Kind.OBJECT_FIELD,
|
if (currentSelection) {
|
||||||
name: {kind: Kind.NAME, value: field},
|
const targetFieldName = fieldPath[fieldPath.length - 1];
|
||||||
value: {kind: Kind.ENUM, value: sorter.direction} // 'asc' for ascending order, 'desc' for descending order
|
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: [] },
|
||||||
};
|
};
|
||||||
|
currentSelection.arguments.push(orderByArg);
|
||||||
orderByArg.value.fields.push(sorterField);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
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
|
* Apply filters to the AST
|
||||||
* @param ast
|
* @param ast
|
||||||
* @param filters
|
* @param filters
|
||||||
* @param filterFields
|
|
||||||
*/
|
*/
|
||||||
export function applyFilters(ast, filters, filterFields) {
|
export function applyFilters(ast, filters) {
|
||||||
filters.forEach((filter) => {
|
return visit(ast, {
|
||||||
const struct = filter.field.split('.');
|
OperationDefinition: {
|
||||||
visit(ast, {
|
enter(node) {
|
||||||
OperationDefinition: {
|
// Loop through each filter to apply it
|
||||||
enter(node) {
|
filters.forEach(filter => {
|
||||||
node.selectionSet.selections.forEach((selection) => {
|
const fieldPath = filter.field.split('.');
|
||||||
if (selection.name.value === struct[0]) {
|
let currentSelection = node; // Start with the root operation
|
||||||
let whereArg = selection.arguments.find(arg => arg.name.value === 'where');
|
|
||||||
|
|
||||||
if (!whereArg) {
|
// Navigate down the field path to the correct location
|
||||||
whereArg = {
|
for (let i = 0; i < fieldPath.length - 1; i++) {
|
||||||
kind: Kind.ARGUMENT,
|
let found = false;
|
||||||
name: {kind: Kind.NAME, value: 'where'},
|
visit(currentSelection, {
|
||||||
value: {kind: Kind.OBJECT, fields: []}
|
Field: {
|
||||||
};
|
enter(node) {
|
||||||
selection.arguments.push(whereArg);
|
if (node.name.value === fieldPath[i]) {
|
||||||
}
|
currentSelection = node; // Move down to the next level
|
||||||
|
found = true;
|
||||||
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}
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
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
|
* Wrap filters in an 'and' object
|
||||||
* @param ast
|
* @param ast
|
||||||
@@ -112,3 +177,4 @@ export function wrapFiltersInAnd(ast, filterFields) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-enable no-loop-func */
|
||||||
|
|||||||
Reference in New Issue
Block a user