convex-ents 0.8.1 → 0.9.1
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/dist/deletion.js.map +1 -1
- package/dist/functions.d.ts +1 -1
- package/dist/functions.js +244 -66
- package/dist/functions.js.map +1 -1
- package/dist/{index-uXk5iZ86.d.ts → index-nOBiMg01.d.ts} +139 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +254 -68
- package/dist/index.js.map +1 -1
- package/dist/schema.js +10 -2
- package/dist/schema.js.map +1 -1
- package/dist/writer.d.ts +1 -1
- package/dist/writer.js +244 -66
- package/dist/writer.js.map +1 -1
- package/package.json +1 -1
package/dist/schema.js
CHANGED
|
@@ -126,10 +126,18 @@ function defineEntSchema(schema, options) {
|
|
|
126
126
|
const edgeTableName = edge.type === "ref" && edge.table !== void 0 ? edge.table : inverseEdge === void 0 ? `${tableName}_${edge.name}` : inverseEdge.name !== tableName ? `${tableName}_${inverseEdge.name}_to_${edge.name}` : `${inverseEdge.name}_to_${edge.name}`;
|
|
127
127
|
const forwardId = edge.type === "ref" && edge.field !== void 0 ? edge.field : inverseEdge === void 0 ? "aId" : tableName === otherTableName ? inverseEdge.name + "Id" : tableName + "Id";
|
|
128
128
|
const inverseId = isSelfDirected && edge.type === "ref" && edge.inverseField !== void 0 ? edge.inverseField : inverseEdge === void 0 ? "bId" : inverseEdge.type === "ref" && inverseEdge.field !== void 0 ? inverseEdge.field : tableName === otherTableName ? edge.name + "Id" : otherTableName + "Id";
|
|
129
|
-
|
|
129
|
+
const edgeTable = defineEnt({
|
|
130
130
|
[forwardId]: import_values.v.id(tableName),
|
|
131
131
|
[inverseId]: import_values.v.id(otherTableName)
|
|
132
|
-
}).index(forwardId, [forwardId, inverseId]).index(inverseId
|
|
132
|
+
}).index(forwardId, [forwardId]).index(inverseId, [inverseId]).index(`${forwardId}_${inverseId}`, [forwardId, inverseId]);
|
|
133
|
+
const isSymmetric = inverseEdge === void 0;
|
|
134
|
+
if (!isSymmetric) {
|
|
135
|
+
edgeTable.index(`${inverseId}_${forwardId}`, [
|
|
136
|
+
forwardId,
|
|
137
|
+
inverseId
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
140
|
+
schema[edgeTableName] = edgeTable;
|
|
133
141
|
edge.type = "ref";
|
|
134
142
|
edge.table = edgeTableName;
|
|
135
143
|
edge.field = forwardId;
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema.ts"],"sourcesContent":["import {\n DataModelFromSchemaDefinition,\n DefineSchemaOptions,\n GenericDataModel,\n GenericTableIndexes,\n GenericTableSearchIndexes,\n GenericTableVectorIndexes,\n SchemaDefinition,\n SearchIndexConfig,\n TableDefinition,\n VectorIndexConfig,\n defineSchema,\n} from \"convex/server\";\nimport {\n GenericId,\n GenericValidator,\n ObjectType,\n PropertyValidators,\n VAny,\n VFloat64,\n VId,\n VObject,\n VOptional,\n Validator,\n v,\n} from \"convex/values\";\n\nexport function defineEntSchema<\n Schema extends Record<string, EntDefinition>,\n StrictTableNameTypes extends boolean = true,\n>(\n schema: Schema,\n options?: DefineSchemaOptions<StrictTableNameTypes>,\n): SchemaDefinition<Schema, StrictTableNameTypes> {\n // Set the properties of edges which requires knowing their inverses,\n // and add edge tables.\n const tableNames = Object.keys(schema);\n for (const tableName of tableNames) {\n const table = schema[tableName];\n for (const edge of edgeConfigsBeforeDefineSchema(table)) {\n if (\n // Skip inverse edges, we process their forward edges\n (edge.cardinality === \"multiple\" &&\n edge.type === \"ref\" &&\n edge.inverse !== undefined) ||\n // symmetric is only set by defineEntSchema,\n // so we already processed the pair\n (edge as any).symmetric !== undefined\n ) {\n continue;\n }\n\n const otherTableName = edge.to;\n const otherTable = schema[otherTableName];\n if (otherTable === undefined) {\n throw new Error(\n `Edge \"${edge.name}\" in table \"${tableName}\" ` +\n `points to an undefined table \"${otherTableName}\"`,\n );\n }\n\n const isSelfDirected = edge.to === tableName;\n\n const inverseEdgeCandidates = edgeConfigsBeforeDefineSchema(\n otherTable,\n ).filter(canBeInverseEdge(tableName, edge, isSelfDirected));\n if (inverseEdgeCandidates.length > 1) {\n throw new Error(\n `Edge \"${edge.name}\" in table \"${tableName}\" ` +\n `has too many potential inverse edges in table \"${otherTableName}\": ` +\n `${inverseEdgeCandidates\n .map((edge) => `\"${edge.name}\"`)\n .join(\", \")}`,\n );\n }\n const inverseEdge: EdgeConfigBeforeDefineSchema | undefined =\n inverseEdgeCandidates[0];\n\n if (\n edge.cardinality === \"single\" &&\n edge.type === \"field\" &&\n inverseEdge === undefined\n ) {\n throw new Error(\n `Missing inverse edge in table \"${otherTableName}\" ` +\n `for edge \"${edge.name}\" in table \"${tableName}\"`,\n );\n }\n\n // Default `ref` on the multiple end of the edge,\n if (edge.cardinality === \"single\" && edge.type === \"ref\") {\n if (inverseEdge === undefined) {\n throw new Error(\n `Missing inverse edge in table \"${otherTableName}\" ${\n edge.ref !== null ? `with field \"${edge.ref}\" ` : \"\"\n }for edge \"${edge.name}\" in table \"${tableName}\"`,\n );\n }\n if (\n inverseEdge.cardinality === \"single\" &&\n inverseEdge.type === \"ref\"\n ) {\n // TODO: If we want to support optional 1:1 edges in the future\n // throw new Error(\n // `Both edge \"${edge.name}\" on ent \"${inverseEdge.to}\" and ` +\n // `edge \"${inverseEdge.name}\" on ent \"${edge.to}\" are marked ` +\n // `as optional, specify which table should store the 1:1 edge by ` +\n // `providing a \\`field\\` name.`\n // );\n throw new Error(\n `Both edge \"${edge.name}\" in table \"${inverseEdge.to}\" and ` +\n `edge \"${inverseEdge.name}\" in table \"${edge.to}\" are marked ` +\n `as optional, choose one to be required.`,\n );\n }\n if (\n inverseEdge.cardinality !== \"single\" ||\n inverseEdge.type !== \"field\"\n ) {\n throw new Error(\n `Unexpected inverse edge type ${edge.name}, ${inverseEdge?.name}`,\n );\n }\n if (edge.ref === null) {\n (edge as any).ref = inverseEdge.field;\n }\n // For now the the non-optional end is always unique\n (inverseEdge as any).unique = true;\n }\n if (\n (edge.cardinality === \"single\" && edge.type === \"ref\") ||\n (edge.cardinality === \"multiple\" && edge.type === \"field\")\n ) {\n if (\n edge.deletion !== undefined &&\n deletionConfigFromEntDefinition(otherTable) === undefined\n ) {\n throw new Error(\n `Cannot specify soft deletion behavior for edge ` +\n `\"${edge.name}\" in table \"${tableName}\" ` +\n `because the target table \"${otherTableName}\" does not have ` +\n `a \"soft\" or \"scheduled\" deletion behavior ` +\n `configured.`,\n );\n }\n }\n if (edge.cardinality === \"multiple\") {\n if (!isSelfDirected && inverseEdge === undefined) {\n throw new Error(\n `Missing inverse edge in table \"${otherTableName}\" ` +\n `for edge \"${edge.name}\" in table \"${tableName}\"`,\n );\n }\n\n if (inverseEdge?.cardinality === \"single\") {\n if (inverseEdge.type === \"ref\") {\n throw new Error(\n `The edge \"${inverseEdge.name}\" in table \"${otherTableName}\" ` +\n `cannot be optional, as it must store the 1:many edge as a field. ` +\n `Check the its inverse edge \"${edge.name}\" in table \"${tableName}\".`,\n );\n }\n if (edge.type === \"ref\") {\n throw new Error(\n `The edge \"${inverseEdge.name}\" in table \"${otherTableName}\" ` +\n `cannot be singular, as the edge \"${edge.name}\" in table \"${tableName}\" did not ` +\n `specify the \\`ref\\` option.`,\n );\n }\n (edge as any).type = \"field\";\n (edge as any).ref = inverseEdge.field;\n }\n\n if (inverseEdge?.cardinality === \"multiple\" || isSelfDirected) {\n if (!isSelfDirected && edge?.type === \"field\") {\n throw new Error(\n `The edge \"${edge.name}\" in table \"${tableName}\" ` +\n `specified \\`ref\\`, but its inverse edge \"${inverseEdge.name}\" ` +\n `in table \"${otherTableName}\" is not the singular end of a 1:many edge.`,\n );\n }\n if (inverseEdge?.type === \"field\") {\n throw new Error(\n `The edge \"${inverseEdge.name}\" in table \"${otherTableName}\" ` +\n `specified \\`ref\\`, but its inverse edge \"${edge.name}\" ` +\n `in table \"${tableName}\" is not the singular end of a 1:many edge.`,\n );\n }\n\n const edgeTableName =\n edge.type === \"ref\" && edge.table !== undefined\n ? edge.table\n : inverseEdge === undefined\n ? `${tableName}_${edge.name}`\n : inverseEdge.name !== tableName\n ? `${tableName}_${inverseEdge.name}_to_${edge.name}`\n : `${inverseEdge.name}_to_${edge.name}`;\n\n const forwardId =\n edge.type === \"ref\" && edge.field !== undefined\n ? edge.field\n : inverseEdge === undefined\n ? \"aId\"\n : tableName === otherTableName\n ? inverseEdge.name + \"Id\"\n : tableName + \"Id\";\n const inverseId =\n isSelfDirected &&\n edge.type === \"ref\" &&\n edge.inverseField !== undefined\n ? edge.inverseField\n : inverseEdge === undefined\n ? \"bId\"\n : inverseEdge.type === \"ref\" && inverseEdge.field !== undefined\n ? inverseEdge.field\n : tableName === otherTableName\n ? edge.name + \"Id\"\n : otherTableName + \"Id\";\n // Add the table\n (schema as any)[edgeTableName] = defineEnt({\n [forwardId]: v.id(tableName),\n [inverseId]: v.id(otherTableName),\n })\n .index(forwardId, [forwardId, inverseId])\n .index(inverseId, [inverseId, forwardId]);\n\n (edge as any).type = \"ref\";\n (edge as any).table = edgeTableName;\n (edge as any).field = forwardId;\n (edge as any).ref = inverseId;\n (edge as any).symmetric = inverseEdge === undefined;\n if (inverseEdge !== undefined) {\n inverseEdge.type = \"ref\";\n (inverseEdge as any).table = edgeTableName;\n (inverseEdge as any).field = inverseId;\n (inverseEdge as any).ref = forwardId;\n (inverseEdge as any).symmetric = false;\n }\n }\n }\n }\n }\n return defineSchema(schema, options);\n}\n\nfunction canBeInverseEdge(\n tableName: string,\n edge: EdgeConfigBeforeDefineSchema,\n isSelfDirected: boolean,\n) {\n return (candidate: EdgeConfigBeforeDefineSchema) => {\n if (candidate.to !== tableName) {\n return false;\n }\n // Simple: pick out explicit inverse edges\n if (isSelfDirected) {\n return (\n candidate.cardinality === \"multiple\" &&\n candidate.type === \"ref\" &&\n candidate.inverse === edge.name\n );\n }\n // If both ref and field are known, only consider matching edges (from the ref side)\n if (\n (edge.cardinality === \"single\" &&\n edge.type === \"ref\" &&\n edge.ref !== null) ||\n (edge.cardinality === \"multiple\" &&\n edge.type === \"field\" &&\n edge.ref !== true)\n ) {\n if (candidate.cardinality === \"single\" && candidate.type === \"field\") {\n return edge.ref === candidate.field;\n }\n }\n // If both ref and field are known, only consider matching edges (from the field side)\n if (\n edge.cardinality === \"single\" &&\n edge.type === \"field\" &&\n edge.field !== null\n ) {\n if (\n (candidate.cardinality === \"single\" &&\n candidate.type === \"ref\" &&\n candidate.ref !== null) ||\n (candidate.cardinality === \"multiple\" &&\n candidate.type === \"field\" &&\n candidate.ref !== true)\n ) {\n return edge.field === candidate.ref;\n }\n }\n\n // If table is known on both ends, only consider matching edges\n if (\n edge.cardinality === \"multiple\" &&\n edge.type === \"ref\" &&\n edge.table !== undefined\n ) {\n return (\n candidate.cardinality === \"multiple\" &&\n candidate.type === \"ref\" &&\n edge.table === candidate.table\n );\n }\n if (\n candidate.cardinality === \"multiple\" &&\n candidate.type === \"ref\" &&\n candidate.table !== undefined\n ) {\n return (\n edge.cardinality === \"multiple\" &&\n edge.type === \"ref\" &&\n edge.table === candidate.table\n );\n }\n return true;\n };\n}\n\nfunction edgeConfigsBeforeDefineSchema(table: EntDefinition) {\n return Object.values(\n (table as any).edgeConfigs as Record<string, EdgeConfigBeforeDefineSchema>,\n );\n}\n\nfunction deletionConfigFromEntDefinition(table: EntDefinition) {\n return (table as any).deletionConfig as DeletionConfig | undefined;\n}\n\nexport function defineEnt<DocumentSchema extends PropertyValidators>(\n documentSchema: DocumentSchema,\n): EntDefinition<ObjectValidator<DocumentSchema>> {\n return new EntDefinitionImpl(documentSchema) as any;\n}\n\nexport function defineEntFromTable<\n DocumentType extends GenericValidator = GenericValidator,\n // eslint-disable-next-line @typescript-eslint/ban-types\n Indexes extends GenericTableIndexes = {},\n // eslint-disable-next-line @typescript-eslint/ban-types\n SearchIndexes extends GenericTableSearchIndexes = {},\n // eslint-disable-next-line @typescript-eslint/ban-types\n VectorIndexes extends GenericTableVectorIndexes = {},\n>(\n definition: TableDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes\n >,\n): EntDefinition<DocumentType, Indexes, SearchIndexes, VectorIndexes> {\n const validator: DocumentType = definition.validator;\n if (validator.kind !== \"object\") {\n throw new Error(\n \"Only tables with object definition are supported in Ents, not unions\",\n );\n }\n\n const entDefinition = defineEnt(validator.fields);\n // @ts-expect-error Private fields\n entDefinition.indexes = definition.indexes;\n // @ts-expect-error Private fields\n entDefinition.searchIndexes = definition.searchIndexes;\n // @ts-expect-error Private fields\n entDefinition.vectorIndexes = definition.vectorIndexes;\n return entDefinition as any;\n}\n\ntype DefineEntFromTables<\n T extends { [key: string]: TableDefinition<any, any, any, any> },\n> = {\n [K in keyof T]: T[K] extends TableDefinition<\n infer D,\n infer I,\n infer S,\n infer V\n >\n ? EntDefinition<D, I, S, V>\n : never;\n};\n\nexport function defineEntsFromTables<\n T extends { [key: string]: TableDefinition<any, any, any, any> },\n>(definitions: T): DefineEntFromTables<T> {\n const result: any = {};\n for (const key in definitions) {\n result[key] = defineEntFromTable(definitions[key]);\n }\n return result;\n}\n\ntype GenericEdges = Record<string, GenericEdgeConfig>;\n\nexport type GenericEdgeConfig = {\n name: string;\n to: string;\n cardinality: \"single\" | \"multiple\";\n type: \"field\" | \"ref\";\n};\n\ntype ExtractFieldPaths<T extends Validator<any, any, any>> =\n // Add in the system fields available in index definitions.\n // This should be everything except for `_id` because thats added to indexes\n // automatically.\n T[\"fieldPaths\"] | keyof SystemFields;\n\ntype ObjectFieldType<\n FieldName extends string,\n T extends Validator<any, any, any>,\n> = T[\"isOptional\"] extends \"optional\"\n ? { [key in FieldName]?: T[\"type\"] }\n : { [key in FieldName]: T[\"type\"] };\n\ntype AddField<\n V extends GenericValidator,\n FieldName extends string,\n P extends GenericValidator,\n> =\n // Note: We can't use the `AddField` type to add fields to a union type, but ents\n // do not support schemas with top level unions\n V extends VObject<\n infer TypeScriptType,\n infer Fields,\n infer IsOptional,\n infer FieldPaths\n >\n ? VObject<\n Expand<TypeScriptType & ObjectFieldType<FieldName, P>>,\n Expand<Fields & { FieldName: P }>,\n IsOptional,\n FieldPaths | FieldName\n >\n : V extends VAny\n ? VAny\n : never;\nexport interface EntDefinition<\n DocumentType extends Validator<any, any, any> = Validator<any, any, any>,\n // eslint-disable-next-line @typescript-eslint/ban-types\n Indexes extends GenericTableIndexes = {},\n // eslint-disable-next-line @typescript-eslint/ban-types\n SearchIndexes extends GenericTableSearchIndexes = {},\n // eslint-disable-next-line @typescript-eslint/ban-types\n VectorIndexes extends GenericTableVectorIndexes = {},\n // eslint-disable-next-line @typescript-eslint/ban-types\n Edges extends GenericEdges = {},\n> extends TableDefinition<DocumentType, Indexes, SearchIndexes, VectorIndexes> {\n /**\n * Define an index on this table.\n *\n * To learn about indexes, see [Defining Indexes](https://docs.convex.dev/using/indexes).\n *\n * @param name - The name of the index.\n * @param fields - The fields to index, in order. Must specify at least one\n * field.\n * @returns A {@link TableDefinition} with this index included.\n */\n index<\n IndexName extends string,\n FirstFieldPath extends ExtractFieldPaths<DocumentType>,\n RestFieldPaths extends ExtractFieldPaths<DocumentType>[],\n >(\n name: IndexName,\n fields: [FirstFieldPath, ...RestFieldPaths],\n ): EntDefinition<\n DocumentType,\n Expand<\n Indexes &\n Record<IndexName, [FirstFieldPath, ...RestFieldPaths, \"_creationTime\"]>\n >,\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n\n /**\n * Define a search index on this table.\n *\n * To learn about search indexes, see [Search](https://docs.convex.dev/text-search).\n *\n * @param name - The name of the index.\n * @param indexConfig - The search index configuration object.\n * @returns A {@link TableDefinition} with this search index included.\n */\n searchIndex<\n IndexName extends string,\n SearchField extends ExtractFieldPaths<DocumentType>,\n FilterFields extends ExtractFieldPaths<DocumentType> = never,\n >(\n name: IndexName,\n indexConfig: Expand<SearchIndexConfig<SearchField, FilterFields>>,\n ): EntDefinition<\n DocumentType,\n Indexes,\n Expand<\n SearchIndexes &\n Record<\n IndexName,\n {\n searchField: SearchField;\n filterFields: FilterFields;\n }\n >\n >,\n VectorIndexes,\n Edges\n >;\n\n // /**\n // * Define a vector index on this table.\n // *\n // * To learn about vector indexes, see [Vector Search](https://docs.convex.dev/vector-search).\n // *\n // * @param name - The name of the index.\n // * @param indexConfig - The vector index configuration object.\n // * @returns A {@link TableDefinition} with this vector index included.\n // */\n vectorIndex<\n IndexName extends string,\n VectorField extends ExtractFieldPaths<DocumentType>,\n FilterFields extends ExtractFieldPaths<DocumentType> = never,\n >(\n name: IndexName,\n indexConfig: Expand<VectorIndexConfig<VectorField, FilterFields>>,\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n Expand<\n VectorIndexes &\n Record<\n IndexName,\n {\n vectorField: VectorField;\n dimensions: number;\n filterFields: FilterFields;\n }\n >\n >,\n Edges\n >;\n\n field<FieldName extends string, T extends GenericValidator>(\n field: FieldName,\n validator: T,\n ): EntDefinition<\n AddField<DocumentType, FieldName, T>,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n field<FieldName extends string, T extends Validator<any, any, any>>(\n field: FieldName,\n validator: T,\n options: { index: true },\n ): EntDefinition<\n AddField<DocumentType, FieldName, T>,\n Indexes & { [key in FieldName]: [FieldName, \"_creationTime\"] },\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n field<FieldName extends string, T extends Validator<any, any, any>>(\n field: FieldName,\n validator: T,\n options: { unique: true },\n ): EntDefinition<\n AddField<DocumentType, FieldName, T>,\n Indexes & { [key in FieldName]: [FieldName, \"_creationTime\"] },\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n field<FieldName extends string, T extends Validator<any, \"required\", any>>(\n field: FieldName,\n validator: T,\n options: { default: T[\"type\"] },\n ): EntDefinition<\n AddField<DocumentType, FieldName, T>,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n\n edge<EdgeName extends string>(\n edge: EdgeName,\n ): EntDefinition<\n AddField<DocumentType, `${EdgeName}Id`, VId<GenericId<`${EdgeName}s`>>>,\n Indexes & { [key in `${EdgeName}Id`]: [`${EdgeName}Id`, \"_creationTime\"] },\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgeName]: {\n name: EdgeName;\n to: `${EdgeName}s`;\n type: \"field\";\n cardinality: \"single\";\n };\n }\n >;\n edge<EdgeName extends string, const FieldName extends string>(\n edge: EdgeName,\n options: { field: FieldName },\n ): EntDefinition<\n AddField<DocumentType, NoInfer<FieldName>, VId<GenericId<`${EdgeName}s`>>>,\n Indexes & {\n [key in NoInfer<FieldName>]: [NoInfer<FieldName>, \"_creationTime\"];\n },\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgeName]: {\n name: EdgeName;\n to: `${EdgeName}s`;\n type: \"field\";\n cardinality: \"single\";\n };\n }\n >;\n edge<\n EdgeName extends string,\n const FieldName extends string,\n const ToTable extends string,\n >(\n edge: EdgeName,\n options: { field: FieldName; to: ToTable },\n ): EntDefinition<\n AddField<DocumentType, NoInfer<FieldName>, VId<GenericId<`${ToTable}`>>>,\n Indexes & {\n [key in NoInfer<FieldName>]: [NoInfer<FieldName>, \"_creationTime\"];\n },\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgeName]: {\n name: EdgeName;\n to: ToTable;\n type: \"field\";\n cardinality: \"single\";\n };\n }\n >;\n edge<EdgeName extends string>(\n edge: EdgeName,\n options: {\n optional: true;\n ref?: string;\n deletion?: \"soft\";\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgeName]: {\n name: EdgeName;\n to: `${EdgeName}s`;\n type: \"ref\";\n cardinality: \"single\";\n };\n }\n >;\n edge<EdgeName extends string, const ToTable extends string>(\n edge: EdgeName,\n options: {\n optional: true;\n to: ToTable;\n ref?: string;\n deletion?: \"soft\";\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgeName]: {\n name: EdgeName;\n to: NoInfer<ToTable>;\n type: \"ref\";\n cardinality: \"single\";\n };\n }\n >;\n\n /**\n * Define many:1 edge to another table.\n * @param edge The name of the edge, also the name of the target table.\n * @param options.ref The name of the field that stores the many:1 edge\n * on the other table, or `true` to infer it.\n */\n edges<EdgesName extends string>(\n edge: EdgesName,\n options: {\n ref: true | string;\n deletion?: \"soft\";\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgesName]: {\n name: EdgesName;\n to: EdgesName;\n type: \"field\";\n cardinality: \"multiple\";\n };\n }\n >;\n /**\n * Define many:1 edge to another table.\n * @param edge The name of the edge.\n * @param options.to Name of the table the edge points to.\n * If it's the same as the table this edge is defined on, this edge is\n * a symmetric, self-directed many:many edge.\n * @param options.ref The name of the field that stores the many:1 edge\n * on the other table, or `true` to infer it.\n */\n edges<EdgesName extends string, TableName extends string>(\n edge: EdgesName,\n options: {\n to: TableName;\n ref: true | string;\n deletion?: \"soft\";\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgesName]: {\n name: EdgesName;\n to: NoInfer<TableName>;\n type: \"field\";\n cardinality: \"multiple\";\n };\n }\n >;\n\n /**\n * Define many:many edge to another table.\n * @param edge The name of the edge, also the name of the target table.\n * @param options.table Optional, name of the table to store the many:many edge in.\n * @param options.field Optional, name of the field to store the ID of the\n * this end of the many:many edge.\n */\n edges<EdgesName extends string>(\n edge: EdgesName,\n options?: {\n table?: string;\n field?: string;\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgesName]: {\n name: EdgesName;\n to: EdgesName;\n type: \"ref\";\n cardinality: \"multiple\";\n };\n }\n >;\n /**\n * Define many:many edge to another table.\n * @param edge The name of the edge.\n * @param options.to Name of the table the edge points to.\n * If it's the same as the table this edge is defined on, this edge is\n * a symmetric, self-directed many:many edge.\n * @param options.table Optional, name of the table to store the many:many edge in.\n * @param options.field Optional, name of the field to store the ID of the\n * of the source end of the forward many:many edge.\n * @param options.inverseField Optional, name of the field to store the ID\n * of the target end of the forward edge. Only allowed for symmetric,\n * self-directed many:many edges.\n */\n edges<EdgesName extends string, TableName extends string>(\n edge: EdgesName,\n options: {\n to: TableName;\n table?: string;\n field?: string;\n inverseField?: string;\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgesName]: {\n name: EdgesName;\n to: NoInfer<TableName>;\n type: \"ref\";\n cardinality: \"multiple\";\n };\n }\n >;\n /**\n * Define self-directed, assymetric, many:many edge.\n * @param edge The name of the edge.\n * @param options.to Name of the table the edge points to.\n * Must be the same as the table this edge is defined on.\n * @param options.inverse Name of the inverse edge.\n * @param options.table Optional, name of the table to store the many:many edge in.\n * @param options.field Optional, name of the field to store the ID of the\n * of the source end of the forward many:many edge.\n * @param options.inverseField Optional, name of the field to store the ID\n * of the target end of the forward many:many edge.\n */\n edges<\n EdgesName extends string,\n TableName extends string,\n InverseEdgesNames extends string,\n >(\n edge: EdgesName,\n options: {\n to: TableName;\n inverse: InverseEdgesNames;\n table?: string;\n field?: string;\n inverseField?: string;\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgesName]: {\n name: EdgesName;\n to: NoInfer<TableName>;\n type: \"ref\";\n cardinality: \"multiple\";\n };\n } & {\n [key in NoInfer<InverseEdgesNames>]: {\n name: NoInfer<InverseEdgesNames>;\n to: NoInfer<TableName>;\n type: \"ref\";\n cardinality: \"multiple\";\n };\n }\n >;\n\n /**\n * Add the \"soft\" deletion behavior to this ent.\n *\n * When the ent is \"soft\" deleted, its `deletionTime` field is set to the\n * current time and it is not actually deleted.\n *\n * @param type `\"soft\"`\n */\n deletion(\n type: \"soft\",\n ): EntDefinition<\n AddField<DocumentType, \"deletionTime\", VOptional<VFloat64>>,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n /**\n * Add the \"scheduled\" deletion behavior to this ent.\n *\n * The ent is first \"soft\" deleted and its hard deletion is scheduled\n * to run in a separate mutation.\n *\n * @param type `\"scheduled\"`\n * @param options.delayMs If the `delayMs` option is specified,\n * the hard deletion is scheduled to happen after the specified\n * time duration.\n */\n deletion(\n type: \"scheduled\",\n options?: {\n delayMs: number;\n },\n ): EntDefinition<\n AddField<DocumentType, \"deletionTime\", VOptional<VFloat64>>,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n}\n\ntype NoInfer<T> = [T][T extends any ? 0 : never];\n\ntype FieldOptions = {\n index?: true;\n unique?: true;\n default?: any;\n};\n\ntype EdgeOptions = {\n optional?: true;\n field?: string;\n ref?: string;\n to?: string;\n};\n\ntype EdgesOptions = {\n to?: string;\n inverse?: string;\n ref?: string;\n table?: string;\n field?: string;\n inverseField?: string;\n deletion: \"soft\";\n};\n\nclass EntDefinitionImpl {\n validator: GenericValidator;\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n private indexes: Index[] = [];\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n private searchIndexes: SearchIndex[] = [];\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n private vectorIndexes: VectorIndex[] = [];\n\n private documentSchema: Record<string, Validator<any, any, any>>;\n\n private edgeConfigs: Record<string, EdgeConfigBeforeDefineSchema> = {};\n\n private fieldConfigs: Record<string, FieldConfig> = {};\n\n private defaults: Record<string, any> = {};\n\n private deletionConfig: DeletionConfig | undefined;\n\n constructor(documentSchema: Record<string, Validator<any, any, any>>) {\n this.documentSchema = documentSchema;\n this.validator = v.object(documentSchema);\n }\n\n index(name: any, fields: any) {\n this.indexes.push({ indexDescriptor: name, fields });\n return this;\n }\n\n searchIndex(name: any, indexConfig: any) {\n this.searchIndexes.push({\n indexDescriptor: name,\n searchField: indexConfig.searchField,\n filterFields: indexConfig.filterFields || [],\n });\n return this;\n }\n\n vectorIndex(name: any, indexConfig: any) {\n this.vectorIndexes.push({\n indexDescriptor: name,\n vectorField: indexConfig.vectorField,\n dimensions: indexConfig.dimensions,\n filterFields: indexConfig.filterFields || [],\n });\n return this;\n }\n\n /**\n * Export the contents of this definition.\n *\n * This is called internally by the Convex framework.\n * @internal\n */\n export() {\n return {\n indexes: this.indexes,\n searchIndexes: this.searchIndexes,\n vectorIndexes: this.vectorIndexes,\n documentType: (v.object(this.documentSchema) as any).json,\n };\n }\n\n field(name: string, validator: any, options?: FieldOptions): this {\n if (this.documentSchema[name] !== undefined) {\n // TODO: Store the fieldConfigs in an array so that we can\n // do the uniqueness check in defineEntSchema where we\n // know the table name.\n throw new Error(`Duplicate field \"${name}\"`);\n }\n const finalValidator =\n options?.default !== undefined ? v.optional(validator) : validator;\n this.documentSchema = { ...this.documentSchema, [name]: finalValidator };\n if (options?.unique === true || options?.index === true) {\n this.indexes.push({ indexDescriptor: name, fields: [name] });\n }\n if (options?.default !== undefined) {\n this.defaults[name] = options.default;\n }\n if (options?.unique === true) {\n this.fieldConfigs[name] = { name, unique: true };\n }\n return this;\n }\n\n edge(edgeName: string, options?: EdgeOptions): this {\n if (this.edgeConfigs[edgeName] !== undefined) {\n // TODO: Store the edgeConfigs in an array so that we can\n // do the uniqueness check in defineEntSchema where we\n // know the source table name.\n throw new Error(`Duplicate edge \"${edgeName}\"`);\n }\n const to = options?.to ?? edgeName + \"s\";\n if (options?.optional !== true) {\n const fieldName = options?.field ?? edgeName + \"Id\";\n this.documentSchema = { ...this.documentSchema, [fieldName]: v.id(to) };\n this.edgeConfigs[edgeName] = {\n name: edgeName,\n to,\n cardinality: \"single\",\n type: \"field\",\n field: fieldName,\n };\n this.indexes.push({\n indexDescriptor: fieldName,\n fields: [fieldName],\n });\n return this;\n }\n if (options.optional === true) {\n this.edgeConfigs[edgeName] = {\n name: edgeName,\n to,\n cardinality: \"single\",\n type: \"ref\",\n ref: options.ref ?? null,\n };\n }\n return this;\n }\n\n edges(name: string, options?: EdgesOptions): this {\n const cardinality = \"multiple\";\n const to = options?.to ?? name;\n const ref = options?.ref;\n const table = options?.table;\n // TODO: Do this later when we have the table name,\n // or rework schema to use a builder pattern.\n if (ref !== undefined && table !== undefined) {\n throw new Error(\n `Cannot specify both \\`ref\\` and \\`table\\` for the same edge, ` +\n `as the former is for 1:many edges and the latter ` +\n `for many:many edges. Config: \\`${JSON.stringify(options)}\\``,\n );\n }\n const field = options?.field;\n const inverseField = options?.inverseField;\n // TODO: Do this later when we have the table name,\n // or rework schema to use a builder pattern.\n if (\n (field !== undefined || inverseField !== undefined) &&\n table === undefined\n ) {\n throw new Error(\n `Specify \\`table\\` if you're customizing the \\`field\\` or ` +\n `\\`inverseField\\` for a many:many edge. ` +\n `Config: \\`${JSON.stringify(options)}\\``,\n );\n }\n const inverseName = options?.inverse;\n const deletion = options?.deletion;\n this.edgeConfigs[name] =\n ref !== undefined\n ? { name, to, cardinality, type: \"field\", ref, deletion }\n : { name, to, cardinality, type: \"ref\", table, field, inverseField };\n if (inverseName !== undefined) {\n this.edgeConfigs[inverseName] = {\n name: inverseName,\n to,\n cardinality,\n type: \"ref\",\n inverse: name,\n table,\n };\n }\n return this;\n }\n\n deletion(type: \"soft\" | \"scheduled\", options?: { delayMs: number }): this {\n if (this.documentSchema.deletionTime !== undefined) {\n // TODO: Put the check where we know the table name.\n throw new Error(\n `Cannot enable \"${type}\" deletion because \"deletionTime\" field ` +\n `was already defined.`,\n );\n }\n if (this.deletionConfig !== undefined) {\n // TODO: Put the check where we know the table name.\n throw new Error(`Deletion behavior can only be specified once.`);\n }\n this.documentSchema = {\n ...this.documentSchema,\n deletionTime: v.optional(v.number()),\n };\n this.deletionConfig = { type, ...options };\n return this;\n }\n}\n\nexport type EdgeConfig = {\n name: string;\n to: string;\n} & (\n | ({\n cardinality: \"single\";\n } & (\n | {\n type: \"field\";\n field: string;\n unique: boolean;\n }\n | {\n type: \"ref\";\n ref: string;\n deletion?: \"soft\";\n }\n ))\n | ({\n cardinality: \"multiple\";\n } & (\n | {\n type: \"field\";\n ref: string;\n deletion?: \"soft\";\n }\n | {\n type: \"ref\";\n table: string;\n field: string;\n ref: string;\n inverse: boolean;\n symmetric: boolean;\n }\n ))\n);\n\ntype EdgeConfigBeforeDefineSchema = {\n name: string;\n to: string;\n} & (\n | ({\n cardinality: \"single\";\n } & (\n | {\n type: \"field\";\n field: string;\n }\n | {\n type: \"ref\";\n ref: null | string;\n deletion?: \"soft\";\n }\n ))\n | ({\n cardinality: \"multiple\";\n } & (\n | {\n type: \"field\";\n ref: true | string;\n deletion?: \"soft\";\n }\n | {\n type: \"ref\";\n table?: string;\n field?: string;\n inverseField?: string;\n inverse?: string;\n }\n ))\n);\n\nexport type FieldConfig = {\n name: string;\n unique: boolean;\n};\n\nexport type Expand<ObjectType extends Record<any, any>> =\n ObjectType extends Record<any, any>\n ? {\n [Key in keyof ObjectType]: ObjectType[Key];\n }\n : never;\nexport type SystemFields = {\n _creationTime: number;\n};\n\ntype ObjectValidator<Validators extends PropertyValidators> = VObject<\n // Compute the TypeScript type this validator refers to.\n ObjectType<Validators>,\n Validators\n>;\n\nexport type GenericEntsDataModel = GenericDataModel &\n Record<string, GenericEntModel>;\n\nexport type GenericEntModel = {\n edges: Record<string, GenericEdgeConfig>;\n};\n\nexport type DeletionConfig =\n | {\n type: \"soft\";\n }\n | {\n type: \"scheduled\";\n delayMs?: number;\n };\n\nexport type EntDataModelFromSchema<\n SchemaDef extends SchemaDefinition<any, boolean>,\n> = DataModelFromSchemaDefinition<SchemaDef> & {\n [TableName in keyof SchemaDef[\"tables\"] &\n string]: SchemaDef[\"tables\"][TableName] extends EntDefinition<\n any,\n any,\n any,\n any,\n infer Edges\n >\n ? {\n edges: Edges;\n }\n : never;\n};\n\nexport function getEntDefinitions<\n SchemaDef extends SchemaDefinition<any, boolean>,\n>(schema: SchemaDef): EntDataModelFromSchema<typeof schema> {\n const tables = schema.tables;\n return Object.entries(tables).reduce(\n (acc, [tableName, table]: [any, any]) => {\n acc[tableName] = {\n indexes: (\n table.indexes as {\n indexDescriptor: string;\n fields: string[];\n }[]\n ).reduce(\n (acc, { indexDescriptor, fields }) => {\n acc[indexDescriptor] = fields;\n return acc;\n },\n {} as Record<string, string[]>,\n ),\n defaults: table.defaults,\n edges: table.edgeConfigs,\n fields: table.fieldConfigs,\n deletionConfig: table.deletionConfig,\n };\n return acc;\n },\n {} as Record<string, any>,\n ) as any;\n}\n"],"mappings":"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","names":["edge","acc"]}
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts"],"sourcesContent":["import {\n DataModelFromSchemaDefinition,\n DefineSchemaOptions,\n GenericDataModel,\n GenericTableIndexes,\n GenericTableSearchIndexes,\n GenericTableVectorIndexes,\n SchemaDefinition,\n SearchIndexConfig,\n TableDefinition,\n VectorIndexConfig,\n defineSchema,\n} from \"convex/server\";\nimport {\n GenericId,\n GenericValidator,\n ObjectType,\n PropertyValidators,\n VAny,\n VFloat64,\n VId,\n VObject,\n VOptional,\n Validator,\n v,\n} from \"convex/values\";\n\nexport function defineEntSchema<\n Schema extends Record<string, EntDefinition>,\n StrictTableNameTypes extends boolean = true,\n>(\n schema: Schema,\n options?: DefineSchemaOptions<StrictTableNameTypes>,\n): SchemaDefinition<Schema, StrictTableNameTypes> {\n // Set the properties of edges which requires knowing their inverses,\n // and add edge tables.\n const tableNames = Object.keys(schema);\n for (const tableName of tableNames) {\n const table = schema[tableName];\n for (const edge of edgeConfigsBeforeDefineSchema(table)) {\n if (\n // Skip inverse edges, we process their forward edges\n (edge.cardinality === \"multiple\" &&\n edge.type === \"ref\" &&\n edge.inverse !== undefined) ||\n // symmetric is only set by defineEntSchema,\n // so we already processed the pair\n (edge as any).symmetric !== undefined\n ) {\n continue;\n }\n\n const otherTableName = edge.to;\n const otherTable = schema[otherTableName];\n if (otherTable === undefined) {\n throw new Error(\n `Edge \"${edge.name}\" in table \"${tableName}\" ` +\n `points to an undefined table \"${otherTableName}\"`,\n );\n }\n\n const isSelfDirected = edge.to === tableName;\n\n const inverseEdgeCandidates = edgeConfigsBeforeDefineSchema(\n otherTable,\n ).filter(canBeInverseEdge(tableName, edge, isSelfDirected));\n if (inverseEdgeCandidates.length > 1) {\n throw new Error(\n `Edge \"${edge.name}\" in table \"${tableName}\" ` +\n `has too many potential inverse edges in table \"${otherTableName}\": ` +\n `${inverseEdgeCandidates\n .map((edge) => `\"${edge.name}\"`)\n .join(\", \")}`,\n );\n }\n const inverseEdge: EdgeConfigBeforeDefineSchema | undefined =\n inverseEdgeCandidates[0];\n\n if (\n edge.cardinality === \"single\" &&\n edge.type === \"field\" &&\n inverseEdge === undefined\n ) {\n throw new Error(\n `Missing inverse edge in table \"${otherTableName}\" ` +\n `for edge \"${edge.name}\" in table \"${tableName}\"`,\n );\n }\n\n // Default `ref` on the multiple end of the edge,\n if (edge.cardinality === \"single\" && edge.type === \"ref\") {\n if (inverseEdge === undefined) {\n throw new Error(\n `Missing inverse edge in table \"${otherTableName}\" ${\n edge.ref !== null ? `with field \"${edge.ref}\" ` : \"\"\n }for edge \"${edge.name}\" in table \"${tableName}\"`,\n );\n }\n if (\n inverseEdge.cardinality === \"single\" &&\n inverseEdge.type === \"ref\"\n ) {\n // TODO: If we want to support optional 1:1 edges in the future\n // throw new Error(\n // `Both edge \"${edge.name}\" on ent \"${inverseEdge.to}\" and ` +\n // `edge \"${inverseEdge.name}\" on ent \"${edge.to}\" are marked ` +\n // `as optional, specify which table should store the 1:1 edge by ` +\n // `providing a \\`field\\` name.`\n // );\n throw new Error(\n `Both edge \"${edge.name}\" in table \"${inverseEdge.to}\" and ` +\n `edge \"${inverseEdge.name}\" in table \"${edge.to}\" are marked ` +\n `as optional, choose one to be required.`,\n );\n }\n if (\n inverseEdge.cardinality !== \"single\" ||\n inverseEdge.type !== \"field\"\n ) {\n throw new Error(\n `Unexpected inverse edge type ${edge.name}, ${inverseEdge?.name}`,\n );\n }\n if (edge.ref === null) {\n (edge as any).ref = inverseEdge.field;\n }\n // For now the the non-optional end is always unique\n (inverseEdge as any).unique = true;\n }\n if (\n (edge.cardinality === \"single\" && edge.type === \"ref\") ||\n (edge.cardinality === \"multiple\" && edge.type === \"field\")\n ) {\n if (\n edge.deletion !== undefined &&\n deletionConfigFromEntDefinition(otherTable) === undefined\n ) {\n throw new Error(\n `Cannot specify soft deletion behavior for edge ` +\n `\"${edge.name}\" in table \"${tableName}\" ` +\n `because the target table \"${otherTableName}\" does not have ` +\n `a \"soft\" or \"scheduled\" deletion behavior ` +\n `configured.`,\n );\n }\n }\n if (edge.cardinality === \"multiple\") {\n if (!isSelfDirected && inverseEdge === undefined) {\n throw new Error(\n `Missing inverse edge in table \"${otherTableName}\" ` +\n `for edge \"${edge.name}\" in table \"${tableName}\"`,\n );\n }\n\n if (inverseEdge?.cardinality === \"single\") {\n if (inverseEdge.type === \"ref\") {\n throw new Error(\n `The edge \"${inverseEdge.name}\" in table \"${otherTableName}\" ` +\n `cannot be optional, as it must store the 1:many edge as a field. ` +\n `Check the its inverse edge \"${edge.name}\" in table \"${tableName}\".`,\n );\n }\n if (edge.type === \"ref\") {\n throw new Error(\n `The edge \"${inverseEdge.name}\" in table \"${otherTableName}\" ` +\n `cannot be singular, as the edge \"${edge.name}\" in table \"${tableName}\" did not ` +\n `specify the \\`ref\\` option.`,\n );\n }\n (edge as any).type = \"field\";\n (edge as any).ref = inverseEdge.field;\n }\n\n if (inverseEdge?.cardinality === \"multiple\" || isSelfDirected) {\n if (!isSelfDirected && edge?.type === \"field\") {\n throw new Error(\n `The edge \"${edge.name}\" in table \"${tableName}\" ` +\n `specified \\`ref\\`, but its inverse edge \"${inverseEdge.name}\" ` +\n `in table \"${otherTableName}\" is not the singular end of a 1:many edge.`,\n );\n }\n if (inverseEdge?.type === \"field\") {\n throw new Error(\n `The edge \"${inverseEdge.name}\" in table \"${otherTableName}\" ` +\n `specified \\`ref\\`, but its inverse edge \"${edge.name}\" ` +\n `in table \"${tableName}\" is not the singular end of a 1:many edge.`,\n );\n }\n\n const edgeTableName =\n edge.type === \"ref\" && edge.table !== undefined\n ? edge.table\n : inverseEdge === undefined\n ? `${tableName}_${edge.name}`\n : inverseEdge.name !== tableName\n ? `${tableName}_${inverseEdge.name}_to_${edge.name}`\n : `${inverseEdge.name}_to_${edge.name}`;\n\n const forwardId =\n edge.type === \"ref\" && edge.field !== undefined\n ? edge.field\n : inverseEdge === undefined\n ? \"aId\"\n : tableName === otherTableName\n ? inverseEdge.name + \"Id\"\n : tableName + \"Id\";\n const inverseId =\n isSelfDirected &&\n edge.type === \"ref\" &&\n edge.inverseField !== undefined\n ? edge.inverseField\n : inverseEdge === undefined\n ? \"bId\"\n : inverseEdge.type === \"ref\" && inverseEdge.field !== undefined\n ? inverseEdge.field\n : tableName === otherTableName\n ? edge.name + \"Id\"\n : otherTableName + \"Id\";\n // Add the table\n const edgeTable = defineEnt({\n [forwardId]: v.id(tableName),\n [inverseId]: v.id(otherTableName),\n })\n .index(forwardId, [forwardId])\n .index(inverseId, [inverseId])\n .index(`${forwardId}_${inverseId}`, [forwardId, inverseId]);\n const isSymmetric = inverseEdge === undefined;\n if (!isSymmetric) {\n edgeTable.index(`${inverseId}_${forwardId}`, [\n forwardId,\n inverseId,\n ]);\n }\n (schema as any)[edgeTableName] = edgeTable;\n (edge as any).type = \"ref\";\n (edge as any).table = edgeTableName;\n (edge as any).field = forwardId;\n (edge as any).ref = inverseId;\n (edge as any).symmetric = inverseEdge === undefined;\n if (inverseEdge !== undefined) {\n inverseEdge.type = \"ref\";\n (inverseEdge as any).table = edgeTableName;\n (inverseEdge as any).field = inverseId;\n (inverseEdge as any).ref = forwardId;\n (inverseEdge as any).symmetric = false;\n }\n }\n }\n }\n }\n return defineSchema(schema, options);\n}\n\nfunction canBeInverseEdge(\n tableName: string,\n edge: EdgeConfigBeforeDefineSchema,\n isSelfDirected: boolean,\n) {\n return (candidate: EdgeConfigBeforeDefineSchema) => {\n if (candidate.to !== tableName) {\n return false;\n }\n // Simple: pick out explicit inverse edges\n if (isSelfDirected) {\n return (\n candidate.cardinality === \"multiple\" &&\n candidate.type === \"ref\" &&\n candidate.inverse === edge.name\n );\n }\n // If both ref and field are known, only consider matching edges (from the ref side)\n if (\n (edge.cardinality === \"single\" &&\n edge.type === \"ref\" &&\n edge.ref !== null) ||\n (edge.cardinality === \"multiple\" &&\n edge.type === \"field\" &&\n edge.ref !== true)\n ) {\n if (candidate.cardinality === \"single\" && candidate.type === \"field\") {\n return edge.ref === candidate.field;\n }\n }\n // If both ref and field are known, only consider matching edges (from the field side)\n if (\n edge.cardinality === \"single\" &&\n edge.type === \"field\" &&\n edge.field !== null\n ) {\n if (\n (candidate.cardinality === \"single\" &&\n candidate.type === \"ref\" &&\n candidate.ref !== null) ||\n (candidate.cardinality === \"multiple\" &&\n candidate.type === \"field\" &&\n candidate.ref !== true)\n ) {\n return edge.field === candidate.ref;\n }\n }\n\n // If table is known on both ends, only consider matching edges\n if (\n edge.cardinality === \"multiple\" &&\n edge.type === \"ref\" &&\n edge.table !== undefined\n ) {\n return (\n candidate.cardinality === \"multiple\" &&\n candidate.type === \"ref\" &&\n edge.table === candidate.table\n );\n }\n if (\n candidate.cardinality === \"multiple\" &&\n candidate.type === \"ref\" &&\n candidate.table !== undefined\n ) {\n return (\n edge.cardinality === \"multiple\" &&\n edge.type === \"ref\" &&\n edge.table === candidate.table\n );\n }\n return true;\n };\n}\n\nfunction edgeConfigsBeforeDefineSchema(table: EntDefinition) {\n return Object.values(\n (table as any).edgeConfigs as Record<string, EdgeConfigBeforeDefineSchema>,\n );\n}\n\nfunction deletionConfigFromEntDefinition(table: EntDefinition) {\n return (table as any).deletionConfig as DeletionConfig | undefined;\n}\n\nexport function defineEnt<DocumentSchema extends PropertyValidators>(\n documentSchema: DocumentSchema,\n): EntDefinition<ObjectValidator<DocumentSchema>> {\n return new EntDefinitionImpl(documentSchema) as any;\n}\n\nexport function defineEntFromTable<\n DocumentType extends GenericValidator = GenericValidator,\n // eslint-disable-next-line @typescript-eslint/ban-types\n Indexes extends GenericTableIndexes = {},\n // eslint-disable-next-line @typescript-eslint/ban-types\n SearchIndexes extends GenericTableSearchIndexes = {},\n // eslint-disable-next-line @typescript-eslint/ban-types\n VectorIndexes extends GenericTableVectorIndexes = {},\n>(\n definition: TableDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes\n >,\n): EntDefinition<DocumentType, Indexes, SearchIndexes, VectorIndexes> {\n const validator: DocumentType = definition.validator;\n if (validator.kind !== \"object\") {\n throw new Error(\n \"Only tables with object definition are supported in Ents, not unions\",\n );\n }\n\n const entDefinition = defineEnt(validator.fields);\n // @ts-expect-error Private fields\n entDefinition.indexes = definition.indexes;\n // @ts-expect-error Private fields\n entDefinition.searchIndexes = definition.searchIndexes;\n // @ts-expect-error Private fields\n entDefinition.vectorIndexes = definition.vectorIndexes;\n return entDefinition as any;\n}\n\ntype DefineEntFromTables<\n T extends { [key: string]: TableDefinition<any, any, any, any> },\n> = {\n [K in keyof T]: T[K] extends TableDefinition<\n infer D,\n infer I,\n infer S,\n infer V\n >\n ? EntDefinition<D, I, S, V>\n : never;\n};\n\nexport function defineEntsFromTables<\n T extends { [key: string]: TableDefinition<any, any, any, any> },\n>(definitions: T): DefineEntFromTables<T> {\n const result: any = {};\n for (const key in definitions) {\n result[key] = defineEntFromTable(definitions[key]);\n }\n return result;\n}\n\ntype GenericEdges = Record<string, GenericEdgeConfig>;\n\nexport type GenericEdgeConfig = {\n name: string;\n to: string;\n cardinality: \"single\" | \"multiple\";\n type: \"field\" | \"ref\";\n};\n\ntype ExtractFieldPaths<T extends Validator<any, any, any>> =\n // Add in the system fields available in index definitions.\n // This should be everything except for `_id` because thats added to indexes\n // automatically.\n T[\"fieldPaths\"] | keyof SystemFields;\n\ntype ObjectFieldType<\n FieldName extends string,\n T extends Validator<any, any, any>,\n> = T[\"isOptional\"] extends \"optional\"\n ? { [key in FieldName]?: T[\"type\"] }\n : { [key in FieldName]: T[\"type\"] };\n\ntype AddField<\n V extends GenericValidator,\n FieldName extends string,\n P extends GenericValidator,\n> =\n // Note: We can't use the `AddField` type to add fields to a union type, but ents\n // do not support schemas with top level unions\n V extends VObject<\n infer TypeScriptType,\n infer Fields,\n infer IsOptional,\n infer FieldPaths\n >\n ? VObject<\n Expand<TypeScriptType & ObjectFieldType<FieldName, P>>,\n Expand<Fields & { FieldName: P }>,\n IsOptional,\n FieldPaths | FieldName\n >\n : V extends VAny\n ? VAny\n : never;\nexport interface EntDefinition<\n DocumentType extends Validator<any, any, any> = Validator<any, any, any>,\n // eslint-disable-next-line @typescript-eslint/ban-types\n Indexes extends GenericTableIndexes = {},\n // eslint-disable-next-line @typescript-eslint/ban-types\n SearchIndexes extends GenericTableSearchIndexes = {},\n // eslint-disable-next-line @typescript-eslint/ban-types\n VectorIndexes extends GenericTableVectorIndexes = {},\n // eslint-disable-next-line @typescript-eslint/ban-types\n Edges extends GenericEdges = {},\n> extends TableDefinition<DocumentType, Indexes, SearchIndexes, VectorIndexes> {\n /**\n * Define an index on this table.\n *\n * To learn about indexes, see [Defining Indexes](https://docs.convex.dev/using/indexes).\n *\n * @param name - The name of the index.\n * @param fields - The fields to index, in order. Must specify at least one\n * field.\n * @returns A {@link TableDefinition} with this index included.\n */\n index<\n IndexName extends string,\n FirstFieldPath extends ExtractFieldPaths<DocumentType>,\n RestFieldPaths extends ExtractFieldPaths<DocumentType>[],\n >(\n name: IndexName,\n fields: [FirstFieldPath, ...RestFieldPaths],\n ): EntDefinition<\n DocumentType,\n Expand<\n Indexes &\n Record<IndexName, [FirstFieldPath, ...RestFieldPaths, \"_creationTime\"]>\n >,\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n\n /**\n * Define a search index on this table.\n *\n * To learn about search indexes, see [Search](https://docs.convex.dev/text-search).\n *\n * @param name - The name of the index.\n * @param indexConfig - The search index configuration object.\n * @returns A {@link TableDefinition} with this search index included.\n */\n searchIndex<\n IndexName extends string,\n SearchField extends ExtractFieldPaths<DocumentType>,\n FilterFields extends ExtractFieldPaths<DocumentType> = never,\n >(\n name: IndexName,\n indexConfig: Expand<SearchIndexConfig<SearchField, FilterFields>>,\n ): EntDefinition<\n DocumentType,\n Indexes,\n Expand<\n SearchIndexes &\n Record<\n IndexName,\n {\n searchField: SearchField;\n filterFields: FilterFields;\n }\n >\n >,\n VectorIndexes,\n Edges\n >;\n\n // /**\n // * Define a vector index on this table.\n // *\n // * To learn about vector indexes, see [Vector Search](https://docs.convex.dev/vector-search).\n // *\n // * @param name - The name of the index.\n // * @param indexConfig - The vector index configuration object.\n // * @returns A {@link TableDefinition} with this vector index included.\n // */\n vectorIndex<\n IndexName extends string,\n VectorField extends ExtractFieldPaths<DocumentType>,\n FilterFields extends ExtractFieldPaths<DocumentType> = never,\n >(\n name: IndexName,\n indexConfig: Expand<VectorIndexConfig<VectorField, FilterFields>>,\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n Expand<\n VectorIndexes &\n Record<\n IndexName,\n {\n vectorField: VectorField;\n dimensions: number;\n filterFields: FilterFields;\n }\n >\n >,\n Edges\n >;\n\n field<FieldName extends string, T extends GenericValidator>(\n field: FieldName,\n validator: T,\n ): EntDefinition<\n AddField<DocumentType, FieldName, T>,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n field<FieldName extends string, T extends Validator<any, any, any>>(\n field: FieldName,\n validator: T,\n options: { index: true },\n ): EntDefinition<\n AddField<DocumentType, FieldName, T>,\n Indexes & { [key in FieldName]: [FieldName, \"_creationTime\"] },\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n field<FieldName extends string, T extends Validator<any, any, any>>(\n field: FieldName,\n validator: T,\n options: { unique: true },\n ): EntDefinition<\n AddField<DocumentType, FieldName, T>,\n Indexes & { [key in FieldName]: [FieldName, \"_creationTime\"] },\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n field<FieldName extends string, T extends Validator<any, \"required\", any>>(\n field: FieldName,\n validator: T,\n options: { default: T[\"type\"] },\n ): EntDefinition<\n AddField<DocumentType, FieldName, T>,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n\n edge<EdgeName extends string>(\n edge: EdgeName,\n ): EntDefinition<\n AddField<DocumentType, `${EdgeName}Id`, VId<GenericId<`${EdgeName}s`>>>,\n Indexes & { [key in `${EdgeName}Id`]: [`${EdgeName}Id`, \"_creationTime\"] },\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgeName]: {\n name: EdgeName;\n to: `${EdgeName}s`;\n type: \"field\";\n cardinality: \"single\";\n };\n }\n >;\n edge<EdgeName extends string, const FieldName extends string>(\n edge: EdgeName,\n options: { field: FieldName },\n ): EntDefinition<\n AddField<DocumentType, NoInfer<FieldName>, VId<GenericId<`${EdgeName}s`>>>,\n Indexes & {\n [key in NoInfer<FieldName>]: [NoInfer<FieldName>, \"_creationTime\"];\n },\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgeName]: {\n name: EdgeName;\n to: `${EdgeName}s`;\n type: \"field\";\n cardinality: \"single\";\n };\n }\n >;\n edge<\n EdgeName extends string,\n const FieldName extends string,\n const ToTable extends string,\n >(\n edge: EdgeName,\n options: { field: FieldName; to: ToTable },\n ): EntDefinition<\n AddField<DocumentType, NoInfer<FieldName>, VId<GenericId<`${ToTable}`>>>,\n Indexes & {\n [key in NoInfer<FieldName>]: [NoInfer<FieldName>, \"_creationTime\"];\n },\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgeName]: {\n name: EdgeName;\n to: ToTable;\n type: \"field\";\n cardinality: \"single\";\n };\n }\n >;\n edge<EdgeName extends string>(\n edge: EdgeName,\n options: {\n optional: true;\n ref?: string;\n deletion?: \"soft\";\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgeName]: {\n name: EdgeName;\n to: `${EdgeName}s`;\n type: \"ref\";\n cardinality: \"single\";\n };\n }\n >;\n edge<EdgeName extends string, const ToTable extends string>(\n edge: EdgeName,\n options: {\n optional: true;\n to: ToTable;\n ref?: string;\n deletion?: \"soft\";\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgeName]: {\n name: EdgeName;\n to: NoInfer<ToTable>;\n type: \"ref\";\n cardinality: \"single\";\n };\n }\n >;\n\n /**\n * Define many:1 edge to another table.\n * @param edge The name of the edge, also the name of the target table.\n * @param options.ref The name of the field that stores the many:1 edge\n * on the other table, or `true` to infer it.\n */\n edges<EdgesName extends string>(\n edge: EdgesName,\n options: {\n ref: true | string;\n deletion?: \"soft\";\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgesName]: {\n name: EdgesName;\n to: EdgesName;\n type: \"field\";\n cardinality: \"multiple\";\n };\n }\n >;\n /**\n * Define many:1 edge to another table.\n * @param edge The name of the edge.\n * @param options.to Name of the table the edge points to.\n * If it's the same as the table this edge is defined on, this edge is\n * a symmetric, self-directed many:many edge.\n * @param options.ref The name of the field that stores the many:1 edge\n * on the other table, or `true` to infer it.\n */\n edges<EdgesName extends string, TableName extends string>(\n edge: EdgesName,\n options: {\n to: TableName;\n ref: true | string;\n deletion?: \"soft\";\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgesName]: {\n name: EdgesName;\n to: NoInfer<TableName>;\n type: \"field\";\n cardinality: \"multiple\";\n };\n }\n >;\n\n /**\n * Define many:many edge to another table.\n * @param edge The name of the edge, also the name of the target table.\n * @param options.table Optional, name of the table to store the many:many edge in.\n * @param options.field Optional, name of the field to store the ID of the\n * this end of the many:many edge.\n */\n edges<EdgesName extends string>(\n edge: EdgesName,\n options?: {\n table?: string;\n field?: string;\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgesName]: {\n name: EdgesName;\n to: EdgesName;\n type: \"ref\";\n cardinality: \"multiple\";\n };\n }\n >;\n /**\n * Define many:many edge to another table.\n * @param edge The name of the edge.\n * @param options.to Name of the table the edge points to.\n * If it's the same as the table this edge is defined on, this edge is\n * a symmetric, self-directed many:many edge.\n * @param options.table Optional, name of the table to store the many:many edge in.\n * @param options.field Optional, name of the field to store the ID of the\n * of the source end of the forward many:many edge.\n * @param options.inverseField Optional, name of the field to store the ID\n * of the target end of the forward edge. Only allowed for symmetric,\n * self-directed many:many edges.\n */\n edges<EdgesName extends string, TableName extends string>(\n edge: EdgesName,\n options: {\n to: TableName;\n table?: string;\n field?: string;\n inverseField?: string;\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgesName]: {\n name: EdgesName;\n to: NoInfer<TableName>;\n type: \"ref\";\n cardinality: \"multiple\";\n };\n }\n >;\n /**\n * Define self-directed, assymetric, many:many edge.\n * @param edge The name of the edge.\n * @param options.to Name of the table the edge points to.\n * Must be the same as the table this edge is defined on.\n * @param options.inverse Name of the inverse edge.\n * @param options.table Optional, name of the table to store the many:many edge in.\n * @param options.field Optional, name of the field to store the ID of the\n * of the source end of the forward many:many edge.\n * @param options.inverseField Optional, name of the field to store the ID\n * of the target end of the forward many:many edge.\n */\n edges<\n EdgesName extends string,\n TableName extends string,\n InverseEdgesNames extends string,\n >(\n edge: EdgesName,\n options: {\n to: TableName;\n inverse: InverseEdgesNames;\n table?: string;\n field?: string;\n inverseField?: string;\n },\n ): EntDefinition<\n DocumentType,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges & {\n [key in EdgesName]: {\n name: EdgesName;\n to: NoInfer<TableName>;\n type: \"ref\";\n cardinality: \"multiple\";\n };\n } & {\n [key in NoInfer<InverseEdgesNames>]: {\n name: NoInfer<InverseEdgesNames>;\n to: NoInfer<TableName>;\n type: \"ref\";\n cardinality: \"multiple\";\n };\n }\n >;\n\n /**\n * Add the \"soft\" deletion behavior to this ent.\n *\n * When the ent is \"soft\" deleted, its `deletionTime` field is set to the\n * current time and it is not actually deleted.\n *\n * @param type `\"soft\"`\n */\n deletion(\n type: \"soft\",\n ): EntDefinition<\n AddField<DocumentType, \"deletionTime\", VOptional<VFloat64>>,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n /**\n * Add the \"scheduled\" deletion behavior to this ent.\n *\n * The ent is first \"soft\" deleted and its hard deletion is scheduled\n * to run in a separate mutation.\n *\n * @param type `\"scheduled\"`\n * @param options.delayMs If the `delayMs` option is specified,\n * the hard deletion is scheduled to happen after the specified\n * time duration.\n */\n deletion(\n type: \"scheduled\",\n options?: {\n delayMs: number;\n },\n ): EntDefinition<\n AddField<DocumentType, \"deletionTime\", VOptional<VFloat64>>,\n Indexes,\n SearchIndexes,\n VectorIndexes,\n Edges\n >;\n}\n\ntype NoInfer<T> = [T][T extends any ? 0 : never];\n\ntype FieldOptions = {\n index?: true;\n unique?: true;\n default?: any;\n};\n\ntype EdgeOptions = {\n optional?: true;\n field?: string;\n ref?: string;\n to?: string;\n};\n\ntype EdgesOptions = {\n to?: string;\n inverse?: string;\n ref?: string;\n table?: string;\n field?: string;\n inverseField?: string;\n deletion: \"soft\";\n};\n\nclass EntDefinitionImpl {\n validator: GenericValidator;\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n private indexes: Index[] = [];\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n private searchIndexes: SearchIndex[] = [];\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n private vectorIndexes: VectorIndex[] = [];\n\n private documentSchema: Record<string, Validator<any, any, any>>;\n\n private edgeConfigs: Record<string, EdgeConfigBeforeDefineSchema> = {};\n\n private fieldConfigs: Record<string, FieldConfig> = {};\n\n private defaults: Record<string, any> = {};\n\n private deletionConfig: DeletionConfig | undefined;\n\n constructor(documentSchema: Record<string, Validator<any, any, any>>) {\n this.documentSchema = documentSchema;\n this.validator = v.object(documentSchema);\n }\n\n index(name: any, fields: any) {\n this.indexes.push({ indexDescriptor: name, fields });\n return this;\n }\n\n searchIndex(name: any, indexConfig: any) {\n this.searchIndexes.push({\n indexDescriptor: name,\n searchField: indexConfig.searchField,\n filterFields: indexConfig.filterFields || [],\n });\n return this;\n }\n\n vectorIndex(name: any, indexConfig: any) {\n this.vectorIndexes.push({\n indexDescriptor: name,\n vectorField: indexConfig.vectorField,\n dimensions: indexConfig.dimensions,\n filterFields: indexConfig.filterFields || [],\n });\n return this;\n }\n\n /**\n * Export the contents of this definition.\n *\n * This is called internally by the Convex framework.\n * @internal\n */\n export() {\n return {\n indexes: this.indexes,\n searchIndexes: this.searchIndexes,\n vectorIndexes: this.vectorIndexes,\n documentType: (v.object(this.documentSchema) as any).json,\n };\n }\n\n field(name: string, validator: any, options?: FieldOptions): this {\n if (this.documentSchema[name] !== undefined) {\n // TODO: Store the fieldConfigs in an array so that we can\n // do the uniqueness check in defineEntSchema where we\n // know the table name.\n throw new Error(`Duplicate field \"${name}\"`);\n }\n const finalValidator =\n options?.default !== undefined ? v.optional(validator) : validator;\n this.documentSchema = { ...this.documentSchema, [name]: finalValidator };\n if (options?.unique === true || options?.index === true) {\n this.indexes.push({ indexDescriptor: name, fields: [name] });\n }\n if (options?.default !== undefined) {\n this.defaults[name] = options.default;\n }\n if (options?.unique === true) {\n this.fieldConfigs[name] = { name, unique: true };\n }\n return this;\n }\n\n edge(edgeName: string, options?: EdgeOptions): this {\n if (this.edgeConfigs[edgeName] !== undefined) {\n // TODO: Store the edgeConfigs in an array so that we can\n // do the uniqueness check in defineEntSchema where we\n // know the source table name.\n throw new Error(`Duplicate edge \"${edgeName}\"`);\n }\n const to = options?.to ?? edgeName + \"s\";\n if (options?.optional !== true) {\n const fieldName = options?.field ?? edgeName + \"Id\";\n this.documentSchema = { ...this.documentSchema, [fieldName]: v.id(to) };\n this.edgeConfigs[edgeName] = {\n name: edgeName,\n to,\n cardinality: \"single\",\n type: \"field\",\n field: fieldName,\n };\n this.indexes.push({\n indexDescriptor: fieldName,\n fields: [fieldName],\n });\n return this;\n }\n if (options.optional === true) {\n this.edgeConfigs[edgeName] = {\n name: edgeName,\n to,\n cardinality: \"single\",\n type: \"ref\",\n ref: options.ref ?? null,\n };\n }\n return this;\n }\n\n edges(name: string, options?: EdgesOptions): this {\n const cardinality = \"multiple\";\n const to = options?.to ?? name;\n const ref = options?.ref;\n const table = options?.table;\n // TODO: Do this later when we have the table name,\n // or rework schema to use a builder pattern.\n if (ref !== undefined && table !== undefined) {\n throw new Error(\n `Cannot specify both \\`ref\\` and \\`table\\` for the same edge, ` +\n `as the former is for 1:many edges and the latter ` +\n `for many:many edges. Config: \\`${JSON.stringify(options)}\\``,\n );\n }\n const field = options?.field;\n const inverseField = options?.inverseField;\n // TODO: Do this later when we have the table name,\n // or rework schema to use a builder pattern.\n if (\n (field !== undefined || inverseField !== undefined) &&\n table === undefined\n ) {\n throw new Error(\n `Specify \\`table\\` if you're customizing the \\`field\\` or ` +\n `\\`inverseField\\` for a many:many edge. ` +\n `Config: \\`${JSON.stringify(options)}\\``,\n );\n }\n const inverseName = options?.inverse;\n const deletion = options?.deletion;\n this.edgeConfigs[name] =\n ref !== undefined\n ? { name, to, cardinality, type: \"field\", ref, deletion }\n : { name, to, cardinality, type: \"ref\", table, field, inverseField };\n if (inverseName !== undefined) {\n this.edgeConfigs[inverseName] = {\n name: inverseName,\n to,\n cardinality,\n type: \"ref\",\n inverse: name,\n table,\n };\n }\n return this;\n }\n\n deletion(type: \"soft\" | \"scheduled\", options?: { delayMs: number }): this {\n if (this.documentSchema.deletionTime !== undefined) {\n // TODO: Put the check where we know the table name.\n throw new Error(\n `Cannot enable \"${type}\" deletion because \"deletionTime\" field ` +\n `was already defined.`,\n );\n }\n if (this.deletionConfig !== undefined) {\n // TODO: Put the check where we know the table name.\n throw new Error(`Deletion behavior can only be specified once.`);\n }\n this.documentSchema = {\n ...this.documentSchema,\n deletionTime: v.optional(v.number()),\n };\n this.deletionConfig = { type, ...options };\n return this;\n }\n}\n\nexport type EdgeConfig = {\n name: string;\n to: string;\n} & (\n | ({\n cardinality: \"single\";\n } & (\n | {\n type: \"field\";\n field: string;\n unique: boolean;\n }\n | {\n type: \"ref\";\n ref: string;\n deletion?: \"soft\";\n }\n ))\n | ({\n cardinality: \"multiple\";\n } & (\n | {\n type: \"field\";\n ref: string;\n deletion?: \"soft\";\n }\n | {\n type: \"ref\";\n table: string;\n field: string;\n ref: string;\n inverse: boolean;\n symmetric: boolean;\n }\n ))\n);\n\ntype EdgeConfigBeforeDefineSchema = {\n name: string;\n to: string;\n} & (\n | ({\n cardinality: \"single\";\n } & (\n | {\n type: \"field\";\n field: string;\n }\n | {\n type: \"ref\";\n ref: null | string;\n deletion?: \"soft\";\n }\n ))\n | ({\n cardinality: \"multiple\";\n } & (\n | {\n type: \"field\";\n ref: true | string;\n deletion?: \"soft\";\n }\n | {\n type: \"ref\";\n table?: string;\n field?: string;\n inverseField?: string;\n inverse?: string;\n }\n ))\n);\n\nexport type FieldConfig = {\n name: string;\n unique: boolean;\n};\n\nexport type Expand<ObjectType extends Record<any, any>> =\n ObjectType extends Record<any, any>\n ? {\n [Key in keyof ObjectType]: ObjectType[Key];\n }\n : never;\nexport type SystemFields = {\n _creationTime: number;\n};\n\ntype ObjectValidator<Validators extends PropertyValidators> = VObject<\n // Compute the TypeScript type this validator refers to.\n ObjectType<Validators>,\n Validators\n>;\n\nexport type GenericEntsDataModel = GenericDataModel &\n Record<string, GenericEntModel>;\n\nexport type GenericEntModel = {\n edges: Record<string, GenericEdgeConfig>;\n};\n\nexport type DeletionConfig =\n | {\n type: \"soft\";\n }\n | {\n type: \"scheduled\";\n delayMs?: number;\n };\n\nexport type EntDataModelFromSchema<\n SchemaDef extends SchemaDefinition<any, boolean>,\n> = DataModelFromSchemaDefinition<SchemaDef> & {\n [TableName in keyof SchemaDef[\"tables\"] &\n string]: SchemaDef[\"tables\"][TableName] extends EntDefinition<\n any,\n any,\n any,\n any,\n infer Edges\n >\n ? {\n edges: Edges;\n }\n : never;\n};\n\nexport function getEntDefinitions<\n SchemaDef extends SchemaDefinition<any, boolean>,\n>(schema: SchemaDef): EntDataModelFromSchema<typeof schema> {\n const tables = schema.tables;\n return Object.entries(tables).reduce(\n (acc, [tableName, table]: [any, any]) => {\n acc[tableName] = {\n indexes: (\n table.indexes as {\n indexDescriptor: string;\n fields: string[];\n }[]\n ).reduce(\n (acc, { indexDescriptor, fields }) => {\n acc[indexDescriptor] = fields;\n return acc;\n },\n {} as Record<string, string[]>,\n ),\n defaults: table.defaults,\n edges: table.edgeConfigs,\n fields: table.fieldConfigs,\n deletionConfig: table.deletionConfig,\n };\n return acc;\n },\n {} as Record<string, any>,\n ) as any;\n}\n"],"mappings":"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","names":["edge","acc"]}
|
package/dist/writer.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import 'convex/server';
|
|
2
2
|
import 'convex/values';
|
|
3
|
-
export { E as EdgeChanges, a as WithEdgeInserts, c as WithEdgePatches, b as WithEdges, W as WriterImplBase } from './index-
|
|
3
|
+
export { E as EdgeChanges, a as WithEdgeInserts, c as WithEdgePatches, b as WithEdges, W as WriterImplBase } from './index-nOBiMg01.js';
|
|
4
4
|
import './schema.js';
|
|
5
5
|
import './deletion.js';
|
package/dist/writer.js
CHANGED
|
@@ -80,8 +80,13 @@ var PromiseQueryOrNullImpl = class _PromiseQueryOrNullImpl extends Promise {
|
|
|
80
80
|
this.ctx,
|
|
81
81
|
this.entDefinitions,
|
|
82
82
|
this.table,
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
async () => {
|
|
84
|
+
const query = await this.retrieve();
|
|
85
|
+
if (query === null) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return await query.paginate(paginationOpts);
|
|
89
|
+
}
|
|
85
90
|
);
|
|
86
91
|
}
|
|
87
92
|
take(n) {
|
|
@@ -197,50 +202,23 @@ var PromiseQueryOrNullImpl = class _PromiseQueryOrNullImpl extends Promise {
|
|
|
197
202
|
}
|
|
198
203
|
async _take(n) {
|
|
199
204
|
const query = await this.retrieve();
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
let numItems = n;
|
|
208
|
-
const docs = [];
|
|
209
|
-
let hasMore = true;
|
|
210
|
-
const iterator = query[Symbol.asyncIterator]();
|
|
211
|
-
while (hasMore && docs.length < n) {
|
|
212
|
-
const page = [];
|
|
213
|
-
for (let i = 0; i < numItems; i++) {
|
|
214
|
-
const { done, value } = await iterator.next();
|
|
215
|
-
if (done) {
|
|
216
|
-
hasMore = false;
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
page.push(value);
|
|
220
|
-
}
|
|
221
|
-
docs.push(
|
|
222
|
-
...(await filterByReadRule(
|
|
223
|
-
this.ctx,
|
|
224
|
-
this.entDefinitions,
|
|
225
|
-
this.table,
|
|
226
|
-
page,
|
|
227
|
-
false
|
|
228
|
-
)).slice(0, n - docs.length)
|
|
229
|
-
);
|
|
230
|
-
numItems = Math.min(64, numItems * 2);
|
|
231
|
-
}
|
|
232
|
-
return docs;
|
|
205
|
+
return await takeFromQuery(
|
|
206
|
+
query,
|
|
207
|
+
n,
|
|
208
|
+
this.ctx,
|
|
209
|
+
this.entDefinitions,
|
|
210
|
+
this.table
|
|
211
|
+
);
|
|
233
212
|
}
|
|
234
213
|
};
|
|
235
214
|
var PromisePaginationResultOrNullImpl = class extends Promise {
|
|
236
|
-
constructor(ctx, entDefinitions, table, retrieve
|
|
215
|
+
constructor(ctx, entDefinitions, table, retrieve) {
|
|
237
216
|
super(() => {
|
|
238
217
|
});
|
|
239
218
|
this.ctx = ctx;
|
|
240
219
|
this.entDefinitions = entDefinitions;
|
|
241
220
|
this.table = table;
|
|
242
221
|
this.retrieve = retrieve;
|
|
243
|
-
this.paginationOpts = paginationOpts;
|
|
244
222
|
}
|
|
245
223
|
async map(callbackFn) {
|
|
246
224
|
const result = await this;
|
|
@@ -253,11 +231,10 @@ var PromisePaginationResultOrNullImpl = class extends Promise {
|
|
|
253
231
|
};
|
|
254
232
|
}
|
|
255
233
|
async docs() {
|
|
256
|
-
const
|
|
257
|
-
if (
|
|
234
|
+
const result = await this.retrieve();
|
|
235
|
+
if (result === null) {
|
|
258
236
|
return null;
|
|
259
237
|
}
|
|
260
|
-
const result = await query.paginate(this.paginationOpts);
|
|
261
238
|
return {
|
|
262
239
|
...result,
|
|
263
240
|
page: await filterByReadRule(
|
|
@@ -390,15 +367,185 @@ var PromiseEntsOrNullImpl = class extends Promise {
|
|
|
390
367
|
).then(onfulfilled, onrejected);
|
|
391
368
|
}
|
|
392
369
|
};
|
|
393
|
-
var PromiseEdgeOrNullImpl = class extends PromiseEntsOrNullImpl {
|
|
394
|
-
constructor(ctx, entDefinitions, table,
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
370
|
+
var PromiseEdgeOrNullImpl = class _PromiseEdgeOrNullImpl extends PromiseEntsOrNullImpl {
|
|
371
|
+
constructor(ctx, entDefinitions, table, edgeDefinition, retrieveSourceId, retrieveQuery, retrieveDoc = async (edgeDoc) => {
|
|
372
|
+
const sourceId = edgeDoc[edgeDefinition.field];
|
|
373
|
+
const targetId = edgeDoc[edgeDefinition.ref];
|
|
374
|
+
const doc = await this.ctx.db.get(targetId);
|
|
375
|
+
if (doc === null) {
|
|
376
|
+
throw new Error(
|
|
377
|
+
`Dangling reference for edge "${edgeDefinition.name}" in table "${this.table}" for document with ID "${sourceId}": Could not find a document with ID "${targetId}" in table "${edgeDefinition.to}" (edge document ID is "${edgeDoc._id}").`
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
return doc;
|
|
381
|
+
}) {
|
|
382
|
+
super(
|
|
383
|
+
ctx,
|
|
384
|
+
entDefinitions,
|
|
385
|
+
table,
|
|
386
|
+
async () => {
|
|
387
|
+
const query = await retrieveQuery();
|
|
388
|
+
if (query === null) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
const edgeDocs = await query.collect();
|
|
392
|
+
return await Promise.all(edgeDocs.map(retrieveDoc));
|
|
393
|
+
},
|
|
394
|
+
false
|
|
395
|
+
);
|
|
396
|
+
this.edgeDefinition = edgeDefinition;
|
|
397
|
+
this.retrieveSourceId = retrieveSourceId;
|
|
398
|
+
this.retrieveQuery = retrieveQuery;
|
|
399
|
+
this.retrieveDoc = retrieveDoc;
|
|
398
400
|
}
|
|
399
|
-
async has(
|
|
400
|
-
const
|
|
401
|
-
|
|
401
|
+
async has(targetId) {
|
|
402
|
+
const sourceId = await this.retrieveSourceId();
|
|
403
|
+
if (sourceId === null) {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
const edgeDoc = this.ctx.db.query(this.edgeDefinition.table).withIndex(
|
|
407
|
+
`${this.edgeDefinition.field}_${this.edgeDefinition.ref}`,
|
|
408
|
+
(q) => q.eq(this.edgeDefinition.field, sourceId).eq(
|
|
409
|
+
this.edgeDefinition.ref,
|
|
410
|
+
targetId
|
|
411
|
+
)
|
|
412
|
+
).first();
|
|
413
|
+
return edgeDoc !== null;
|
|
414
|
+
}
|
|
415
|
+
order(order) {
|
|
416
|
+
return new _PromiseEdgeOrNullImpl(
|
|
417
|
+
this.ctx,
|
|
418
|
+
this.entDefinitions,
|
|
419
|
+
this.table,
|
|
420
|
+
this.edgeDefinition,
|
|
421
|
+
this.retrieveSourceId,
|
|
422
|
+
async () => {
|
|
423
|
+
const query = await this.retrieveQuery();
|
|
424
|
+
if (query === null) {
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
return query.order(order);
|
|
428
|
+
}
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
paginate(paginationOpts) {
|
|
432
|
+
return new PromisePaginationResultOrNullImpl(
|
|
433
|
+
this.ctx,
|
|
434
|
+
this.entDefinitions,
|
|
435
|
+
this.table,
|
|
436
|
+
async () => {
|
|
437
|
+
const query = await this.retrieveQuery();
|
|
438
|
+
if (query === null) {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
const result = await query.paginate(paginationOpts);
|
|
442
|
+
return {
|
|
443
|
+
...result,
|
|
444
|
+
page: await Promise.all(result.page.map(this.retrieveDoc))
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
take(n) {
|
|
450
|
+
return new PromiseEntsOrNullImpl(
|
|
451
|
+
this.ctx,
|
|
452
|
+
this.entDefinitions,
|
|
453
|
+
this.table,
|
|
454
|
+
async () => {
|
|
455
|
+
return await this._take(n);
|
|
456
|
+
},
|
|
457
|
+
false
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
first() {
|
|
461
|
+
return new PromiseEntOrNullImpl(
|
|
462
|
+
this.ctx,
|
|
463
|
+
this.entDefinitions,
|
|
464
|
+
this.table,
|
|
465
|
+
async () => {
|
|
466
|
+
const docs = await this._take(1);
|
|
467
|
+
if (docs === null) {
|
|
468
|
+
return nullRetriever;
|
|
469
|
+
}
|
|
470
|
+
const [doc] = docs;
|
|
471
|
+
return loadedRetriever(doc);
|
|
472
|
+
},
|
|
473
|
+
false
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
firstX() {
|
|
477
|
+
return new PromiseEntWriterImpl(
|
|
478
|
+
this.ctx,
|
|
479
|
+
this.entDefinitions,
|
|
480
|
+
this.table,
|
|
481
|
+
async () => {
|
|
482
|
+
const docs = await this._take(1);
|
|
483
|
+
if (docs === null) {
|
|
484
|
+
return nullRetriever;
|
|
485
|
+
}
|
|
486
|
+
const [doc] = docs;
|
|
487
|
+
if (doc === void 0) {
|
|
488
|
+
throw new Error("Query returned no documents");
|
|
489
|
+
}
|
|
490
|
+
return loadedRetriever(doc);
|
|
491
|
+
},
|
|
492
|
+
false
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
unique() {
|
|
496
|
+
return new PromiseEntOrNullImpl(
|
|
497
|
+
this.ctx,
|
|
498
|
+
this.entDefinitions,
|
|
499
|
+
this.table,
|
|
500
|
+
async () => {
|
|
501
|
+
const docs = await this._take(2);
|
|
502
|
+
if (docs === null) {
|
|
503
|
+
return nullRetriever;
|
|
504
|
+
}
|
|
505
|
+
if (docs.length === 0) {
|
|
506
|
+
return nullRetriever;
|
|
507
|
+
}
|
|
508
|
+
if (docs.length === 2) {
|
|
509
|
+
throw new Error("unique() query returned more than one result");
|
|
510
|
+
}
|
|
511
|
+
const [doc] = docs;
|
|
512
|
+
return loadedRetriever(doc);
|
|
513
|
+
},
|
|
514
|
+
false
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
uniqueX() {
|
|
518
|
+
return new PromiseEntWriterImpl(
|
|
519
|
+
this.ctx,
|
|
520
|
+
this.entDefinitions,
|
|
521
|
+
this.table,
|
|
522
|
+
async () => {
|
|
523
|
+
const docs = await this._take(2);
|
|
524
|
+
if (docs === null) {
|
|
525
|
+
return nullRetriever;
|
|
526
|
+
}
|
|
527
|
+
if (docs.length === 0) {
|
|
528
|
+
throw new Error("Query returned no documents");
|
|
529
|
+
}
|
|
530
|
+
if (docs.length === 2) {
|
|
531
|
+
throw new Error("unique() query returned more than one result");
|
|
532
|
+
}
|
|
533
|
+
const [doc] = docs;
|
|
534
|
+
return loadedRetriever(doc);
|
|
535
|
+
},
|
|
536
|
+
true
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
async _take(n) {
|
|
540
|
+
const query = await this.retrieveQuery();
|
|
541
|
+
return await takeFromQuery(
|
|
542
|
+
query,
|
|
543
|
+
n,
|
|
544
|
+
this.ctx,
|
|
545
|
+
this.entDefinitions,
|
|
546
|
+
this.table,
|
|
547
|
+
this.retrieveDoc
|
|
548
|
+
);
|
|
402
549
|
}
|
|
403
550
|
};
|
|
404
551
|
var PromiseEntOrNullImpl = class extends Promise {
|
|
@@ -452,29 +599,21 @@ var PromiseEntOrNullImpl = class extends Promise {
|
|
|
452
599
|
return new PromiseEdgeOrNullImpl(
|
|
453
600
|
this.ctx,
|
|
454
601
|
this.entDefinitions,
|
|
455
|
-
|
|
456
|
-
edgeDefinition
|
|
457
|
-
async (
|
|
602
|
+
this.table,
|
|
603
|
+
edgeDefinition,
|
|
604
|
+
async () => {
|
|
605
|
+
const { id } = await this.retrieve();
|
|
606
|
+
return id;
|
|
607
|
+
},
|
|
608
|
+
async () => {
|
|
458
609
|
const { id } = await this.retrieve();
|
|
459
610
|
if (id === null) {
|
|
460
611
|
return null;
|
|
461
612
|
}
|
|
462
|
-
|
|
613
|
+
return this.ctx.db.query(edgeDefinition.table).withIndex(
|
|
463
614
|
edgeDefinition.field,
|
|
464
|
-
(q) =>
|
|
465
|
-
)
|
|
466
|
-
return (await Promise.all(
|
|
467
|
-
edgeDocs.map(
|
|
468
|
-
(edgeDoc) => this.ctx.db.get(edgeDoc[edgeDefinition.ref])
|
|
469
|
-
)
|
|
470
|
-
)).filter((doc, i) => {
|
|
471
|
-
if (doc === null) {
|
|
472
|
-
throw new Error(
|
|
473
|
-
`Dangling reference for edge "${edgeDefinition.name}" in table "${this.table}" for document with ID "${id}": Could not find a document with ID "${edgeDocs[i][edgeDefinition.field]}" in table "${edgeDefinition.to}" (edge document ID is "${edgeDocs[i]._id}").`
|
|
474
|
-
);
|
|
475
|
-
}
|
|
476
|
-
return true;
|
|
477
|
-
});
|
|
615
|
+
(q) => q.eq(edgeDefinition.field, id)
|
|
616
|
+
);
|
|
478
617
|
}
|
|
479
618
|
);
|
|
480
619
|
}
|
|
@@ -798,6 +937,45 @@ function loadedRetriever(doc) {
|
|
|
798
937
|
doc: async () => doc
|
|
799
938
|
};
|
|
800
939
|
}
|
|
940
|
+
async function takeFromQuery(query, n, ctx, entDefinitions, table, mapToResult) {
|
|
941
|
+
if (query === null) {
|
|
942
|
+
return null;
|
|
943
|
+
}
|
|
944
|
+
const readPolicy = getReadRule(entDefinitions, table);
|
|
945
|
+
if (readPolicy === void 0) {
|
|
946
|
+
const results = await query.take(n);
|
|
947
|
+
if (mapToResult === void 0) {
|
|
948
|
+
return results;
|
|
949
|
+
}
|
|
950
|
+
return Promise.all(results.map(mapToResult));
|
|
951
|
+
}
|
|
952
|
+
let numItems = n;
|
|
953
|
+
const docs = [];
|
|
954
|
+
let hasMore = true;
|
|
955
|
+
const iterator = query[Symbol.asyncIterator]();
|
|
956
|
+
while (hasMore && docs.length < n) {
|
|
957
|
+
const page = [];
|
|
958
|
+
for (let i = 0; i < numItems; i++) {
|
|
959
|
+
const { done, value } = await iterator.next();
|
|
960
|
+
if (done) {
|
|
961
|
+
hasMore = false;
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
page.push(mapToResult === void 0 ? value : await mapToResult(value));
|
|
965
|
+
}
|
|
966
|
+
docs.push(
|
|
967
|
+
...(await filterByReadRule(
|
|
968
|
+
ctx,
|
|
969
|
+
entDefinitions,
|
|
970
|
+
table,
|
|
971
|
+
page,
|
|
972
|
+
false
|
|
973
|
+
)).slice(0, n - docs.length)
|
|
974
|
+
);
|
|
975
|
+
numItems = Math.min(64, numItems * 2);
|
|
976
|
+
}
|
|
977
|
+
return docs;
|
|
978
|
+
}
|
|
801
979
|
async function filterByReadRule(ctx, entDefinitions, table, docs, throwIfNull) {
|
|
802
980
|
if (docs === null) {
|
|
803
981
|
return null;
|