convex-ents 0.10.0 → 0.12.0
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.
- package/README.md +4 -0
- package/dist/deletion.d.ts +1 -1
- package/dist/deletion.js.map +1 -1
- package/dist/functions.d.ts +1 -1
- package/dist/functions.js +28 -493
- package/dist/functions.js.map +1 -1
- package/dist/{index-olos0Rx-.d.ts → index-kwzjMMHy.d.ts} +6 -375
- package/dist/index.d.ts +1 -1
- package/dist/index.js +32 -662
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +34 -0
- package/dist/schema.js +7 -3
- package/dist/schema.js.map +1 -1
- package/dist/shared.d.ts +1 -1
- package/dist/shared.js.map +1 -1
- package/dist/writer.d.ts +2 -2
- package/dist/writer.js +18 -13
- package/dist/writer.js.map +1 -1
- package/package.json +2 -1
- package/dist/actions.d.ts +0 -6
- package/dist/actions.js +0 -662
- package/dist/actions.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Convex Ents
|
|
2
2
|
|
|
3
|
+
> Ents is in maintenance mode. We're open to taking PRs, and will make sure it
|
|
4
|
+
> doesn't break. There will not be active feature development from the Convex
|
|
5
|
+
> team.
|
|
6
|
+
|
|
3
7
|
Convex Ents are an ergonomic layer on top of the Convex built-in ctx.db API for
|
|
4
8
|
reading from and writing to the database. They simplify working with
|
|
5
9
|
relationships between documents, allow specifying unique fields, default values
|
package/dist/deletion.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ type Origin = {
|
|
|
13
13
|
table: string;
|
|
14
14
|
deletionTime: number;
|
|
15
15
|
};
|
|
16
|
-
declare const vApproach: convex_values.VUnion<"
|
|
16
|
+
declare const vApproach: convex_values.VUnion<"cascade" | "paginate", [convex_values.VLiteral<"cascade", "required">, convex_values.VLiteral<"paginate", "required">], "required", never>;
|
|
17
17
|
type Approach = Infer<typeof vApproach>;
|
|
18
18
|
declare function scheduledDeleteFactory<EntsDataModel extends GenericEntsDataModel>(entDefinitions: EntsDataModel, options?: {
|
|
19
19
|
scheduledDelete: ScheduledDeleteFuncRef;
|
package/dist/deletion.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/deletion.ts","../src/shared.ts"],"sourcesContent":["import {\n FunctionReference,\n GenericMutationCtx,\n IndexRangeBuilder,\n RegisteredMutation,\n internalMutationGeneric as internalMutation,\n makeFunctionReference,\n} from \"convex/server\";\nimport { GenericId, Infer, convexToJson, v } from \"convex/values\";\nimport { GenericEntsDataModel } from \"./schema\";\nimport { getEdgeDefinitions } from \"./shared\";\n\nexport type ScheduledDeleteFuncRef = FunctionReference<\n \"mutation\",\n \"internal\",\n {\n origin: Origin;\n stack: Stack;\n inProgress: boolean;\n },\n void\n>;\n\ntype Origin = {\n id: string;\n table: string;\n deletionTime: number;\n};\n\nconst vApproach = v.union(v.literal(\"cascade\"), v.literal(\"paginate\"));\n\ntype Approach = Infer<typeof vApproach>;\n\nexport function scheduledDeleteFactory<\n EntsDataModel extends GenericEntsDataModel,\n>(\n entDefinitions: EntsDataModel,\n options?: {\n scheduledDelete: ScheduledDeleteFuncRef;\n },\n): RegisteredMutation<\n \"internal\",\n { origin: Origin; stack: Stack; inProgress: boolean },\n Promise<void>\n> {\n const selfRef =\n options?.scheduledDelete ??\n (makeFunctionReference(\n \"functions:scheduledDelete\",\n ) as unknown as ScheduledDeleteFuncRef);\n return internalMutation({\n args: {\n origin: v.object({\n id: v.string(),\n table: v.string(),\n deletionTime: v.number(),\n }),\n stack: v.array(\n v.union(\n v.object({\n id: v.string(),\n table: v.string(),\n edges: v.array(\n v.object({\n approach: vApproach,\n table: v.string(),\n indexName: v.string(),\n }),\n ),\n }),\n v.object({\n approach: vApproach,\n cursor: v.union(v.string(), v.null()),\n table: v.string(),\n indexName: v.string(),\n fieldValue: v.any(),\n }),\n ),\n ),\n inProgress: v.boolean(),\n },\n handler: async (ctx, { origin, stack, inProgress }) => {\n const originId = ctx.db.normalizeId(origin.table, origin.id);\n if (originId === null) {\n throw new Error(`Invalid ID \"${origin.id}\" for table ${origin.table}`);\n }\n // Check that we still want to delete\n // Note: Doesn't support scheduled deletion starting with system table\n const doc = await ctx.db.get(originId);\n if (doc.deletionTime !== origin.deletionTime) {\n if (inProgress) {\n console.error(\n `[Ents] Already in-progress scheduled deletion for \"${origin.id}\" was cancelled!`,\n );\n } else {\n console.log(\n `[Ents] Scheduled deletion for \"${origin.id}\" was cancelled`,\n );\n }\n return;\n }\n await progressScheduledDeletion(\n { ctx, entDefinitions, selfRef, origin },\n newCounter(),\n inProgress\n ? stack\n : [\n {\n id: originId,\n table: origin.table,\n edges: getEdgeArgs(entDefinitions, origin.table),\n },\n ],\n );\n },\n });\n}\n\n// Heuristic:\n// Ent at the end of an edge\n// has soft or scheduled deletion behavior && has cascading edges: schedule individually\n// has cascading edges: paginate by 1\n// else: paginate by decent number\nfunction getEdgeArgs(entDefinitions: GenericEntsDataModel, table: string) {\n const edges = getEdgeDefinitions(entDefinitions, table);\n return Object.values(edges).flatMap((edgeDefinition) => {\n if (\n (edgeDefinition.cardinality === \"single\" &&\n edgeDefinition.type === \"ref\") ||\n (edgeDefinition.cardinality === \"multiple\" &&\n edgeDefinition.type === \"field\")\n ) {\n const table = edgeDefinition.to;\n const targetEdges = getEdgeDefinitions(entDefinitions, table);\n const hasCascadingEdges = Object.values(targetEdges).some(\n (edgeDefinition) =>\n (edgeDefinition.cardinality === \"single\" &&\n edgeDefinition.type === \"ref\") ||\n edgeDefinition.cardinality === \"multiple\",\n );\n const approach = hasCascadingEdges ? \"cascade\" : \"paginate\";\n\n const indexName = edgeDefinition.ref;\n return [{ table, indexName, approach } as const];\n } else if (edgeDefinition.cardinality === \"multiple\") {\n const table = edgeDefinition.table;\n return [\n {\n table,\n indexName: edgeDefinition.field,\n approach: \"paginate\",\n } as const,\n ...(edgeDefinition.symmetric\n ? [\n {\n table,\n indexName: edgeDefinition.ref,\n approach: \"paginate\",\n } as const,\n ]\n : []),\n ];\n } else {\n return [];\n }\n });\n}\n\ntype PaginationArgs = {\n approach: Approach;\n table: string;\n cursor: string | null;\n indexName: string;\n fieldValue: any;\n};\n\ntype EdgeArgs = {\n approach: Approach;\n table: string;\n indexName: string;\n};\n\ntype Stack = (\n | { id: string; table: string; edges: EdgeArgs[] }\n | PaginationArgs\n)[];\n\ntype CascadeCtx = {\n ctx: GenericMutationCtx<any>;\n entDefinitions: GenericEntsDataModel;\n selfRef: ScheduledDeleteFuncRef;\n origin: Origin;\n};\n\nasync function progressScheduledDeletion(\n cascade: CascadeCtx,\n counter: Counter,\n stack: Stack,\n) {\n const { ctx } = cascade;\n const last = stack[stack.length - 1];\n\n if (\"id\" in last) {\n const edgeArgs = last.edges[0];\n if (edgeArgs === undefined) {\n await ctx.db.delete(last.id as GenericId<any>);\n if (stack.length > 1) {\n await continueOrSchedule(cascade, counter, stack.slice(0, -1));\n }\n } else {\n const updated = { ...last, edges: last.edges.slice(1) };\n await paginateOrCascade(\n cascade,\n counter,\n stack.slice(0, -1).concat(updated),\n {\n cursor: null,\n fieldValue: last.id,\n ...edgeArgs,\n },\n );\n }\n } else {\n await paginateOrCascade(cascade, counter, stack, last);\n }\n}\n\nconst MAXIMUM_DOCUMENTS_READ = 8192 / 4;\nconst MAXIMUM_BYTES_READ = 2 ** 18;\n\nasync function paginateOrCascade(\n cascade: CascadeCtx,\n counter: Counter,\n stack: Stack,\n { table, approach, indexName, fieldValue, cursor }: PaginationArgs,\n) {\n const { ctx, entDefinitions } = cascade;\n const { page, continueCursor, isDone, bytesRead } = await paginate(\n ctx,\n { table, indexName, fieldValue },\n {\n cursor,\n ...limitsBasedOnCounter(\n counter,\n approach === \"paginate\"\n ? { numItems: MAXIMUM_DOCUMENTS_READ }\n : { numItems: 1 },\n ),\n },\n );\n\n const updatedCounter = incrementCounter(counter, page.length, bytesRead);\n const updated = {\n approach,\n table,\n cursor: continueCursor,\n indexName,\n fieldValue,\n };\n const relevantStack = cursor === null ? stack : stack.slice(0, -1);\n const updatedStack =\n isDone && (approach === \"paginate\" || page.length === 0)\n ? relevantStack\n : relevantStack.concat(\n approach === \"cascade\"\n ? [\n updated,\n {\n id: page[0]._id,\n table,\n edges: getEdgeArgs(entDefinitions, table),\n },\n ]\n : [updated],\n );\n if (approach === \"paginate\") {\n await Promise.all(page.map((doc) => ctx.db.delete(doc._id)));\n }\n await continueOrSchedule(cascade, updatedCounter, updatedStack);\n}\n\nasync function continueOrSchedule(\n cascade: CascadeCtx,\n counter: Counter,\n stack: Stack,\n) {\n if (shouldSchedule(counter)) {\n const { ctx, selfRef, origin } = cascade;\n await ctx.scheduler.runAfter(0, selfRef, {\n origin,\n stack,\n inProgress: true,\n });\n } else {\n await progressScheduledDeletion(cascade, counter, stack);\n }\n}\n\ntype Counter = {\n numDocuments: number;\n numBytesRead: number;\n};\n\nfunction newCounter() {\n return {\n numDocuments: 0,\n numBytesRead: 0,\n };\n}\n\nfunction incrementCounter(\n counter: Counter,\n numDocuments: number,\n numBytesRead: number,\n) {\n return {\n numDocuments: counter.numDocuments + numDocuments,\n numBytesRead: counter.numBytesRead + numBytesRead,\n };\n}\n\nfunction limitsBasedOnCounter(\n counter: Counter,\n { numItems }: { numItems: number },\n) {\n return {\n numItems: Math.max(1, numItems - counter.numDocuments),\n maximumBytesRead: Math.max(1, MAXIMUM_BYTES_READ - counter.numBytesRead),\n };\n}\n\nfunction shouldSchedule(counter: Counter) {\n return (\n counter.numDocuments >= MAXIMUM_DOCUMENTS_READ ||\n counter.numBytesRead >= MAXIMUM_BYTES_READ\n );\n}\n\nasync function paginate(\n ctx: GenericMutationCtx<any>,\n {\n table,\n indexName,\n fieldValue,\n }: { table: string; indexName: string; fieldValue: any },\n {\n cursor,\n numItems,\n maximumBytesRead,\n }: {\n cursor: string | null;\n numItems: number;\n maximumBytesRead: number;\n },\n) {\n const query = ctx.db\n .query(table)\n .withIndex(indexName, (q) =>\n (q.eq(indexName, fieldValue) as IndexRangeBuilder<any, any, any>).gt(\n \"_creationTime\",\n cursor === null ? cursor : +cursor,\n ),\n );\n\n let bytesRead = 0;\n const results = [];\n let isDone = true;\n\n for await (const doc of query) {\n if (results.length >= numItems) {\n isDone = false;\n break;\n }\n const size = JSON.stringify(convexToJson(doc)).length * 8;\n\n results.push(doc);\n bytesRead += size;\n\n // Check this after we read the doc, since reading it already\n // happened anyway, and to make sure we return at least one\n // result.\n if (bytesRead > maximumBytesRead) {\n isDone = false;\n break;\n }\n }\n return {\n page: results,\n continueCursor:\n results.length === 0\n ? cursor\n : \"\" + results[results.length - 1]._creationTime,\n isDone,\n bytesRead,\n };\n}\n","import {\n DocumentByName,\n FieldTypeFromFieldPath,\n SystemDataModel,\n TableNamesInDataModel,\n} from \"convex/server\";\nimport { EdgeConfig, GenericEdgeConfig, GenericEntsDataModel } from \"./schema\";\n\nexport type EntsSystemDataModel = {\n [key in keyof SystemDataModel]: SystemDataModel[key] & {\n edges: Record<string, never>;\n };\n};\n\nexport type PromiseEdgeResult<\n EdgeConfig extends GenericEdgeConfig,\n MultipleRef,\n MultipleField,\n SingleRef,\n SingleField,\n> = EdgeConfig[\"cardinality\"] extends \"multiple\"\n ? EdgeConfig[\"type\"] extends \"ref\"\n ? MultipleRef\n : MultipleField\n : EdgeConfig[\"type\"] extends \"ref\"\n ? SingleRef\n : SingleField;\n\nexport type IndexFieldTypesForEq<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>,\n T extends string[],\n> = Pop<{\n [K in keyof T]: FieldTypeFromFieldPath<\n DocumentByName<EntsDataModel, Table>,\n T[K]\n >;\n}>;\n\ntype Pop<T extends any[]> = T extends [...infer Rest, infer _Last]\n ? Rest\n : never;\n\nexport function getEdgeDefinitions<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>,\n>(entDefinitions: EntsDataModel, table: Table) {\n return entDefinitions[table].edges as Record<\n keyof EntsDataModel[Table][\"edges\"],\n EdgeConfig\n >;\n}\n"],"mappings":"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","names":["internalMutation","table","edgeDefinition"]}
|
|
1
|
+
{"version":3,"sources":["../src/deletion.ts","../src/shared.ts"],"sourcesContent":["import {\n FunctionReference,\n GenericMutationCtx,\n IndexRangeBuilder,\n RegisteredMutation,\n internalMutationGeneric as internalMutation,\n makeFunctionReference,\n} from \"convex/server\";\nimport { GenericId, Infer, convexToJson, v } from \"convex/values\";\nimport { GenericEntsDataModel } from \"./schema\";\nimport { getEdgeDefinitions } from \"./shared\";\n\nexport type ScheduledDeleteFuncRef = FunctionReference<\n \"mutation\",\n \"internal\",\n {\n origin: Origin;\n stack: Stack;\n inProgress: boolean;\n },\n void\n>;\n\ntype Origin = {\n id: string;\n table: string;\n deletionTime: number;\n};\n\nconst vApproach = v.union(v.literal(\"cascade\"), v.literal(\"paginate\"));\n\ntype Approach = Infer<typeof vApproach>;\n\nexport function scheduledDeleteFactory<\n EntsDataModel extends GenericEntsDataModel,\n>(\n entDefinitions: EntsDataModel,\n options?: {\n scheduledDelete: ScheduledDeleteFuncRef;\n },\n): RegisteredMutation<\n \"internal\",\n { origin: Origin; stack: Stack; inProgress: boolean },\n Promise<void>\n> {\n const selfRef =\n options?.scheduledDelete ??\n (makeFunctionReference(\n \"functions:scheduledDelete\",\n ) as unknown as ScheduledDeleteFuncRef);\n return internalMutation({\n args: {\n origin: v.object({\n id: v.string(),\n table: v.string(),\n deletionTime: v.number(),\n }),\n stack: v.array(\n v.union(\n v.object({\n id: v.string(),\n table: v.string(),\n edges: v.array(\n v.object({\n approach: vApproach,\n table: v.string(),\n indexName: v.string(),\n }),\n ),\n }),\n v.object({\n approach: vApproach,\n cursor: v.union(v.string(), v.null()),\n table: v.string(),\n indexName: v.string(),\n fieldValue: v.any(),\n }),\n ),\n ),\n inProgress: v.boolean(),\n },\n handler: async (ctx, { origin, stack, inProgress }) => {\n const originId = ctx.db.normalizeId(origin.table, origin.id);\n if (originId === null) {\n throw new Error(`Invalid ID \"${origin.id}\" for table ${origin.table}`);\n }\n // Check that we still want to delete\n // Note: Doesn't support scheduled deletion starting with system table\n const doc = await ctx.db.get(originId);\n if (doc.deletionTime !== origin.deletionTime) {\n if (inProgress) {\n console.error(\n `[Ents] Already in-progress scheduled deletion for \"${origin.id}\" was cancelled!`,\n );\n } else {\n console.log(\n `[Ents] Scheduled deletion for \"${origin.id}\" was cancelled`,\n );\n }\n return;\n }\n await progressScheduledDeletion(\n { ctx, entDefinitions, selfRef, origin },\n newCounter(),\n inProgress\n ? stack\n : [\n {\n id: originId,\n table: origin.table,\n edges: getEdgeArgs(entDefinitions, origin.table),\n },\n ],\n );\n },\n });\n}\n\n// Heuristic:\n// Ent at the end of an edge\n// has soft or scheduled deletion behavior && has cascading edges: schedule individually\n// has cascading edges: paginate by 1\n// else: paginate by decent number\nfunction getEdgeArgs(entDefinitions: GenericEntsDataModel, table: string) {\n const edges = getEdgeDefinitions(entDefinitions, table);\n return Object.values(edges).flatMap((edgeDefinition) => {\n if (\n (edgeDefinition.cardinality === \"single\" &&\n edgeDefinition.type === \"ref\") ||\n (edgeDefinition.cardinality === \"multiple\" &&\n edgeDefinition.type === \"field\")\n ) {\n const table = edgeDefinition.to;\n const targetEdges = getEdgeDefinitions(entDefinitions, table);\n const hasCascadingEdges = Object.values(targetEdges).some(\n (edgeDefinition) =>\n (edgeDefinition.cardinality === \"single\" &&\n edgeDefinition.type === \"ref\") ||\n edgeDefinition.cardinality === \"multiple\",\n );\n const approach = hasCascadingEdges ? \"cascade\" : \"paginate\";\n\n const indexName = edgeDefinition.ref;\n return [{ table, indexName, approach } as const];\n } else if (edgeDefinition.cardinality === \"multiple\") {\n const table = edgeDefinition.table;\n return [\n {\n table,\n indexName: edgeDefinition.field,\n approach: \"paginate\",\n } as const,\n ...(edgeDefinition.symmetric\n ? [\n {\n table,\n indexName: edgeDefinition.ref,\n approach: \"paginate\",\n } as const,\n ]\n : []),\n ];\n } else {\n return [];\n }\n });\n}\n\ntype PaginationArgs = {\n approach: Approach;\n table: string;\n cursor: string | null;\n indexName: string;\n fieldValue: any;\n};\n\ntype EdgeArgs = {\n approach: Approach;\n table: string;\n indexName: string;\n};\n\ntype Stack = (\n | { id: string; table: string; edges: EdgeArgs[] }\n | PaginationArgs\n)[];\n\ntype CascadeCtx = {\n ctx: GenericMutationCtx<any>;\n entDefinitions: GenericEntsDataModel;\n selfRef: ScheduledDeleteFuncRef;\n origin: Origin;\n};\n\nasync function progressScheduledDeletion(\n cascade: CascadeCtx,\n counter: Counter,\n stack: Stack,\n) {\n const { ctx } = cascade;\n const last = stack[stack.length - 1];\n\n if (\"id\" in last) {\n const edgeArgs = last.edges[0];\n if (edgeArgs === undefined) {\n await ctx.db.delete(last.id as GenericId<any>);\n if (stack.length > 1) {\n await continueOrSchedule(cascade, counter, stack.slice(0, -1));\n }\n } else {\n const updated = { ...last, edges: last.edges.slice(1) };\n await paginateOrCascade(\n cascade,\n counter,\n stack.slice(0, -1).concat(updated),\n {\n cursor: null,\n fieldValue: last.id,\n ...edgeArgs,\n },\n );\n }\n } else {\n await paginateOrCascade(cascade, counter, stack, last);\n }\n}\n\nconst MAXIMUM_DOCUMENTS_READ = 8192 / 4;\nconst MAXIMUM_BYTES_READ = 2 ** 18;\n\nasync function paginateOrCascade(\n cascade: CascadeCtx,\n counter: Counter,\n stack: Stack,\n { table, approach, indexName, fieldValue, cursor }: PaginationArgs,\n) {\n const { ctx, entDefinitions } = cascade;\n const { page, continueCursor, isDone, bytesRead } = await paginate(\n ctx,\n { table, indexName, fieldValue },\n {\n cursor,\n ...limitsBasedOnCounter(\n counter,\n approach === \"paginate\"\n ? { numItems: MAXIMUM_DOCUMENTS_READ }\n : { numItems: 1 },\n ),\n },\n );\n\n const updatedCounter = incrementCounter(counter, page.length, bytesRead);\n const updated = {\n approach,\n table,\n cursor: continueCursor,\n indexName,\n fieldValue,\n };\n const relevantStack = cursor === null ? stack : stack.slice(0, -1);\n const updatedStack =\n isDone && (approach === \"paginate\" || page.length === 0)\n ? relevantStack\n : relevantStack.concat(\n approach === \"cascade\"\n ? [\n updated,\n {\n id: page[0]._id,\n table,\n edges: getEdgeArgs(entDefinitions, table),\n },\n ]\n : [updated],\n );\n if (approach === \"paginate\") {\n await Promise.all(page.map((doc) => ctx.db.delete(doc._id)));\n }\n await continueOrSchedule(cascade, updatedCounter, updatedStack);\n}\n\nasync function continueOrSchedule(\n cascade: CascadeCtx,\n counter: Counter,\n stack: Stack,\n) {\n if (shouldSchedule(counter)) {\n const { ctx, selfRef, origin } = cascade;\n await ctx.scheduler.runAfter(0, selfRef, {\n origin,\n stack,\n inProgress: true,\n });\n } else {\n await progressScheduledDeletion(cascade, counter, stack);\n }\n}\n\ntype Counter = {\n numDocuments: number;\n numBytesRead: number;\n};\n\nfunction newCounter() {\n return {\n numDocuments: 0,\n numBytesRead: 0,\n };\n}\n\nfunction incrementCounter(\n counter: Counter,\n numDocuments: number,\n numBytesRead: number,\n) {\n return {\n numDocuments: counter.numDocuments + numDocuments,\n numBytesRead: counter.numBytesRead + numBytesRead,\n };\n}\n\nfunction limitsBasedOnCounter(\n counter: Counter,\n { numItems }: { numItems: number },\n) {\n return {\n numItems: Math.max(1, numItems - counter.numDocuments),\n maximumBytesRead: Math.max(1, MAXIMUM_BYTES_READ - counter.numBytesRead),\n };\n}\n\nfunction shouldSchedule(counter: Counter) {\n return (\n counter.numDocuments >= MAXIMUM_DOCUMENTS_READ ||\n counter.numBytesRead >= MAXIMUM_BYTES_READ\n );\n}\n\nasync function paginate(\n ctx: GenericMutationCtx<any>,\n {\n table,\n indexName,\n fieldValue,\n }: { table: string; indexName: string; fieldValue: any },\n {\n cursor,\n numItems,\n maximumBytesRead,\n }: {\n cursor: string | null;\n numItems: number;\n maximumBytesRead: number;\n },\n) {\n const query = ctx.db\n .query(table)\n .withIndex(indexName, (q) =>\n (q.eq(indexName, fieldValue) as IndexRangeBuilder<any, any, any>).gt(\n \"_creationTime\",\n cursor === null ? cursor : +cursor,\n ),\n );\n\n let bytesRead = 0;\n const results = [];\n let isDone = true;\n\n for await (const doc of query) {\n if (results.length >= numItems) {\n isDone = false;\n break;\n }\n const size = JSON.stringify(convexToJson(doc)).length * 8;\n\n results.push(doc);\n bytesRead += size;\n\n // Check this after we read the doc, since reading it already\n // happened anyway, and to make sure we return at least one\n // result.\n if (bytesRead > maximumBytesRead) {\n isDone = false;\n break;\n }\n }\n return {\n page: results,\n continueCursor:\n results.length === 0\n ? cursor\n : \"\" + results[results.length - 1]._creationTime,\n isDone,\n bytesRead,\n };\n}\n","import {\n DocumentByName,\n FieldTypeFromFieldPath,\n SystemDataModel,\n TableNamesInDataModel,\n} from \"convex/server\";\nimport { EdgeConfig, GenericEdgeConfig, GenericEntsDataModel } from \"./schema\";\n\nexport type EntsSystemDataModel = {\n [key in keyof SystemDataModel]: SystemDataModel[key] & {\n edges: Record<string, never>;\n };\n};\n\nexport type PromiseEdgeResult<\n EdgeConfig extends GenericEdgeConfig,\n MultipleRef,\n MultipleField,\n SingleOptional,\n Single,\n> = EdgeConfig[\"cardinality\"] extends \"multiple\"\n ? EdgeConfig[\"type\"] extends \"ref\"\n ? MultipleRef\n : MultipleField\n : EdgeConfig[\"type\"] extends \"ref\"\n ? SingleOptional\n : EdgeConfig[\"optional\"] extends true\n ? SingleOptional\n : Single;\n\nexport type IndexFieldTypesForEq<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>,\n T extends string[],\n> = Pop<{\n [K in keyof T]: FieldTypeFromFieldPath<\n DocumentByName<EntsDataModel, Table>,\n T[K]\n >;\n}>;\n\ntype Pop<T extends any[]> = T extends [...infer Rest, infer _Last]\n ? Rest\n : never;\n\nexport function getEdgeDefinitions<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>,\n>(entDefinitions: EntsDataModel, table: Table) {\n return entDefinitions[table].edges as Record<\n keyof EntsDataModel[Table][\"edges\"],\n EdgeConfig\n >;\n}\n"],"mappings":"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","names":["internalMutation","table","edgeDefinition"]}
|
package/dist/functions.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'convex/values';
|
|
2
2
|
import 'convex/server';
|
|
3
|
-
export { a1 as DocRetriever, I as Ent, a0 as EntMutationCtx, $ as EntQueryCtx, G as EntsTable, H as EntsTableWriter, J as GenericEnt, Z as GenericEntWriter, C as PromiseArray, B as PromiseArrayOrNull, K as PromiseEdge, w as PromiseEdgeEnts, s as PromiseEdgeEntsOrNull, y as PromiseEdgeEntsWriter, u as PromiseEdgeEntsWriterOrNull, L as PromiseEdgeOrThrow, v as PromiseEdgeOrderedEnts, r as PromiseEdgeOrderedEntsOrNull, x as PromiseEdgeOrderedEntsWriter, t as PromiseEdgeOrderedEntsWriterOrNull, M as PromiseEdgeWriter, O as PromiseEdgeWriterOrNull, N as PromiseEdgeWriterOrThrow, A as PromiseEnt, _ as PromiseEntId, z as PromiseEntOrNull, Y as PromiseEntWriter, X as PromiseEntWriterOrNull, p as PromiseEnts, n as PromiseEntsOrNull, q as PromiseEntsOrNulls, S as PromiseEntsWriter, o as PromiseEntsWriterOrNull, j as PromiseOrderedQuery, i as PromiseOrderedQueryBase, P as PromiseOrderedQueryOrNull, Q as PromiseOrderedQueryWriter, d as PromiseOrderedQueryWriterOrNull, m as PromisePaginationResult, l as PromisePaginationResultOrNull, U as PromisePaginationResultWriter, T as PromisePaginationResultWriterOrNull, k as PromiseQuery, e as PromiseQueryOrNull, R as PromiseQueryWriter, f as PromiseQueryWriterOrNull, h as PromiseTable, g as PromiseTableBase, V as PromiseTableWriter, a2 as addEntRules, D as entWrapper, F as entsTableFactory, a5 as getDeletionConfig, a3 as getReadRule, a4 as getWriteRule } from './index-olos0Rx-.js';
|
|
4
3
|
import './deletion.js';
|
|
5
4
|
import './schema.js';
|
|
6
5
|
import './shared.js';
|
|
6
|
+
export { a1 as DocRetriever, I as Ent, a0 as EntMutationCtx, $ as EntQueryCtx, G as EntsTable, H as EntsTableWriter, J as GenericEnt, Z as GenericEntWriter, C as PromiseArray, B as PromiseArrayOrNull, K as PromiseEdge, w as PromiseEdgeEnts, s as PromiseEdgeEntsOrNull, y as PromiseEdgeEntsWriter, u as PromiseEdgeEntsWriterOrNull, L as PromiseEdgeOrThrow, v as PromiseEdgeOrderedEnts, r as PromiseEdgeOrderedEntsOrNull, x as PromiseEdgeOrderedEntsWriter, t as PromiseEdgeOrderedEntsWriterOrNull, M as PromiseEdgeWriter, O as PromiseEdgeWriterOrNull, N as PromiseEdgeWriterOrThrow, A as PromiseEnt, _ as PromiseEntId, z as PromiseEntOrNull, Y as PromiseEntWriter, X as PromiseEntWriterOrNull, p as PromiseEnts, n as PromiseEntsOrNull, q as PromiseEntsOrNulls, S as PromiseEntsWriter, o as PromiseEntsWriterOrNull, j as PromiseOrderedQuery, i as PromiseOrderedQueryBase, P as PromiseOrderedQueryOrNull, Q as PromiseOrderedQueryWriter, d as PromiseOrderedQueryWriterOrNull, m as PromisePaginationResult, l as PromisePaginationResultOrNull, U as PromisePaginationResultWriter, T as PromisePaginationResultWriterOrNull, k as PromiseQuery, e as PromiseQueryOrNull, R as PromiseQueryWriter, f as PromiseQueryWriterOrNull, h as PromiseTable, g as PromiseTableBase, V as PromiseTableWriter, a2 as addEntRules, D as entWrapper, F as entsTableFactory, a5 as getDeletionConfig, a3 as getReadRule, a4 as getWriteRule } from './index-kwzjMMHy.js';
|
package/dist/functions.js
CHANGED
|
@@ -29,471 +29,8 @@ __export(functions_exports, {
|
|
|
29
29
|
});
|
|
30
30
|
module.exports = __toCommonJS(functions_exports);
|
|
31
31
|
|
|
32
|
-
// src/actions.ts
|
|
33
|
-
var import_server = require("convex/server");
|
|
34
|
-
|
|
35
|
-
// src/shared.ts
|
|
36
|
-
function getEdgeDefinitions(entDefinitions, table) {
|
|
37
|
-
return entDefinitions[table].edges;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// src/actions.ts
|
|
41
|
-
var PromiseQueryActionOrNullImpl = class _PromiseQueryActionOrNullImpl extends Promise {
|
|
42
|
-
constructor(ctx, entDefinitions, table, read) {
|
|
43
|
-
super(() => {
|
|
44
|
-
});
|
|
45
|
-
this.ctx = ctx;
|
|
46
|
-
this.entDefinitions = entDefinitions;
|
|
47
|
-
this.table = table;
|
|
48
|
-
this.read = read;
|
|
49
|
-
}
|
|
50
|
-
filter(predicate) {
|
|
51
|
-
return new _PromiseQueryActionOrNullImpl(
|
|
52
|
-
this.ctx,
|
|
53
|
-
this.entDefinitions,
|
|
54
|
-
this.table,
|
|
55
|
-
this.read.concat({ filter: serializeFilterPredicate(predicate) })
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
order(order, indexName) {
|
|
59
|
-
return new _PromiseQueryActionOrNullImpl(
|
|
60
|
-
this.ctx,
|
|
61
|
-
this.entDefinitions,
|
|
62
|
-
this.table,
|
|
63
|
-
this.read.concat({
|
|
64
|
-
order: [
|
|
65
|
-
order,
|
|
66
|
-
...indexName === void 0 ? [] : [indexName]
|
|
67
|
-
]
|
|
68
|
-
})
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
paginate(paginationOpts) {
|
|
72
|
-
return new PromisePaginationResultActionOrNullImpl(
|
|
73
|
-
this.ctx,
|
|
74
|
-
this.entDefinitions,
|
|
75
|
-
this.table,
|
|
76
|
-
this.read.concat({ paginate: paginationOpts })
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
async take(n) {
|
|
80
|
-
return await runRead(this.ctx, this.read.concat({ take: n }));
|
|
81
|
-
}
|
|
82
|
-
first() {
|
|
83
|
-
return new PromiseEntActionImpl(
|
|
84
|
-
this.ctx,
|
|
85
|
-
this.entDefinitions,
|
|
86
|
-
this.table,
|
|
87
|
-
this.read.concat({ first: true })
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
firstX() {
|
|
91
|
-
return new PromiseEntActionImpl(
|
|
92
|
-
this.ctx,
|
|
93
|
-
this.entDefinitions,
|
|
94
|
-
this.table,
|
|
95
|
-
this.read.concat({ firstX: true })
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
unique() {
|
|
99
|
-
return new PromiseEntActionImpl(
|
|
100
|
-
this.ctx,
|
|
101
|
-
this.entDefinitions,
|
|
102
|
-
this.table,
|
|
103
|
-
this.read.concat({ unique: true })
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
uniqueX() {
|
|
107
|
-
return new PromiseEntActionImpl(
|
|
108
|
-
this.ctx,
|
|
109
|
-
this.entDefinitions,
|
|
110
|
-
this.table,
|
|
111
|
-
this.read.concat({ uniqueX: true })
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
then(onfulfilled, onrejected) {
|
|
115
|
-
const docs = runRead(this.ctx, this.read);
|
|
116
|
-
return docs.then(onfulfilled, onrejected);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
var PromiseEdgeActionOrNullImpl = class extends PromiseQueryActionOrNullImpl {
|
|
120
|
-
async has(targetId) {
|
|
121
|
-
return runRead(this.ctx, this.read.concat({ has: targetId }));
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
var PromiseTableActionImpl = class extends PromiseQueryActionOrNullImpl {
|
|
125
|
-
constructor(ctx, entDefinitions, table) {
|
|
126
|
-
super(ctx, entDefinitions, table, [{ table: [table] }]);
|
|
127
|
-
}
|
|
128
|
-
get(...args) {
|
|
129
|
-
return new PromiseEntActionImpl(
|
|
130
|
-
this.ctx,
|
|
131
|
-
this.entDefinitions,
|
|
132
|
-
this.table,
|
|
133
|
-
this.read.concat({ get: args })
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
getX(...args) {
|
|
137
|
-
return new PromiseEntActionImpl(
|
|
138
|
-
this.ctx,
|
|
139
|
-
this.entDefinitions,
|
|
140
|
-
this.table,
|
|
141
|
-
this.read.concat({ getX: args })
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
async getMany(...args) {
|
|
145
|
-
return await runRead(this.ctx, this.read.concat({ getMany: args }));
|
|
146
|
-
}
|
|
147
|
-
async getManyX(...args) {
|
|
148
|
-
return await runRead(this.ctx, this.read.concat({ getManyX: args }));
|
|
149
|
-
}
|
|
150
|
-
async normalizeId(id) {
|
|
151
|
-
return await runRead(this.ctx, this.read.concat({ normalizeId: id }));
|
|
152
|
-
}
|
|
153
|
-
async normalizeIdX(id) {
|
|
154
|
-
return await runRead(this.ctx, this.read.concat({ normalizeIdX: id }));
|
|
155
|
-
}
|
|
156
|
-
withIndex(indexName, indexRange) {
|
|
157
|
-
return new PromiseQueryActionOrNullImpl(
|
|
158
|
-
this.ctx,
|
|
159
|
-
this.entDefinitions,
|
|
160
|
-
this.table,
|
|
161
|
-
[
|
|
162
|
-
{
|
|
163
|
-
table: [
|
|
164
|
-
this.table,
|
|
165
|
-
indexName,
|
|
166
|
-
serializeIndexRange(indexRange)
|
|
167
|
-
]
|
|
168
|
-
}
|
|
169
|
-
]
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
search(indexName, searchFilter) {
|
|
173
|
-
return new PromiseQueryActionOrNullImpl(
|
|
174
|
-
this.ctx,
|
|
175
|
-
this.entDefinitions,
|
|
176
|
-
this.table,
|
|
177
|
-
this.read.concat({
|
|
178
|
-
search: [indexName, serializeSearchFilter(searchFilter)]
|
|
179
|
-
})
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
insert(value) {
|
|
183
|
-
return new PromiseEntIdActionImpl(
|
|
184
|
-
this.ctx,
|
|
185
|
-
this.entDefinitions,
|
|
186
|
-
this.table,
|
|
187
|
-
this.read.concat({ insert: value })
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
// TODO: fluent API
|
|
191
|
-
async insertMany(values) {
|
|
192
|
-
return await runWrite(
|
|
193
|
-
this.ctx,
|
|
194
|
-
this.read.concat({ insertMany: values })
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
var PromisePaginationResultActionOrNullImpl = class extends Promise {
|
|
199
|
-
constructor(ctx, entDefinitions, table, read) {
|
|
200
|
-
super(() => {
|
|
201
|
-
});
|
|
202
|
-
this.ctx = ctx;
|
|
203
|
-
this.entDefinitions = entDefinitions;
|
|
204
|
-
this.table = table;
|
|
205
|
-
this.read = read;
|
|
206
|
-
}
|
|
207
|
-
then(onfulfilled, onrejected) {
|
|
208
|
-
return runRead(this.ctx, this.read).then(onfulfilled, onrejected);
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
var PromiseEntActionImpl = class _PromiseEntActionImpl extends Promise {
|
|
212
|
-
constructor(ctx, entDefinitions, table, read) {
|
|
213
|
-
super(() => {
|
|
214
|
-
});
|
|
215
|
-
this.ctx = ctx;
|
|
216
|
-
this.entDefinitions = entDefinitions;
|
|
217
|
-
this.table = table;
|
|
218
|
-
this.read = read;
|
|
219
|
-
}
|
|
220
|
-
then(onfulfilled, onrejected) {
|
|
221
|
-
return runRead(this.ctx, this.read).then(onfulfilled, onrejected);
|
|
222
|
-
}
|
|
223
|
-
edge(edge) {
|
|
224
|
-
return this.edgeImpl(edge);
|
|
225
|
-
}
|
|
226
|
-
edgeX(edge) {
|
|
227
|
-
return this.edgeImpl(edge, true);
|
|
228
|
-
}
|
|
229
|
-
edgeImpl(edge, throwIfNull = false) {
|
|
230
|
-
const edgeDefinition = getEdgeDefinitions(this.entDefinitions, this.table)[edge];
|
|
231
|
-
const read = throwIfNull ? { edgeX: edge } : { edge };
|
|
232
|
-
if (edgeDefinition.cardinality === "multiple") {
|
|
233
|
-
if (edgeDefinition.type === "ref") {
|
|
234
|
-
return new PromiseEdgeActionOrNullImpl(
|
|
235
|
-
this.ctx,
|
|
236
|
-
this.entDefinitions,
|
|
237
|
-
edgeDefinition.to,
|
|
238
|
-
this.read.concat(read)
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
return new PromiseQueryActionOrNullImpl(
|
|
242
|
-
this.ctx,
|
|
243
|
-
this.entDefinitions,
|
|
244
|
-
edgeDefinition.to,
|
|
245
|
-
this.read.concat(read)
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
return new _PromiseEntActionImpl(
|
|
249
|
-
this.ctx,
|
|
250
|
-
this.entDefinitions,
|
|
251
|
-
edgeDefinition.to,
|
|
252
|
-
this.read.concat(read)
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
patch(value) {
|
|
256
|
-
return new PromiseEntIdActionImpl(
|
|
257
|
-
this.ctx,
|
|
258
|
-
this.entDefinitions,
|
|
259
|
-
this.table,
|
|
260
|
-
this.read.concat({ patch: value })
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
replace(value) {
|
|
264
|
-
return new PromiseEntIdActionImpl(
|
|
265
|
-
this.ctx,
|
|
266
|
-
this.entDefinitions,
|
|
267
|
-
this.table,
|
|
268
|
-
this.read.concat({ replace: value })
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
async delete() {
|
|
272
|
-
return await runWrite(
|
|
273
|
-
this.ctx,
|
|
274
|
-
this.read.concat({ delete: true })
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
var PromiseEntIdActionImpl = class extends Promise {
|
|
279
|
-
constructor(ctx, entDefinitions, table, write) {
|
|
280
|
-
super(() => {
|
|
281
|
-
});
|
|
282
|
-
this.ctx = ctx;
|
|
283
|
-
this.entDefinitions = entDefinitions;
|
|
284
|
-
this.table = table;
|
|
285
|
-
this.write = write;
|
|
286
|
-
}
|
|
287
|
-
async get() {
|
|
288
|
-
return await runWrite(this.ctx, this.write.concat({ get: [] }));
|
|
289
|
-
}
|
|
290
|
-
then(onfulfilled, onrejected) {
|
|
291
|
-
return runWrite(this.ctx, this.write).then(onfulfilled, onrejected);
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
async function runRead(ctx, read) {
|
|
295
|
-
const readRef = ctx?.actionRead ?? (0, import_server.makeFunctionReference)("functions:read");
|
|
296
|
-
return await ctx.runQuery(readRef, { read });
|
|
297
|
-
}
|
|
298
|
-
async function runWrite(ctx, write) {
|
|
299
|
-
const writeRef = ctx?.actionRead ?? (0, import_server.makeFunctionReference)("functions:write");
|
|
300
|
-
return await ctx.runMutation(writeRef, { write });
|
|
301
|
-
}
|
|
302
|
-
var IndexRangeBuilderImpl = class _IndexRangeBuilderImpl {
|
|
303
|
-
constructor(rangeExpressions) {
|
|
304
|
-
this.rangeExpressions = rangeExpressions;
|
|
305
|
-
}
|
|
306
|
-
static new() {
|
|
307
|
-
return new _IndexRangeBuilderImpl([]);
|
|
308
|
-
}
|
|
309
|
-
eq(fieldName, value) {
|
|
310
|
-
return new _IndexRangeBuilderImpl(
|
|
311
|
-
this.rangeExpressions.concat({
|
|
312
|
-
type: "Eq",
|
|
313
|
-
fieldPath: fieldName,
|
|
314
|
-
value: value === void 0 ? "$undefined" : value
|
|
315
|
-
})
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
gt(fieldName, value) {
|
|
319
|
-
return new _IndexRangeBuilderImpl(
|
|
320
|
-
this.rangeExpressions.concat({
|
|
321
|
-
type: "Gt",
|
|
322
|
-
fieldPath: fieldName,
|
|
323
|
-
value
|
|
324
|
-
})
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
gte(fieldName, value) {
|
|
328
|
-
return new _IndexRangeBuilderImpl(
|
|
329
|
-
this.rangeExpressions.concat({
|
|
330
|
-
type: "Gte",
|
|
331
|
-
fieldPath: fieldName,
|
|
332
|
-
value
|
|
333
|
-
})
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
lt(fieldName, value) {
|
|
337
|
-
return new _IndexRangeBuilderImpl(
|
|
338
|
-
this.rangeExpressions.concat({
|
|
339
|
-
type: "Lt",
|
|
340
|
-
fieldPath: fieldName,
|
|
341
|
-
value
|
|
342
|
-
})
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
lte(fieldName, value) {
|
|
346
|
-
return new _IndexRangeBuilderImpl(
|
|
347
|
-
this.rangeExpressions.concat({
|
|
348
|
-
type: "Lte",
|
|
349
|
-
fieldPath: fieldName,
|
|
350
|
-
value
|
|
351
|
-
})
|
|
352
|
-
);
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
function serializeIndexRange(indexRange) {
|
|
356
|
-
if (indexRange === void 0) {
|
|
357
|
-
return void 0;
|
|
358
|
-
}
|
|
359
|
-
return (indexRange?.(
|
|
360
|
-
IndexRangeBuilderImpl.new()
|
|
361
|
-
)).rangeExpressions;
|
|
362
|
-
}
|
|
363
|
-
function serializeFilterPredicate(predicate) {
|
|
364
|
-
return serializeExpression(predicate(filterBuilderImpl));
|
|
365
|
-
}
|
|
366
|
-
var filterBuilderImpl = {
|
|
367
|
-
// Comparisons /////////////////////////////////////////////////////////////
|
|
368
|
-
eq(l, r) {
|
|
369
|
-
return new FilterExpression({
|
|
370
|
-
eq: [serializeExpression(l), serializeExpression(r)]
|
|
371
|
-
});
|
|
372
|
-
},
|
|
373
|
-
neq(l, r) {
|
|
374
|
-
return new FilterExpression({
|
|
375
|
-
neq: [serializeExpression(l), serializeExpression(r)]
|
|
376
|
-
});
|
|
377
|
-
},
|
|
378
|
-
lt(l, r) {
|
|
379
|
-
return new FilterExpression({
|
|
380
|
-
lt: [serializeExpression(l), serializeExpression(r)]
|
|
381
|
-
});
|
|
382
|
-
},
|
|
383
|
-
lte(l, r) {
|
|
384
|
-
return new FilterExpression({
|
|
385
|
-
lte: [serializeExpression(l), serializeExpression(r)]
|
|
386
|
-
});
|
|
387
|
-
},
|
|
388
|
-
gt(l, r) {
|
|
389
|
-
return new FilterExpression({
|
|
390
|
-
gt: [serializeExpression(l), serializeExpression(r)]
|
|
391
|
-
});
|
|
392
|
-
},
|
|
393
|
-
gte(l, r) {
|
|
394
|
-
return new FilterExpression({
|
|
395
|
-
gte: [serializeExpression(l), serializeExpression(r)]
|
|
396
|
-
});
|
|
397
|
-
},
|
|
398
|
-
// Arithmetic //////////////////////////////////////////////////////////////
|
|
399
|
-
add(l, r) {
|
|
400
|
-
return new FilterExpression({
|
|
401
|
-
add: [serializeExpression(l), serializeExpression(r)]
|
|
402
|
-
});
|
|
403
|
-
},
|
|
404
|
-
sub(l, r) {
|
|
405
|
-
return new FilterExpression({
|
|
406
|
-
sub: [serializeExpression(l), serializeExpression(r)]
|
|
407
|
-
});
|
|
408
|
-
},
|
|
409
|
-
mul(l, r) {
|
|
410
|
-
return new FilterExpression({
|
|
411
|
-
mul: [serializeExpression(l), serializeExpression(r)]
|
|
412
|
-
});
|
|
413
|
-
},
|
|
414
|
-
div(l, r) {
|
|
415
|
-
return new FilterExpression({
|
|
416
|
-
div: [serializeExpression(l), serializeExpression(r)]
|
|
417
|
-
});
|
|
418
|
-
},
|
|
419
|
-
mod(l, r) {
|
|
420
|
-
return new FilterExpression({
|
|
421
|
-
mod: [serializeExpression(l), serializeExpression(r)]
|
|
422
|
-
});
|
|
423
|
-
},
|
|
424
|
-
neg(x) {
|
|
425
|
-
return new FilterExpression({ neg: serializeExpression(x) });
|
|
426
|
-
},
|
|
427
|
-
// Logic ///////////////////////////////////////////////////////////////////
|
|
428
|
-
and(...exprs) {
|
|
429
|
-
return new FilterExpression({ and: exprs.map(serializeExpression) });
|
|
430
|
-
},
|
|
431
|
-
or(...exprs) {
|
|
432
|
-
return new FilterExpression({ or: exprs.map(serializeExpression) });
|
|
433
|
-
},
|
|
434
|
-
not(x) {
|
|
435
|
-
return new FilterExpression({ not: serializeExpression(x) });
|
|
436
|
-
},
|
|
437
|
-
// Other ///////////////////////////////////////////////////////////////////
|
|
438
|
-
field(fieldPath) {
|
|
439
|
-
return new FilterExpression({ field: fieldPath });
|
|
440
|
-
}
|
|
441
|
-
};
|
|
442
|
-
function serializeExpression(expr) {
|
|
443
|
-
if (expr instanceof FilterExpression) {
|
|
444
|
-
return expr.serialize();
|
|
445
|
-
} else {
|
|
446
|
-
return {
|
|
447
|
-
literal: expr === void 0 ? "$undefined" : expr
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
var FilterExpression = class {
|
|
452
|
-
inner;
|
|
453
|
-
constructor(inner) {
|
|
454
|
-
this.inner = inner;
|
|
455
|
-
}
|
|
456
|
-
serialize() {
|
|
457
|
-
return this.inner;
|
|
458
|
-
}
|
|
459
|
-
};
|
|
460
|
-
function serializeSearchFilter(searchFilter) {
|
|
461
|
-
return searchFilter(
|
|
462
|
-
SearchFilterBuilderImpl.new()
|
|
463
|
-
).export();
|
|
464
|
-
}
|
|
465
|
-
var SearchFilterBuilderImpl = class _SearchFilterBuilderImpl {
|
|
466
|
-
constructor(filters) {
|
|
467
|
-
this.filters = filters;
|
|
468
|
-
}
|
|
469
|
-
static new() {
|
|
470
|
-
return new _SearchFilterBuilderImpl([]);
|
|
471
|
-
}
|
|
472
|
-
search(fieldName, query) {
|
|
473
|
-
return new _SearchFilterBuilderImpl(
|
|
474
|
-
this.filters.concat({
|
|
475
|
-
type: "Search",
|
|
476
|
-
fieldPath: fieldName,
|
|
477
|
-
value: query
|
|
478
|
-
})
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
eq(fieldName, value) {
|
|
482
|
-
return new _SearchFilterBuilderImpl(
|
|
483
|
-
this.filters.concat({
|
|
484
|
-
type: "Eq",
|
|
485
|
-
fieldPath: fieldName,
|
|
486
|
-
value: value === void 0 ? "$undefiend" : value
|
|
487
|
-
})
|
|
488
|
-
);
|
|
489
|
-
}
|
|
490
|
-
export() {
|
|
491
|
-
return this.filters;
|
|
492
|
-
}
|
|
493
|
-
};
|
|
494
|
-
|
|
495
32
|
// src/schema.ts
|
|
496
|
-
var
|
|
33
|
+
var import_server = require("convex/server");
|
|
497
34
|
var import_values = require("convex/values");
|
|
498
35
|
function edgeCompoundIndexName(edgeDefinition) {
|
|
499
36
|
return edgeCompoundIndexNameRaw(edgeDefinition.field, edgeDefinition.ref);
|
|
@@ -502,8 +39,13 @@ function edgeCompoundIndexNameRaw(idA, idB) {
|
|
|
502
39
|
return `${idA}_${idB}`;
|
|
503
40
|
}
|
|
504
41
|
|
|
42
|
+
// src/shared.ts
|
|
43
|
+
function getEdgeDefinitions(entDefinitions, table) {
|
|
44
|
+
return entDefinitions[table].edges;
|
|
45
|
+
}
|
|
46
|
+
|
|
505
47
|
// src/writer.ts
|
|
506
|
-
var
|
|
48
|
+
var import_server2 = require("convex/server");
|
|
507
49
|
var WriterImplBase = class _WriterImplBase {
|
|
508
50
|
constructor(ctx, entDefinitions, table) {
|
|
509
51
|
this.ctx = ctx;
|
|
@@ -560,7 +102,7 @@ var WriterImplBase = class _WriterImplBase {
|
|
|
560
102
|
}
|
|
561
103
|
await this.writeEdges(id, edges, isDeletingSoftly);
|
|
562
104
|
if (deletionConfig !== void 0 && deletionConfig.type === "scheduled") {
|
|
563
|
-
const fnRef = this.ctx.scheduledDelete ?? (0,
|
|
105
|
+
const fnRef = this.ctx.scheduledDelete ?? (0, import_server2.makeFunctionReference)(
|
|
564
106
|
"functions:scheduledDelete"
|
|
565
107
|
);
|
|
566
108
|
await this.ctx.scheduler.runAfter(deletionConfig.delayMs ?? 0, fnRef, {
|
|
@@ -1278,7 +820,7 @@ var PromiseEdgeOrNullImpl = class _PromiseEdgeOrNullImpl extends PromiseEntsOrNu
|
|
|
1278
820
|
if (sourceId === null) {
|
|
1279
821
|
return null;
|
|
1280
822
|
}
|
|
1281
|
-
const edgeDoc = this.ctx.db.query(this.edgeDefinition.table).withIndex(
|
|
823
|
+
const edgeDoc = await this.ctx.db.query(this.edgeDefinition.table).withIndex(
|
|
1282
824
|
edgeCompoundIndexName(this.edgeDefinition),
|
|
1283
825
|
(q) => q.eq(this.edgeDefinition.field, sourceId).eq(
|
|
1284
826
|
this.edgeDefinition.ref,
|
|
@@ -1534,10 +1076,18 @@ var PromiseEntOrNullImpl = class extends Promise {
|
|
|
1534
1076
|
return {
|
|
1535
1077
|
id: otherId,
|
|
1536
1078
|
doc: async () => {
|
|
1079
|
+
if (otherId === void 0) {
|
|
1080
|
+
if (edgeDefinition.optional) {
|
|
1081
|
+
return null;
|
|
1082
|
+
}
|
|
1083
|
+
throw new Error(
|
|
1084
|
+
`Unexpected null reference for edge "${edgeDefinition.name}" in table "${this.table}" on document with ID "${id}": Expected an ID for a document in table "${edgeDefinition.to}".`
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1537
1087
|
const otherDoc = await this.ctx.db.get(otherId);
|
|
1538
1088
|
if (otherDoc === null) {
|
|
1539
1089
|
throw new Error(
|
|
1540
|
-
`Dangling reference for edge "${edgeDefinition.name}" in table "${this.table}"
|
|
1090
|
+
`Dangling reference for edge "${edgeDefinition.name}" in table "${this.table}" on document with ID "${id}": Could not find a document with ID "${otherId}" in table "${edgeDefinition.to}".`
|
|
1541
1091
|
);
|
|
1542
1092
|
}
|
|
1543
1093
|
return otherDoc;
|
|
@@ -1646,36 +1196,21 @@ function entsTableFactory(ctx, entDefinitions, options) {
|
|
|
1646
1196
|
if (typeof table2 !== "string") {
|
|
1647
1197
|
throw new Error(`Expected table name, got \`${table2}\``);
|
|
1648
1198
|
}
|
|
1649
|
-
if (
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
return new
|
|
1199
|
+
if (indexName !== void 0) {
|
|
1200
|
+
return new PromiseTableImpl(
|
|
1201
|
+
enrichedCtx,
|
|
1202
|
+
entDefinitions,
|
|
1203
|
+
table2
|
|
1204
|
+
).withIndex(indexName, indexRange);
|
|
1205
|
+
}
|
|
1206
|
+
if (ctx.db.insert !== void 0) {
|
|
1207
|
+
return new PromiseTableWriterImpl(
|
|
1658
1208
|
enrichedCtx,
|
|
1659
1209
|
entDefinitions,
|
|
1660
1210
|
table2
|
|
1661
1211
|
);
|
|
1662
|
-
} else {
|
|
1663
|
-
if (indexName !== void 0) {
|
|
1664
|
-
return new PromiseTableImpl(
|
|
1665
|
-
enrichedCtx,
|
|
1666
|
-
entDefinitions,
|
|
1667
|
-
table2
|
|
1668
|
-
).withIndex(indexName, indexRange);
|
|
1669
|
-
}
|
|
1670
|
-
if (ctx.db.insert !== void 0) {
|
|
1671
|
-
return new PromiseTableWriterImpl(
|
|
1672
|
-
enrichedCtx,
|
|
1673
|
-
entDefinitions,
|
|
1674
|
-
table2
|
|
1675
|
-
);
|
|
1676
|
-
}
|
|
1677
|
-
return new PromiseTableImpl(enrichedCtx, entDefinitions, table2);
|
|
1678
1212
|
}
|
|
1213
|
+
return new PromiseTableImpl(enrichedCtx, entDefinitions, table2);
|
|
1679
1214
|
};
|
|
1680
1215
|
table.system = table;
|
|
1681
1216
|
return table;
|