@gaganref/confect-test 10.3.1-fork.87 → 10.3.1-fork.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/internal/Attempt.d.ts +77 -0
  2. package/dist/internal/Attempt.d.ts.map +1 -0
  3. package/dist/internal/Attempt.js +154 -0
  4. package/dist/internal/Attempt.js.map +1 -0
  5. package/dist/internal/ConvexTest.d.ts +34 -0
  6. package/dist/internal/ConvexTest.d.ts.map +1 -0
  7. package/dist/internal/ConvexTest.js +59 -0
  8. package/dist/internal/ConvexTest.js.map +1 -0
  9. package/dist/internal/Execution.d.ts +167 -0
  10. package/dist/internal/Execution.d.ts.map +1 -0
  11. package/dist/internal/Execution.js +790 -0
  12. package/dist/internal/Execution.js.map +1 -0
  13. package/dist/internal/Globals.d.ts +11 -0
  14. package/dist/internal/Globals.d.ts.map +1 -0
  15. package/dist/internal/Globals.js +76 -0
  16. package/dist/internal/Globals.js.map +1 -0
  17. package/dist/internal/Invocation.d.ts +57 -0
  18. package/dist/internal/Invocation.d.ts.map +1 -0
  19. package/dist/internal/Invocation.js +145 -0
  20. package/dist/internal/Invocation.js.map +1 -0
  21. package/dist/internal/Kernel.d.ts +93 -0
  22. package/dist/internal/Kernel.d.ts.map +1 -0
  23. package/dist/internal/Kernel.js +91 -0
  24. package/dist/internal/Kernel.js.map +1 -0
  25. package/dist/internal/KernelQuery.d.ts +55 -0
  26. package/dist/internal/KernelQuery.d.ts.map +1 -0
  27. package/dist/internal/KernelQuery.js +205 -0
  28. package/dist/internal/KernelQuery.js.map +1 -0
  29. package/dist/internal/KernelRefusal.d.ts +77 -0
  30. package/dist/internal/KernelRefusal.d.ts.map +1 -0
  31. package/dist/internal/KernelRefusal.js +73 -0
  32. package/dist/internal/KernelRefusal.js.map +1 -0
  33. package/dist/internal/KernelValues.d.ts +136 -0
  34. package/dist/internal/KernelValues.d.ts.map +1 -0
  35. package/dist/internal/KernelValues.js +266 -0
  36. package/dist/internal/KernelValues.js.map +1 -0
  37. package/dist/internal/ReadSet.d.ts +55 -0
  38. package/dist/internal/ReadSet.d.ts.map +1 -0
  39. package/dist/internal/ReadSet.js +29 -0
  40. package/dist/internal/ReadSet.js.map +1 -0
  41. package/package.json +3 -3
  42. package/src/internal/Attempt.ts +185 -0
  43. package/src/internal/ConvexTest.ts +118 -0
  44. package/src/internal/Execution.ts +1430 -0
  45. package/src/internal/Globals.ts +93 -0
  46. package/src/internal/Invocation.ts +291 -0
  47. package/src/internal/Kernel.ts +190 -0
  48. package/src/internal/KernelQuery.ts +405 -0
  49. package/src/internal/KernelRefusal.ts +88 -0
  50. package/src/internal/KernelValues.ts +725 -0
  51. package/src/internal/ReadSet.ts +108 -0
