Browse Source

Update query function

Add parsing for query directives.
master
TheoryOfNekomata 6 months ago
parent
commit
0397c9c12c
2 changed files with 108 additions and 74 deletions
  1. +75
    -69
      packages/core/src/backend/data-source/queries.ts
  2. +33
    -5
      packages/core/test/features/query.test.ts

+ 75
- 69
packages/core/src/backend/data-source/queries.ts View File

@@ -1,92 +1,98 @@
export const DIRECTIVE_MAP = { export const DIRECTIVE_MAP = {
'=': 'equals', '=': 'equals',
'!=': 'not-equals', '!=': 'not-equals',
'<': 'greater-than',
'>': 'less-than',
'<=': 'greater-than-equal',
'>=': 'less-than-equal',
'>=': 'greater-than-equal',
'<=': 'less-than-equal',
'>': 'greater-than',
'<': 'less-than',
}; };


export const DATA_SOURCE_QUERY_OPERATORS = Object.keys(DIRECTIVE_MAP) as (keyof typeof DIRECTIVE_MAP)[]; export const DATA_SOURCE_QUERY_OPERATORS = Object.keys(DIRECTIVE_MAP) as (keyof typeof DIRECTIVE_MAP)[];


export type DataSourceQueryOperator = typeof DATA_SOURCE_QUERY_OPERATORS[number]; export type DataSourceQueryOperator = typeof DATA_SOURCE_QUERY_OPERATORS[number];


export interface DataSourceQuery {
export interface DataSourceOperatorQuery {
lhs: string; lhs: string;
operator: DataSourceQueryOperator; operator: DataSourceQueryOperator;
rhs: string; rhs: string;
} }


export interface DataSourceFunctionQuery {
name: string;
args: string[];
}

export type DataSourceQuery = DataSourceOperatorQuery | DataSourceFunctionQuery;

interface ConvertToDataSourceQueryCollectionOptions { interface ConvertToDataSourceQueryCollectionOptions {
} }


const parseDirectives = (valueRaw: string) => { const parseDirectives = (valueRaw: string) => {
let operator = '=';

let hasDirective: boolean;
let valueTest = valueRaw.toLowerCase();
let valuePredicate = valueRaw;
const fragments = valueTest.split('.');
const directiveShorthands = Object.values(DIRECTIVE_MAP).map((s) => {
// TODO how to parse?
})
do {
hasDirective = false;

if (valueTest.startsWith('.neq.')) {
operator = '!=';

valueTest = valueTest.slice('.neq.'.length);
valuePredicate = valuePredicate.slice('.neq.'.length);
hasDirective = true;
} else if (valueTest.startsWith('.gt.eq.')) {
operator = '>=';

valueTest = valueTest.slice('.gt.eq.'.length);
valuePredicate = valuePredicate.slice('.gt.eq.'.length);
hasDirective = true;
} else if (valueTest.startsWith('.gte.')) {
operator = '>=';

valueTest = valueTest.slice('.gte.'.length);
valuePredicate = valuePredicate.slice('.gte.'.length);
hasDirective = true;
} else if (valueTest.startsWith('.lt.eq.')) {
operator = '<=';

valueTest = valueTest.slice('.lt.eq.'.length);
valuePredicate = valuePredicate.slice('.lt.eq.'.length);
hasDirective = true;
} else if (valueTest.startsWith('.lte.')) {
operator = '<=';

valueTest = valueTest.slice('.lte.'.length);
valuePredicate = valuePredicate.slice('.lte.'.length);
hasDirective = true;
} else if (valueTest.startsWith('.gt.')) {
operator = '>';

valueTest = valueTest.slice('.gt.'.length);
valuePredicate = valuePredicate.slice('.gt.'.length);
hasDirective = true;
} else if (valueTest.startsWith('.lt.')) {
operator = '<';

valueTest = valueTest.slice('.lt.'.length);
valuePredicate = valuePredicate.slice('.lt.'.length);
hasDirective = true;
} else if (valueTest.startsWith('.eq.')) {
operator = '=';

valueTest = valueTest.slice('.eq.'.length);
valuePredicate = valuePredicate.slice('.eq.'.length);
hasDirective = true;
}
} while (hasDirective);
const fragments = valueRaw.split('.');

if (!(
fragments.length > 1 && fragments[0].length === 0
)) {
return {
operator: '=',
rhs: valueRaw,
};
}

const theOperator = fragments.slice(1, -1).reduce(
(theState, f) => {
const whichDirective = Object.entries(DIRECTIVE_MAP).find(
([, match]) => {
const remainingChars = match.split('').reduce(
(rem, matchChar) => {
if (matchChar === rem.charAt(0)) {
return rem.slice(1);
}

return rem;
},
f.toLowerCase()
);

return remainingChars.length <= 0;
},
);

const selectedOperator = whichDirective?.[0] ?? theState.operator;

if (selectedOperator === '=') {
if (theState.operator === '>') {
return {
...theState,
operator: '>=',
currentToken: `${theState.currentToken}${f}`,
};
}

if (theState.operator === '<') {
return {
...theState,
operator: '<=',
currentToken: `${theState.currentToken}${f}`,
};
}
}

return {
...theState,
operator: selectedOperator,
currentToken: `${theState.currentToken}${f}`,
};
},
{
operator: undefined as (string | undefined),
currentToken: '',
},
);


return { return {
operator,
rhs: valuePredicate,
operator: theOperator.operator ?? '=',
rhs: fragments.at(-1),
}; };
}; };




+ 33
- 5
packages/core/test/features/query.test.ts View File

@@ -78,11 +78,24 @@ describe('query', () => {
]); ]);
}); });


it('returns a greater than or equal expression query', () => {
it.only('returns a greater than or equal expression query', () => {
// expect(
// convertToDataSourceQueryCollection(
// new URLSearchParams({
// attr: '.gt.eq.foo'
// })
// )
// ).toEqual([
// {
// lhs: 'attr',
// operator: '>=',
// rhs: '"foo"',
// },
// ]);
expect( expect(
convertToDataSourceQueryCollection( convertToDataSourceQueryCollection(
new URLSearchParams({ new URLSearchParams({
attr: '.gt.eq.foo'
attr: '.gte.foo'
}) })
) )
).toEqual([ ).toEqual([
@@ -92,19 +105,34 @@ describe('query', () => {
rhs: '"foo"', rhs: '"foo"',
}, },
]); ]);

expect( expect(
convertToDataSourceQueryCollection( convertToDataSourceQueryCollection(
new URLSearchParams({ new URLSearchParams({
attr: '.gte.foo'
attr: '.neq.test'
}) })
) )
).toEqual([ ).toEqual([
{ {
lhs: 'attr', lhs: 'attr',
operator: '>=',
rhs: '"foo"',
operator: '!=',
rhs: '"test"',
}, },
]); ]);

// expect(
// convertToDataSourceQueryCollection(
// new URLSearchParams({
// attr: '.gte.foo..test'
// })
// )
// ).toEqual([
// {
// lhs: 'attr',
// operator: '>=',
// rhs: '"foo.test"',
// },
// ]);
}); });


it('returns a less than or equal expression query', () => { it('returns a less than or equal expression query', () => {


Loading…
Cancel
Save