Skip to content

Commit 279f177

Browse files
committed
serde for undefined
1 parent 9bf5efc commit 279f177

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,6 +1,6 @@
11
/* eslint-disable no-unexpected-multiline */
22
import type { Value } from "convex/values";
3-
import { convexToJson, jsonToConvex } from "convex/values";
3+
import { convexToJson, compareValues, jsonToConvex } from "convex/values";
44
import type {
55
DataModelFromSchemaDefinition,
66
DocumentByInfo,
@@ -21,9 +21,8 @@ import type {
2121
SystemDataModel,
2222
TableNamesInDataModel,
2323
} from "convex/server";
24-
import { compareValues } from "./compare.js";
2524

26-
export type IndexKey = Value[];
25+
export type IndexKey = (Value | undefined)[];
2726

2827
//
2928
// Helper functions
@@ -349,7 +348,7 @@ abstract class QueryStream<T extends GenericStreamItem>
349348
};
350349
if (opts.cursor !== null) {
351350
newStartKey = {
352-
key: jsonToConvex(JSON.parse(opts.cursor)) as IndexKey,
351+
key: deserializeCursor(opts.cursor),
353352
inclusive: false,
354353
};
355354
}
@@ -362,7 +361,7 @@ abstract class QueryStream<T extends GenericStreamItem>
362361
let maxRows: number | undefined = opts.numItems;
363362
if (opts.endCursor) {
364363
newEndKey = {
365-
key: jsonToConvex(JSON.parse(opts.endCursor)) as IndexKey,
364+
key: deserializeCursor(opts.endCursor),
366365
inclusive: true,
367366
};
368367
// If there's an endCursor, continue until we get there even if it's more
@@ -391,7 +390,7 @@ abstract class QueryStream<T extends GenericStreamItem>
391390
(maxRowsToRead !== undefined && indexKeys.length >= maxRowsToRead)
392391
) {
393392
hasMore = true;
394-
continueCursor = JSON.stringify(convexToJson(indexKey as Value));
393+
continueCursor = serializeCursor(indexKey);
395394
break;
396395
}
397396
}
@@ -410,9 +409,7 @@ abstract class QueryStream<T extends GenericStreamItem>
410409
isDone: !hasMore,
411410
continueCursor,
412411
pageStatus,
413-
splitCursor: splitCursor
414-
? JSON.stringify(convexToJson(splitCursor as Value))
415-
: undefined,
412+
splitCursor: splitCursor ? serializeCursor(splitCursor) : undefined,
416413
};
417414
}
418415
async collect() {
@@ -1851,3 +1848,26 @@ function compareKeys(key1: Key, key2: Key): number {
18511848
// of key2.kind is valid...
18521849
throw new Error(`Unexpected key kind: ${key1.kind as any}`);
18531850
}
1851+
1852+
function serializeCursor(key: IndexKey): string {
1853+
return JSON.stringify(
1854+
convexToJson(
1855+
key.map((v): Value => (v === undefined ? { $undefined: true } : v)),
1856+
),
1857+
);
1858+
}
1859+
1860+
function deserializeCursor(cursor: string): IndexKey {
1861+
return (jsonToConvex(JSON.parse(cursor)) as Value[]).map((v) => {
1862+
if (typeof v === "object" && !Array.isArray(v) && v !== null) {
1863+
const entries = Object.entries(v);
1864+
if (entries.length === 1 && entries[0]![0] === "$undefined") {
1865+
// This is a special case for the undefined value.
1866+
// It's not a valid value in the index, but it's a valid value in the
1867+
// cursor.
1868+
return undefined;
1869+
}
1870+
}
1871+
return v;
1872+
});
1873+
}

0 commit comments

Comments
 (0)