Skip to content

Commit 63c3562

Browse files
committed
fix: encodePaginationTokens to encode plain objects without secondary sort ID
1 parent 0fafa68 commit 63c3562

File tree

1 file changed

+30
-21
lines changed

1 file changed

+30
-21
lines changed

src/utils/query.ts

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@ export type PaginationResponse<T> = {
2323
hasNext: boolean;
2424
};
2525

26+
/**
27+
* Return true only for "simple" POJOs: `{}` created by object literals or
28+
* `Object.create(null)`. Arrays, class instances, Dates, BSON objects, etc.
29+
* will return false.
30+
*/
31+
function isPlainObject(value: unknown): value is Record<string, any> {
32+
if (value === null || typeof value !== 'object') return false;
33+
const proto = Object.getPrototypeOf(value);
34+
return proto === Object.prototype || proto === null;
35+
}
36+
37+
38+
2639
/**
2740
* Helper function to encode pagination tokens.
2841
*
@@ -38,38 +51,34 @@ export type PaginationResponse<T> = {
3851
*
3952
* @returns void
4053
*/
41-
function encodePaginationTokens(params: PaginationParams, response: PaginationResponse<any>): void {
54+
function encodePaginationTokens(
55+
params: PaginationParams,
56+
response: PaginationResponse<any>
57+
): void {
4258
const shouldSecondarySortOnId = params.paginatedField !== '_id';
4359

44-
if (response.previous) {
60+
// ----- previous ----------------------------------------------------------
61+
if (response.previous && isPlainObject(response.previous)) {
4562
let previousPaginatedField = objectPath.get(response.previous, params.paginatedField);
4663
if (params.sortCaseInsensitive) {
4764
previousPaginatedField = previousPaginatedField?.toLowerCase?.() ?? '';
4865
}
49-
if (shouldSecondarySortOnId) {
50-
if (
51-
typeof response.previous === 'object' &&
52-
response.previous !== null &&
53-
'_id' in response.previous
54-
) {
55-
response.previous = bsonUrlEncoding.encode([previousPaginatedField, response.previous._id]);
56-
}
57-
} else {
58-
response.previous = bsonUrlEncoding.encode(previousPaginatedField);
59-
}
66+
67+
response.previous = shouldSecondarySortOnId && '_id' in response.previous
68+
? bsonUrlEncoding.encode([previousPaginatedField, response.previous._id])
69+
: bsonUrlEncoding.encode(previousPaginatedField);
6070
}
61-
if (response.next) {
71+
72+
// ----- next --------------------------------------------------------------
73+
if (response.next && isPlainObject(response.next)) {
6274
let nextPaginatedField = objectPath.get(response.next, params.paginatedField);
6375
if (params.sortCaseInsensitive) {
6476
nextPaginatedField = nextPaginatedField?.toLowerCase?.() ?? '';
6577
}
66-
if (shouldSecondarySortOnId) {
67-
if (typeof response.next === 'object' && response.next !== null && '_id' in response.next) {
68-
response.next = bsonUrlEncoding.encode([nextPaginatedField, response.next._id]);
69-
}
70-
} else {
71-
response.next = bsonUrlEncoding.encode(nextPaginatedField);
72-
}
78+
79+
response.next = shouldSecondarySortOnId && '_id' in response.next
80+
? bsonUrlEncoding.encode([nextPaginatedField, response.next._id])
81+
: bsonUrlEncoding.encode(nextPaginatedField);
7382
}
7483
}
7584

0 commit comments

Comments
 (0)