From 1883c2d92f85740d87b3686cbb2ea3918a46f04c Mon Sep 17 00:00:00 2001 From: Andreas <132681533+anddyyyy46@users.noreply.github.com> Date: Mon, 9 Sep 2024 11:39:37 +0200 Subject: [PATCH] fix: sql query for multifilter (#970) --- src/filter.ts | 16 ++++----- src/paginate.spec.ts | 83 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 8 deletions(-) diff --git a/src/filter.ts b/src/filter.ts index 1f93ef48..158492f1 100644 --- a/src/filter.ts +++ b/src/filter.ts @@ -322,8 +322,8 @@ export function addFilter( const filter = parseFilter(query, filterableColumns) const filterEntries = Object.entries(filter) - const orFilters = filterEntries.filter(([_, value]) => value.some((v) => v.comparator === '$or')) - const andFilters = filterEntries.filter(([_, value]) => value.some((v) => v.comparator !== '$or')) + const orFilters = filterEntries.filter(([_, value]) => value[0].comparator === '$or') + const andFilters = filterEntries.filter(([_, value]) => value[0].comparator === '$and') qb.andWhere( new Brackets((qb: SelectQueryBuilder) => { @@ -333,13 +333,13 @@ export function addFilter( }) ) - qb.andWhere( - new Brackets((qb: SelectQueryBuilder) => { - for (const [column] of andFilters) { + for (const [column] of andFilters) { + qb.andWhere( + new Brackets((qb: SelectQueryBuilder) => { addWhereCondition(qb, column, filter) - } - }) - ) + }) + ) + } return qb } diff --git a/src/paginate.spec.ts b/src/paginate.spec.ts index 18033761..13253d8e 100644 --- a/src/paginate.spec.ts +++ b/src/paginate.spec.ts @@ -2255,6 +2255,89 @@ describe('paginate', () => { ) }) + it('should return result based on two multifilters chained together with and operator', async () => { + const config: PaginateConfig = { + sortableColumns: ['id'], + filterableColumns: { + name: true, + color: true, + }, + } + const query: PaginateQuery = { + path: '', + filter: { + name: ['Milo', '$or:Garfield'], + color: ['brown', '$or:white'], + }, + } + const result = await paginate(query, catRepo, config) + const expected = cats.filter( + (cat) => + (cat.name === 'Milo' || cat.name === 'Garfield') && (cat.color === 'brown' || cat.color === 'white') + ) + expect(result.data).toStrictEqual(expected) + expect(result.links.current).toBe( + '?page=1&limit=20&sortBy=id:ASC&filter.name=Milo&filter.name=$or:Garfield&filter.color=brown&filter.color=$or:white' + ) + }) + + it('should return result based on two multifilters chained together with or operator', async () => { + const config: PaginateConfig = { + sortableColumns: ['id'], + filterableColumns: { + name: true, + color: true, + }, + } + const query: PaginateQuery = { + path: '', + filter: { + name: ['$or:Milo', '$or:Garfield'], + color: ['$or:brown', '$or:white'], + }, + } + const result = await paginate(query, catRepo, config) + const expected = cats.filter( + (cat) => cat.name === 'Milo' || cat.name === 'Garfield' || cat.color === 'brown' || cat.color === 'white' + ) + expect(result.data).toStrictEqual(expected) + expect(result.links.current).toBe( + '?page=1&limit=20&sortBy=id:ASC&filter.name=$or:Milo&filter.name=$or:Garfield&filter.color=$or:brown&filter.color=$or:white' + ) + }) + + it('should return result based on filters chained together with and operators and or operators', async () => { + const config: PaginateConfig = { + sortableColumns: ['id'], + filterableColumns: { + name: true, + color: true, + age: true, + cutenessLevel: true, + }, + } + const query: PaginateQuery = { + path: '', + filter: { + name: ['$or:Milo', '$or:Garfield'], + age: '$or:$null', + color: ['brown', '$or:white'], + cutenessLevel: [CutenessLevel.HIGH, `$or:${CutenessLevel.LOW}`], + }, + } + const result = await paginate(query, catRepo, config) + const expected = cats.filter( + (cat) => + (cat.name === 'Milo' || cat.name === 'Garfield' || !cat.age) && + (cat.color === 'brown' || cat.color === 'white') && + (cat.cutenessLevel === CutenessLevel.HIGH || cat.cutenessLevel === CutenessLevel.LOW) + ) + expect(result.data).toStrictEqual(expected) + expect(result.links.current).toBe( + '?page=1&limit=20&sortBy=id:ASC&filter.name=$or:Milo&filter.name=$or:Garfield&filter.age=$or:$null&filter.color=brown&filter.color=$or:white&filter.cutenessLevel=high&filter.cutenessLevel=$or:low' + ) + }) + it("should return all columns if select doesn't contain all primary columns", async () => { const config: PaginateConfig = { sortableColumns: ['id', 'name'],