- I wrote a function I am pretty sure gave me brain damage, but it works, and that is A-OK
Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -113,46 +113,25 @@ 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
|
||||
let topLevel = false;
|
||||
|
||||
// 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
|
||||
// Determine if the filter should be applied at the top level
|
||||
if (fieldPath[0].startsWith('[') && fieldPath[0].endsWith(']')) {
|
||||
fieldPath[0] = fieldPath[0].substring(1, fieldPath[0].length - 1); // Strip the brackets
|
||||
topLevel = true;
|
||||
}
|
||||
|
||||
// Apply the filter at the correct level
|
||||
if (currentSelection) {
|
||||
if (topLevel) {
|
||||
// Construct the filter for a top-level application
|
||||
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 = {
|
||||
const nestedFilter = {
|
||||
kind: Kind.OBJECT_FIELD,
|
||||
name: { kind: Kind.NAME, value: targetFieldName },
|
||||
value: {
|
||||
@@ -165,15 +144,125 @@ export function applyFilters(ast, filters) {
|
||||
},
|
||||
};
|
||||
|
||||
// Add the new filter condition
|
||||
whereArg.value.fields.push(filterField);
|
||||
// Find or create the where argument for the top-level field
|
||||
let whereArg = node.selectionSet.selections
|
||||
.find(selection => selection.name.value === fieldPath[0])
|
||||
?.arguments.find(arg => arg.name.value === 'where');
|
||||
|
||||
if (!whereArg) {
|
||||
whereArg = {
|
||||
kind: Kind.ARGUMENT,
|
||||
name: { kind: Kind.NAME, value: 'where' },
|
||||
value: { kind: Kind.OBJECT, fields: [] },
|
||||
};
|
||||
const topLevelSelection = node.selectionSet.selections.find(selection =>
|
||||
selection.name.value === fieldPath[0]
|
||||
);
|
||||
if (topLevelSelection) {
|
||||
topLevelSelection.arguments = topLevelSelection.arguments || [];
|
||||
topLevelSelection.arguments.push(whereArg);
|
||||
}
|
||||
}
|
||||
|
||||
// Correctly position the nested filter without an extra 'where'
|
||||
if (fieldPath.length > 2) { // More than one level deep
|
||||
let currentField = whereArg.value;
|
||||
fieldPath.slice(1, -1).forEach((path, index) => {
|
||||
let existingField = currentField.fields.find(f => f.name.value === path);
|
||||
if (!existingField) {
|
||||
existingField = {
|
||||
kind: Kind.OBJECT_FIELD,
|
||||
name: { kind: Kind.NAME, value: path },
|
||||
value: { kind: Kind.OBJECT, fields: [] }
|
||||
};
|
||||
currentField.fields.push(existingField);
|
||||
}
|
||||
currentField = existingField.value;
|
||||
});
|
||||
currentField.fields.push(nestedFilter);
|
||||
} else { // Directly under the top level
|
||||
whereArg.value.fields.push(nestedFilter);
|
||||
}
|
||||
} else {
|
||||
// Initialize a reference to the current selection to traverse down the AST
|
||||
let currentSelection = node;
|
||||
let whereArgFound = false;
|
||||
|
||||
// Iterate over the fieldPath, except for the last entry, to navigate the structure
|
||||
for (let i = 0; i < fieldPath.length - 1; i++) {
|
||||
const fieldName = fieldPath[i];
|
||||
let fieldFound = false;
|
||||
|
||||
// Check if the current selection has a selectionSet and selections
|
||||
if (currentSelection.selectionSet && currentSelection.selectionSet.selections) {
|
||||
// Look for the field in the current selection's selections
|
||||
const selection = currentSelection.selectionSet.selections.find(sel => sel.name.value === fieldName);
|
||||
if (selection) {
|
||||
// Move down the AST to the found selection
|
||||
currentSelection = selection;
|
||||
fieldFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the field was not found in the current path, it's an issue
|
||||
if (!fieldFound) {
|
||||
console.error(`Field ${fieldName} not found in the current selection.`);
|
||||
return; // Exit the loop and function due to error
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, currentSelection should be the parent field where the filter needs to be applied
|
||||
// Check if the 'where' argument already exists in the current selection
|
||||
const whereArg = currentSelection.arguments.find(arg => arg.name.value === 'where');
|
||||
if (whereArg) {
|
||||
whereArgFound = true;
|
||||
} else {
|
||||
// If not found, create a new 'where' argument for the current selection
|
||||
currentSelection.arguments.push({
|
||||
kind: Kind.ARGUMENT,
|
||||
name: { kind: Kind.NAME, value: 'where' },
|
||||
value: { kind: Kind.OBJECT, fields: [] } // Empty fields array to be populated with the filter
|
||||
});
|
||||
}
|
||||
|
||||
// Assuming the last entry in fieldPath is the field to apply the filter on
|
||||
const targetField = fieldPath[fieldPath.length - 1];
|
||||
const filterValue = {
|
||||
kind: getGraphQLKind(filter.value),
|
||||
value: filter.value,
|
||||
};
|
||||
|
||||
// Construct the filter field object
|
||||
const filterField = {
|
||||
kind: Kind.OBJECT_FIELD,
|
||||
name: { kind: Kind.NAME, value: targetField },
|
||||
value: {
|
||||
kind: Kind.OBJECT,
|
||||
fields: [{
|
||||
kind: Kind.OBJECT_FIELD,
|
||||
name: { kind: Kind.NAME, value: filter.operator },
|
||||
value: filterValue,
|
||||
}],
|
||||
},
|
||||
};
|
||||
|
||||
// Add the filter field to the 'where' clause of the current selection
|
||||
if (whereArgFound) {
|
||||
whereArg.value.fields.push(filterField);
|
||||
} else {
|
||||
// If the whereArg was newly created, find it again (since we didn't store its reference) and add the filter
|
||||
currentSelection.arguments.find(arg => arg.name.value === 'where').value.fields.push(filterField);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the GraphQL kind for a value
|
||||
* @param value
|
||||
|
||||
Reference in New Issue
Block a user