@@ -21,7 +21,9 @@ function encodePaginationTokens(params, response) {
21
21
22
22
if ( response . previous ) {
23
23
let previousPaginatedField = objectPath . get ( response . previous , params . paginatedField ) ;
24
- if ( params . sortCaseInsensitive ) previousPaginatedField = previousPaginatedField . toLowerCase ( ) ;
24
+ if ( params . sortCaseInsensitive ) {
25
+ previousPaginatedField = previousPaginatedField ?. toLowerCase ?. ( ) ?? '' ;
26
+ }
25
27
if ( shouldSecondarySortOnId ) {
26
28
response . previous = bsonUrlEncoding . encode ( [ previousPaginatedField , response . previous . _id ] ) ;
27
29
} else {
@@ -30,7 +32,9 @@ function encodePaginationTokens(params, response) {
30
32
}
31
33
if ( response . next ) {
32
34
let nextPaginatedField = objectPath . get ( response . next , params . paginatedField ) ;
33
- if ( params . sortCaseInsensitive ) nextPaginatedField = nextPaginatedField . toLowerCase ( ) ;
35
+ if ( params . sortCaseInsensitive ) {
36
+ nextPaginatedField = nextPaginatedField ?. toLowerCase ?. ( ) ?? '' ;
37
+ }
34
38
if ( shouldSecondarySortOnId ) {
35
39
response . next = bsonUrlEncoding . encode ( [ nextPaginatedField , response . next . _id ] ) ;
36
40
} else {
@@ -112,36 +116,90 @@ module.exports = {
112
116
113
117
const sortAsc =
114
118
( ! params . sortAscending && params . previous ) || ( params . sortAscending && ! params . previous ) ;
115
- const comparisonOp = sortAsc ? '$gt' : '$lt' ;
116
119
117
120
// a `next` cursor will have precedence over a `previous` cursor.
118
121
const op = params . next || params . previous ;
119
122
120
123
if ( params . paginatedField == '_id' ) {
121
- return {
122
- _id : {
123
- [ comparisonOp ] : op ,
124
- } ,
125
- } ;
124
+ if ( sortAsc ) {
125
+ return { _id : { $gt : op } } ;
126
+ } else {
127
+ return { _id : { $lt : op } } ;
128
+ }
126
129
} else {
127
130
const field = params . sortCaseInsensitive ? '__lc' : params . paginatedField ;
128
- return {
129
- $or : [
130
- {
131
- [ field ] : {
132
- [ comparisonOp ] : op [ 0 ] ,
133
- } ,
134
- } ,
135
- {
136
- [ field ] : {
137
- $eq : op [ 0 ] ,
138
- } ,
139
- _id : {
140
- [ comparisonOp ] : op [ 1 ] ,
141
- } ,
142
- } ,
143
- ] ,
144
- } ;
131
+
132
+ const notUndefined = { [ field ] : { $exists : true } } ;
133
+ const onlyUndefs = { [ field ] : { $exists : false } } ;
134
+ const notNullNorUndefined = { [ field ] : { $ne : null } } ;
135
+ const nullOrUndefined = { [ field ] : null } ;
136
+ const onlyNulls = { $and : [ { [ field ] : { $exists : true } } , { [ field ] : null } ] } ;
137
+
138
+ const [ paginatedFieldValue , idValue ] = op ;
139
+ switch ( paginatedFieldValue ) {
140
+ case null :
141
+ if ( sortAsc ) {
142
+ return {
143
+ $or : [
144
+ notNullNorUndefined ,
145
+ {
146
+ ...onlyNulls ,
147
+ _id : { $gt : idValue } ,
148
+ } ,
149
+ ] ,
150
+ } ;
151
+ } else {
152
+ return {
153
+ $or : [
154
+ onlyUndefs ,
155
+ {
156
+ ...onlyNulls ,
157
+ _id : { $lt : idValue } ,
158
+ } ,
159
+ ] ,
160
+ } ;
161
+ }
162
+ case undefined :
163
+ if ( sortAsc ) {
164
+ return {
165
+ $or : [
166
+ notUndefined ,
167
+ {
168
+ ...onlyUndefs ,
169
+ _id : { $gt : idValue } ,
170
+ } ,
171
+ ] ,
172
+ } ;
173
+ } else {
174
+ return {
175
+ ...onlyUndefs ,
176
+ _id : { $lt : idValue } ,
177
+ } ;
178
+ }
179
+ default :
180
+ if ( sortAsc ) {
181
+ return {
182
+ $or : [
183
+ { [ field ] : { $gt : paginatedFieldValue } } ,
184
+ {
185
+ [ field ] : { $eq : paginatedFieldValue } ,
186
+ _id : { $gt : idValue } ,
187
+ } ,
188
+ ] ,
189
+ } ;
190
+ } else {
191
+ return {
192
+ $or : [
193
+ { [ field ] : { $lt : paginatedFieldValue } } ,
194
+ nullOrUndefined ,
195
+ {
196
+ [ field ] : { $eq : paginatedFieldValue } ,
197
+ _id : { $lt : idValue } ,
198
+ } ,
199
+ ] ,
200
+ } ;
201
+ }
202
+ }
145
203
}
146
204
} ,
147
205
} ;
0 commit comments