feat: added $ilike operator (#373)

This commit is contained in:
Anderson R 2022-11-03 08:20:08 -03:00 committed by GitHub
parent ea86b6d502
commit 23b2e762f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 1 deletions

View File

@ -13,7 +13,7 @@ Pagination and filtering helper method for TypeORM repositories or query builder
- Pagination conforms to [JSON:API](https://jsonapi.org/) - Pagination conforms to [JSON:API](https://jsonapi.org/)
- Sort by multiple columns - Sort by multiple columns
- Search across columns - Search across columns
- Filter using operators (`$eq`, `$not`, `$null`, `$in`, `$gt`, `$gte`, `$lt`, `$lte`, `$btw`) - Filter using operators (`$eq`, `$not`, `$null`, `$in`, `$gt`, `$gte`, `$lt`, `$lte`, `$btw`, `$ilike`)
- Include relations - Include relations
## Installation ## Installation

View File

@ -1146,6 +1146,29 @@ describe('paginate', () => {
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.name=$not:Leche&filter.color=white') expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.name=$not:Leche&filter.color=white')
}) })
it('should return result based on $ilike filter', async () => {
const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'],
filterableColumns: {
name: [FilterOperator.ILIKE],
},
}
const query: PaginateQuery = {
path: '',
filter: {
name: '$ilike:Garf',
},
}
const result = await paginate<CatEntity>(query, catRepo, config)
expect(result.meta.filter).toStrictEqual({
name: '$ilike:Garf',
})
expect(result.data).toStrictEqual([cats[1]])
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.name=$ilike:Garf')
})
it('should return result based on filter and search term', async () => { it('should return result based on filter and search term', async () => {
const config: PaginateConfig<CatEntity> = { const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'], sortableColumns: ['id'],
@ -1338,6 +1361,7 @@ describe('paginate', () => {
{ operator: '$lte', result: true }, { operator: '$lte', result: true },
{ operator: '$btw', result: true }, { operator: '$btw', result: true },
{ operator: '$not', result: true }, { operator: '$not', result: true },
{ operator: '$ilike', result: true },
{ operator: '$fake', result: false }, { operator: '$fake', result: false },
])('should check operator "$operator" valid is $result', ({ operator, result }) => { ])('should check operator "$operator" valid is $result', ({ operator, result }) => {
expect(isOperator(operator)).toStrictEqual(result) expect(isOperator(operator)).toStrictEqual(result)
@ -1353,12 +1377,14 @@ describe('paginate', () => {
{ operator: '$lte', name: 'LessThanOrEqual' }, { operator: '$lte', name: 'LessThanOrEqual' },
{ operator: '$btw', name: 'Between' }, { operator: '$btw', name: 'Between' },
{ operator: '$not', name: 'Not' }, { operator: '$not', name: 'Not' },
{ operator: '$ilike', name: 'ILike' },
])('should get operator function $name for "$operator"', ({ operator, name }) => { ])('should get operator function $name for "$operator"', ({ operator, name }) => {
const func = OperatorSymbolToFunction.get(operator as FilterOperator) const func = OperatorSymbolToFunction.get(operator as FilterOperator)
expect(func.name).toStrictEqual(name) expect(func.name).toStrictEqual(name)
}) })
it.each([ it.each([
{ string: '$ilike:value', tokens: [null, '$ilike', 'value'] },
{ string: '$eq:value', tokens: [null, '$eq', 'value'] }, { string: '$eq:value', tokens: [null, '$eq', 'value'] },
{ string: '$eq:val:ue', tokens: [null, '$eq', 'val:ue'] }, { string: '$eq:val:ue', tokens: [null, '$eq', 'val:ue'] },
{ string: '$in:value1,value2,value3', tokens: [null, '$in', 'value1,value2,value3'] }, { string: '$in:value1,value2,value3', tokens: [null, '$in', 'value1,value2,value3'] },

View File

@ -69,6 +69,7 @@ export enum FilterOperator {
LTE = '$lte', LTE = '$lte',
BTW = '$btw', BTW = '$btw',
NOT = '$not', NOT = '$not',
ILIKE = '$ilike',
} }
export function isOperator(value: unknown): value is FilterOperator { export function isOperator(value: unknown): value is FilterOperator {
@ -85,6 +86,7 @@ export const OperatorSymbolToFunction = new Map<FilterOperator, (...args: any[])
[FilterOperator.LTE, LessThanOrEqual], [FilterOperator.LTE, LessThanOrEqual],
[FilterOperator.BTW, Between], [FilterOperator.BTW, Between],
[FilterOperator.NOT, Not], [FilterOperator.NOT, Not],
[FilterOperator.ILIKE, ILike],
]) ])
export function getFilterTokens(raw: string): string[] { export function getFilterTokens(raw: string): string[] {
@ -145,6 +147,9 @@ function parseFilter<T>(query: PaginateQuery, config: PaginateConfig<T>) {
case FilterOperator.IN: case FilterOperator.IN:
filter[column] = OperatorSymbolToFunction.get(op1)(value.split(',')) filter[column] = OperatorSymbolToFunction.get(op1)(value.split(','))
break break
case FilterOperator.ILIKE:
filter[column] = OperatorSymbolToFunction.get(op1)(`%${value}%`)
break
default: default:
filter[column] = OperatorSymbolToFunction.get(op1)(value) filter[column] = OperatorSymbolToFunction.get(op1)(value)
break break