feat: extend filter with enable all ops config
This commit is contained in:
parent
0c45c6da63
commit
3fa48d4f63
20
README.md
20
README.md
@ -370,12 +370,28 @@ const config: PaginateConfig<CatEntity> = {
|
||||
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||
```
|
||||
|
||||
## Single Filters
|
||||
## Filters
|
||||
|
||||
Filter operators must be whitelisted per column in `PaginateConfig`.
|
||||
|
||||
### Examples
|
||||
|
||||
#### Code
|
||||
|
||||
```typescript
|
||||
const config: PaginateConfig<CatEntity> = {
|
||||
// ...
|
||||
filterableColumns: {
|
||||
// Whitelist operators individually
|
||||
id: [FilterOperator.EQ, FilterSuffix.NOT],
|
||||
'toys.name': [FilterOperator.IN],
|
||||
|
||||
// Whitelist all operators on a single column
|
||||
age: true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
`?filter.name=$eq:Milo` is equivalent with `?filter.name=Milo`
|
||||
|
||||
`?filter.age=$btw:4,6` where column `age` is between `4` and `6`
|
||||
@ -398,7 +414,7 @@ Filter operators must be whitelisted per column in `PaginateConfig`.
|
||||
|
||||
## Multi Filters
|
||||
|
||||
Multi filters are filters that can be applied to a single column with a comparator. As for single filters, multi filters must be whitelisted per column in `PaginateConfig`.
|
||||
Multi filters are filters that can be applied to a single column with a comparator.
|
||||
|
||||
### Examples
|
||||
|
||||
|
@ -227,7 +227,7 @@ export function getFilterTokens(raw?: string): FilterToken | null {
|
||||
|
||||
export function parseFilter(
|
||||
query: PaginateQuery,
|
||||
filterableColumns?: { [column: string]: (FilterOperator | FilterSuffix)[] }
|
||||
filterableColumns?: { [column: string]: (FilterOperator | FilterSuffix)[] | true }
|
||||
): ColumnsFilters {
|
||||
const filter: ColumnsFilters = {}
|
||||
if (!filterableColumns || !query.filter) {
|
||||
@ -242,20 +242,28 @@ export function parseFilter(
|
||||
const statements = !Array.isArray(input) ? [input] : input
|
||||
for (const raw of statements) {
|
||||
const token = getFilterTokens(raw)
|
||||
if (
|
||||
!token ||
|
||||
!(
|
||||
allowedOperators.includes(token.operator) ||
|
||||
(token.suffix === FilterSuffix.NOT &&
|
||||
allowedOperators.includes(token.suffix) &&
|
||||
token.operator === FilterOperator.EQ) ||
|
||||
(token.suffix &&
|
||||
allowedOperators.includes(token.suffix) &&
|
||||
allowedOperators.includes(token.operator))
|
||||
)
|
||||
) {
|
||||
if (!token) {
|
||||
continue
|
||||
}
|
||||
if (allowedOperators === true) {
|
||||
if (token.operator && !isOperator(token.operator)) {
|
||||
continue
|
||||
}
|
||||
if (token.suffix && !isSuffix(token.suffix)) {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
token.operator &&
|
||||
token.operator !== FilterOperator.EQ &&
|
||||
!allowedOperators.includes(token.operator)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
if (token.suffix && !allowedOperators.includes(token.suffix)) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
const params: (typeof filter)[0][0] = {
|
||||
comparator: token.comparator,
|
||||
@ -297,7 +305,7 @@ export function parseFilter(
|
||||
export function addFilter<T>(
|
||||
qb: SelectQueryBuilder<T>,
|
||||
query: PaginateQuery,
|
||||
filterableColumns?: { [column: string]: (FilterOperator | FilterSuffix)[] }
|
||||
filterableColumns?: { [column: string]: (FilterOperator | FilterSuffix)[] | true }
|
||||
): SelectQueryBuilder<T> {
|
||||
const filter = parseFilter(query, filterableColumns)
|
||||
return qb.andWhere(
|
||||
|
@ -2155,4 +2155,41 @@ describe('paginate', () => {
|
||||
expect(result.data[0].home).toBeDefined()
|
||||
expect(result.data[0].home.pillows).toStrictEqual(cat.home.pillows)
|
||||
})
|
||||
|
||||
it('should allow all filters on a field when passing boolean', async () => {
|
||||
const config: PaginateConfig<CatEntity> = {
|
||||
sortableColumns: ['id'],
|
||||
filterableColumns: {
|
||||
id: true,
|
||||
},
|
||||
}
|
||||
const query: PaginateQuery = {
|
||||
path: '',
|
||||
filter: {
|
||||
id: '$not:$in:1,2,5',
|
||||
},
|
||||
}
|
||||
|
||||
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||
|
||||
expect(result.data).toStrictEqual([cats[2], cats[3]])
|
||||
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.id=$not:$in:1,2,5')
|
||||
})
|
||||
|
||||
it('should ignore all filters on a field when not passing anything', async () => {
|
||||
const config: PaginateConfig<CatEntity> = {
|
||||
sortableColumns: ['id'],
|
||||
}
|
||||
const query: PaginateQuery = {
|
||||
path: '',
|
||||
filter: {
|
||||
id: '$not:$in:1,2,5',
|
||||
},
|
||||
}
|
||||
|
||||
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||
|
||||
expect(result.data).toStrictEqual([cats[0], cats[1], cats[2], cats[3], cats[4]])
|
||||
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.id=$not:$in:1,2,5')
|
||||
})
|
||||
})
|
||||
|
@ -66,7 +66,7 @@ export interface PaginateConfig<T> {
|
||||
defaultLimit?: number
|
||||
where?: FindOptionsWhere<T> | FindOptionsWhere<T>[]
|
||||
filterableColumns?: {
|
||||
[key in Column<T> | string]?: (FilterOperator | FilterSuffix)[]
|
||||
[key in Column<T> | string]?: (FilterOperator | FilterSuffix)[] | true
|
||||
}
|
||||
loadEagerRelations?: boolean
|
||||
withDeleted?: boolean
|
||||
|
Loading…
Reference in New Issue
Block a user