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
@@ -348,7 +347,7 @@ abstract class QueryStream<T extends GenericStreamItem>
348
347
} ;
349
348
if ( opts . cursor !== null ) {
350
349
newStartKey = {
351
- key : jsonToConvex ( JSON . parse ( opts . cursor ) ) as IndexKey ,
350
+ key : deserializeCursor ( opts . cursor ) ,
352
351
inclusive : false ,
353
352
} ;
354
353
}
@@ -361,7 +360,7 @@ abstract class QueryStream<T extends GenericStreamItem>
361
360
let maxRows : number | undefined = opts . numItems ;
362
361
if ( opts . endCursor ) {
363
362
newEndKey = {
364
- key : jsonToConvex ( JSON . parse ( opts . endCursor ) ) as IndexKey ,
363
+ key : deserializeCursor ( opts . endCursor ) ,
365
364
inclusive : true ,
366
365
} ;
367
366
// If there's an endCursor, continue until we get there even if it's more
@@ -390,7 +389,7 @@ abstract class QueryStream<T extends GenericStreamItem>
390
389
( maxRowsToRead !== undefined && indexKeys . length >= maxRowsToRead )
391
390
) {
392
391
hasMore = true ;
393
- continueCursor = JSON . stringify ( convexToJson ( indexKey as Value ) ) ;
392
+ continueCursor = serializeCursor ( indexKey ) ;
394
393
break ;
395
394
}
396
395
}
@@ -409,9 +408,7 @@ abstract class QueryStream<T extends GenericStreamItem>
409
408
isDone : ! hasMore ,
410
409
continueCursor,
411
410
pageStatus,
412
- splitCursor : splitCursor
413
- ? JSON . stringify ( convexToJson ( splitCursor as Value ) )
414
- : undefined ,
411
+ splitCursor : splitCursor ? serializeCursor ( splitCursor ) : undefined ,
415
412
} ;
416
413
}
417
414
async collect ( ) {
@@ -1850,3 +1847,26 @@ function compareKeys(key1: Key, key2: Key): number {
1850
1847
// of key2.kind is valid...
1851
1848
throw new Error ( `Unexpected key kind: ${ key1 . kind as any } ` ) ;
1852
1849
}
1850
+
1851
+ function serializeCursor ( key : IndexKey ) : string {
1852
+ return JSON . stringify (
1853
+ convexToJson (
1854
+ key . map ( ( v ) : Value => ( v === undefined ? { $undefined : true } : v ) ) ,
1855
+ ) ,
1856
+ ) ;
1857
+ }
1858
+
1859
+ function deserializeCursor ( cursor : string ) : IndexKey {
1860
+ return ( jsonToConvex ( JSON . parse ( cursor ) ) as Value [ ] ) . map ( ( v ) => {
1861
+ if ( typeof v === "object" && ! Array . isArray ( v ) && v !== null ) {
1862
+ const entries = Object . entries ( v ) ;
1863
+ if ( entries . length === 1 && entries [ 0 ] ! [ 0 ] === "$undefined" ) {
1864
+ // This is a special case for the undefined value.
1865
+ // It's not a valid value in the index, but it's a valid value in the
1866
+ // cursor.
1867
+ return undefined ;
1868
+ }
1869
+ }
1870
+ return v ;
1871
+ } ) ;
1872
+ }
0 commit comments