Implement model prefix stripping and leading operator handling in utility functions
This commit introduces new functions to handle model prefix stripping and leading operator detection in the `utils.js` file. The `stripModelPrefixFromExpression` and `splitLeadingOperator` functions are added to enhance expression parsing. Additionally, existing functions are updated to utilize these new utilities, improving the handling of expressions in filters. Corresponding tests are added to ensure the correctness of the new functionality, particularly for equality and not-equal expressions.
This commit is contained in:
parent
1f679825df
commit
a7b613c88b
@ -38,4 +38,16 @@ describe('parseFilter number fields', () => {
|
||||
const result = await parseFilter('_reference', 'JOB*', jobModel);
|
||||
expect(result._reference).toEqual({ $regex: '^JOB.*$', $options: 'i' });
|
||||
});
|
||||
|
||||
it('strips model prefix from equality expressions', async () => {
|
||||
await expect(parseFilter('_reference', 'GCF:EJX3EXUZYW2U', jobModel)).resolves.toEqual({
|
||||
_reference: { $regex: '^EJX3EXUZYW2U$', $options: 'i' },
|
||||
});
|
||||
});
|
||||
|
||||
it('strips model prefix from not-equal expressions', async () => {
|
||||
await expect(parseFilter('_reference', '<>GCF:EJX3EXUZYW2U', jobModel)).resolves.toEqual({
|
||||
_reference: { $ne: 'EJX3EXUZYW2U' },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
45
src/utils.js
45
src/utils.js
@ -198,6 +198,26 @@ function parsePrefixedValue(value) {
|
||||
return { prefix: null, suffix: trimmed, hadPrefix: false };
|
||||
}
|
||||
|
||||
const FILTER_OPERATOR_PREFIXES = ['<>', '>=', '<=', '>', '<', '='];
|
||||
|
||||
function splitLeadingOperator(str) {
|
||||
const text = String(str).trim();
|
||||
for (const op of FILTER_OPERATOR_PREFIXES) {
|
||||
if (text.startsWith(op)) {
|
||||
return { operator: op, operand: text.slice(op.length).trim() };
|
||||
}
|
||||
}
|
||||
return { operator: '', operand: text };
|
||||
}
|
||||
|
||||
// Strips a model prefix (e.g. GCF:) from an expression, including after a leading operator.
|
||||
function stripModelPrefixFromExpression(expression) {
|
||||
const { operator, operand } = splitLeadingOperator(expression);
|
||||
const { suffix, hadPrefix } = parsePrefixedValue(operand);
|
||||
if (!hadPrefix) return expression;
|
||||
return operator + suffix;
|
||||
}
|
||||
|
||||
function buildRegexOp(pattern, useOptions = true) {
|
||||
const op = { $regex: pattern };
|
||||
if (useOptions) op.$options = 'i';
|
||||
@ -242,12 +262,12 @@ function getRefModelEntryFromPrefix(prefix) {
|
||||
}
|
||||
|
||||
function stripPrefixFromOperand(operand) {
|
||||
const { suffix, hadPrefix } = parsePrefixedValue(String(operand).trim());
|
||||
return hadPrefix ? suffix : String(operand).trim();
|
||||
return stripModelPrefixFromExpression(operand);
|
||||
}
|
||||
|
||||
function getRefModelEntryForToken(token, fallbackRefName) {
|
||||
const { prefix, hadPrefix } = parsePrefixedValue(String(token).trim());
|
||||
const { operand } = splitLeadingOperator(token);
|
||||
const { prefix, hadPrefix } = parsePrefixedValue(operand);
|
||||
if (hadPrefix) {
|
||||
const entry = getRefModelEntryFromPrefix(prefix);
|
||||
if (entry) return entry;
|
||||
@ -741,9 +761,15 @@ function combineAndRefIds(children) {
|
||||
}
|
||||
|
||||
async function resolveRefOperand(operand, refModelEntry, operator = 'eq') {
|
||||
const lookupOperand = String(operand).trim();
|
||||
const { prefix, suffix, hadPrefix } = parsePrefixedValue(lookupOperand);
|
||||
if (hadPrefix) {
|
||||
const prefixEntry = getRefModelEntryFromPrefix(prefix);
|
||||
if (prefixEntry) refModelEntry = prefixEntry;
|
||||
}
|
||||
|
||||
if (!refModelEntry?.model) return NO_MATCH_CONDITION;
|
||||
|
||||
const lookupOperand = String(operand).trim();
|
||||
const objectId = extractObjectIdFromOperand(lookupOperand);
|
||||
|
||||
if (objectId) {
|
||||
@ -752,14 +778,16 @@ async function resolveRefOperand(operand, refModelEntry, operator = 'eq') {
|
||||
return NO_MATCH_CONDITION;
|
||||
}
|
||||
|
||||
const expression = buildRefListExpression(operator, lookupOperand);
|
||||
const ids = await listRefModelIds(refModelEntry, expression);
|
||||
const expressionOperand = hadPrefix ? suffix : lookupOperand;
|
||||
|
||||
if (operator === 'ne') {
|
||||
const ids = await listRefModelIds(refModelEntry, expressionOperand);
|
||||
if (ids.length === 0) return { query: {} };
|
||||
return { op: { $nin: ids } };
|
||||
}
|
||||
|
||||
const expression = buildRefListExpression(operator, expressionOperand);
|
||||
const ids = await listRefModelIds(refModelEntry, expression);
|
||||
return idsToCondition(ids);
|
||||
}
|
||||
|
||||
@ -850,9 +878,8 @@ async function parseFilter(property, value, model = null) {
|
||||
}
|
||||
|
||||
let expression = trimmed;
|
||||
if (fieldKind.kind === 'default' && expression.charAt(3) === ':') {
|
||||
const afterColon = value.split(':')[1];
|
||||
expression = afterColon != null ? afterColon.trim() : '';
|
||||
if (fieldKind.kind === 'default') {
|
||||
expression = stripModelPrefixFromExpression(expression);
|
||||
}
|
||||
|
||||
const isDateField = looksLikeDateField(property);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user