Skip to content

Commit fd81d21

Browse files
committed
serde for undefined
1 parent 5069445 commit fd81d21

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

packages/convex-helpers/server/stream.ts

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Value } from "convex/values";
2-
import { convexToJson, jsonToConvex } from "convex/values";
2+
import { convexToJson, compareValues, jsonToConvex } from "convex/values";
33
import type {
44
DataModelFromSchemaDefinition,
55
DocumentByInfo,
@@ -20,9 +20,8 @@ import type {
2020
SystemDataModel,
2121
TableNamesInDataModel,
2222
} from "convex/server";
23-
import { compareValues } from "./compare.js";
2423

25-
export type IndexKey = Value[];
24+
export type IndexKey = (Value | undefined)[];
2625

2726
//
2827
// Helper functions
@@ -348,7 +347,7 @@ abstract class QueryStream<T extends GenericStreamItem>
348347
};
349348
if (opts.cursor !== null) {
350349
newStartKey = {
351-
key: jsonToConvex(JSON.parse(opts.cursor)) as IndexKey,
350+
key: deserializeCursor(opts.cursor),
352351
inclusive: false,
353352
};
354353
}
@@ -361,7 +360,7 @@ abstract class QueryStream<T extends GenericStreamItem>
361360
let maxRows: number | undefined = opts.numItems;
362361
if (opts.endCursor) {
363362
newEndKey = {
364-
key: jsonToConvex(JSON.parse(opts.endCursor)) as IndexKey,
363+
key: deserializeCursor(opts.endCursor),
365364
inclusive: true,
366365
};
367366
// 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>
390389
(maxRowsToRead !== undefined && indexKeys.length >= maxRowsToRead)
391390
) {
392391
hasMore = true;
393-
continueCursor = JSON.stringify(convexToJson(indexKey as Value));
392+
continueCursor = serializeCursor(indexKey);
394393
break;
395394
}
396395
}
@@ -409,9 +408,7 @@ abstract class QueryStream<T extends GenericStreamItem>
409408
isDone: !hasMore,
410409
continueCursor,
411410
pageStatus,
412-
splitCursor: splitCursor
413-
? JSON.stringify(convexToJson(splitCursor as Value))
414-
: undefined,
411+
splitCursor: splitCursor ? serializeCursor(splitCursor) : undefined,
415412
};
416413
}
417414
async collect() {
@@ -1850,3 +1847,26 @@ function compareKeys(key1: Key, key2: Key): number {
18501847
// of key2.kind is valid...
18511848
throw new Error(`Unexpected key kind: ${key1.kind as any}`);
18521849
}
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

Comments
 (0)