1
1
import type { Value } from "convex/values" ;
2
- import { convexToJson , jsonToConvex } from "convex/values" ;
2
+ import { convexToJson , compareValues , jsonToConvex } from "convex/values" ;
3
3
import type {
4
4
DataModelFromSchemaDefinition ,
5
5
DocumentByInfo ,
@@ -20,9 +20,8 @@ import type {
20
20
SystemDataModel ,
21
21
TableNamesInDataModel ,
22
22
} from "convex/server" ;
23
- import { compareValues } from "./compare.js" ;
24
23
25
- export type IndexKey = Value [ ] ;
24
+ export type IndexKey = ( Value | undefined ) [ ] ;
26
25
27
26
//
28
27
// Helper functions
@@ -328,7 +327,7 @@ abstract class QueryStream<T extends GenericStreamItem>
328
327
} ;
329
328
if ( opts . cursor !== null ) {
330
329
newStartKey = {
331
- key : jsonToConvex ( JSON . parse ( opts . cursor ) ) as IndexKey ,
330
+ key : deserializeCursor ( opts . cursor ) ,
332
331
inclusive : false ,
333
332
} ;
334
333
}
@@ -341,7 +340,7 @@ abstract class QueryStream<T extends GenericStreamItem>
341
340
let maxRows : number | undefined = opts . numItems ;
342
341
if ( opts . endCursor ) {
343
342
newEndKey = {
344
- key : jsonToConvex ( JSON . parse ( opts . endCursor ) ) as IndexKey ,
343
+ key : deserializeCursor ( opts . endCursor ) ,
345
344
inclusive : true ,
346
345
} ;
347
346
// If there's an endCursor, continue until we get there even if it's more
@@ -370,7 +369,7 @@ abstract class QueryStream<T extends GenericStreamItem>
370
369
( maxRowsToRead !== undefined && indexKeys . length >= maxRowsToRead )
371
370
) {
372
371
hasMore = true ;
373
- continueCursor = JSON . stringify ( convexToJson ( indexKey as Value ) ) ;
372
+ continueCursor = serializeCursor ( indexKey ) ;
374
373
break ;
375
374
}
376
375
}
@@ -389,9 +388,7 @@ abstract class QueryStream<T extends GenericStreamItem>
389
388
isDone : ! hasMore ,
390
389
continueCursor,
391
390
pageStatus,
392
- splitCursor : splitCursor
393
- ? JSON . stringify ( convexToJson ( splitCursor as Value ) )
394
- : undefined ,
391
+ splitCursor : splitCursor ? serializeCursor ( splitCursor ) : undefined ,
395
392
} ;
396
393
}
397
394
async collect ( ) {
@@ -1821,3 +1818,26 @@ function compareKeys(key1: Key, key2: Key): number {
1821
1818
// of key2.kind is valid...
1822
1819
throw new Error ( `Unexpected key kind: ${ key1 . kind as any } ` ) ;
1823
1820
}
1821
+
1822
+ function serializeCursor ( key : IndexKey ) : string {
1823
+ return JSON . stringify (
1824
+ convexToJson (
1825
+ key . map ( ( v ) : Value => ( v === undefined ? { $undefined : true } : v ) ) ,
1826
+ ) ,
1827
+ ) ;
1828
+ }
1829
+
1830
+ function deserializeCursor ( cursor : string ) : IndexKey {
1831
+ return ( jsonToConvex ( JSON . parse ( cursor ) ) as Value [ ] ) . map ( ( v ) => {
1832
+ if ( typeof v === "object" && ! Array . isArray ( v ) && v !== null ) {
1833
+ const entries = Object . entries ( v ) ;
1834
+ if ( entries . length === 1 && entries [ 0 ] ! [ 0 ] === "$undefined" ) {
1835
+ // This is a special case for the undefined value.
1836
+ // It's not a valid value in the index, but it's a valid value in the
1837
+ // cursor.
1838
+ return undefined ;
1839
+ }
1840
+ }
1841
+ return v ;
1842
+ } ) ;
1843
+ }
0 commit comments