@@ -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