Skip to content

Commit 0cb764a

Browse files
committed
fix: remove paging by inner join approach
- it may cause returns empty result
1 parent bfd7867 commit 0cb764a

File tree

2 files changed

+9
-40
lines changed

2 files changed

+9
-40
lines changed

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,6 @@ Cursor-based pagination works with [TypeORM Query Builder](https://typeorm.io/#/
1212

1313
> If this project is helpful to you, I truly appreciate you all for your stars ⭐⭐⭐ and contributions 💪💪💪.
1414
15-
## Recommend Upgrading
16-
17-
Previous version use [TypeORM](https://typeorm.io/#/select-query-builder/using-pagination) `.take()` to retrive paging data, the TypeORM will fetch entity id first, then generating second query and map first query results ids to `IN (...)` query, this may lead to significant performance losses with a large number of first results.
18-
19-
The version `v0.3.0+` uses inner join on sub query entity table with paging parameters and limit, under this approach, the TypeORM will not generate a super long `IN (...)` query.
20-
2115
## Installation
2216

2317
`npm install typeorm-cursor-pagination --save`

src/Paginator.ts

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ export default class Paginator<Entity> {
4343

4444
private alias: string = pascalToUnderscore(this.entity.name);
4545

46-
private pagingAlias = 'paging';
47-
4846
private limit = 100;
4947

5048
private order: Order = 'DESC';
@@ -118,24 +116,12 @@ export default class Paginator<Entity> {
118116
Object.assign(cursors, this.decode(this.beforeCursor as string));
119117
}
120118

121-
builder.innerJoin((paging) => {
122-
const pagingSubQuery = paging
123-
.from(this.entity, this.pagingAlias)
124-
.select(this.paginationKeys.map((key) => escape(key)))
125-
.limit(this.limit + 1)
126-
.orderBy(this.buildOrder(this.pagingAlias, escape));
127-
128-
if (Object.keys(cursors).length > 0) {
129-
pagingSubQuery
130-
.andWhere(new Brackets((where) => this.buildCursorQuery(where, cursors, escape)));
131-
}
132-
133-
return pagingSubQuery;
134-
},
135-
this.pagingAlias,
136-
this.buildPagingInnerJoinCondition(escape));
119+
if (Object.keys(cursors).length > 0) {
120+
builder.andWhere(new Brackets((where) => this.buildCursorQuery(where, cursors, escape)));
121+
}
137122

138-
builder.orderBy(this.buildOrder(this.alias, escape));
123+
builder.take(this.limit + 1);
124+
builder.orderBy(this.buildOrder());
139125

140126
return builder;
141127
}
@@ -146,22 +132,11 @@ export default class Paginator<Entity> {
146132
let query = '';
147133
this.paginationKeys.forEach((key) => {
148134
params[key] = cursors[key];
149-
where.orWhere(`${query}${escape(this.pagingAlias)}.${escape(key)} ${operator} :${key}`, params);
150-
query = `${query}${escape(this.pagingAlias)}.${escape(key)} = :${key} AND `;
135+
where.orWhere(`${query}${escape(this.alias)}.${escape(key)} ${operator} :${key}`, params);
136+
query = `${query}${escape(this.alias)}.${escape(key)} = :${key} AND `;
151137
});
152138
}
153139

154-
private buildPagingInnerJoinCondition(escape: EscapeFn): string {
155-
return this.paginationKeys.reduce((prev, next) => {
156-
let query = `${escape(this.alias)}.${escape(next)} = ${escape(this.pagingAlias)}.${escape(next)}`;
157-
if (prev !== '') {
158-
query = `AND ${query}`;
159-
}
160-
161-
return `${prev} ${query}`;
162-
}, '');
163-
}
164-
165140
private getOperator(): string {
166141
if (this.hasAfterCursor()) {
167142
return this.order === 'ASC' ? '>' : '<';
@@ -174,7 +149,7 @@ export default class Paginator<Entity> {
174149
return '=';
175150
}
176151

177-
private buildOrder(alias: string, escape: EscapeFn): OrderByCondition {
152+
private buildOrder(): OrderByCondition {
178153
let { order } = this;
179154

180155
if (!this.hasAfterCursor() && this.hasBeforeCursor()) {
@@ -183,7 +158,7 @@ export default class Paginator<Entity> {
183158

184159
const orderByCondition: OrderByCondition = {};
185160
this.paginationKeys.forEach((key) => {
186-
orderByCondition[`${escape(alias)}.${escape(key)}`] = order;
161+
orderByCondition[`${this.alias}.${key}`] = order;
187162
});
188163

189164
return orderByCondition;

0 commit comments

Comments
 (0)