2020-06-26 21:25:03 +00:00
|
|
|
import { createParamDecorator, ExecutionContext } from '@nestjs/common'
|
|
|
|
import { Request } from 'express'
|
2021-08-19 14:42:18 +00:00
|
|
|
import { pickBy, Dictionary, isString, mapKeys } from 'lodash'
|
2020-06-26 21:25:03 +00:00
|
|
|
|
|
|
|
export interface PaginateQuery {
|
|
|
|
page?: number
|
|
|
|
limit?: number
|
|
|
|
sortBy?: [string, string][]
|
2021-10-12 11:01:53 +00:00
|
|
|
searchBy?: string[]
|
2020-06-28 17:34:00 +00:00
|
|
|
search?: string
|
2021-08-19 14:42:18 +00:00
|
|
|
filter?: { [column: string]: string | string[] }
|
2023-02-15 09:16:35 +00:00
|
|
|
select?: string[]
|
2020-06-26 21:25:03 +00:00
|
|
|
path: string
|
|
|
|
}
|
|
|
|
|
2023-02-15 09:16:35 +00:00
|
|
|
const singleSplit = (param: string, res: any[]) => res.push(param)
|
|
|
|
|
|
|
|
const multipleSplit = (param: string, res: any[]) => {
|
|
|
|
const items = param.split(':')
|
|
|
|
if (items.length === 2) {
|
|
|
|
res.push(items as [string, string])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const multipleAndCommaSplit = (param: string, res: any[]) => {
|
|
|
|
const set = new Set<string>(param.split(','))
|
|
|
|
set.forEach((item) => res.push(item))
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseParam<T>(queryParam: unknown, parserLogic: (param: string, res: any[]) => void): T[] | undefined {
|
|
|
|
const res = []
|
|
|
|
if (queryParam) {
|
|
|
|
const params = !Array.isArray(queryParam) ? [queryParam] : queryParam
|
|
|
|
for (const param of params) {
|
|
|
|
if (isString(param)) {
|
|
|
|
parserLogic(param, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res.length ? res : undefined
|
|
|
|
}
|
|
|
|
|
2021-08-19 11:30:06 +00:00
|
|
|
export const Paginate = createParamDecorator((_data: unknown, ctx: ExecutionContext): PaginateQuery => {
|
|
|
|
const request: Request = ctx.switchToHttp().getRequest()
|
|
|
|
const { query } = request
|
2021-11-01 08:30:09 +00:00
|
|
|
|
|
|
|
// Determine if Express or Fastify to rebuild the original url and reduce down to protocol, host and base url
|
2023-02-15 09:16:35 +00:00
|
|
|
let originalUrl: any
|
2021-11-01 08:30:09 +00:00
|
|
|
if (request.originalUrl) {
|
|
|
|
originalUrl = request.protocol + '://' + request.get('host') + request.originalUrl
|
|
|
|
} else {
|
|
|
|
originalUrl = request.protocol + '://' + request.hostname + request.url
|
|
|
|
}
|
|
|
|
const urlParts = new URL(originalUrl)
|
|
|
|
const path = urlParts.protocol + '//' + urlParts.host + urlParts.pathname
|
2020-06-26 21:25:03 +00:00
|
|
|
|
2023-02-15 09:16:35 +00:00
|
|
|
const searchBy = parseParam<string>(query.searchBy, singleSplit)
|
|
|
|
const sortBy = parseParam<[string, string]>(query.sortBy, multipleSplit)
|
|
|
|
const select = parseParam<string>(query.select, multipleAndCommaSplit)
|
2021-10-12 11:01:53 +00:00
|
|
|
|
2021-08-19 14:42:18 +00:00
|
|
|
const filter = mapKeys(
|
|
|
|
pickBy(
|
|
|
|
query,
|
|
|
|
(param, name) =>
|
|
|
|
name.includes('filter.') &&
|
|
|
|
(isString(param) || (Array.isArray(param) && (param as any[]).every((p) => isString(p))))
|
|
|
|
) as Dictionary<string | string[]>,
|
|
|
|
(_param, name) => name.replace('filter.', '')
|
|
|
|
)
|
|
|
|
|
2021-08-19 11:30:06 +00:00
|
|
|
return {
|
|
|
|
page: query.page ? parseInt(query.page.toString(), 10) : undefined,
|
|
|
|
limit: query.limit ? parseInt(query.limit.toString(), 10) : undefined,
|
2023-02-15 09:16:35 +00:00
|
|
|
sortBy,
|
2021-08-19 11:30:06 +00:00
|
|
|
search: query.search ? query.search.toString() : undefined,
|
2023-02-15 09:16:35 +00:00
|
|
|
searchBy,
|
2021-08-19 14:42:18 +00:00
|
|
|
filter: Object.keys(filter).length ? filter : undefined,
|
2023-02-15 09:16:35 +00:00
|
|
|
select,
|
2021-08-19 11:30:06 +00:00
|
|
|
path,
|
2020-06-26 21:25:03 +00:00
|
|
|
}
|
2021-08-19 11:30:06 +00:00
|
|
|
})
|