# Nest.js Paginate ![Main CI](https://github.com/ppetzold/nestjs-paginate/workflows/Main%20CI/badge.svg) [![npm](https://img.shields.io/npm/v/nestjs-paginate.svg)](https://www.npmjs.com/package/nestjs-paginate) [![downloads](https://img.shields.io/npm/dt/nestjs-paginate.svg)](https://www.npmjs.com/package/nestjs-paginate) [![codecov](https://codecov.io/gh/ppetzold/nestjs-paginate/branch/master/graph/badge.svg)](https://codecov.io/gh/ppetzold/nestjs-paginate) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) ![GitHub](https://img.shields.io/github/license/ppetzold/nestjs-paginate) Pagination and filtering helper method for TypeORM repositories or query builders using [Nest.js](https://nestjs.com/) framework. - Pagination conforms to [JSON:API](https://jsonapi.org/) - Sort by multiple columns - Search across columns - Filter using operators (`$eq`, `$not`, `$null`, `$in`, `$gt`, `$gte`, `$lt`, `$lte`, `$btw`) - Include relations ## Installation ``` npm install nestjs-paginate ``` ## Usage ### Example The following code exposes a route that can be utilized like so: #### Endpoint ```url http://localhost:3000/cats?limit=5&page=2&sortBy=color:DESC&search=i&filter.age=$gte:3 ``` #### Result ```json { "data": [ { "id": 4, "name": "George", "color": "white", "age": 3 }, { "id": 5, "name": "Leche", "color": "white", "age": 6 }, { "id": 2, "name": "Garfield", "color": "ginger", "age": 4 }, { "id": 1, "name": "Milo", "color": "brown", "age": 5 }, { "id": 3, "name": "Kitty", "color": "black", "age": 3 } ], "meta": { "itemsPerPage": 5, "totalItems": 12, "currentPage": 2, "totalPages": 3, "sortBy": [["color", "DESC"]], "search": "i", "filter": { "age": "$gte:3" } }, "links": { "first": "http://localhost:3000/cats?limit=5&page=1&sortBy=color:DESC&search=i&filter.age=$gte:3", "previous": "http://localhost:3000/cats?limit=5&page=1&sortBy=color:DESC&search=i&filter.age=$gte:3", "current": "http://localhost:3000/cats?limit=5&page=2&sortBy=color:DESC&search=i&filter.age=$gte:3", "next": "http://localhost:3000/cats?limit=5&page=3&sortBy=color:DESC&search=i&filter.age=$gte:3", "last": "http://localhost:3000/cats?limit=5&page=3&sortBy=color:DESC&search=i&filter.age=$gte:3" } } ``` #### Code ```ts import { Controller, Injectable, Get } from '@nestjs/common' import { InjectRepository } from '@nestjs/typeorm' import { FilterOperator, Paginate, PaginateQuery, paginate, Paginated } from 'nestjs-paginate' import { Repository, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' @Entity() export class CatEntity { @PrimaryGeneratedColumn() id: number @Column('text') name: string @Column('text') color: string @Column('int') age: number } @Injectable() export class CatsService { constructor( @InjectRepository(CatEntity) private readonly catsRepository: Repository ) {} public findAll(query: PaginateQuery): Promise> { return paginate(query, this.catsRepository, { sortableColumns: ['id', 'name', 'color', 'age'], searchableColumns: ['name', 'color', 'age'], defaultSortBy: [['id', 'DESC']], filterableColumns: { age: [FilterOperator.GTE, FilterOperator.LTE], }, }) } } @Controller('cats') export class CatsController { constructor(private readonly catsService: CatsService) {} @Get() public findAll(@Paginate() query: PaginateQuery): Promise> { return this.catsService.findAll(query) } } ``` ### Config ```ts const paginateConfig: PaginateConfig { /** * Required: true (must have a minimum of one column) * Type: (keyof CatEntity)[] * Description: These are the columns that are valid to be sorted by. */ sortableColumns: ['id', 'name', 'color'], /** * Required: false * Type: [keyof CatEntity, 'ASC' | 'DESC'][] * Default: [[sortableColumns[0], 'ASC]] * Description: The order to display the sorted entities. */ defaultSortBy: [['name', 'DESC']], /** * Required: false * Type: (keyof CatEntity)[] * Description: These columns will be searched through when using the search query * param. Limit search scope further by using `searchBy` query param. */ searchableColumns: ['name', 'color'], /** * Required: false * Type: TypeORM partial selection * Default: None * https://typeorm.io/select-query-builder#partial-selection */ select: ['name', 'color'], /** * Required: false * Type: number * Default: 100 * Description: The maximum amount of entities to return per page. */ maxLimit: 20, /** * Required: false * Type: number * Default: 20 */ defaultLimit: 50, /** * Required: false * Type: TypeORM find options * Default: None * https://typeorm.io/#/find-optionsfind-options.md */ where: { color: 'ginger' }, /** * Required: false * Type: { [key in CatEntity]?: FilterOperator[] } - Operators based on TypeORM find operators * Default: None * https://typeorm.io/#/find-options/advanced-options */ filterableColumns: { age: [FilterOperator.EQ, FilterOperator.IN] }, /** * Required: false * Type: RelationColumn * Description: Indicates what relations of entity should be loaded. */ relations: [], /** * Required: false * Type: boolean * Description: Disables the global condition of "non-deleted" for the entity with delete date columns. * https://typeorm.io/select-query-builder#querying-deleted-rows */ withDeleted: false, } ``` ## Usage with Query Builder You can paginate custom queries by passing on the query builder: ### Example ```typescript const queryBuilder = repo .createQueryBuilder('cats') .leftJoinAndSelect('cats.owner', 'owner') .where('cats.owner = :ownerId', { ownerId }) const result = await paginate(query, queryBuilder, config) ``` ## Usage with Relations Similar as with repositories, you can utilize `relations` as a simplified left-join form: ### Example #### Endpoint ```url http://localhost:3000/cats?filter.toys.name=$in:Mouse,String ``` #### Code ```typescript const config: PaginateConfig = { relations: ['toys'], sortableColumns: ['id', 'name', 'toys.name'], filterableColumns: { 'toys.name': [FilterOperator.IN], }, } const result = await paginate(query, catRepo, config) ```