@@ -0,0 +1,91 @@
1
+ import { host } from "./Globals.js";
2
+ import { resolveCommittedValues, tableNameFromId } from "./KernelValues.js";
3
+ import { covers } from "./ReadSet.js";
4
+ //#region src/internal/Kernel.ts
5
+ const empty = {
6
+ tables: /* @__PURE__ */ new Map(),
7
+ version: 0,
8
+ commitTs: 0n,
9
+ log: []
10
+ };
11
+ /**
12
+ * The committed row for `id` in `componentPath`, if any.
13
+ */
14
+ const get = (state, componentPath, id) => {
15
+ const tableName = tableNameFromId(id);
16
+ return tableName === null ? void 0 : state.tables.get(componentPath)?.get(tableName)?.get(id);
17
+ };
18
+ /**
19
+ * Every committed row of one table in one component.
20
+ */
21
+ const rows = (state, componentPath, tableName) => state.tables.get(componentPath)?.get(tableName)?.values() ?? [];
22
+ /**
23
+ * Publish one attempt's writes as a single commit at `commitTs`. Every
24
+ * component's writes land in the same version, so a reader sees all of them or
25
+ * none. A commit with no writes publishes nothing and leaves the state as it
26
+ * was.
27
+ */
28
+ const apply = (state, writes, commitTs) => {
29
+ if (writes.length === 0) return state;
30
+ const version = state.version + 1;
31
+ const tables = new Map(Array.from(state.tables, ([path, byTable]) => [path, new Map(byTable)]));
32
+ const changes = writes.map(({ componentPath, id, doc }) => ({
33
+ componentPath,
34
+ id,
35
+ before: get(state, componentPath, id)?.doc ?? null,
36
+ after: doc === null ? null : resolveCommittedValues(doc, commitTs)
37
+ }));
38
+ const touched = /* @__PURE__ */ new Set();
39
+ for (const { componentPath, id, after } of changes) {
40
+ const tableName = tableNameFromId(id);
41
+ const byTable = tables.get(componentPath) ?? /* @__PURE__ */ new Map();
42
+ tables.set(componentPath, byTable);
43
+ const key = `${componentPath}\u0000${tableName}`;
44
+ const table = touched.has(key) ? byTable.get(tableName) : new Map(byTable.get(tableName) ?? []);
45
+ touched.add(key);
46
+ byTable.set(tableName, table);
47
+ if (after === null) table.delete(id);
48
+ else table.set(id, {
49
+ doc: after,
50
+ version
51
+ });
52
+ }
53
+ return {
54
+ tables,
55
+ version,
56
+ commitTs,
57
+ log: [...state.log, {
58
+ version,
59
+ commitTs,
60
+ changes
61
+ }]
62
+ };
63
+ };
64
+ /**
65
+ * The first change published after version `snapshot` that invalidates one of
66
+ * `reads`, if any.
67
+ */
68
+ const conflict = (state, snapshot, reads) => {
69
+ for (const commit of state.log.slice(snapshot)) for (const change of commit.changes) if (reads.some((read) => covers(read, change))) return change;
70
+ };
71
+ /**
72
+ * The wall clock, as convex-test reads it. Each answer is the time in
73
+ * nanoseconds when it is asked for, bumped past the previous answer when the
74
+ * clock stands still.
75
+ */
76
+ const wallClock = () => {
77
+ let latest = 0n;
78
+ const now = () => host(() => Date.now());
79
+ return {
80
+ now,
81
+ commitTs: () => {
82
+ const nanos = BigInt(now()) * 1000000n;
83
+ latest = nanos > latest ? nanos : latest + 1n;
84
+ return latest;
85
+ }
86
+ };
87
+ };
88
+ //#endregion
89
+ export { apply, conflict, empty, get, rows, wallClock };
90
+
91
+ //# sourceMappingURL=Kernel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Kernel.js","names":["ReadSet.covers","Globals.host"],"sources":["../../src/internal/Kernel.ts"],"sourcesContent":["import * as Globals from \"./Globals.js\";\nimport type { DocumentId, StoredDocument } from \"./KernelValues.js\";\nimport { resolveCommittedValues, tableNameFromId } from \"./KernelValues.js\";\nimport * as ReadSet from \"./ReadSet.js\";\n\n/**\n * The number of commits the kernel has published. The empty world is 0.\n */\nexport type Version = number;\n\n/**\n * A committed document and the version that wrote it.\n */\nexport interface Row {\n readonly doc: StoredDocument;\n readonly version: Version;\n}\n\n/**\n * Committed rows, keyed by component path, then table name, then document ID. A\n * published state is never changed. A commit makes a new one.\n */\nexport type Tables = ReadonlyMap<\n string,\n ReadonlyMap<string, ReadonlyMap<DocumentId, Row>>\n>;\n\n/**\n * One document's final value in a commit. `null` deletes it.\n */\nexport interface Write {\n readonly componentPath: string;\n readonly id: DocumentId;\n readonly doc: StoredDocument | null;\n}\n\n/**\n * One document a commit changed: its value before and after. `null` is absent.\n */\nexport interface Change {\n readonly componentPath: string;\n readonly id: DocumentId;\n readonly before: StoredDocument | null;\n readonly after: StoredDocument | null;\n}\n\nexport interface Commit {\n readonly version: Version;\n readonly commitTs: bigint;\n readonly changes: ReadonlyArray<Change>;\n}\n\n/**\n * The kernel's committed state: rows, the latest version and commit timestamp,\n * and the write log, oldest first.\n */\nexport interface State {\n readonly tables: Tables;\n readonly version: Version;\n readonly commitTs: bigint;\n readonly log: ReadonlyArray<Commit>;\n}\n\nexport const empty: State = {\n tables: new Map(),\n version: 0,\n commitTs: 0n,\n log: [],\n};\n\n/**\n * The committed row for `id` in `componentPath`, if any.\n */\nexport const get = (\n state: State,\n componentPath: string,\n id: DocumentId,\n): Row | undefined => {\n const tableName = tableNameFromId(id);\n return tableName === null\n ? undefined\n : state.tables.get(componentPath)?.get(tableName)?.get(id);\n};\n\n/**\n * Every committed row of one table in one component.\n */\nexport const rows = (\n state: State,\n componentPath: string,\n tableName: string,\n): Iterable<Row> =>\n state.tables.get(componentPath)?.get(tableName)?.values() ?? [];\n\n/**\n * Publish one attempt's writes as a single commit at `commitTs`. Every\n * component's writes land in the same version, so a reader sees all of them or\n * none. A commit with no writes publishes nothing and leaves the state as it\n * was.\n */\nexport const apply = (\n state: State,\n writes: ReadonlyArray<Write>,\n commitTs: bigint,\n): State => {\n if (writes.length === 0) return state;\n const version = state.version + 1;\n const tables = new Map(\n Array.from(state.tables, ([path, byTable]) => [path, new Map(byTable)]),\n );\n const changes = writes.map(({ componentPath, id, doc }): Change => ({\n componentPath,\n id,\n before: get(state, componentPath, id)?.doc ?? null,\n after: doc === null ? null : resolveCommittedValues(doc, commitTs),\n }));\n const touched = new Set<string>();\n for (const { componentPath, id, after } of changes) {\n const tableName = tableNameFromId(id)!;\n const byTable = tables.get(componentPath) ?? new Map();\n tables.set(componentPath, byTable);\n const key = `${componentPath}\\u0000${tableName}`;\n const table = touched.has(key)\n ? byTable.get(tableName)!\n : new Map(byTable.get(tableName) ?? []);\n touched.add(key);\n byTable.set(tableName, table);\n if (after === null) table.delete(id);\n else table.set(id, { doc: after, version });\n }\n return {\n tables,\n version,\n commitTs,\n log: [...state.log, { version, commitTs, changes }],\n };\n};\n\n/**\n * The first change published after version `snapshot` that invalidates one of\n * `reads`, if any.\n */\nexport const conflict = (\n state: State,\n snapshot: Version,\n reads: ReadonlyArray<ReadSet.Read>,\n): Change | undefined => {\n for (const commit of state.log.slice(snapshot)) {\n for (const change of commit.changes) {\n if (reads.some((read) => ReadSet.covers(read, change))) return change;\n }\n }\n return undefined;\n};\n\n/**\n * What the driver supplies. The kernel holds no clock of its own.\n */\nexport interface KernelRuntime {\n /**\n * The time in milliseconds, for each inserted document's creation time.\n */\n readonly now: () => number;\n /**\n * The commit timestamp of `version`, asked once as it is published. The\n * answers strictly increase. A mutation that wrote nothing publishes no\n * version and asks nothing.\n */\n readonly commitTs: (version: Version) => bigint;\n}\n\n/**\n * The wall clock, as convex-test reads it. Each answer is the time in\n * nanoseconds when it is asked for, bumped past the previous answer when the\n * clock stands still.\n */\nexport const wallClock = (): KernelRuntime => {\n let latest = 0n;\n // The host's clock, never the copy a bound handler pinned.\n // oxlint-disable-next-line effecttsgo/global-date -- The default runtime is the wall clock. A driver that replays supplies its own.\n const now = () => Globals.host(() => Date.now());\n return {\n now,\n commitTs: () => {\n const nanos = BigInt(now()) * 1_000_000n;\n latest = nanos > latest ? nanos : latest + 1n;\n return latest;\n },\n };\n};\n"],"mappings":";;;;AA+DA,MAAa,QAAe;CAC1B,wBAAQ,IAAI,IAAI;CAChB,SAAS;CACT,UAAU;CACV,KAAK,CAAC;AACR;;;;AAKA,MAAa,OACX,OACA,eACA,OACoB;CACpB,MAAM,YAAY,gBAAgB,EAAE;CACpC,OAAO,cAAc,OACjB,KAAA,IACA,MAAM,OAAO,IAAI,aAAa,CAAC,EAAE,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE;AAC7D;;;;AAKA,MAAa,QACX,OACA,eACA,cAEA,MAAM,OAAO,IAAI,aAAa,CAAC,EAAE,IAAI,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;;;;;;;AAQhE,MAAa,SACX,OACA,QACA,aACU;CACV,IAAI,OAAO,WAAW,GAAG,OAAO;CAChC,MAAM,UAAU,MAAM,UAAU;CAChC,MAAM,SAAS,IAAI,IACjB,MAAM,KAAK,MAAM,SAAS,CAAC,MAAM,aAAa,CAAC,MAAM,IAAI,IAAI,OAAO,CAAC,CAAC,CACxE;CACA,MAAM,UAAU,OAAO,KAAK,EAAE,eAAe,IAAI,WAAmB;EAClE;EACA;EACA,QAAQ,IAAI,OAAO,eAAe,EAAE,CAAC,EAAE,OAAO;EAC9C,OAAO,QAAQ,OAAO,OAAO,uBAAuB,KAAK,QAAQ;CACnE,EAAE;CACF,MAAM,0BAAU,IAAI,IAAY;CAChC,KAAK,MAAM,EAAE,eAAe,IAAI,WAAW,SAAS;EAClD,MAAM,YAAY,gBAAgB,EAAE;EACpC,MAAM,UAAU,OAAO,IAAI,aAAa,qBAAK,IAAI,IAAI;EACrD,OAAO,IAAI,eAAe,OAAO;EACjC,MAAM,MAAM,GAAG,cAAc,QAAQ;EACrC,MAAM,QAAQ,QAAQ,IAAI,GAAG,IACzB,QAAQ,IAAI,SAAS,IACrB,IAAI,IAAI,QAAQ,IAAI,SAAS,KAAK,CAAC,CAAC;EACxC,QAAQ,IAAI,GAAG;EACf,QAAQ,IAAI,WAAW,KAAK;EAC5B,IAAI,UAAU,MAAM,MAAM,OAAO,EAAE;OAC9B,MAAM,IAAI,IAAI;GAAE,KAAK;GAAO;EAAQ,CAAC;CAC5C;CACA,OAAO;EACL;EACA;EACA;EACA,KAAK,CAAC,GAAG,MAAM,KAAK;GAAE;GAAS;GAAU;EAAQ,CAAC;CACpD;AACF;;;;;AAMA,MAAa,YACX,OACA,UACA,UACuB;CACvB,KAAK,MAAM,UAAU,MAAM,IAAI,MAAM,QAAQ,GAC3C,KAAK,MAAM,UAAU,OAAO,SAC1B,IAAI,MAAM,MAAM,SAASA,OAAe,MAAM,MAAM,CAAC,GAAG,OAAO;AAIrE;;;;;;AAuBA,MAAa,kBAAiC;CAC5C,IAAI,SAAS;CAGb,MAAM,YAAYC,WAAmB,KAAK,IAAI,CAAC;CAC/C,OAAO;EACL;EACA,gBAAgB;GACd,MAAM,QAAQ,OAAO,IAAI,CAAC,IAAI;GAC9B,SAAS,QAAQ,SAAS,QAAQ,SAAS;GAC3C,OAAO;EACT;CACF;AACF"}
@@ -0,0 +1,55 @@
1
+ import type { GenericDocument, GenericSchema, SchemaDefinition } from "convex/server";
2
+ import * as ReadSet from "./ReadSet.js";
3
+ import type { Index, SerializedQuery, StoredDocument, ValidatorJSON } from "./KernelValues.js";
4
+ /**
5
+ * A component's tables as its schema declares them.
6
+ */
7
+ export interface KernelSchema {
8
+ readonly schemaValidation: boolean;
9
+ readonly tables: ReadonlyMap<string, {
10
+ readonly indexes: ReadonlyArray<Index>;
11
+ readonly documentType: ValidatorJSON;
12
+ }>;
13
+ }
14
+ export declare const exportSchema: (schema: SchemaDefinition<GenericSchema, boolean> | null | undefined) => KernelSchema | null;
15
+ /**
16
+ * Check a document against its table's declared type, as the backend does
17
+ * before a write.
18
+ */
19
+ export declare const validateDocument: (schema: KernelSchema | null, tableName: string, doc: Record<string, unknown>) => void;
20
+ /**
21
+ * An interval a query reads, before it says where it starts and how far it got.
22
+ */
23
+ export type Interval = Omit<ReadSet.IntervalRead, "componentPath" | "after" | "through">;
24
+ /**
25
+ * What a query reads: one table of one component, as the running attempt sees
26
+ * it. `read` records an interval in the attempt's read set and returns how to
27
+ * advance it.
28
+ */
29
+ export interface TableView {
30
+ readonly schema: KernelSchema | null;
31
+ readonly scan: (tableName: string) => ReadonlyArray<StoredDocument>;
32
+ readonly read: (interval: Interval, after: ReadSet.Key | null) => (through: ReadSet.Key | "end") => void;
33
+ }
34
+ /**
35
+ * A query's documents in order. The source is read when the query starts, as a
36
+ * snapshot, and consumed lazily. The read set holds the prefix the stream has
37
+ * examined, filtered documents included, or the whole range once it ends.
38
+ */
39
+ export declare const stream: (view: TableView, query: SerializedQuery) => Iterator<GenericDocument>;
40
+ export interface PageRequest {
41
+ readonly query: SerializedQuery;
42
+ readonly cursor: string | null;
43
+ readonly endCursor?: string | null;
44
+ readonly pageSize: number;
45
+ readonly maximumRowsRead?: number | null;
46
+ readonly maximumBytesRead?: number | null;
47
+ }
48
+ export declare const paginate: (view: TableView, { query, cursor, endCursor, pageSize, maximumRowsRead, maximumBytesRead, }: PageRequest) => {
49
+ page: GenericDocument[];
50
+ isDone: boolean;
51
+ continueCursor: string;
52
+ splitCursor: string | null;
53
+ pageStatus: "SplitRecommended" | "SplitRequired" | null;
54
+ };
55
+ //# sourceMappingURL=KernelQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KernelQuery.d.ts","sourceRoot":"","sources":["../../src/internal/KernelQuery.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAQvB,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,EAEV,KAAK,EACL,eAAe,EAEf,cAAc,EACd,aAAa,EACd,MAAM,mBAAmB,CAAC;AAY3B;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAC1B,MAAM,EACN;QACE,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;QACvC,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;KACtC,CACF,CAAC;CACH;AAED,eAAO,MAAM,YAAY,WACf,gBAAgB,CAAC,aAAa,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,KAClE,YAAY,GAAG,IA4BjB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,WACnB,YAAY,GAAG,IAAI,aAChB,MAAM,OACZ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,SAM7B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,IAAI,CACzB,OAAO,CAAC,YAAY,EACpB,eAAe,GAAG,OAAO,GAAG,SAAS,CACtC,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,aAAa,CAAC,cAAc,CAAC,CAAC;IACpE,QAAQ,CAAC,IAAI,EAAE,CACb,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,OAAO,CAAC,GAAG,GAAG,IAAI,KACtB,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,GAAG,KAAK,KAAK,IAAI,CAAC;CAC7C;AA4GD;;;;GAIG;AACH,eAAO,MAAM,MAAM,SACX,SAAS,SACR,eAAe,KACrB,QAAQ,CAAC,eAAe,CAe1B,CAAC;AAqCF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,eAAO,MAAM,QAAQ,SACb,SAAS,8EAQZ,WAAW;;;;;;CAkGf,CAAC"}
@@ -0,0 +1,205 @@
1
+ import { evaluateFieldPath, evaluateFilter, evaluateRangeFilter, isValidIdentifier, resolvePendingValues, validateFieldNames, validateIndexRangeExpression, validateValidator } from "./KernelValues.js";
2
+ import { keyOf } from "./ReadSet.js";
3
+ import { requiresBinary } from "./KernelRefusal.js";
4
+ import { compareValues, convexToJson, getDocumentSize, jsonToConvex } from "convex/values";
5
+ //#region src/internal/KernelQuery.ts
6
+ const exportSchema = (schema) => {
7
+ if (schema === null || schema === void 0) return null;
8
+ const exported = {
9
+ schemaValidation: schema.schemaValidation,
10
+ tables: new Map(Object.entries(schema.tables).map(([name, table]) => [name, table.export()]))
11
+ };
12
+ exported.tables.forEach((table, tableName) => {
13
+ if (!isValidIdentifier(tableName)) throw new Error(`Table names must be valid identifiers, got "${tableName}"`);
14
+ validateFieldNames(table.documentType);
15
+ table.indexes.forEach(({ indexDescriptor }) => {
16
+ if (!isValidIdentifier(indexDescriptor)) throw new Error(`Index names must be valid identifiers, got "${indexDescriptor}"`);
17
+ });
18
+ });
19
+ return exported;
20
+ };
21
+ /**
22
+ * Check a document against its table's declared type, as the backend does
23
+ * before a write.
24
+ */
25
+ const validateDocument = (schema, tableName, doc) => {
26
+ if (schema === null || !schema.schemaValidation) return;
27
+ const validator = schema.tables.get(tableName)?.documentType;
28
+ if (validator === void 0) return;
29
+ validateValidator(validator, resolvePendingValues(doc));
30
+ };
31
+ const resolveSource = (view, query) => {
32
+ const source = query.source;
33
+ let docs;
34
+ let fieldPathsToSortBy;
35
+ let order;
36
+ let table;
37
+ let range = [];
38
+ switch (source.type) {
39
+ case "FullTableScan":
40
+ table = source.tableName;
41
+ docs = [...view.scan(source.tableName)];
42
+ order = source.order ?? "asc";
43
+ fieldPathsToSortBy = ["_creationTime"];
44
+ break;
45
+ case "IndexRange": {
46
+ const [tableName, indexName] = source.indexName.split(".");
47
+ table = tableName;
48
+ range = source.range;
49
+ order = source.order ?? "asc";
50
+ let fields;
51
+ if (indexName === "by_creation_time") fields = ["_creationTime", "_id"];
52
+ else if (indexName === "by_id") fields = ["_id"];
53
+ else {
54
+ const index = view.schema?.tables.get(tableName)?.indexes.find(({ indexDescriptor }) => indexDescriptor === indexName);
55
+ if (index === void 0) throw new Error(`Cannot use index "${indexName}" for table "${tableName}" because it is not declared in the schema.`);
56
+ fields = index.fields.concat(["_creationTime", "_id"]);
57
+ }
58
+ fieldPathsToSortBy = fields;
59
+ validateIndexRangeExpression(source, fields);
60
+ docs = view.scan(tableName).filter((doc) => source.range.every((filter) => evaluateRangeFilter(doc, filter)));
61
+ break;
62
+ }
63
+ case "Search": throw requiresBinary("textSearch");
64
+ }
65
+ const filters = query.operators.filter((operator) => "filter" in operator).map((operator) => operator.filter);
66
+ const limit = query.operators.find((operator) => "limit" in operator) ?? null;
67
+ const orderMultiplier = order === "asc" ? 1 : -1;
68
+ docs.sort((a, b) => {
69
+ for (const fp of fieldPathsToSortBy) {
70
+ const v = compareValues(evaluateFieldPath(fp, a), evaluateFieldPath(fp, b));
71
+ if (v !== 0) return v * orderMultiplier;
72
+ }
73
+ return 0;
74
+ });
75
+ return {
76
+ sortedDocs: docs,
77
+ filterFn: (doc) => filters.every((f) => evaluateFilter(doc, f)),
78
+ limit: limit?.limit ?? null,
79
+ order,
80
+ interval: {
81
+ kind: "interval",
82
+ table,
83
+ fields: fieldPathsToSortBy.includes("_id") ? fieldPathsToSortBy : [...fieldPathsToSortBy, "_id"],
84
+ order,
85
+ range
86
+ }
87
+ };
88
+ };
89
+ /**
90
+ * A query's documents in order. The source is read when the query starts, as a
91
+ * snapshot, and consumed lazily. The read set holds the prefix the stream has
92
+ * examined, filtered documents included, or the whole range once it ends.
93
+ */
94
+ const stream = (view, query) => {
95
+ const { sortedDocs, filterFn, limit, interval } = resolveSource(view, query);
96
+ const examined = view.read(interval, null);
97
+ return (function* () {
98
+ let returned = 0;
99
+ for (const doc of sortedDocs) {
100
+ if (limit !== null && returned >= limit) return;
101
+ examined(keyOf(interval.fields, doc));
102
+ if (filterFn(doc)) {
103
+ returned++;
104
+ yield doc;
105
+ }
106
+ }
107
+ examined("end");
108
+ })();
109
+ };
110
+ const encodeCursor = (doc, fieldPaths) => JSON.stringify(fieldPaths.map((fp) => {
111
+ const k = evaluateFieldPath(fp, doc);
112
+ return k === void 0 ? null : JSON.stringify(convexToJson(k));
113
+ }));
114
+ const parseCursor = (c) => c ? JSON.parse(c).map((k) => k === null ? void 0 : jsonToConvex(JSON.parse(k))) : null;
115
+ const compareToCursor = (doc, cursorKeys, fieldPaths, order) => {
116
+ const orderMultiplier = order === "asc" ? 1 : -1;
117
+ for (let i = 0; i < fieldPaths.length; i++) {
118
+ const cmp = compareValues(evaluateFieldPath(fieldPaths[i], doc), cursorKeys[i]);
119
+ if (cmp !== 0) return cmp * orderMultiplier;
120
+ }
121
+ return 0;
122
+ };
123
+ const paginate = (view, { query, cursor, endCursor, pageSize, maximumRowsRead, maximumBytesRead }) => {
124
+ const { sortedDocs, filterFn, order, interval } = resolveSource(view, query);
125
+ if (cursor === "_end_cursor") return {
126
+ page: [],
127
+ isDone: true,
128
+ continueCursor: "_end_cursor",
129
+ splitCursor: null,
130
+ pageStatus: null
131
+ };
132
+ const cursorFields = interval.fields;
133
+ const cursorKeys = parseCursor(cursor);
134
+ const hasEndBoundary = !!endCursor && endCursor !== "_end_cursor";
135
+ const endCursorKeys = hasEndBoundary ? parseCursor(endCursor) : null;
136
+ const examined = view.read(interval, cursorKeys);
137
+ let reachedEnd = true;
138
+ const page = [];
139
+ let isInPage = cursor === null;
140
+ let continueCursor = "_end_cursor";
141
+ let splitCursor = null;
142
+ let pageStatus = null;
143
+ let rowsRead = 0;
144
+ let bytesRead = 0;
145
+ const readDocCursors = [];
146
+ for (let i = 0; i < sortedDocs.length; i++) {
147
+ const doc = sortedDocs[i];
148
+ const isLastDoc = i === sortedDocs.length - 1;
149
+ if (!isInPage) {
150
+ if (cursorKeys) {
151
+ if (compareToCursor(doc, cursorKeys, cursorFields, order) > 0) isInPage = true;
152
+ else continue;
153
+ }
154
+ }
155
+ if (hasEndBoundary && endCursorKeys) {
156
+ const cmp = compareToCursor(doc, endCursorKeys, cursorFields, order);
157
+ if (cmp >= 0) {
158
+ reachedEnd = false;
159
+ examined(endCursorKeys);
160
+ if (cmp === 0) {
161
+ rowsRead += 1;
162
+ bytesRead += getDocumentSize(doc);
163
+ readDocCursors.push(encodeCursor(doc, cursorFields));
164
+ if (filterFn(doc)) page.push(doc);
165
+ continueCursor = encodeCursor(doc, cursorFields);
166
+ }
167
+ break;
168
+ }
169
+ }
170
+ rowsRead += 1;
171
+ bytesRead += getDocumentSize(doc);
172
+ readDocCursors.push(encodeCursor(doc, cursorFields));
173
+ examined(keyOf(cursorFields, doc));
174
+ const hitLimit = !!maximumRowsRead && rowsRead >= maximumRowsRead || !!maximumBytesRead && bytesRead >= maximumBytesRead;
175
+ if (filterFn(doc)) page.push(doc);
176
+ if (hitLimit) {
177
+ reachedEnd = false;
178
+ pageStatus = "SplitRequired";
179
+ continueCursor = encodeCursor(doc, cursorFields);
180
+ break;
181
+ }
182
+ if (!endCursor && page.length >= pageSize) {
183
+ reachedEnd = isLastDoc;
184
+ if (!isLastDoc) continueCursor = encodeCursor(doc, cursorFields);
185
+ break;
186
+ }
187
+ }
188
+ if (reachedEnd) examined(endCursorKeys ?? "end");
189
+ if (pageStatus === "SplitRequired" && readDocCursors.length >= 2) splitCursor = readDocCursors[Math.floor((readDocCursors.length - 1) / 2)];
190
+ else if (pageStatus === null && rowsRead > pageSize + 1 && readDocCursors.length >= 2) {
191
+ pageStatus = "SplitRecommended";
192
+ splitCursor = readDocCursors[Math.floor((readDocCursors.length - 1) / 2)];
193
+ }
194
+ return {
195
+ page,
196
+ isDone: continueCursor === "_end_cursor",
197
+ continueCursor,
198
+ splitCursor,
199
+ pageStatus
200
+ };
201
+ };
202
+ //#endregion
203
+ export { exportSchema, paginate, stream, validateDocument };
204
+
205
+ //# sourceMappingURL=KernelQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KernelQuery.js","names":["KernelRefusal.requiresBinary","ReadSet.keyOf"],"sources":["../../src/internal/KernelQuery.ts"],"sourcesContent":["// Derived from convex-test 0.0.65 (index.ts, `DatabaseFake`), Copyright Convex,\n// Inc., licensed under the Apache License, Version 2.0\n// (https://www.apache.org/licenses/LICENSE-2.0). The ordering, index range and\n// pagination rules are convex-test's. They read a table through the attempt\n// that runs the query instead of convex-test's database, and record the\n// interval each query examined.\n\nimport type {\n GenericDocument,\n GenericSchema,\n SchemaDefinition,\n} from \"convex/server\";\nimport {\n compareValues,\n convexToJson,\n getDocumentSize,\n jsonToConvex,\n} from \"convex/values\";\nimport * as KernelRefusal from \"./KernelRefusal.js\";\nimport * as ReadSet from \"./ReadSet.js\";\nimport type {\n FilterJson,\n Index,\n SerializedQuery,\n SerializedRangeExpression,\n StoredDocument,\n ValidatorJSON,\n} from \"./KernelValues.js\";\nimport {\n evaluateFieldPath,\n evaluateFilter,\n evaluateRangeFilter,\n isValidIdentifier,\n resolvePendingValues,\n validateFieldNames,\n validateIndexRangeExpression,\n validateValidator,\n} from \"./KernelValues.js\";\n\n/**\n * A component's tables as its schema declares them.\n */\nexport interface KernelSchema {\n readonly schemaValidation: boolean;\n readonly tables: ReadonlyMap<\n string,\n {\n readonly indexes: ReadonlyArray<Index>;\n readonly documentType: ValidatorJSON;\n }\n >;\n}\n\nexport const exportSchema = (\n schema: SchemaDefinition<GenericSchema, boolean> | null | undefined,\n): KernelSchema | null => {\n if (schema === null || schema === undefined) return null;\n const exported: KernelSchema = {\n schemaValidation: (schema as unknown as { schemaValidation: boolean })\n .schemaValidation,\n tables: new Map(\n Object.entries(schema.tables).map(([name, table]) => [\n name,\n (table as unknown as { export: () => any }).export(),\n ]),\n ),\n };\n exported.tables.forEach((table, tableName) => {\n if (!isValidIdentifier(tableName)) {\n throw new Error(\n `Table names must be valid identifiers, got \"${tableName}\"`,\n );\n }\n validateFieldNames(table.documentType);\n table.indexes.forEach(({ indexDescriptor }) => {\n if (!isValidIdentifier(indexDescriptor)) {\n throw new Error(\n `Index names must be valid identifiers, got \"${indexDescriptor}\"`,\n );\n }\n });\n });\n return exported;\n};\n\n/**\n * Check a document against its table's declared type, as the backend does\n * before a write.\n */\nexport const validateDocument = (\n schema: KernelSchema | null,\n tableName: string,\n doc: Record<string, unknown>,\n) => {\n if (schema === null || !schema.schemaValidation) return;\n const validator = schema.tables.get(tableName)?.documentType;\n if (validator === undefined) return;\n validateValidator(validator, resolvePendingValues(doc as GenericDocument));\n};\n\n/**\n * An interval a query reads, before it says where it starts and how far it got.\n */\nexport type Interval = Omit<\n ReadSet.IntervalRead,\n \"componentPath\" | \"after\" | \"through\"\n>;\n\n/**\n * What a query reads: one table of one component, as the running attempt sees\n * it. `read` records an interval in the attempt's read set and returns how to\n * advance it.\n */\nexport interface TableView {\n readonly schema: KernelSchema | null;\n readonly scan: (tableName: string) => ReadonlyArray<StoredDocument>;\n readonly read: (\n interval: Interval,\n after: ReadSet.Key | null,\n ) => (through: ReadSet.Key | \"end\") => void;\n}\n\ninterface ResolvedSource {\n readonly sortedDocs: ReadonlyArray<GenericDocument>;\n readonly filterFn: (doc: GenericDocument) => boolean;\n readonly limit: number | null;\n readonly order: \"asc\" | \"desc\";\n readonly interval: Interval;\n}\n\nconst resolveSource = (\n view: TableView,\n query: SerializedQuery,\n): ResolvedSource => {\n const source = query.source;\n let docs: Array<GenericDocument>;\n let fieldPathsToSortBy: Array<string>;\n let order: \"asc\" | \"desc\";\n let table: string;\n let range: ReadonlyArray<SerializedRangeExpression> = [];\n switch (source.type) {\n case \"FullTableScan\": {\n table = source.tableName;\n docs = [...view.scan(source.tableName)];\n order = source.order ?? \"asc\";\n fieldPathsToSortBy = [\"_creationTime\"];\n break;\n }\n case \"IndexRange\": {\n const [tableName, indexName] = source.indexName.split(\".\") as [\n string,\n string,\n ];\n table = tableName;\n range = source.range;\n order = source.order ?? \"asc\";\n let fields: Array<string>;\n if (indexName === \"by_creation_time\") {\n fields = [\"_creationTime\", \"_id\"];\n } else if (indexName === \"by_id\") {\n fields = [\"_id\"];\n } else {\n const index = view.schema?.tables\n .get(tableName)\n ?.indexes.find(\n ({ indexDescriptor }) => indexDescriptor === indexName,\n );\n if (index === undefined) {\n throw new Error(\n `Cannot use index \"${indexName}\" for table \"${tableName}\" because ` +\n `it is not declared in the schema.`,\n );\n }\n fields = index.fields.concat([\"_creationTime\", \"_id\"]);\n }\n fieldPathsToSortBy = fields;\n validateIndexRangeExpression(source, fields);\n docs = view\n .scan(tableName)\n .filter((doc) =>\n source.range.every((filter) => evaluateRangeFilter(doc, filter)),\n );\n break;\n }\n case \"Search\": {\n throw KernelRefusal.requiresBinary(\"textSearch\");\n }\n }\n\n const filters = query.operators\n .filter(\n (operator): operator is { filter: FilterJson } => \"filter\" in operator,\n )\n .map((operator) => operator.filter);\n const limit =\n query.operators.find(\n (operator): operator is { limit: number } => \"limit\" in operator,\n ) ?? null;\n\n const orderMultiplier = order === \"asc\" ? 1 : -1;\n docs.sort((a, b) => {\n for (const fp of fieldPathsToSortBy) {\n const v = compareValues(\n evaluateFieldPath(fp, a),\n evaluateFieldPath(fp, b),\n );\n if (v !== 0) return v * orderMultiplier;\n }\n return 0;\n });\n\n return {\n sortedDocs: docs,\n filterFn: (doc) => filters.every((f) => evaluateFilter(doc, f)),\n limit: limit?.limit ?? null,\n order,\n interval: {\n kind: \"interval\",\n table,\n fields: fieldPathsToSortBy.includes(\"_id\")\n ? fieldPathsToSortBy\n : [...fieldPathsToSortBy, \"_id\"],\n order,\n range,\n },\n };\n};\n\n/**\n * A query's documents in order. The source is read when the query starts, as a\n * snapshot, and consumed lazily. The read set holds the prefix the stream has\n * examined, filtered documents included, or the whole range once it ends.\n */\nexport const stream = (\n view: TableView,\n query: SerializedQuery,\n): Iterator<GenericDocument> => {\n const { sortedDocs, filterFn, limit, interval } = resolveSource(view, query);\n const examined = view.read(interval, null);\n return (function* () {\n let returned = 0;\n for (const doc of sortedDocs) {\n if (limit !== null && returned >= limit) return;\n examined(ReadSet.keyOf(interval.fields, doc as StoredDocument));\n if (filterFn(doc)) {\n returned++;\n yield doc;\n }\n }\n examined(\"end\");\n })();\n};\n\nconst encodeCursor = (\n doc: GenericDocument,\n fieldPaths: ReadonlyArray<string>,\n): string =>\n JSON.stringify(\n fieldPaths.map((fp) => {\n const k = evaluateFieldPath(fp, doc);\n return k === undefined ? null : JSON.stringify(convexToJson(k));\n }),\n );\n\nconst parseCursor = (c: string | null | undefined) =>\n c\n ? (JSON.parse(c) as Array<string | null>).map((k) =>\n k === null ? undefined : jsonToConvex(JSON.parse(k)),\n )\n : null;\n\nconst compareToCursor = (\n doc: GenericDocument,\n cursorKeys: ReadonlyArray<unknown>,\n fieldPaths: ReadonlyArray<string>,\n order: \"asc\" | \"desc\",\n): number => {\n const orderMultiplier = order === \"asc\" ? 1 : -1;\n for (let i = 0; i < fieldPaths.length; i++) {\n const cmp = compareValues(\n evaluateFieldPath(fieldPaths[i]!, doc),\n cursorKeys[i] as any,\n );\n if (cmp !== 0) return cmp * orderMultiplier;\n }\n return 0;\n};\n\nexport interface PageRequest {\n readonly query: SerializedQuery;\n readonly cursor: string | null;\n readonly endCursor?: string | null;\n readonly pageSize: number;\n readonly maximumRowsRead?: number | null;\n readonly maximumBytesRead?: number | null;\n}\n\nexport const paginate = (\n view: TableView,\n {\n query,\n cursor,\n endCursor,\n pageSize,\n maximumRowsRead,\n maximumBytesRead,\n }: PageRequest,\n) => {\n const { sortedDocs, filterFn, order, interval } = resolveSource(view, query);\n // A page from the terminal cursor reads the empty interval past the end, so\n // it depends on nothing.\n if (cursor === \"_end_cursor\") {\n return {\n page: [],\n isDone: true,\n continueCursor: \"_end_cursor\",\n splitCursor: null,\n pageStatus: null,\n };\n }\n const cursorFields = interval.fields;\n const cursorKeys = parseCursor(cursor);\n const hasEndBoundary = !!endCursor && endCursor !== \"_end_cursor\";\n const endCursorKeys = hasEndBoundary ? parseCursor(endCursor) : null;\n const examined = view.read(interval, cursorKeys);\n let reachedEnd = true;\n\n const page: Array<GenericDocument> = [];\n let isInPage = cursor === null;\n let continueCursor = \"_end_cursor\";\n let splitCursor: string | null = null;\n let pageStatus: \"SplitRecommended\" | \"SplitRequired\" | null = null;\n let rowsRead = 0;\n let bytesRead = 0;\n const readDocCursors: Array<string> = [];\n\n for (let i = 0; i < sortedDocs.length; i++) {\n const doc = sortedDocs[i]!;\n const isLastDoc = i === sortedDocs.length - 1;\n if (!isInPage) {\n if (cursorKeys) {\n if (compareToCursor(doc, cursorKeys, cursorFields, order) > 0) {\n isInPage = true;\n } else {\n continue;\n }\n }\n }\n if (hasEndBoundary && endCursorKeys) {\n const cmp = compareToCursor(doc, endCursorKeys, cursorFields, order);\n if (cmp >= 0) {\n reachedEnd = false;\n examined(endCursorKeys);\n if (cmp === 0) {\n rowsRead += 1;\n bytesRead += getDocumentSize(doc);\n readDocCursors.push(encodeCursor(doc, cursorFields));\n if (filterFn(doc)) page.push(doc);\n continueCursor = encodeCursor(doc, cursorFields);\n }\n break;\n }\n }\n rowsRead += 1;\n bytesRead += getDocumentSize(doc);\n readDocCursors.push(encodeCursor(doc, cursorFields));\n examined(ReadSet.keyOf(cursorFields, doc as StoredDocument));\n const hitLimit =\n (!!maximumRowsRead && rowsRead >= maximumRowsRead) ||\n (!!maximumBytesRead && bytesRead >= maximumBytesRead);\n if (filterFn(doc)) page.push(doc);\n if (hitLimit) {\n reachedEnd = false;\n pageStatus = \"SplitRequired\";\n continueCursor = encodeCursor(doc, cursorFields);\n break;\n }\n if (!endCursor && page.length >= pageSize) {\n reachedEnd = isLastDoc;\n if (!isLastDoc) continueCursor = encodeCursor(doc, cursorFields);\n break;\n }\n }\n // A page bounded by an end cursor examined the range only up to it.\n if (reachedEnd) examined(endCursorKeys ?? \"end\");\n\n if (pageStatus === \"SplitRequired\" && readDocCursors.length >= 2) {\n splitCursor = readDocCursors[Math.floor((readDocCursors.length - 1) / 2)]!;\n } else if (\n pageStatus === null &&\n rowsRead > pageSize + 1 &&\n readDocCursors.length >= 2\n ) {\n pageStatus = \"SplitRecommended\";\n splitCursor = readDocCursors[Math.floor((readDocCursors.length - 1) / 2)]!;\n }\n\n return {\n page,\n isDone: continueCursor === \"_end_cursor\",\n continueCursor,\n splitCursor,\n pageStatus,\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import * as Schema from "effect/Schema";
2
+ declare const RequiresBinary_base: Schema.Class<RequiresBinary, Schema.TaggedStruct<"RequiresBinary", {
3
+ readonly operation: Schema.Literals<readonly ["textSearch", "vectorSearch"]>;
4
+ readonly message: Schema.String;
5
+ }>, import("effect/Cause").YieldableError>;
6
+ /**
7
+ * The kernel never answers this operation in process. Only the binary does.
8
+ */
9
+ export declare class RequiresBinary extends RequiresBinary_base {
10
+ }
11
+ declare const KernelRowPending_base: Schema.Class<KernelRowPending, Schema.TaggedStruct<"KernelRowPending", {
12
+ readonly operation: Schema.String;
13
+ readonly row: Schema.Int;
14
+ readonly message: Schema.String;
15
+ }>, import("effect/Cause").YieldableError>;
16
+ /**
17
+ * A later kernel row supplies this operation. Until then the kernel refuses it
18
+ * rather than answer with convex-test's behaviour.
19
+ */
20
+ export declare class KernelRowPending extends KernelRowPending_base {
21
+ }
22
+ declare const RegisteredAfterOpen_base: Schema.Class<RegisteredAfterOpen, Schema.TaggedStruct<"RegisteredAfterOpen", {
23
+ readonly componentPath: Schema.String;
24
+ readonly message: Schema.String;
25
+ }>, import("effect/Cause").YieldableError>;
26
+ /**
27
+ * A component was registered after the test backend opened, so its modules
28
+ * would load after a function had already run.
29
+ */
30
+ export declare class RegisteredAfterOpen extends RegisteredAfterOpen_base {
31
+ }
32
+ declare const OptimisticConcurrencyControlFailure_base: Schema.Class<OptimisticConcurrencyControlFailure, Schema.TaggedStruct<"OptimisticConcurrencyControlFailure", {
33
+ readonly attempts: Schema.Int;
34
+ readonly message: Schema.String;
35
+ }>, import("effect/Cause").YieldableError>;
36
+ /**
37
+ * Every attempt of a mutation read data a commit changed before it could
38
+ * publish. The kernel gives up on attempt 5.
39
+ */
40
+ export declare class OptimisticConcurrencyControlFailure extends OptimisticConcurrencyControlFailure_base {
41
+ }
42
+ declare const ClosedAttempt_base: Schema.Class<ClosedAttempt, Schema.TaggedStruct<"ClosedAttempt", {
43
+ readonly operation: Schema.String;
44
+ readonly message: Schema.String;
45
+ }>, import("effect/Cause").YieldableError>;
46
+ /**
47
+ * A syscall reached a mutation's attempt after the mutation returned and its
48
+ * syscalls drained, so the attempt was already held or published.
49
+ */
50
+ export declare class ClosedAttempt extends ClosedAttempt_base {
51
+ }
52
+ declare const StaleAttempt_base: Schema.Class<StaleAttempt, Schema.TaggedStruct<"StaleAttempt", {
53
+ readonly id: Schema.String;
54
+ readonly message: Schema.String;
55
+ }>, import("effect/Cause").YieldableError>;
56
+ /**
57
+ * `apply` named an attempt the kernel does not hold: it was already applied, or
58
+ * never prepared.
59
+ */
60
+ export declare class StaleAttempt extends StaleAttempt_base {
61
+ }
62
+ declare const CommitTsNotIncreasing_base: Schema.Class<CommitTsNotIncreasing, Schema.TaggedStruct<"CommitTsNotIncreasing", {
63
+ readonly version: Schema.Int;
64
+ readonly previous: Schema.BigInt;
65
+ readonly commitTs: Schema.BigInt;
66
+ readonly message: Schema.String;
67
+ }>, import("effect/Cause").YieldableError>;
68
+ /**
69
+ * The runtime answered a commit timestamp no greater than the previous
70
+ * commit's.
71
+ */
72
+ export declare class CommitTsNotIncreasing extends CommitTsNotIncreasing_base {
73
+ }
74
+ export declare const requiresBinary: (operation: RequiresBinary["operation"]) => RequiresBinary;
75
+ export declare const rowPending: (operation: string, row: number) => KernelRowPending;
76
+ export {};
77
+ //# sourceMappingURL=KernelRefusal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KernelRefusal.d.ts","sourceRoot":"","sources":["../../src/internal/KernelRefusal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;;;;;AAExC;;GAEG;AACH,qBAAa,cAAe,SAAQ,mBAMnC;CAAG;;;;;;AAEJ;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,qBAOrC;CAAG;;;;;AAEJ;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,wBAGxC;CAAG;;;;;AAEJ;;;GAGG;AACH,qBAAa,mCAAoC,SAAQ,wCAGxD;CAAG;;;;;AAEJ;;;GAGG;AACH,qBAAa,aAAc,SAAQ,kBAGlC;CAAG;;;;;AAEJ;;;GAGG;AACH,qBAAa,YAAa,SAAQ,iBAGjC;CAAG;;;;;;;AAEJ;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,0BAQ1C;CAAG;AAEJ,eAAO,MAAM,cAAc,cAAe,cAAc,CAAC,WAAW,CAAC,mBAIjE,CAAC;AAEL,eAAO,MAAM,UAAU,cAAe,MAAM,OAAO,MAAM,qBAKrD,CAAC"}
@@ -0,0 +1,73 @@
1
+ import * as Schema from "effect/Schema";
2
+ //#region src/internal/KernelRefusal.ts
3
+ /**
4
+ * The kernel never answers this operation in process. Only the binary does.
5
+ */
6
+ var RequiresBinary = class extends Schema.TaggedError()("RequiresBinary", {
7
+ operation: Schema.Literals(["textSearch", "vectorSearch"]),
8
+ message: Schema.String
9
+ }) {};
10
+ /**
11
+ * A later kernel row supplies this operation. Until then the kernel refuses it
12
+ * rather than answer with convex-test's behaviour.
13
+ */
14
+ var KernelRowPending = class extends Schema.TaggedError()("KernelRowPending", {
15
+ operation: Schema.String,
16
+ row: Schema.Int,
17
+ message: Schema.String
18
+ }) {};
19
+ /**
20
+ * A component was registered after the test backend opened, so its modules
21
+ * would load after a function had already run.
22
+ */
23
+ var RegisteredAfterOpen = class extends Schema.TaggedError()("RegisteredAfterOpen", {
24
+ componentPath: Schema.String,
25
+ message: Schema.String
26
+ }) {};
27
+ /**
28
+ * Every attempt of a mutation read data a commit changed before it could
29
+ * publish. The kernel gives up on attempt 5.
30
+ */
31
+ var OptimisticConcurrencyControlFailure = class extends Schema.TaggedError()("OptimisticConcurrencyControlFailure", {
32
+ attempts: Schema.Int,
33
+ message: Schema.String
34
+ }) {};
35
+ /**
36
+ * A syscall reached a mutation's attempt after the mutation returned and its
37
+ * syscalls drained, so the attempt was already held or published.
38
+ */
39
+ var ClosedAttempt = class extends Schema.TaggedError()("ClosedAttempt", {
40
+ operation: Schema.String,
41
+ message: Schema.String
42
+ }) {};
43
+ /**
44
+ * `apply` named an attempt the kernel does not hold: it was already applied, or
45
+ * never prepared.
46
+ */
47
+ var StaleAttempt = class extends Schema.TaggedError()("StaleAttempt", {
48
+ id: Schema.String,
49
+ message: Schema.String
50
+ }) {};
51
+ /**
52
+ * The runtime answered a commit timestamp no greater than the previous
53
+ * commit's.
54
+ */
55
+ var CommitTsNotIncreasing = class extends Schema.TaggedError()("CommitTsNotIncreasing", {
56
+ version: Schema.Int,
57
+ previous: Schema.BigInt,
58
+ commitTs: Schema.BigInt,
59
+ message: Schema.String
60
+ }) {};
61
+ const requiresBinary = (operation) => new RequiresBinary({
62
+ operation,
63
+ message: `The test kernel does not simulate ${operation}. Run this case against the Convex binary.`
64
+ });
65
+ const rowPending = (operation, row) => new KernelRowPending({
66
+ operation,
67
+ row,
68
+ message: `The test kernel supplies ${operation} in build-order row ${row}.`
69
+ });
70
+ //#endregion
71
+ export { ClosedAttempt, CommitTsNotIncreasing, KernelRowPending, OptimisticConcurrencyControlFailure, RegisteredAfterOpen, RequiresBinary, StaleAttempt, requiresBinary, rowPending };
72
+
73
+ //# sourceMappingURL=KernelRefusal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KernelRefusal.js","names":[],"sources":["../../src/internal/KernelRefusal.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\n\n/**\n * The kernel never answers this operation in process. Only the binary does.\n */\nexport class RequiresBinary extends Schema.TaggedError<RequiresBinary>()(\n \"RequiresBinary\",\n {\n operation: Schema.Literals([\"textSearch\", \"vectorSearch\"]),\n message: Schema.String,\n },\n) {}\n\n/**\n * A later kernel row supplies this operation. Until then the kernel refuses it\n * rather than answer with convex-test's behaviour.\n */\nexport class KernelRowPending extends Schema.TaggedError<KernelRowPending>()(\n \"KernelRowPending\",\n {\n operation: Schema.String,\n row: Schema.Int,\n message: Schema.String,\n },\n) {}\n\n/**\n * A component was registered after the test backend opened, so its modules\n * would load after a function had already run.\n */\nexport class RegisteredAfterOpen extends Schema.TaggedError<RegisteredAfterOpen>()(\n \"RegisteredAfterOpen\",\n { componentPath: Schema.String, message: Schema.String },\n) {}\n\n/**\n * Every attempt of a mutation read data a commit changed before it could\n * publish. The kernel gives up on attempt 5.\n */\nexport class OptimisticConcurrencyControlFailure extends Schema.TaggedError<OptimisticConcurrencyControlFailure>()(\n \"OptimisticConcurrencyControlFailure\",\n { attempts: Schema.Int, message: Schema.String },\n) {}\n\n/**\n * A syscall reached a mutation's attempt after the mutation returned and its\n * syscalls drained, so the attempt was already held or published.\n */\nexport class ClosedAttempt extends Schema.TaggedError<ClosedAttempt>()(\n \"ClosedAttempt\",\n { operation: Schema.String, message: Schema.String },\n) {}\n\n/**\n * `apply` named an attempt the kernel does not hold: it was already applied, or\n * never prepared.\n */\nexport class StaleAttempt extends Schema.TaggedError<StaleAttempt>()(\n \"StaleAttempt\",\n { id: Schema.String, message: Schema.String },\n) {}\n\n/**\n * The runtime answered a commit timestamp no greater than the previous\n * commit's.\n */\nexport class CommitTsNotIncreasing extends Schema.TaggedError<CommitTsNotIncreasing>()(\n \"CommitTsNotIncreasing\",\n {\n version: Schema.Int,\n previous: Schema.BigInt,\n commitTs: Schema.BigInt,\n message: Schema.String,\n },\n) {}\n\nexport const requiresBinary = (operation: RequiresBinary[\"operation\"]) =>\n new RequiresBinary({\n operation,\n message: `The test kernel does not simulate ${operation}. Run this case against the Convex binary.`,\n });\n\nexport const rowPending = (operation: string, row: number) =>\n new KernelRowPending({\n operation,\n row,\n message: `The test kernel supplies ${operation} in build-order row ${row}.`,\n });\n"],"mappings":";;;;;AAKA,IAAa,iBAAb,cAAoC,OAAO,YAA4B,CAAC,CACtE,kBACA;CACE,WAAW,OAAO,SAAS,CAAC,cAAc,cAAc,CAAC;CACzD,SAAS,OAAO;AAClB,CACF,CAAC,CAAC,CAAC;;;;;AAMH,IAAa,mBAAb,cAAsC,OAAO,YAA8B,CAAC,CAC1E,oBACA;CACE,WAAW,OAAO;CAClB,KAAK,OAAO;CACZ,SAAS,OAAO;AAClB,CACF,CAAC,CAAC,CAAC;;;;;AAMH,IAAa,sBAAb,cAAyC,OAAO,YAAiC,CAAC,CAChF,uBACA;CAAE,eAAe,OAAO;CAAQ,SAAS,OAAO;AAAO,CACzD,CAAC,CAAC,CAAC;;;;;AAMH,IAAa,sCAAb,cAAyD,OAAO,YAAiD,CAAC,CAChH,uCACA;CAAE,UAAU,OAAO;CAAK,SAAS,OAAO;AAAO,CACjD,CAAC,CAAC,CAAC;;;;;AAMH,IAAa,gBAAb,cAAmC,OAAO,YAA2B,CAAC,CACpE,iBACA;CAAE,WAAW,OAAO;CAAQ,SAAS,OAAO;AAAO,CACrD,CAAC,CAAC,CAAC;;;;;AAMH,IAAa,eAAb,cAAkC,OAAO,YAA0B,CAAC,CAClE,gBACA;CAAE,IAAI,OAAO;CAAQ,SAAS,OAAO;AAAO,CAC9C,CAAC,CAAC,CAAC;;;;;AAMH,IAAa,wBAAb,cAA2C,OAAO,YAAmC,CAAC,CACpF,yBACA;CACE,SAAS,OAAO;CAChB,UAAU,OAAO;CACjB,UAAU,OAAO;CACjB,SAAS,OAAO;AAClB,CACF,CAAC,CAAC,CAAC;AAEH,MAAa,kBAAkB,cAC7B,IAAI,eAAe;CACjB;CACA,SAAS,qCAAqC,UAAU;AAC1D,CAAC;AAEH,MAAa,cAAc,WAAmB,QAC5C,IAAI,iBAAiB;CACnB;CACA;CACA,SAAS,4BAA4B,UAAU,sBAAsB,IAAI;AAC3E,CAAC"}