use hash map for op function lookup
This commit is contained in:
parent
7d85cf94b0
commit
3b09c1c90d
@ -5,8 +5,8 @@ import {
|
|||||||
PaginateConfig,
|
PaginateConfig,
|
||||||
FilterOperator,
|
FilterOperator,
|
||||||
isOperator,
|
isOperator,
|
||||||
getOperatorFn,
|
|
||||||
getFilterTokens,
|
getFilterTokens,
|
||||||
|
OperatorSymbolToFunction,
|
||||||
} from './paginate'
|
} from './paginate'
|
||||||
import { PaginateQuery } from './decorator'
|
import { PaginateQuery } from './decorator'
|
||||||
import { Entity, PrimaryGeneratedColumn, CreateDateColumn } from 'typeorm'
|
import { Entity, PrimaryGeneratedColumn, CreateDateColumn } from 'typeorm'
|
||||||
@ -45,7 +45,7 @@ describe('paginate', () => {
|
|||||||
repo = connection.getRepository(CatEntity)
|
repo = connection.getRepository(CatEntity)
|
||||||
cats = await repo.save([
|
cats = await repo.save([
|
||||||
repo.create({ name: 'Milo', color: 'brown', age: 6 }),
|
repo.create({ name: 'Milo', color: 'brown', age: 6 }),
|
||||||
repo.create({ name: 'Garfield', color: 'ginger', age: null }),
|
repo.create({ name: 'Garfield', color: 'ginger', age: 5 }),
|
||||||
repo.create({ name: 'Shadow', color: 'black', age: 4 }),
|
repo.create({ name: 'Shadow', color: 'black', age: 4 }),
|
||||||
repo.create({ name: 'George', color: 'white', age: 3 }),
|
repo.create({ name: 'George', color: 'white', age: 3 }),
|
||||||
repo.create({ name: 'Leche', color: 'white', age: null }),
|
repo.create({ name: 'Leche', color: 'white', age: null }),
|
||||||
@ -342,7 +342,7 @@ describe('paginate', () => {
|
|||||||
|
|
||||||
const result = await paginate<CatEntity>(query, repo, config)
|
const result = await paginate<CatEntity>(query, repo, config)
|
||||||
|
|
||||||
expect(result.data).toStrictEqual([cats[0], cats[2]])
|
expect(result.data).toStrictEqual([cats[0], cats[1], cats[2]])
|
||||||
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.age=$gte:4')
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.age=$gte:4')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -356,14 +356,14 @@ describe('paginate', () => {
|
|||||||
const query: PaginateQuery = {
|
const query: PaginateQuery = {
|
||||||
path: '',
|
path: '',
|
||||||
filter: {
|
filter: {
|
||||||
age: '$btw:4,6',
|
age: '$btw:4,5',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await paginate<CatEntity>(query, repo, config)
|
const result = await paginate<CatEntity>(query, repo, config)
|
||||||
|
|
||||||
expect(result.data).toStrictEqual([cats[0], cats[2]])
|
expect(result.data).toStrictEqual([cats[1], cats[2]])
|
||||||
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.age=$btw:4,6')
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.age=$btw:4,5')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return result based on is null query', async () => {
|
it('should return result based on is null query', async () => {
|
||||||
@ -382,7 +382,7 @@ describe('paginate', () => {
|
|||||||
|
|
||||||
const result = await paginate<CatEntity>(query, repo, config)
|
const result = await paginate<CatEntity>(query, repo, config)
|
||||||
|
|
||||||
expect(result.data).toStrictEqual([cats[1], cats[4]])
|
expect(result.data).toStrictEqual([cats[4]])
|
||||||
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.age=$null')
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.age=$null')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -402,7 +402,7 @@ describe('paginate', () => {
|
|||||||
|
|
||||||
const result = await paginate<CatEntity>(query, repo, config)
|
const result = await paginate<CatEntity>(query, repo, config)
|
||||||
|
|
||||||
expect(result.data).toStrictEqual([cats[0], cats[2], cats[3]])
|
expect(result.data).toStrictEqual([cats[0], cats[1], cats[2], cats[3]])
|
||||||
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.age=$not:$null')
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.age=$not:$null')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -487,7 +487,7 @@ describe('paginate', () => {
|
|||||||
{ operator: '$btw', name: 'Between' },
|
{ operator: '$btw', name: 'Between' },
|
||||||
{ operator: '$not', name: 'Not' },
|
{ operator: '$not', name: 'Not' },
|
||||||
])('should get operator function $name for "$operator"', ({ operator, name }) => {
|
])('should get operator function $name for "$operator"', ({ operator, name }) => {
|
||||||
const func = getOperatorFn<CatEntity>(operator as FilterOperator)
|
const func = OperatorSymbolToFunction.get(operator as FilterOperator)
|
||||||
expect(func.name).toStrictEqual(name)
|
expect(func.name).toStrictEqual(name)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -72,28 +72,17 @@ export function isOperator(value: unknown): value is FilterOperator {
|
|||||||
return values(FilterOperator).includes(value as any)
|
return values(FilterOperator).includes(value as any)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOperatorFn<T>(op: FilterOperator): (...args: any[]) => FindOperator<T> {
|
export const OperatorSymbolToFunction = new Map<FilterOperator, (...args: any[]) => FindOperator<string>>([
|
||||||
switch (op) {
|
[FilterOperator.EQ, Equal],
|
||||||
case FilterOperator.EQ:
|
[FilterOperator.GT, MoreThan],
|
||||||
return Equal
|
[FilterOperator.GTE, MoreThanOrEqual],
|
||||||
case FilterOperator.GT:
|
[FilterOperator.IN, In],
|
||||||
return MoreThan
|
[FilterOperator.NULL, IsNull],
|
||||||
case FilterOperator.GTE:
|
[FilterOperator.LT, LessThan],
|
||||||
return MoreThanOrEqual
|
[FilterOperator.LTE, LessThanOrEqual],
|
||||||
case FilterOperator.IN:
|
[FilterOperator.BTW, Between],
|
||||||
return In
|
[FilterOperator.NOT, Not],
|
||||||
case FilterOperator.NULL:
|
])
|
||||||
return IsNull
|
|
||||||
case FilterOperator.LT:
|
|
||||||
return LessThan
|
|
||||||
case FilterOperator.LTE:
|
|
||||||
return LessThanOrEqual
|
|
||||||
case FilterOperator.BTW:
|
|
||||||
return Between
|
|
||||||
case FilterOperator.NOT:
|
|
||||||
return Not
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getFilterTokens(raw: string): string[] {
|
export function getFilterTokens(raw: string): string[] {
|
||||||
const tokens = []
|
const tokens = []
|
||||||
@ -125,12 +114,11 @@ export function getFilterTokens(raw: string): string[] {
|
|||||||
|
|
||||||
function parseFilter<T>(query: PaginateQuery, config: PaginateConfig<T>) {
|
function parseFilter<T>(query: PaginateQuery, config: PaginateConfig<T>) {
|
||||||
const filter = {}
|
const filter = {}
|
||||||
|
|
||||||
for (const column of Object.keys(query.filter)) {
|
for (const column of Object.keys(query.filter)) {
|
||||||
if (!(column in config.filterableColumns)) {
|
if (!(column in config.filterableColumns)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const allowedOperators = config.filterableColumns[column as Column<T>]
|
const allowedOperators = config.filterableColumns[column]
|
||||||
const input = query.filter[column]
|
const input = query.filter[column]
|
||||||
const statements = !Array.isArray(input) ? [input] : input
|
const statements = !Array.isArray(input) ? [input] : input
|
||||||
for (const raw of statements) {
|
for (const raw of statements) {
|
||||||
@ -147,12 +135,20 @@ function parseFilter<T>(query: PaginateQuery, config: PaginateConfig<T>) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (isOperator(op1)) {
|
if (isOperator(op1)) {
|
||||||
const args = op1 === FilterOperator.IN || op1 === FilterOperator.BTW ? value.split(',') : value
|
switch (op1) {
|
||||||
filter[column] =
|
case FilterOperator.BTW:
|
||||||
op1 === FilterOperator.BTW ? getOperatorFn<T>(op1)(args[0], args[1]) : getOperatorFn<T>(op1)(args)
|
filter[column] = OperatorSymbolToFunction.get(op1)(...value.split(','))
|
||||||
|
break
|
||||||
|
case FilterOperator.IN:
|
||||||
|
filter[column] = OperatorSymbolToFunction.get(op1)(value.split(','))
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
filter[column] = OperatorSymbolToFunction.get(op1)(value)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isOperator(op2)) {
|
if (isOperator(op2)) {
|
||||||
filter[column] = getOperatorFn<T>(op2)(filter[column])
|
filter[column] = OperatorSymbolToFunction.get(op2)(filter[column])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +232,7 @@ export async function paginate<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (query.filter) {
|
if (query.filter) {
|
||||||
const filter = parseFilter<T>(query, config)
|
const filter = parseFilter(query, config)
|
||||||
queryBuilder.andWhere(new Brackets((qb) => qb.andWhere(filter)))
|
queryBuilder.andWhere(new Brackets((qb) => qb.andWhere(filter)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user