Skip to content

Commit 1f4bcb4

Browse files
Samuel Roybenjamin658
Samuel Roy
authored andcommitted
feat(paginator): convert Order type to enum
Avoid using string literals while allowing a developer to use the type at runtime as an enum [x] Tests are passing + update [x] No breaking changes [x] Make Order type available as enum at runtime
1 parent f7144d8 commit 1f4bcb4

File tree

3 files changed

+50
-32
lines changed

3 files changed

+50
-32
lines changed

src/Paginator.ts

+46-28
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import {
1414
pascalToUnderscore,
1515
} from './utils';
1616

17-
export type Order = 'ASC' | 'DESC';
17+
export enum Order {
18+
ASC = 'ASC',
19+
DESC = 'DESC',
20+
}
1821

1922
export type EscapeFn = (name: string) => string;
2023

@@ -45,13 +48,13 @@ export default class Paginator<Entity> {
4548

4649
private limit = 100;
4750

48-
private order: Order = 'DESC';
51+
private order: Order = Order.DESC;
4952

5053
public constructor(
5154
private entity: ObjectType<Entity>,
5255
private paginationKeys: Extract<keyof Entity, string>[],
5356
private paginationUniqueKey: Extract<keyof Entity, string>,
54-
) { }
57+
) {}
5558

5659
public setAlias(alias: string): void {
5760
this.alias = alias;
@@ -73,7 +76,9 @@ export default class Paginator<Entity> {
7376
this.order = order;
7477
}
7578

76-
public async paginate(builder: SelectQueryBuilder<Entity>): Promise<PagingResult<Entity>> {
79+
public async paginate(
80+
builder: SelectQueryBuilder<Entity>,
81+
): Promise<PagingResult<Entity>> {
7782
const entities = await this.appendPagingQuery(builder).getMany();
7883
const hasMore = entities.length > this.limit;
7984

@@ -107,7 +112,9 @@ export default class Paginator<Entity> {
107112
};
108113
}
109114

110-
private appendPagingQuery(builder: SelectQueryBuilder<Entity>): SelectQueryBuilder<Entity> {
115+
private appendPagingQuery(
116+
builder: SelectQueryBuilder<Entity>,
117+
): SelectQueryBuilder<Entity> {
111118
const cursors: CursorParam = {};
112119

113120
if (this.hasAfterCursor()) {
@@ -117,7 +124,9 @@ export default class Paginator<Entity> {
117124
}
118125

119126
if (Object.keys(cursors).length > 0) {
120-
builder.andWhere(new Brackets((where) => this.buildCursorQuery(where, cursors)));
127+
builder.andWhere(
128+
new Brackets((where) => this.buildCursorQuery(where, cursors)),
129+
);
121130
}
122131

123132
builder.take(this.limit + 1);
@@ -126,31 +135,36 @@ export default class Paginator<Entity> {
126135
return builder;
127136
}
128137

129-
private buildCursorQuery(where: WhereExpressionBuilder, cursors: CursorParam): void {
138+
private buildCursorQuery(
139+
where: WhereExpressionBuilder,
140+
cursors: CursorParam,
141+
): void {
130142
const operator = this.getOperator();
131143
const params: CursorParam = {};
132144
this.paginationKeys.forEach((key) => {
133145
params[key] = cursors[key];
134-
where.andWhere(new Brackets((qb) => {
135-
const paramsHolder = {
136-
[`${key}_1`]: params[key],
137-
[`${key}_2`]: params[key],
138-
};
139-
qb.where(`${this.alias}.${key} ${operator} :${key}_1`, paramsHolder);
140-
if (this.paginationUniqueKey !== key) {
141-
qb.orWhere(`${this.alias}.${key} = :${key}_2`, paramsHolder);
142-
}
143-
}));
146+
where.andWhere(
147+
new Brackets((qb) => {
148+
const paramsHolder = {
149+
[`${key}_1`]: params[key],
150+
[`${key}_2`]: params[key],
151+
};
152+
qb.where(`${this.alias}.${key} ${operator} :${key}_1`, paramsHolder);
153+
if (this.paginationUniqueKey !== key) {
154+
qb.orWhere(`${this.alias}.${key} = :${key}_2`, paramsHolder);
155+
}
156+
}),
157+
);
144158
});
145159
}
146160

147161
private getOperator(): string {
148162
if (this.hasAfterCursor()) {
149-
return this.order === 'ASC' ? '>' : '<';
163+
return this.order === Order.ASC ? '>' : '<';
150164
}
151165

152166
if (this.hasBeforeCursor()) {
153-
return this.order === 'ASC' ? '<' : '>';
167+
return this.order === Order.ASC ? '<' : '>';
154168
}
155169

156170
return '=';
@@ -180,11 +194,13 @@ export default class Paginator<Entity> {
180194
}
181195

182196
private encode(entity: Entity): string {
183-
const payload = this.paginationKeys.map((key) => {
184-
const type = this.getEntityPropertyType(key);
185-
const value = encodeByType(type, entity[key]);
186-
return `${key}:${value}`;
187-
}).join(',');
197+
const payload = this.paginationKeys
198+
.map((key) => {
199+
const type = this.getEntityPropertyType(key);
200+
const value = encodeByType(type, entity[key]);
201+
return `${key}:${value}`;
202+
})
203+
.join(',');
188204

189205
return btoa(payload);
190206
}
@@ -203,13 +219,15 @@ export default class Paginator<Entity> {
203219
}
204220

205221
private getEntityPropertyType(key: string): string {
206-
return Reflect.getMetadata('design:type', this.entity.prototype, key).name.toLowerCase();
222+
return Reflect.getMetadata(
223+
'design:type',
224+
this.entity.prototype,
225+
key,
226+
).name.toLowerCase();
207227
}
208228

209229
private flipOrder(order: Order): Order {
210-
return order === 'ASC'
211-
? 'DESC'
212-
: 'ASC';
230+
return order === Order.ASC ? Order.DESC : Order.ASC;
213231
}
214232

215233
private toPagingResult<Entity>(entities: Entity[]): PagingResult<Entity> {

src/buildPaginator.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export interface PagingQuery {
66
afterCursor?: string;
77
beforeCursor?: string;
88
limit?: number;
9-
order?: Order;
9+
order?: Order | 'ASC' | 'DESC';
1010
}
1111

1212
export interface PaginationOptions<Entity> {
@@ -43,7 +43,7 @@ export function buildPaginator<Entity>(options: PaginationOptions<Entity>): Pagi
4343
}
4444

4545
if (query.order) {
46-
paginator.setOrder(query.order);
46+
paginator.setOrder(query.order as Order);
4747
}
4848

4949
return paginator;

test/pagination.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { createQueryBuilder } from './utils/createQueryBuilder';
55
import { prepareData } from './utils/prepareData';
66
import { User } from './entities/User';
77
import { Photo } from './entities/Photo';
8-
import { buildPaginator } from '../src/index';
8+
import { buildPaginator, Order } from '../src/index';
99

1010
describe('TypeORM cursor-based pagination test', () => {
1111
before(async () => {
@@ -106,7 +106,7 @@ describe('TypeORM cursor-based pagination test', () => {
106106
entity: User,
107107
query: {
108108
limit: 1,
109-
order: 'DESC',
109+
order: Order.DESC,
110110
},
111111
});
112112

0 commit comments

Comments
 (0)