A query package for convenient pagination, filtering and sorting implementation with MikroORM repositories in Nest.js.
- Pagination conforms to JSON:API
- Sort by multiple fields
- Sort by nulls first or last
- Unpaged response (i.e., disabling pagination)
- Various pagination behavior and constraints configuration
- Filter using
operators (
$eq
,$in
,$nin
,$gt
,$gte
,$lt
,$lte
,$ne
,$not
,$like
,$re
,$fulltext
,$exists
,$ilike
,$overlap
,$contains
,$contained
)
- Only work with Rest API
- Only support MySQL, MariaDB, PostgreSQL and SQLite
- Only support offset pagination
- >= Nest.js ^8 || ^9 || ^10
- >= MikroORM ^5.7 || ^6
- >= Typescript 5.0.4
# With Yarn
yarn add @emulienfou/nestjs-mikro-orm-paginate
# With NPM
npm install @emulienfou/nestjs-mikro-orm-paginate
# With PNPM
pnpm add @emulienfou/nestjs-mikro-orm-paginate
// articles.controller.ts
import { Controller, Get } from '@nestjs/common';
import { Paginate, PaginateResponse } from '@emulienfou/nestjs-mikro-orm-paginate';
import { ArticlesService } from './articles.service.ts';
import { ArticleDto } from './dtos/article.dto.ts';
@Controller('/articles')
export class ArticlesController {
constructor(private articlesService: ArticlesService) {
}
@Get('/')
getArticles(@Paginate() query: PaginateQuery): Promise<PaginateResponse<ArticlesDto>> {
return this.articlesService.listArticles(query);
}
}
// articles.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@mikro-orm/nestjs';
import { EntityRepository } from '@mikro-orm/sqlite';
import { PaginateQuery, PaginateResponse, PageFactory } from '@emulienfou/nestjs-mikro-orm-paginate';
import { ArticleEntity } from './article.entity';
import { ArticleDto } from './dtos/article.dto.ts';
@Injectable()
export class ArticlesService {
constructor(@InjectRepository(ArticleEntity) private articleRepository: EntityRepository<ArticleEntity>) {
}
async listArticles(query: PaginateQuery): Promise<PaginateResponse<ArticleDto>> {
return await new PageFactory(query, this.articleRepository).create();
}
}
With @Paginate
, you can now provide the below query parameters to /articles
:
- page: the page number, starting from 1, e.g.,
?page=1
- limit: the page size, default to 10, e.g.,
?limit=20
- sort: the sort expression, e.g.,
?sort=property[field1];direction[asc];nulls-first[true]
- unpaged: whether to disable pagination, default to false, e.g.,
?unpaged=true
- filter:
An example of the response shape is shown as below:
{
"data": [
{
"id": 1,
"title": "Article 1",
"content": "Content 1",
"createdAt": "2021-08-01T00:00:00.000Z",
"updatedAt": "2021-08-01T00:00:00.000Z"
}
],
"meta": {
"totalItems": 1,
"currentPage": 1,
"totalPages": 1,
"itemsPerPage": 10,
"offset": 0,
"sort": [
{
"property": "id",
"direction": "ASC",
"nullsFirst": false
}
],
"unpaged": false,
"filter": {}
},
"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"
}
}
Use the @ApiPaginate
decorator for swagger integration:
// articles.controller.ts
import { Controller, Get } from '@nestjs/common';
import { ApiPaginate, Paginate } from '@emulienfou/nestjs-mikro-orm-paginate';
import { ArticlesService } from './articles.service.ts';
import { ArticleDto } from './dtos/article.dto.ts';
@Controller('/articles')
export class ArticlesController {
constructor(private articlesService: ArticlesService) {
}
@Get('/')
@ApiPaginate({
dto: ArticleDto,
})
getArticles(@Paginate() query: PaginateQuery): Promise<PaginateResponse<ArticlesDto>> {
return this.articlesService.listArticles(query);
}
}