traintrape-moi/server/src/common/utils/pagination.utils.ts

87 lines
2.1 KiB
TypeScript

import { applyDecorators, NotFoundException, Type } from '@nestjs/common'
import { QueryPaginationDto } from '../dto/pagination-query.dto'
import { ApiExtraModels, ApiOkResponse, ApiResponseNoStatusOptions, getSchemaPath } from '@nestjs/swagger'
import { DEFAULT_PAGE_NUMBER, DEFAULT_PAGE_SIZE, PaginateOutputDto } from '../dto/pagination-output.dto'
export interface PrismaPaginationParams {
skip: number
take: number
}
export const paginate = (
query: QueryPaginationDto,
): PrismaPaginationParams => {
const size = query.size || DEFAULT_PAGE_SIZE
const page = query.page || DEFAULT_PAGE_NUMBER
return {
skip: size * (page - 1),
take: size,
}
}
export const paginateOutput = <T>(
data: T[],
total: number,
query: QueryPaginationDto,
): PaginateOutputDto<T> => {
const page = query.page || DEFAULT_PAGE_NUMBER
const size = query.size || DEFAULT_PAGE_SIZE
const lastPage = Math.ceil(total / size)
// if data is empty, return empty array
if (!data.length) {
return {
data,
meta: {
total,
lastPage,
currentPage: page,
totalPerPage: size,
prevPage: null,
nextPage: null,
},
}
}
// if page is greater than last page, throw an error
if (page > lastPage) {
throw new NotFoundException(
`Page ${page} not found. Last page is ${lastPage}`,
)
}
return {
data,
meta: {
total,
lastPage,
currentPage: page,
totalPerPage: size,
prevPage: page > 1 ? page - 1 : null,
nextPage: page < lastPage ? page + 1 : null,
},
}
}
export const ApiOkResponsePaginated = <DataDto extends Type<unknown>>(dataDto: DataDto, options?: ApiResponseNoStatusOptions) =>
applyDecorators(
ApiExtraModels(PaginateOutputDto, dataDto),
ApiOkResponse({
...options,
schema: {
allOf: [
{ $ref: getSchemaPath(PaginateOutputDto) },
{
properties: {
data: {
type: 'array',
items: { $ref: getSchemaPath(dataDto) },
},
},
},
],
},
}),
)