@@ -23,6 +23,19 @@ export type PaginationResponse<T> = {
23
23
hasNext : boolean ;
24
24
} ;
25
25
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
+
26
39
/**
27
40
* Helper function to encode pagination tokens.
28
41
*
@@ -38,38 +51,34 @@ export type PaginationResponse<T> = {
38
51
*
39
52
* @returns void
40
53
*/
41
- function encodePaginationTokens ( params : PaginationParams , response : PaginationResponse < any > ) : void {
54
+ function encodePaginationTokens (
55
+ params : PaginationParams ,
56
+ response : PaginationResponse < any >
57
+ ) : void {
42
58
const shouldSecondarySortOnId = params . paginatedField !== '_id' ;
43
59
44
- if ( response . previous ) {
60
+ // ----- previous ----------------------------------------------------------
61
+ if ( response . previous && isPlainObject ( response . previous ) ) {
45
62
let previousPaginatedField = objectPath . get ( response . previous , params . paginatedField ) ;
46
63
if ( params . sortCaseInsensitive ) {
47
64
previousPaginatedField = previousPaginatedField ?. toLowerCase ?.( ) ?? '' ;
48
65
}
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 ) ;
60
70
}
61
- if ( response . next ) {
71
+
72
+ // ----- next --------------------------------------------------------------
73
+ if ( response . next && isPlainObject ( response . next ) ) {
62
74
let nextPaginatedField = objectPath . get ( response . next , params . paginatedField ) ;
63
75
if ( params . sortCaseInsensitive ) {
64
76
nextPaginatedField = nextPaginatedField ?. toLowerCase ?.( ) ?? '' ;
65
77
}
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 ) ;
73
82
}
74
83
}
75
84
0 commit comments