feat: Add config options to ignore select and searchBy query parameters (#790)

This commit is contained in:
John Olubori David 2023-10-25 14:30:56 +01:00 committed by GitHub
parent 040e8c1a68
commit 3945809ef8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 129 additions and 4 deletions

View File

@ -280,6 +280,22 @@ const paginateConfig: PaginateConfig<CatEntity> {
* Description: Overrides the origin of absolute resource links if set.
*/
origin: 'http://cats.example',
/**
* Required: false
* Type: boolean
* Default: false
* Description: Prevent `searchBy` query param from limiting search scope further. Search will depend upon `searchableColumns` config option only
*/
ignoreSearchByInQueryParam: true,
/**
* Required: false
* Type: boolean
* Default: false
* Description: Prevent `select` query param from limiting selection further. Partial selection will depend upon `select` config option only
*/
ignoreSelectInQueryParam: true,
}
```
@ -466,7 +482,6 @@ You can use two default decorators @ApiOkResponsePaginated and @ApiPagination to
`@ApiPaginationQuery` is for query params
```typescript
@Get()
@ApiOkPaginatedResponse(

View File

@ -2512,6 +2512,110 @@ describe('paginate', () => {
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.id=$not:$in:1,2,5')
})
it('should use searchBy in query param when ignoreSearchByInQueryParam is not defined', async () => {
const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'],
searchableColumns: ['name', 'color'],
}
const query: PaginateQuery = {
path: '',
search: 'Milo',
searchBy: ['color'],
}
const result = await paginate<CatEntity>(query, catRepo, config)
expect(result.data.length).toEqual(0)
expect(result.meta.searchBy).toStrictEqual(['color'])
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&search=Milo&searchBy=color')
})
it('should use searchBy in query param when ignoreSearchByInQueryParam is set to false', async () => {
const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'],
ignoreSearchByInQueryParam: false,
searchableColumns: ['name', 'color'],
}
const query: PaginateQuery = {
path: '',
search: 'Milo',
searchBy: ['color'],
}
const result = await paginate<CatEntity>(query, catRepo, config)
expect(result.data.length).toEqual(0)
expect(result.meta.searchBy).toStrictEqual(['color'])
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&search=Milo&searchBy=color')
})
it('should ignore searchBy in query param when ignoreSearchByInQueryParam is set to true', async () => {
const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'],
ignoreSearchByInQueryParam: true,
searchableColumns: ['name', 'color'],
}
const query: PaginateQuery = {
path: '',
search: 'Milo',
searchBy: ['color'],
}
const result = await paginate<CatEntity>(query, catRepo, config)
expect(result.data.length).toEqual(1)
expect(result.data).toStrictEqual([cats[0]])
expect(result.meta.searchBy).toStrictEqual(['name', 'color'])
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&search=Milo')
})
it('should use select in query param when ignoreSelectInQueryParam is not defined', async () => {
const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'],
select: ['id', 'name', 'color'],
}
const query: PaginateQuery = {
path: '',
select: ['id', 'color'],
}
const result = await paginate<CatEntity>(query, catRepo, config)
expect(result.data[0]).toEqual({ id: cats[0].id, color: cats[0].color })
expect(result.meta.select).toStrictEqual(['id', 'color'])
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&select=id,color')
})
it('should use select in query param when ignoreSelectInQueryParam is set to false', async () => {
const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'],
ignoreSelectInQueryParam: false,
select: ['id', 'name', 'color'],
}
const query: PaginateQuery = {
path: '',
select: ['id', 'color'],
}
const result = await paginate<CatEntity>(query, catRepo, config)
expect(result.data[0]).toEqual({ id: cats[0].id, color: cats[0].color })
expect(result.meta.select).toStrictEqual(['id', 'color'])
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&select=id,color')
})
it('should ignore select in query param when ignoreSelectInQueryParam is set to true', async () => {
const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'],
ignoreSelectInQueryParam: true,
select: ['id', 'name', 'color'],
}
const query: PaginateQuery = {
path: '',
select: ['id', 'color'],
}
const result = await paginate<CatEntity>(query, catRepo, config)
expect(result.data[0]).toEqual({ id: cats[0].id, color: cats[0].color, name: cats[0].name })
expect(result.meta.select).toEqual(undefined)
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC')
})
describe('should return result based on date column filter', () => {
it('with $not and $null operators', async () => {
const config: PaginateConfig<CatEntity> = {

View File

@ -83,6 +83,8 @@ export interface PaginateConfig<T> {
paginationType?: PaginationType
relativePath?: boolean
origin?: string
ignoreSearchByInQueryParam?: boolean
ignoreSelectInQueryParam?: boolean
}
export const DEFAULT_MAX_LIMIT = 100
@ -272,7 +274,9 @@ export async function paginate<T extends ObjectLiteral>(
// When we partial select the columns (main or relation) we must add the primary key column otherwise
// typeorm will not be able to map the result.
const selectParams =
config.select && query.select ? config.select.filter((column) => query.select.includes(column)) : config.select
config.select && query.select && !config.ignoreSelectInQueryParam
? config.select.filter((column) => query.select.includes(column))
: config.select
if (selectParams?.length > 0 && includesAllPrimaryKeyColumns(queryBuilder, selectParams)) {
const cols: string[] = selectParams.reduce((cols, currentCol) => {
const columnProperties = getPropertiesByColumnName(currentCol)
@ -293,7 +297,7 @@ export async function paginate<T extends ObjectLiteral>(
}
if (config.searchableColumns) {
if (query.searchBy) {
if (query.searchBy && !config.ignoreSearchByInQueryParam) {
for (const column of query.searchBy) {
if (isEntityKey(config.searchableColumns, column)) {
searchBy.push(column)
@ -362,7 +366,9 @@ export async function paginate<T extends ObjectLiteral>(
const searchQuery = query.search ? `&search=${query.search}` : ''
const searchByQuery =
query.searchBy && searchBy.length ? searchBy.map((column) => `&searchBy=${column}`).join('') : ''
query.searchBy && searchBy.length && !config.ignoreSearchByInQueryParam
? searchBy.map((column) => `&searchBy=${column}`).join('')
: ''
// Only expose select in meta data if query select differs from config select
const isQuerySelected = selectParams?.length !== config.select?.length