@@ -64,25 +64,9 @@ export type LengthOperator = 'LENGTH';
6464
6565export type ArrayOperator = 'IN';
6666
67- export type CaseOperator = 'CASE';
68-
69- export type CaseNode<Entity, PropType> = {
70- [K in CaseOperator]: CaseExpression<Entity, PropType>;
71- };
72-
73- type InCaseNode<Case> = Case extends CaseNode<infer Entity, infer PropType> ? CaseNode<Entity, PropType[]> : never;
74-
75- export type CaseExpression<Entity, PropType> = {
76- IF: SingleFilterExpr<Entity>;
77- THEN: PropType | CaseNode<Entity, PropType>;
78- ELSE: PropType | CaseNode<Entity, PropType>;
79- };
80-
8167export type NullOperator = 'NULL';
8268
83- export type Operator = ComparisonOperator | ArrayOperator | CaseOperator | NullOperator;
84-
85- export type BinaryOperator = Exclude<Operator, CaseOperator>;
69+ export type Operator = ComparisonOperator | ArrayOperator | NullOperator;
8670
8771export type ModifierFunction = 'LOWER' | 'TRIM';
8872
@@ -104,37 +88,42 @@ export type LengthExprWithModifier =
10488 { [K in NullOperator]?: never } &
10589 { [K in ModifierFunction]?: boolean };
10690
107- export type FilterExpr<T, Case = never > =
108- { [K in ComparisonOperator]?: T | Case } &
109- { [K in ArrayOperator]?: T[] | InCaseNode<Case> } &
91+ export type FilterExpr<T> =
92+ { [K in ComparisonOperator]?: T } &
93+ { [K in ArrayOperator]?: T[] } &
11094 { [K in keyof LengthExpr]?: never };
11195
112- export type FilterExprWithoutNull<T, Case = never > =
113- RequireAtLeastOne<FilterExpr<T, Case >> &
96+ export type FilterExprWithoutNull<T> =
97+ RequireAtLeastOne<FilterExpr<T>> &
11498 { [K in NullOperator]?: never } &
11599 { [K in ModifierFunction]?: boolean };
116100
117- export type FilterExprWithNull<T, Case = never > =
118- FilterExpr<T, Case > &
101+ export type FilterExprWithNull<T> =
102+ FilterExpr<T> &
119103 { [K in NullOperator]?: boolean} &
120104 { [K in ModifierFunction]?: never };
121105
122- export type MapOperators<T, Case = never > = LengthExprWithModifier | FilterExprWithoutNull<T, Case > | FilterExprWithNull<T, Case >;
106+ export type MapOperators<T> = LengthExprWithModifier | FilterExprWithoutNull<T> | FilterExprWithNull<T>;
123107
124108export type SingleFilterExpr<T> = {
125109 [P in keyof T]?: T[P] extends Array<infer U> | undefined
126110 ? U extends Record<any, any>
127111 ? SingleFilterExpr<U> | { NOT?: SingleFilterExpr<U> }
128- : MapOperators<U, CaseNode<T, T[P]> >
112+ : MapOperators<U>
129113 : T[P] extends Record<any, any> | undefined
130114 ? SingleFilterExpr<T[P]> | { NOT?: SingleFilterExpr<T[P]> }
131- : MapOperators<T[P], CaseNode<T, T[P]> >;
115+ : MapOperators<T[P]>;
132116};
133117
134118export type QueryFilter<T> = SingleFilterExpr<T> & {
135119 OR?: QueryFilter<T>[];
136120 AND?: QueryFilter<T>[];
137121 NOT?: QueryFilter<T>;
122+ CASE?: {
123+ IF: QueryFilter<T>;
124+ THEN: QueryFilter<T>;
125+ ELSE: QueryFilter<T>;
126+ };
138127};
139128
140129export type ConditionalOrderByCase<E> = {
@@ -194,7 +183,7 @@ const comparisonOperatorList: ComparisonOperator[] = [
194183 'LIKE'
195184];
196185
197- const comparisonOperatorMap: Record<BinaryOperator , string> = {
186+ const comparisonOperatorMap: Record<Operator , string> = {
198187 EQ: '=',
199188 NE: '!=',
200189 LT: '<',
@@ -259,7 +248,7 @@ const flattenWhere = (
259248 `not ${flattedNot.length > 1 ? '(' : ''}${flattedNot.join(' and ')}${flattedNot.length > 1 ? ')' : ''}`
260249 );
261250 } else if (prop === 'CASE') {
262- entries.push(evaluateCaseExpression(propValue as CaseExpression <any, any>, setModifiers , nestedPaths));
251+ entries.push(evaluateCaseExpression(propValue as QueryFilter <any> , nestedPaths));
263252 } else if (propValue) {
264253 for (const [operator, value] of Object.entries(propValue)) {
265254 if (value === undefined) continue;
@@ -268,40 +257,27 @@ const flattenWhere = (
268257 `${setModifiers.reduce(
269258 (acc, [first]) => `${first.toLowerCase()}(${acc})`,
270259 nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')
271- )} ${comparisonOperatorMap[operator as BinaryOperator]} ${
272- typeof value === 'object'
273- ? flattenWhere(value, nestedPaths)
274- : typeof value === 'string'
275- ? setModifiers.reduce((acc, [first]) => `${first}(${acc})`, JSON.stringify(value))
276- : value
260+ )} ${comparisonOperatorMap[operator as Operator]} ${
261+ typeof value === 'string' ? JSON.stringify(value) : value
277262 }`
278263 );
279264 } else if ((operator as Operator) === 'NULL') {
280265 entries.push(
281- `${!value ? 'not ' : ''}${nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')} ${comparisonOperatorMap[operator as BinaryOperator ]}`
266+ `${!value ? 'not ' : ''}${nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')} ${comparisonOperatorMap[operator as Operator ]}`
282267 );
283268 } else if ((operator as Operator) === 'IN') {
284- if (typeof value === 'object' && !Array.isArray(value) && value.CASE) {
285- entries.push(
286- `${setModifiers.reduce(
287- (acc, [first]) => `${first}(${acc})`,
288- nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')
289- )} ${comparisonOperatorMap[operator as BinaryOperator]} ${evaluateCaseExpression(value.CASE as CaseExpression<any, any>, setModifiers, nestedPaths)}`
290- );
291- } else if(value.length === 0) {
269+ if(value.length === 0) {
292270 entries.push('1 = 0')
293271 } else {
294272 entries.push(
295273 `${setModifiers.reduce(
296274 (acc, [first]) => `${first.toLowerCase()}(${acc})`,
297275 nestedPaths.some((path) => path === prop) ? nestedPaths.join('.') : [...nestedPaths, prop].join('.')
298- )} ${comparisonOperatorMap[operator as BinaryOperator ]} [${value.map((v: string | number) =>
276+ )} ${comparisonOperatorMap[operator as Operator ]} [${value.map((v: string | number) =>
299277 typeof v === 'string' ? setModifiers.reduce((acc, [first]) => `${first}(${acc})`, JSON.stringify(v)) : v
300278 )}]`
301279 );
302280 }
303- } else if ((operator as Operator) === 'CASE') {
304- entries.push(evaluateCaseExpression(value as CaseExpression<any, any>, setModifiers, nestedPaths));
305281 } else if ((operator as LengthOperator) === 'LENGTH') {
306282 const lengthProp = `length(${setModifiers.reduce(
307283 (acc, [first]) => `${first.toLowerCase()}(${acc})`,
@@ -326,24 +302,8 @@ const flattenWhere = (
326302 return entries;
327303};
328304
329- const evaluateCaseExpression = <FilterProps, PropType>(
330- exp: CaseExpression<FilterProps, PropType>,
331- setModifiers: [string, any][],
332- nestedPaths: string[]
333- ): string =>
334- `(${flattenWhere(exp.IF, nestedPaths)} ? ${
335- typeof exp.THEN === 'string' || Array.isArray(exp.THEN)
336- ? setModifiers.reduce((acc, [first]) => `${first}(${acc})`, JSON.stringify(exp.THEN))
337- : typeof exp.THEN === 'number' || typeof exp.THEN === 'boolean'
338- ? exp.THEN
339- : evaluateCaseExpression((exp.THEN as CaseNode<FilterProps, PropType>).CASE, setModifiers, nestedPaths)
340- } : ${
341- typeof exp.ELSE === 'string' || Array.isArray(exp.ELSE)
342- ? setModifiers.reduce((acc, [first]) => `${first}(${acc})`, JSON.stringify(exp.ELSE))
343- : typeof exp.ELSE === 'number' || typeof exp.ELSE === 'boolean'
344- ? exp.ELSE
345- : evaluateCaseExpression((exp.ELSE as CaseNode<FilterProps, PropType>).CASE, setModifiers, nestedPaths)
346- })`;
305+ const evaluateCaseExpression = (exp: QueryFilter<any>, nestedPaths: string[]): string =>
306+ `(${flattenWhere(exp.IF as QueryFilter<any>, nestedPaths)} ? ${flattenWhere(exp.THEN as QueryFilter<any>, nestedPaths)} : ${flattenWhere(exp.ELSE as QueryFilter<any>, nestedPaths)})`;
347307
348308const assembleOrderBy = (orderBy: OrderBy<any>[] = []): Record<string, string> => {
349309 if(!orderBy.length) {
0 commit comments