feat: customized links (#331)
This commit is contained in:
parent
98cadc6f7d
commit
c513993908
15
README.md
15
README.md
@ -234,6 +234,21 @@ const paginateConfig: PaginateConfig<CatEntity> {
|
|||||||
* https://typeorm.io/select-query-builder#querying-deleted-rows
|
* https://typeorm.io/select-query-builder#querying-deleted-rows
|
||||||
*/
|
*/
|
||||||
withDeleted: false,
|
withDeleted: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required: false
|
||||||
|
* Type: boolean
|
||||||
|
* Default: false
|
||||||
|
* Description: Generate relative paths in the resource links.
|
||||||
|
*/
|
||||||
|
relativePath: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required: false
|
||||||
|
* Type: string
|
||||||
|
* Description: Overrides the origin of absolute resource links if set.
|
||||||
|
*/
|
||||||
|
origin: 'http://cats.example',
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -160,6 +160,70 @@ describe('paginate', () => {
|
|||||||
expect(links.last).toBe('?page=3&limit=2&sortBy=id:ASC')
|
expect(links.last).toBe('?page=3&limit=2&sortBy=id:ASC')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should return a relative path', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id'],
|
||||||
|
relativePath: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: 'http://localhost/cats',
|
||||||
|
page: 2,
|
||||||
|
limit: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
const { links } = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
expect(links.first).toBe('/cats?page=1&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.previous).toBe('/cats?page=1&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.current).toBe('/cats?page=2&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.next).toBe('/cats?page=3&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.last).toBe('/cats?page=3&limit=2&sortBy=id:ASC')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an absolute path', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id'],
|
||||||
|
relativePath: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: 'http://localhost/cats',
|
||||||
|
page: 2,
|
||||||
|
limit: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
const { links } = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
expect(links.first).toBe('http://localhost/cats?page=1&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.previous).toBe('http://localhost/cats?page=1&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.current).toBe('http://localhost/cats?page=2&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.next).toBe('http://localhost/cats?page=3&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.last).toBe('http://localhost/cats?page=3&limit=2&sortBy=id:ASC')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an absolute path with new origin', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id'],
|
||||||
|
relativePath: false,
|
||||||
|
origin: 'http://cats.example',
|
||||||
|
}
|
||||||
|
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: 'http://localhost/cats',
|
||||||
|
page: 2,
|
||||||
|
limit: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
const { links } = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
expect(links.first).toBe('http://cats.example/cats?page=1&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.previous).toBe('http://cats.example/cats?page=1&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.current).toBe('http://cats.example/cats?page=2&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.next).toBe('http://cats.example/cats?page=3&limit=2&sortBy=id:ASC')
|
||||||
|
expect(links.last).toBe('http://cats.example/cats?page=3&limit=2&sortBy=id:ASC')
|
||||||
|
})
|
||||||
|
|
||||||
it('should return only current link if zero results', async () => {
|
it('should return only current link if zero results', async () => {
|
||||||
const config: PaginateConfig<CatEntity> = {
|
const config: PaginateConfig<CatEntity> = {
|
||||||
sortableColumns: ['id'],
|
sortableColumns: ['id'],
|
||||||
|
@ -55,6 +55,8 @@ export interface PaginateConfig<T> {
|
|||||||
where?: FindOptionsWhere<T> | FindOptionsWhere<T>[]
|
where?: FindOptionsWhere<T> | FindOptionsWhere<T>[]
|
||||||
filterableColumns?: { [key in Column<T>]?: FilterOperator[] }
|
filterableColumns?: { [key in Column<T>]?: FilterOperator[] }
|
||||||
withDeleted?: boolean
|
withDeleted?: boolean
|
||||||
|
relativePath?: boolean
|
||||||
|
origin?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum FilterOperator {
|
export enum FilterOperator {
|
||||||
@ -165,7 +167,26 @@ export async function paginate<T>(
|
|||||||
const limit = Math.min(query.limit || config.defaultLimit || 20, config.maxLimit || 100)
|
const limit = Math.min(query.limit || config.defaultLimit || 20, config.maxLimit || 100)
|
||||||
const sortBy = [] as SortBy<T>
|
const sortBy = [] as SortBy<T>
|
||||||
const searchBy: Column<T>[] = []
|
const searchBy: Column<T>[] = []
|
||||||
const path = query.path
|
let path
|
||||||
|
|
||||||
|
const r = new RegExp('^(?:[a-z+]+:)?//', 'i')
|
||||||
|
let queryOrigin = ''
|
||||||
|
let queryPath = ''
|
||||||
|
if (r.test(query.path)) {
|
||||||
|
const url = new URL(query.path)
|
||||||
|
queryOrigin = url.origin
|
||||||
|
queryPath = url.pathname
|
||||||
|
} else {
|
||||||
|
queryPath = query.path
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.relativePath) {
|
||||||
|
path = queryPath
|
||||||
|
} else if (config.origin) {
|
||||||
|
path = config.origin + queryPath
|
||||||
|
} else {
|
||||||
|
path = queryOrigin + queryPath
|
||||||
|
}
|
||||||
|
|
||||||
function isEntityKey(entityColumns: Column<T>[], column: string): column is Column<T> {
|
function isEntityKey(entityColumns: Column<T>[], column: string): column is Column<T> {
|
||||||
return !!entityColumns.find((c) => c === column)
|
return !!entityColumns.find((c) => c === column)
|
||||||
|
Loading…
Reference in New Issue
Block a user