Skip to content

Commit

Permalink
Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
charlesBochet committed Sep 19, 2024
1 parent b91d9cd commit 42490dc
Show file tree
Hide file tree
Showing 10 changed files with 544 additions and 442 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { FindOptionsWhere, ObjectLiteral } from 'typeorm';
import {
Brackets,
NotBrackets,
SelectQueryBuilder,
WhereExpressionBuilder,
} from 'typeorm';

import { RecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';

Expand All @@ -8,106 +13,134 @@ import { GraphqlQueryFilterFieldParser } from './graphql-query-filter-field.pars

export class GraphqlQueryFilterConditionParser {
private fieldMetadataMap: FieldMetadataMap;
private fieldConditionParser: GraphqlQueryFilterFieldParser;
private queryFilterFieldParser: GraphqlQueryFilterFieldParser;

constructor(fieldMetadataMap: FieldMetadataMap) {
this.fieldMetadataMap = fieldMetadataMap;
this.fieldConditionParser = new GraphqlQueryFilterFieldParser(
this.queryFilterFieldParser = new GraphqlQueryFilterFieldParser(
this.fieldMetadataMap,
);
}

public parse(
conditions: RecordFilter,
isNegated = false,
): FindOptionsWhere<ObjectLiteral> | FindOptionsWhere<ObjectLiteral>[] {
if (Array.isArray(conditions)) {
return this.parseAndCondition(conditions, isNegated);
queryBuilder: SelectQueryBuilder<any>,
objectNameSingular: string,
filter: RecordFilter,
): SelectQueryBuilder<any> {
if (!filter || Object.keys(filter).length === 0) {
return queryBuilder;
}

const result: FindOptionsWhere<ObjectLiteral> = {};

for (const [key, value] of Object.entries(conditions)) {
switch (key) {
case 'and': {
const andConditions = this.parseAndCondition(value, isNegated);
return queryBuilder.where(
new Brackets((qb) => {
Object.entries(filter).forEach(([key, value], index) => {
this.parseKeyFilter(qb, objectNameSingular, key, value, index === 0);
});
}),
);
}

return andConditions.map((condition) => ({
...result,
...condition,
}));
private parseKeyFilter(
queryBuilder: WhereExpressionBuilder,
objectNameSingular: string,
key: string,
value: any,
isFirst = false,
): void {
switch (key) {
case 'and': {
const andWhereCondition = new Brackets((qb) => {
value.forEach((filter: RecordFilter, index: number) => {
const whereCondition = new Brackets((qb) => {
Object.entries(filter).forEach(
([subFilterkey, subFilterValue]) => {
this.parseKeyFilter(
qb,
objectNameSingular,
subFilterkey,
subFilterValue,
);
},
);
});

if (index === 0) {
qb.where(whereCondition);
}
qb.andWhere(whereCondition);
});
});

if (isFirst) {
queryBuilder.where(andWhereCondition);
}
case 'or': {
const orConditions = this.parseOrCondition(value, isNegated);

return orConditions.map((condition) => ({ ...result, ...condition }));
}
case 'not':
Object.assign(result, this.parse(value, !isNegated));
break;
default:
Object.assign(
result,
this.fieldConditionParser.parse(key, value, isNegated),
);
queryBuilder.andWhere(andWhereCondition);
break;
}
}

return result;
}
case 'or': {
const orWhereCondition = new Brackets((qb) => {
value.forEach((filter: RecordFilter, index: number) => {
const whereCondition = new Brackets((qb) => {
Object.entries(filter).forEach(
([subFilterkey, subFilterValue]) => {
this.parseKeyFilter(
qb,
objectNameSingular,
subFilterkey,
subFilterValue,
);
},
);
});

if (index === 0) {
qb.where(whereCondition);
}
qb.orWhere(whereCondition);
});
});

if (isFirst) {
queryBuilder.where(orWhereCondition);
}

private parseAndCondition(
conditions: RecordFilter[],
isNegated: boolean,
): FindOptionsWhere<ObjectLiteral>[] {
const parsedConditions = conditions.map((condition) =>
this.parse(condition, isNegated),
);
queryBuilder.andWhere(orWhereCondition);

return this.combineConditions(parsedConditions, isNegated ? 'or' : 'and');
}
break;
}
case 'not': {
const notWhereCondition = new NotBrackets((qb) => {
Object.entries(value).forEach(
([subFilterkey, subFilterValue], index) => {
this.parseKeyFilter(
qb,
objectNameSingular,
subFilterkey,
subFilterValue,
index === 0,
);
},
);
});

private parseOrCondition(
conditions: RecordFilter[],
isNegated: boolean,
): FindOptionsWhere<ObjectLiteral>[] {
const parsedConditions = conditions.map((condition) =>
this.parse(condition, isNegated),
);
if (isFirst) {
queryBuilder.where(notWhereCondition);
}

return this.combineConditions(parsedConditions, isNegated ? 'and' : 'or');
}
queryBuilder.andWhere(notWhereCondition);

private combineConditions(
conditions: (
| FindOptionsWhere<ObjectLiteral>
| FindOptionsWhere<ObjectLiteral>[]
)[],
combineType: 'and' | 'or',
): FindOptionsWhere<ObjectLiteral>[] {
if (combineType === 'and') {
return conditions.reduce<FindOptionsWhere<ObjectLiteral>[]>(
(acc, condition) => {
if (Array.isArray(condition)) {
return acc.flatMap((accCondition) =>
condition.map((subCondition) => ({
...accCondition,
...subCondition,
})),
);
}

return acc.map((accCondition) => ({
...accCondition,
...condition,
}));
},
[{}],
);
break;
}
default:
this.queryFilterFieldParser.parse(
queryBuilder,
objectNameSingular,
key,
value,
isFirst,
);
break;
}

return conditions.flatMap((condition) =>
Array.isArray(condition) ? condition : [condition],
);
}
}
Loading

0 comments on commit 42490dc

Please sign in to comment.