Gathering detailed insights and metrics for @trmaphi/nestjs-typeorm-paginate
Gathering detailed insights and metrics for @trmaphi/nestjs-typeorm-paginate
npm install @trmaphi/nestjs-typeorm-paginate
Typescript
Module System
Node Version
NPM Version
TypeScript (98.27%)
JavaScript (1.73%)
Love this project? Help keep it running — sponsor us today! 🚀
Total Downloads
1,073
Last Day
1
Last Week
3
Last Month
21
Last Year
103
MIT License
856 Stars
763 Commits
129 Forks
9 Watchers
8 Branches
30 Contributors
Updated on Feb 14, 2025
Minified
Minified + Gzipped
Latest Version
3.1.6
Package Id
@trmaphi/nestjs-typeorm-paginate@3.1.6
Unpacked Size
33.41 kB
Size
9.99 kB
File Count
23
NPM Version
6.14.14
Node Version
14.17.4
Cumulative downloads
Total Downloads
Last Day
0%
1
Compared to previous day
Last Week
-25%
3
Compared to previous week
Last Month
200%
21
Compared to previous month
Last Year
-25.4%
103
Compared to previous year
1
2
Please vote on your prefered method of querying! Take+Skip vs Limit+Offset
Pagination helper method for TypeORM repositories or queryBuilders with strict typings
1$ yarn add nestjs-typeorm-paginate
or
1$ npm i nestjs-typeorm-paginate
1import { Injectable } from '@nestjs/common'; 2import { Repository } from 'typeorm'; 3import { InjectRepository } from '@nestjs/typeorm'; 4import { CatEntity } from './entities'; 5import { 6 paginate, 7 Pagination, 8 IPaginationOptions, 9} from 'nestjs-typeorm-paginate'; 10 11@Injectable() 12export class CatService { 13 constructor( 14 @InjectRepository(CatEntity) 15 private readonly repository: Repository<CatEntity>, 16 ) {} 17 18 async paginate(options: IPaginationOptions): Promise<Pagination<CatEntity>> { 19 return paginate<CatEntity>(this.repository, options); 20 } 21}
1import { Injectable } from '@nestjs/common'; 2import { Repository } from 'typeorm'; 3import { InjectRepository } from '@nestjs/typeorm'; 4import { CatEntity } from './entities'; 5import { 6 paginate, 7 Pagination, 8 IPaginationOptions, 9} from 'nestjs-typeorm-paginate'; 10 11@Injectable() 12export class CatService { 13 constructor( 14 @InjectRepository(CatEntity) 15 private readonly repository: Repository<CatEntity>, 16 ) {} 17 18 async paginate(options: IPaginationOptions): Promise<Pagination<CatEntity>> { 19 const queryBuilder = this.repository.createQueryBuilder('c'); 20 queryBuilder.orderBy('c.name', 'DESC'); // Or whatever you need to do 21 22 return paginate<CatEntity>(queryBuilder, options); 23 } 24}
1import { Controller, DefaultValuePipe, Get, ParseIntPipe, Query } from '@nestjs/common'; 2import { CatService } from './cat.service'; 3import { CatEntity } from './cat.entity'; 4import { Pagination } from 'nestjs-typeorm-paginate'; 5 6@Controller('cats') 7export class CatsController { 8 constructor(private readonly catService: CatService) {} 9 @Get('') 10 async index( 11 @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number = 1, 12 @Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number = 10, 13 ): Promise<Pagination<CatEntity>> { 14 limit = limit > 100 ? 100 : limit; 15 return this.catService.paginate({ 16 page, 17 limit, 18 route: 'http://cats.com/cats', 19 }); 20 } 21}
If you use
ParseIntPipe
on the query params (as in the example), don't forget to also addDefaultValuePipe
. See issue 517 for more info.
the
route
property of the paginate options can also be the short version of an absolute path , In this case, it would be/cats
instead ofhttp://cats.com/cats
1{ 2 "items": [ 3 { 4 "lives": 9, 5 "type": "tabby", 6 "name": "Bobby" 7 }, 8 { 9 "lives": 2, 10 "type": "Ginger", 11 "name": "Garfield" 12 }, 13 { 14 "lives": 6, 15 "type": "Black", 16 "name": "Witch's mate" 17 }, 18 { 19 "lives": 7, 20 "type": "Purssian Grey", 21 "name": "Alisdaya" 22 }, 23 { 24 "lives": 1, 25 "type": "Alistair", 26 "name": "ali" 27 }, 28 ... 29 ], 30 "meta": { 31 "itemCount": 10, 32 "totalItems": 20, 33 "itemsPerPage": 10, 34 "totalPages": 5, 35 "currentPage": 2 36 }, 37 "links" : { 38 "first": "http://cats.com/cats?limit=10", 39 "previous": "http://cats.com/cats?page=1&limit=10", 40 "next": "http://cats.com/cats?page=3&limit=10", 41 "last": "http://cats.com/cats?page=5&limit=10" 42 } 43}
items
: An array of SomeEntity
meta.itemCount
: The length of items array (i.e., the amount of items on this page)
meta.totalItems
: The total amount of SomeEntity matching the filter conditions
meta.itemsPerPage
: The requested items per page (i.e., the limit
parameter)
meta.totalPages
: The total amount of pages (based on the limit
)
meta.currentPage
: The current page this paginator "points" to
links.first
: A URL for the first page to call | ""
(blank) if no route
is defined
links.previous
: A URL for the previous page to call | ""
(blank) if no previous to call
links.next
: A URL for the next page to call | ""
(blank) if no page to call
links.last
: A URL for the last page to call | ""
(blank) if no route
is defined
Do note that
links.first
may not have the 'page' query param defined
1@Injectable() 2export class CatService { 3 constructor( 4 @InjectRepository(CatEntity) 5 private readonly repository: Repository<CatEntity>, 6 ) {} 7 8 async paginate(options: IPaginationOptions): Promise<Pagination<CatEntity>> { 9 return paginate<CatEntity>(this.repository, options, { 10 lives: 9, 11 }); 12 } 13}
Eager loading should work with typeorm's eager property out the box. Like so
1import { Entity, OneToMany } from 'typeorm'; 2 3@Entity() 4export class CatEntity { 5 @OneToMany(t => TigerKingEntity, tigerKing.cats, { 6 eager: true, 7 }) 8 tigerKings: TigerKingEntity[]; 9} 10 11// service 12class CatService { 13 constructor(private readonly repository: Repository<CatEntity>) {} 14 15 async paginate(page: number, limit: number): Promise<Pagination<CatEntity>> { 16 return paginate(this.repository, { page, limit }); 17 } 18}
However, when using the query builder you'll have to hydrate the entities yourself. Here is a crude example that I've used in the past. It's not great but this is partially what typeORM will do.
1const results = paginate(queryBuilder, { page, limit }); 2 3return new Pagination( 4 await Promise.all( 5 results.items.map(async (item: SomeEntity) => { 6 const hydrate = await this.someRepository.findByEntity(item); 7 item.hydrated = hydrate; 8 9 return item; 10 }), 11 ), 12 results.meta, 13 results.links, 14);
1const queryBuilder = this.repository 2 .createQueryBuilder<{ type: string; totalLives: string }>('c') 3 .select('c.type', 'type') 4 .addSelect('SUM(c.lives)', 'totalLives') 5 .groupBy('c.type') 6 .orderBy('c.type', 'DESC'); // Or whatever you need to do 7 8return paginateRaw(queryBuilder, options);
A similar approach is used for TypeORM's getRawAndEntities
Let's assume there's a joined table that matches each cat with its cat toys. And we want to bring how many toys each cat has.
1 2const queryBuilder = this.repository 3 .createQueryBuilder<{ type: string; totalLives: string }>('cat') 4 .leftJoinAndSelect('cat.toys', 'toys') 5 .addSelect('COUNT(toys)::INTEGER', 'toyCount') 6 .groupBy('cat.name');
This will allow us to get the paginated cats information with the additional raw query to build our actual response value. The return pagination object will be the same, but you're now able to handle or map the results and the raw objects as needed.
1const [pagination, rawResults] = await paginateRawAndEntities(query, options); 2pagination.items.map((item, index) => { 3 // we can do what we need with the items and raw results here 4 // change your items using rawResults.find(raw => raw.id === item.id) 5}); 6return pagination;
Since the values of the raw results will include all the joined table items as queried, you must make sure to handle the items as needed for your use case. Refer to TypeORM's getRawAndEntities implementation as needed.
The rawResults array will look something like this:
1[ 2 { // Bobby appears 3 times due to the joined query 3 "cat_lives": 9, 4 "cat_type": "tabby", 5 "cat_name": "Bobby", 6 "toyCount": 3 7 }, 8 { 9 "cat_lives": 9, 10 "cat_type": "tabby", 11 "cat_name": "Bobby", 12 "toyCount": 3 13 }, 14 { 15 "cat_lives": 9, 16 "cat_type": "tabby", 17 "cat_name": "Bobby", 18 "toyCount": 3 19 }, 20 { 21 "cat_lives": 2, 22 "cat_type": "Ginger", 23 "cat_name": "Garfield", 24 "toyCount": 1 25 }, 26 ... 27]
If you wanted to alter the meta data that is returned from the pagination object. Then use the metaTransformer
in the options like so
1 2class CustomPaginationMeta { 3 constructor( 4 public readonly count: number, 5 public readonly total: number, 6 ) {} 7} 8 9return paginate<MyEntity, CustomPaginationMeta>(this.repository, { 10 page, 11 limit, 12 metaTransformer: (meta: IPaginationMeta): CustomPaginationMeta => new CustomPaginationMeta( 13 meta.itemCount, 14 meta.totalItems, 15 ), 16 });
This will result in the above returning CustomPaginationMeta
in the meta
property instead of the default IPaginationMeta
.
If you want to alter the limit
and/or page
labels in meta links, then use routingLabels
in the options like so
1 2return paginate<MyEntity>(this.repository, { 3 page, 4 limit, 5 routingLabels: { 6 limitLabel: 'page-size', // default: limit 7 pageLabel: 'current-page', //default: page 8 } 9 });
This will result links like http://example.com/something?current-page=1&page-size=3
.
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
Found 1/2 approved changesets -- score normalized to 5
Reason
8 existing vulnerabilities detected
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2025-02-10
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More