Skip to content

Commit b9748a6

Browse files
authored
feat: added global configuration to simplify global routes configs and fixed a bug with an empty string origin (#1092)
1 parent c877816 commit b9748a6

File tree

7 files changed

+109
-10
lines changed

7 files changed

+109
-10
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,25 @@ npm install nestjs-paginate
2727

2828
## Usage
2929

30+
### Global configurations
31+
32+
You can configure the global settings for all paginated routes by updating the default global configuration
33+
using below method. Ideally, you need to do it as soon as possible in your application main bootstrap method,
34+
as it affects all paginated routes, and swagger generation logic.
35+
36+
```typescript
37+
import { updateGlobalConfig } from 'nestjs-paginate'
38+
39+
updateGlobalConfig({
40+
// this is default configuration
41+
defaultOrigin: undefined,
42+
defaultLimit: 20,
43+
defaultMaxLimit: 100,
44+
});
45+
```
46+
47+
48+
3049
### Example
3150

3251
The following code exposes a route that can be utilized like so:

src/global-config.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export interface NestjsPaginateGlobalConfig {
2+
defaultOrigin: string | undefined
3+
defaultLimit: number
4+
defaultMaxLimit: number
5+
}
6+
7+
const globalConfig: NestjsPaginateGlobalConfig = {
8+
defaultOrigin: undefined,
9+
defaultLimit: 20,
10+
defaultMaxLimit: 100,
11+
}
12+
13+
export const updateGlobalConfig = (newConfig: Partial<NestjsPaginateGlobalConfig>) => {
14+
Object.assign(globalConfig, newConfig)
15+
}
16+
17+
export default globalConfig

src/helper.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,11 @@ export function isDateColumnType(type: any): boolean {
351351
export function quoteVirtualColumn(columnName: string, isMySqlOrMariaDb: boolean): string {
352352
return isMySqlOrMariaDb ? `\`${columnName}\`` : `"${columnName}"`
353353
}
354+
355+
export function isNil(v: unknown): boolean {
356+
return v === null || v === undefined
357+
}
358+
359+
export function isNotNil(v: unknown): boolean {
360+
return !isNil(v)
361+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './decorator'
22
export * from './paginate'
33
export * from './swagger'
4+
export * from './global-config'

src/paginate.spec.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
parseFilterToken,
2323
} from './filter'
2424
import { paginate, PaginateConfig, Paginated, PaginationLimit, PaginationType } from './paginate'
25+
import globalConfig, { updateGlobalConfig } from './global-config'
2526

2627
// Disable debug logs during tests
2728
beforeAll(() => {
@@ -285,6 +286,57 @@ describe('paginate', () => {
285286
expect(result.data).toStrictEqual(cats.slice(0, 1))
286287
})
287288

289+
it('should accept and use empty string as default origin in config, even if global provided', async () => {
290+
updateGlobalConfig({
291+
defaultOrigin: 'http://localhost:8081',
292+
})
293+
294+
const config: PaginateConfig<CatEntity> = {
295+
sortableColumns: ['id'],
296+
defaultSortBy: [['id', 'ASC']],
297+
defaultLimit: 1,
298+
origin: '',
299+
}
300+
301+
const query: PaginateQuery = {
302+
path: 'http://localhost:8080/cat',
303+
}
304+
305+
const result = await paginate<CatEntity>(query, catRepo, config)
306+
307+
expect(result).toBeInstanceOf(Paginated)
308+
expect(result.links.current).toStrictEqual('/cat?page=1&limit=1&sortBy=id:ASC')
309+
310+
updateGlobalConfig({
311+
defaultOrigin: undefined,
312+
})
313+
})
314+
315+
it('should use default origin from global config if provided, over the one from request', async () => {
316+
updateGlobalConfig({
317+
defaultOrigin: 'http://localhost:8081',
318+
})
319+
320+
const config: PaginateConfig<CatEntity> = {
321+
sortableColumns: ['id'],
322+
defaultSortBy: [['id', 'ASC']],
323+
defaultLimit: 1,
324+
}
325+
326+
const query: PaginateQuery = {
327+
path: 'http://localhost:8080/cat',
328+
}
329+
330+
const result = await paginate<CatEntity>(query, catRepo, config)
331+
332+
expect(result).toBeInstanceOf(Paginated)
333+
expect(result.links.current).toStrictEqual('http://localhost:8081/cat?page=1&limit=1&sortBy=id:ASC')
334+
335+
updateGlobalConfig({
336+
defaultOrigin: undefined,
337+
})
338+
})
339+
288340
it('should accept a query builder', async () => {
289341
const config: PaginateConfig<CatEntity> = {
290342
sortableColumns: ['id'],
@@ -499,7 +551,7 @@ describe('paginate', () => {
499551

500552
const result = await paginate<CatEntity>(query, catRepo, config)
501553

502-
expect(result.data).toStrictEqual(cats.slice(0, PaginationLimit.DEFAULT_LIMIT))
554+
expect(result.data).toStrictEqual(cats.slice(0, globalConfig.defaultLimit))
503555
})
504556

505557
it('should return the count without data ignoring maxLimit if limit is COUNTER_ONLY', async () => {

src/paginate.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import {
2828
isEntityKey,
2929
isFindOperator,
3030
isISODate,
31+
isNil,
32+
isNotNil,
3133
isRepository,
3234
JoinMethod,
3335
MappedColumns,
@@ -39,6 +41,7 @@ import {
3941
RelationSchemaInput,
4042
SortBy,
4143
} from './helper'
44+
import globalConfig from './global-config'
4245

4346
const logger: Logger = new Logger('nestjs-paginate')
4447

@@ -105,8 +108,6 @@ export interface PaginateConfig<T> {
105108
export enum PaginationLimit {
106109
NO_PAGINATION = -1,
107110
COUNTER_ONLY = 0,
108-
DEFAULT_LIMIT = 20,
109-
DEFAULT_MAX_LIMIT = 100,
110111
}
111112

112113
function generateWhereStatement<T>(
@@ -208,8 +209,8 @@ export async function paginate<T extends ObjectLiteral>(
208209

209210
const page = positiveNumberOrDefault(query.page, 1, 1)
210211

211-
const defaultLimit = config.defaultLimit || PaginationLimit.DEFAULT_LIMIT
212-
const maxLimit = config.maxLimit || PaginationLimit.DEFAULT_MAX_LIMIT
212+
const defaultLimit = config.defaultLimit || globalConfig.defaultLimit
213+
const maxLimit = config.maxLimit || globalConfig.defaultMaxLimit
213214

214215
const isPaginated = !(
215216
query.limit === PaginationLimit.COUNTER_ONLY ||
@@ -951,10 +952,10 @@ export async function paginate<T extends ObjectLiteral>(
951952
const { queryOrigin, queryPath } = getQueryUrlComponents(query.path)
952953
if (config.relativePath) {
953954
path = queryPath
954-
} else if (config.origin) {
955+
} else if (isNotNil(config.origin)) {
955956
path = config.origin + queryPath
956957
} else {
957-
path = queryOrigin + queryPath
958+
path = (isNil(globalConfig.defaultOrigin) ? queryOrigin : globalConfig.defaultOrigin) + queryPath
958959
}
959960
}
960961

src/swagger/api-paginated-query.decorator.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { applyDecorators } from '@nestjs/common'
22
import { ApiQuery } from '@nestjs/swagger'
33
import { FilterComparator } from '../filter'
4-
import { FilterOperator, FilterSuffix, PaginateConfig, PaginationLimit } from '../paginate'
4+
import { FilterOperator, FilterSuffix, PaginateConfig } from '../paginate'
5+
import globalConfig from '../global-config'
56

67
const DEFAULT_VALUE_KEY = 'Default Value'
78

@@ -45,8 +46,8 @@ function Limit(paginationConfig: PaginateConfig<any>) {
4546
name: 'limit',
4647
description: `Number of records per page.
4748
${p('Example', '20')}
48-
${p(DEFAULT_VALUE_KEY, paginationConfig?.defaultLimit?.toString() || PaginationLimit.DEFAULT_LIMIT.toString())}
49-
${p('Max Value', paginationConfig.maxLimit?.toString() || PaginationLimit.DEFAULT_MAX_LIMIT.toString())}
49+
${p(DEFAULT_VALUE_KEY, paginationConfig?.defaultLimit?.toString() || globalConfig.defaultLimit.toString())}
50+
${p('Max Value', paginationConfig.maxLimit?.toString() || globalConfig.defaultMaxLimit.toString())}
5051
5152
If provided value is greater than max value, max value will be applied.
5253
`,

0 commit comments

Comments
 (0)