convex-ents 0.1.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.
@@ -0,0 +1,293 @@
1
+ import { DefineSchemaOptions, SchemaDefinition, GenericDocument, GenericTableIndexes, GenericTableSearchIndexes, GenericTableVectorIndexes, TableDefinition, SearchIndexConfig, VectorIndexConfig, GenericDataModel, DataModelFromSchemaDefinition } from 'convex/server';
2
+ import { Validator, GenericId, PropertyValidators, ObjectType } from 'convex/values';
3
+
4
+ declare function defineEntSchema<Schema extends Record<string, EntDefinition>, StrictTableNameTypes extends boolean = true>(schema: Schema, options?: DefineSchemaOptions<StrictTableNameTypes>): SchemaDefinition<Schema, StrictTableNameTypes>;
5
+ declare function defineEnt<DocumentSchema extends Record<string, Validator<any, any, any>>>(documentSchema: DocumentSchema): EntDefinition<ExtractDocument<ObjectValidator<DocumentSchema>>, ExtractFieldPaths<ObjectValidator<DocumentSchema>>>;
6
+ type GenericEdges = Record<string, GenericEdgeConfig>;
7
+ type GenericEdgeConfig = {
8
+ name: string;
9
+ to: string;
10
+ cardinality: "single" | "multiple";
11
+ type: "field" | "ref";
12
+ };
13
+ interface EntDefinition<Document extends GenericDocument = GenericDocument, FieldPaths extends string = string, Indexes extends GenericTableIndexes = {}, SearchIndexes extends GenericTableSearchIndexes = {}, VectorIndexes extends GenericTableVectorIndexes = {}, Edges extends GenericEdges = {}> extends TableDefinition<Document, FieldPaths, Indexes, SearchIndexes, VectorIndexes> {
14
+ /**
15
+ * Define an index on this table.
16
+ *
17
+ * To learn about indexes, see [Defining Indexes](https://docs.convex.dev/using/indexes).
18
+ *
19
+ * @param name - The name of the index.
20
+ * @param fields - The fields to index, in order. Must specify at least one
21
+ * field.
22
+ * @returns A {@link TableDefinition} with this index included.
23
+ */
24
+ index<IndexName extends string, FirstFieldPath extends FieldPaths, RestFieldPaths extends FieldPaths[]>(name: IndexName, fields: [FirstFieldPath, ...RestFieldPaths]): EntDefinition<Document, FieldPaths, Expand<Indexes & Record<IndexName, [FirstFieldPath, ...RestFieldPaths, "_creationTime"]>>, SearchIndexes, VectorIndexes, Edges>;
25
+ /**
26
+ * Define a search index on this table.
27
+ *
28
+ * To learn about search indexes, see [Search](https://docs.convex.dev/text-search).
29
+ *
30
+ * @param name - The name of the index.
31
+ * @param indexConfig - The search index configuration object.
32
+ * @returns A {@link TableDefinition} with this search index included.
33
+ */
34
+ searchIndex<IndexName extends string, SearchField extends FieldPaths, FilterFields extends FieldPaths = never>(name: IndexName, indexConfig: Expand<SearchIndexConfig<SearchField, FilterFields>>): EntDefinition<Document, FieldPaths, Indexes, Expand<SearchIndexes & Record<IndexName, {
35
+ searchField: SearchField;
36
+ filterFields: FilterFields;
37
+ }>>, VectorIndexes, Edges>;
38
+ vectorIndex<IndexName extends string, VectorField extends FieldPaths, FilterFields extends FieldPaths = never>(name: IndexName, indexConfig: Expand<VectorIndexConfig<VectorField, FilterFields>>): EntDefinition<Document, FieldPaths, Indexes, SearchIndexes, Expand<VectorIndexes & Record<IndexName, {
39
+ vectorField: VectorField;
40
+ dimensions: number;
41
+ filterFields: FilterFields;
42
+ }>>, Edges>;
43
+ field<FieldName extends string, T extends Validator<any, any, any>>(field: FieldName, validator: T): EntDefinition<Document & ObjectFieldType<FieldName, T>, FieldPaths | FieldName, Indexes, SearchIndexes, VectorIndexes, Edges>;
44
+ field<FieldName extends string, T extends Validator<any, any, any>>(field: FieldName, validator: T, options: {
45
+ index: true;
46
+ }): EntDefinition<Document & ObjectFieldType<FieldName, T>, FieldPaths | FieldName, Indexes & {
47
+ [key in FieldName]: [FieldName];
48
+ }, SearchIndexes, VectorIndexes, Edges>;
49
+ field<FieldName extends string, T extends Validator<any, any, any>>(field: FieldName, validator: T, options: {
50
+ unique: true;
51
+ }): EntDefinition<Document & ObjectFieldType<FieldName, T>, FieldPaths | FieldName, Indexes & {
52
+ [key in FieldName]: [FieldName];
53
+ }, SearchIndexes, VectorIndexes, Edges>;
54
+ field<FieldName extends string, T extends Validator<any, false, any>>(field: FieldName, validator: T, options: {
55
+ default: T["type"];
56
+ }): EntDefinition<Document & ObjectFieldType<FieldName, T>, FieldPaths | FieldName, Indexes, SearchIndexes, VectorIndexes, Edges>;
57
+ edge<EdgeName extends string>(edge: EdgeName): EntDefinition<Document & {
58
+ [key in `${EdgeName}Id`]: GenericId<`${EdgeName}s`>;
59
+ }, FieldPaths | `${EdgeName}Id`, Indexes & {
60
+ [key in `${EdgeName}Id`]: [`${EdgeName}Id`];
61
+ }, SearchIndexes, VectorIndexes, Edges & {
62
+ [key in EdgeName]: {
63
+ name: EdgeName;
64
+ to: `${EdgeName}s`;
65
+ type: "field";
66
+ cardinality: "single";
67
+ };
68
+ }>;
69
+ edge<EdgeName extends string, const FieldName extends string>(edge: EdgeName, options: {
70
+ field: FieldName;
71
+ }): EntDefinition<Document & {
72
+ [key in NoInfer<FieldName>]: GenericId<`${EdgeName}s`>;
73
+ }, FieldPaths | NoInfer<FieldName>, Indexes & {
74
+ [key in NoInfer<FieldName>]: [NoInfer<FieldName>];
75
+ }, SearchIndexes, VectorIndexes, Edges & {
76
+ [key in EdgeName]: {
77
+ name: EdgeName;
78
+ to: `${EdgeName}s`;
79
+ type: "field";
80
+ cardinality: "single";
81
+ };
82
+ }>;
83
+ edge<EdgeName extends string, const FieldName extends string, const ToTable extends string>(edge: EdgeName, options: {
84
+ field: FieldName;
85
+ to: ToTable;
86
+ }): EntDefinition<Document & {
87
+ [key in NoInfer<FieldName>]: GenericId<ToTable>;
88
+ }, FieldPaths | NoInfer<FieldName>, Indexes & {
89
+ [key in NoInfer<FieldName>]: [NoInfer<FieldName>];
90
+ }, SearchIndexes, VectorIndexes, Edges & {
91
+ [key in EdgeName]: {
92
+ name: EdgeName;
93
+ to: ToTable;
94
+ type: "field";
95
+ cardinality: "single";
96
+ };
97
+ }>;
98
+ edge<EdgeName extends string>(edge: EdgeName, options: {
99
+ optional: true;
100
+ ref?: string;
101
+ }): EntDefinition<Document, FieldPaths, Indexes, SearchIndexes, VectorIndexes, Edges & {
102
+ [key in EdgeName]: {
103
+ name: EdgeName;
104
+ to: `${EdgeName}s`;
105
+ type: "ref";
106
+ cardinality: "single";
107
+ };
108
+ }>;
109
+ edge<EdgeName extends string, const ToTable extends string>(edge: EdgeName, options: {
110
+ optional: true;
111
+ to: ToTable;
112
+ ref?: string;
113
+ }): EntDefinition<Document, FieldPaths, Indexes, SearchIndexes, VectorIndexes, Edges & {
114
+ [key in EdgeName]: {
115
+ name: EdgeName;
116
+ to: NoInfer<ToTable>;
117
+ type: "ref";
118
+ cardinality: "single";
119
+ };
120
+ }>;
121
+ /**
122
+ * Define many:1 edge to another table.
123
+ * @param edge The name of the edge, also the name of the target table.
124
+ * @param options.ref The name of the field that stores the many:1 edge
125
+ * on the other table, or `true` to infer it.
126
+ */
127
+ edges<EdgesName extends string>(edge: EdgesName, options: {
128
+ ref: true | string;
129
+ }): EntDefinition<Document, FieldPaths, Indexes, SearchIndexes, VectorIndexes, Edges & {
130
+ [key in EdgesName]: {
131
+ name: EdgesName;
132
+ to: EdgesName;
133
+ type: "field";
134
+ cardinality: "multiple";
135
+ };
136
+ }>;
137
+ /**
138
+ * Define many:1 edge to another table.
139
+ * @param edge The name of the edge.
140
+ * @param options.to Name of the table the edge points to.
141
+ * If it's the same as the table this edge is defined on, this edge is
142
+ * a symmetric, self-directed many:many edge.
143
+ * @param options.ref The name of the field that stores the many:1 edge
144
+ * on the other table, or `true` to infer it.
145
+ */
146
+ edges<EdgesName extends string, TableName extends string>(edge: EdgesName, options: {
147
+ to: TableName;
148
+ ref: true | string;
149
+ }): EntDefinition<Document, FieldPaths, Indexes, SearchIndexes, VectorIndexes, Edges & {
150
+ [key in EdgesName]: {
151
+ name: EdgesName;
152
+ to: NoInfer<TableName>;
153
+ type: "field";
154
+ cardinality: "multiple";
155
+ };
156
+ }>;
157
+ /**
158
+ * Define many:many edge to another table.
159
+ * @param edge The name of the edge, also the name of the target table.
160
+ * @param options.table Optional, name of the table to store the many:many edge in.
161
+ * @param options.field Optional, name of the field to store the ID of the
162
+ * this end of the many:many edge.
163
+ */
164
+ edges<EdgesName extends string>(edge: EdgesName, options?: {
165
+ table?: string;
166
+ field?: string;
167
+ }): EntDefinition<Document, FieldPaths, Indexes, SearchIndexes, VectorIndexes, Edges & {
168
+ [key in EdgesName]: {
169
+ name: EdgesName;
170
+ to: EdgesName;
171
+ type: "ref";
172
+ cardinality: "multiple";
173
+ };
174
+ }>;
175
+ /**
176
+ * Define many:many edge to another table.
177
+ * @param edge The name of the edge.
178
+ * @param options.to Name of the table the edge points to.
179
+ * If it's the same as the table this edge is defined on, this edge is
180
+ * a symmetric, self-directed many:many edge.
181
+ * @param options.table Optional, name of the table to store the many:many edge in.
182
+ * @param options.field Optional, name of the field to store the ID of the
183
+ * of the source end of the forward many:many edge.
184
+ * @param options.inverseField Optional, name of the field to store the ID
185
+ * of the target end of the forward edge. Only allowed for symmetric,
186
+ * self-directed many:many edges.
187
+ */
188
+ edges<EdgesName extends string, TableName extends string>(edge: EdgesName, options: {
189
+ to: TableName;
190
+ table?: string;
191
+ field?: string;
192
+ inverseField?: string;
193
+ }): EntDefinition<Document, FieldPaths, Indexes, SearchIndexes, VectorIndexes, Edges & {
194
+ [key in EdgesName]: {
195
+ name: EdgesName;
196
+ to: NoInfer<TableName>;
197
+ type: "ref";
198
+ cardinality: "multiple";
199
+ };
200
+ }>;
201
+ /**
202
+ * Define self-directed, assymetric, many:many edge.
203
+ * @param edge The name of the edge.
204
+ * @param options.to Name of the table the edge points to.
205
+ * Must be the same as the table this edge is defined on.
206
+ * @param options.inverse Name of the inverse edge.
207
+ * @param options.table Optional, name of the table to store the many:many edge in.
208
+ * @param options.field Optional, name of the field to store the ID of the
209
+ * of the source end of the forward many:many edge.
210
+ * @param options.inverseField Optional, name of the field to store the ID
211
+ * of the target end of the forward many:many edge.
212
+ */
213
+ edges<EdgesName extends string, TableName extends string, InverseEdgesNames extends string>(edge: EdgesName, options: {
214
+ to: TableName;
215
+ inverse: InverseEdgesNames;
216
+ table?: string;
217
+ field?: string;
218
+ inverseField?: string;
219
+ }): EntDefinition<Document, FieldPaths, Indexes, SearchIndexes, VectorIndexes, Edges & {
220
+ [key in EdgesName]: {
221
+ name: EdgesName;
222
+ to: NoInfer<TableName>;
223
+ type: "ref";
224
+ cardinality: "multiple";
225
+ };
226
+ } & {
227
+ [key in NoInfer<InverseEdgesNames>]: {
228
+ name: NoInfer<InverseEdgesNames>;
229
+ to: NoInfer<TableName>;
230
+ type: "ref";
231
+ cardinality: "multiple";
232
+ };
233
+ }>;
234
+ }
235
+ type NoInfer<T> = [T][T extends any ? 0 : never];
236
+ type ObjectFieldType<FieldName extends string, T extends Validator<any, any, any>> = T["isOptional"] extends true ? {
237
+ [key in FieldName]?: T["type"];
238
+ } : {
239
+ [key in FieldName]: T["type"];
240
+ };
241
+ type EdgeConfig = {
242
+ name: string;
243
+ to: string;
244
+ } & (({
245
+ cardinality: "single";
246
+ } & ({
247
+ type: "field";
248
+ field: string;
249
+ unique: boolean;
250
+ } | {
251
+ type: "ref";
252
+ ref: string;
253
+ })) | ({
254
+ cardinality: "multiple";
255
+ } & ({
256
+ type: "field";
257
+ ref: string;
258
+ } | {
259
+ type: "ref";
260
+ table: string;
261
+ field: string;
262
+ ref: string;
263
+ inverse: boolean;
264
+ symmetric: boolean;
265
+ })));
266
+ type FieldConfig = {
267
+ name: string;
268
+ unique: boolean;
269
+ };
270
+ type ExtractDocument<T extends Validator<any, any, any>> = Expand<SystemFields & T["type"]>;
271
+ type Expand<ObjectType extends Record<any, any>> = ObjectType extends Record<any, any> ? {
272
+ [Key in keyof ObjectType]: ObjectType[Key];
273
+ } : never;
274
+ type ExtractFieldPaths<T extends Validator<any, any, any>> = T["fieldPaths"] | keyof SystemFields;
275
+ type SystemFields = {
276
+ _creationTime: number;
277
+ };
278
+ type ObjectValidator<Validators extends PropertyValidators> = Validator<ObjectType<Validators>, false, {
279
+ [Property in keyof Validators]: JoinFieldPaths<Property & string, Validators[Property]["fieldPaths"]> | Property;
280
+ }[keyof Validators] & string>;
281
+ type JoinFieldPaths<Start extends string, End extends string> = `${Start}.${End}`;
282
+ type GenericEntsDataModel = GenericDataModel & Record<string, GenericEntModel>;
283
+ type GenericEntModel = {
284
+ edges: Record<string, GenericEdgeConfig>;
285
+ };
286
+ type EntDataModelFromSchema<SchemaDef extends SchemaDefinition<any, boolean>> = DataModelFromSchemaDefinition<SchemaDef> & {
287
+ [TableName in keyof SchemaDef["tables"] & string]: SchemaDef["tables"][TableName] extends EntDefinition<any, any, any, any, any, infer Edges> ? {
288
+ edges: Edges;
289
+ } : never;
290
+ };
291
+ declare function getEntDefinitions<SchemaDef extends SchemaDefinition<any, boolean>>(schema: SchemaDef): EntDataModelFromSchema<typeof schema>;
292
+
293
+ export { type EdgeConfig, type EntDataModelFromSchema, type EntDefinition, type Expand, type FieldConfig, type GenericEdgeConfig, type GenericEntModel, type GenericEntsDataModel, type SystemFields, defineEnt, defineEntSchema, getEntDefinitions };
package/dist/schema.js ADDED
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/schema.ts
21
+ var schema_exports = {};
22
+ __export(schema_exports, {
23
+ defineEnt: () => defineEnt,
24
+ defineEntSchema: () => defineEntSchema,
25
+ getEntDefinitions: () => getEntDefinitions
26
+ });
27
+ module.exports = __toCommonJS(schema_exports);
28
+ var import_server = require("convex/server");
29
+ var import_values = require("convex/values");
30
+ function defineEntSchema(schema, options) {
31
+ const tableNames = Object.keys(schema);
32
+ for (const tableName of tableNames) {
33
+ const table = schema[tableName];
34
+ for (const edge of edgeConfigsFromEntDefinition(table)) {
35
+ if (
36
+ // Skip inverse edges, we process their forward edges
37
+ edge.cardinality === "multiple" && edge.type === "ref" && edge.inverse !== void 0 || // symmetric is only set by defineEntSchema,
38
+ // so we already processed the pair
39
+ edge.symmetric !== void 0
40
+ ) {
41
+ continue;
42
+ }
43
+ const otherTableName = edge.to;
44
+ const otherTable = schema[otherTableName];
45
+ if (otherTable === void 0) {
46
+ throw new Error(
47
+ `Edge "${edge.name}" in table "${tableName}" points to an undefined table "${otherTableName}"`
48
+ );
49
+ }
50
+ const isSelfDirected = edge.to === tableName;
51
+ const inverseEdgeCandidates = edgeConfigsFromEntDefinition(
52
+ otherTable
53
+ ).filter(canBeInverseEdge(tableName, edge, isSelfDirected));
54
+ if (inverseEdgeCandidates.length > 1) {
55
+ throw new Error(
56
+ `Edge "${edge.name}" in table "${tableName}" has too many potential inverse edges in table "${otherTableName}": ${inverseEdgeCandidates.map((edge2) => `"${edge2.name}"`).join(", ")}`
57
+ );
58
+ }
59
+ const inverseEdge = inverseEdgeCandidates[0];
60
+ if (edge.cardinality === "single" && edge.type === "ref") {
61
+ if (inverseEdge === void 0) {
62
+ throw new Error(
63
+ `Missing inverse edge in table "${otherTableName}" ${edge.ref !== null ? `with field "${edge.ref}" ` : ""}for edge "${edge.name}" in table "${tableName}"`
64
+ );
65
+ }
66
+ if (inverseEdge.cardinality === "single" && inverseEdge.type === "ref") {
67
+ throw new Error(
68
+ `Both edge "${edge.name}" in table "${inverseEdge.to}" and edge "${inverseEdge.name}" in table "${edge.to}" are marked as optional, choose one to be required.`
69
+ );
70
+ }
71
+ if (inverseEdge.cardinality !== "single" || inverseEdge.type !== "field") {
72
+ throw new Error(
73
+ `Unexpected inverse edge type ${edge.name}, ${inverseEdge?.name}`
74
+ );
75
+ }
76
+ if (edge.ref === null) {
77
+ edge.ref = inverseEdge.field;
78
+ }
79
+ inverseEdge.unique = true;
80
+ }
81
+ if (edge.cardinality === "multiple") {
82
+ if (!isSelfDirected && inverseEdge === void 0) {
83
+ throw new Error(
84
+ `Missing inverse edge in table "${otherTableName}" for edge "${edge.name}" in table "${tableName}"`
85
+ );
86
+ }
87
+ if (inverseEdge?.cardinality === "single") {
88
+ if (inverseEdge.type === "ref") {
89
+ throw new Error(
90
+ `The edge "${inverseEdge.name}" in table "${otherTableName}" cannot be optional, as it must store the 1:many edge as a field. Check the its inverse edge "${edge.name}" in table "${tableName}".`
91
+ );
92
+ }
93
+ if (edge.type === "ref") {
94
+ throw new Error(
95
+ `The edge "${inverseEdge.name}" in table "${otherTableName}" cannot be singular, as the edge "${edge.name}" in table "${tableName}" did not specify the \`ref\` option.`
96
+ );
97
+ }
98
+ edge.type = "field";
99
+ edge.ref = inverseEdge.field;
100
+ }
101
+ if (inverseEdge?.cardinality === "multiple" || isSelfDirected) {
102
+ if (!isSelfDirected && edge?.type === "field") {
103
+ throw new Error(
104
+ `The edge "${edge.name}" in table "${tableName}" specified \`ref\`, but its inverse edge "${inverseEdge.name}" in table "${otherTableName}" is not the singular end of a 1:many edge.`
105
+ );
106
+ }
107
+ if (inverseEdge?.type === "field") {
108
+ throw new Error(
109
+ `The edge "${inverseEdge.name}" in table "${otherTableName}" specified \`ref\`, but its inverse edge "${edge.name}" in table "${tableName}" is not the singular end of a 1:many edge.`
110
+ );
111
+ }
112
+ 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}`;
113
+ const forwardId = edge.type === "ref" && edge.field !== void 0 ? edge.field : inverseEdge === void 0 ? "aId" : tableName === otherTableName ? inverseEdge.name + "Id" : tableName + "Id";
114
+ 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";
115
+ schema[edgeTableName] = defineEnt({
116
+ [forwardId]: import_values.v.id(tableName),
117
+ [inverseId]: import_values.v.id(otherTableName)
118
+ }).index(forwardId, [forwardId, inverseId]).index(inverseId, [inverseId, forwardId]);
119
+ edge.type = "ref";
120
+ edge.table = edgeTableName;
121
+ edge.field = forwardId;
122
+ edge.ref = inverseId;
123
+ edge.symmetric = inverseEdge === void 0;
124
+ if (inverseEdge !== void 0) {
125
+ inverseEdge.type = "ref";
126
+ inverseEdge.table = edgeTableName;
127
+ inverseEdge.field = inverseId;
128
+ inverseEdge.ref = forwardId;
129
+ inverseEdge.symmetric = false;
130
+ }
131
+ }
132
+ }
133
+ }
134
+ }
135
+ return (0, import_server.defineSchema)(schema, options);
136
+ }
137
+ function canBeInverseEdge(tableName, edge, isSelfDirected) {
138
+ return (candidate) => {
139
+ if (candidate.to !== tableName) {
140
+ return false;
141
+ }
142
+ if (isSelfDirected) {
143
+ return candidate.cardinality === "multiple" && candidate.type === "ref" && candidate.inverse === edge.name;
144
+ }
145
+ if (edge.cardinality === "single" && edge.type === "ref" && edge.ref !== null || edge.cardinality === "multiple" && edge.type === "field" && edge.ref !== true) {
146
+ if (candidate.cardinality === "single" && candidate.type === "field") {
147
+ return edge.ref === candidate.field;
148
+ }
149
+ }
150
+ if (edge.cardinality === "single" && edge.type === "field" && edge.field !== null) {
151
+ if (candidate.cardinality === "single" && candidate.type === "ref" && candidate.ref !== null || candidate.cardinality === "multiple" && candidate.type === "field" && candidate.ref !== true) {
152
+ return edge.field === candidate.ref;
153
+ }
154
+ }
155
+ if (edge.cardinality === "multiple" && edge.type === "ref" && edge.table !== void 0) {
156
+ return candidate.cardinality === "multiple" && candidate.type === "ref" && edge.table === candidate.table;
157
+ }
158
+ if (candidate.cardinality === "multiple" && candidate.type === "ref" && candidate.table !== void 0) {
159
+ return edge.cardinality === "multiple" && edge.type === "ref" && edge.table === candidate.table;
160
+ }
161
+ return true;
162
+ };
163
+ }
164
+ function edgeConfigsFromEntDefinition(table) {
165
+ return Object.values(
166
+ table.edgeConfigs
167
+ );
168
+ }
169
+ function defineEnt(documentSchema) {
170
+ return new EntDefinitionImpl(documentSchema);
171
+ }
172
+ var EntDefinitionImpl = class {
173
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
174
+ // @ts-ignore
175
+ indexes = [];
176
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
177
+ // @ts-ignore
178
+ searchIndexes = [];
179
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
180
+ // @ts-ignore
181
+ vectorIndexes = [];
182
+ documentSchema;
183
+ edgeConfigs = {};
184
+ fieldConfigs = {};
185
+ defaults = {};
186
+ constructor(documentSchema) {
187
+ this.documentSchema = documentSchema;
188
+ }
189
+ index(name, fields) {
190
+ this.indexes.push({ indexDescriptor: name, fields });
191
+ return this;
192
+ }
193
+ searchIndex(name, indexConfig) {
194
+ this.searchIndexes.push({
195
+ indexDescriptor: name,
196
+ searchField: indexConfig.searchField,
197
+ filterFields: indexConfig.filterFields || []
198
+ });
199
+ return this;
200
+ }
201
+ vectorIndex(name, indexConfig) {
202
+ this.vectorIndexes.push({
203
+ indexDescriptor: name,
204
+ vectorField: indexConfig.vectorField,
205
+ dimensions: indexConfig.dimensions,
206
+ filterFields: indexConfig.filterFields || []
207
+ });
208
+ return this;
209
+ }
210
+ /**
211
+ * Export the contents of this definition.
212
+ *
213
+ * This is called internally by the Convex framework.
214
+ * @internal
215
+ */
216
+ export() {
217
+ return {
218
+ indexes: this.indexes,
219
+ searchIndexes: this.searchIndexes,
220
+ vectorIndexes: this.vectorIndexes,
221
+ documentType: import_values.v.object(this.documentSchema).json
222
+ };
223
+ }
224
+ field(name, validator, options) {
225
+ if (this.documentSchema[name] !== void 0) {
226
+ throw new Error(`Duplicate field "${name}"`);
227
+ }
228
+ const finalValidator = options?.default !== void 0 ? import_values.v.optional(validator) : validator;
229
+ this.documentSchema = { ...this.documentSchema, [name]: finalValidator };
230
+ if (options?.unique === true || options?.index === true) {
231
+ this.indexes.push({ indexDescriptor: name, fields: [name] });
232
+ }
233
+ if (options?.default !== void 0) {
234
+ this.defaults[name] = options.default;
235
+ }
236
+ if (options?.unique === true) {
237
+ this.fieldConfigs[name] = { name, unique: true };
238
+ }
239
+ return this;
240
+ }
241
+ edge(edgeName, options) {
242
+ if (this.edgeConfigs[edgeName] !== void 0) {
243
+ throw new Error(`Duplicate edge "${edgeName}"`);
244
+ }
245
+ const to = options?.to ?? edgeName + "s";
246
+ if (options?.optional !== true) {
247
+ const fieldName = options?.field ?? edgeName + "Id";
248
+ this.documentSchema = { ...this.documentSchema, [fieldName]: import_values.v.id(to) };
249
+ this.edgeConfigs[edgeName] = {
250
+ name: edgeName,
251
+ to,
252
+ cardinality: "single",
253
+ type: "field",
254
+ field: fieldName
255
+ };
256
+ this.indexes.push({
257
+ indexDescriptor: fieldName,
258
+ fields: [fieldName]
259
+ });
260
+ return this;
261
+ }
262
+ if (options.optional === true) {
263
+ this.edgeConfigs[edgeName] = {
264
+ name: edgeName,
265
+ to,
266
+ cardinality: "single",
267
+ type: "ref",
268
+ ref: options.ref ?? null
269
+ };
270
+ }
271
+ return this;
272
+ }
273
+ edges(name, options) {
274
+ const cardinality = "multiple";
275
+ const to = options?.to ?? name;
276
+ const ref = options?.ref;
277
+ const table = options?.table;
278
+ if (ref !== void 0 && table !== void 0) {
279
+ throw new Error(
280
+ `Cannot specify both \`ref\` and \`table\` for the same edge, as the former is for 1:many edges and the latter for many:many edges. Config: \`${JSON.stringify(options)}\``
281
+ );
282
+ }
283
+ const field = options?.field;
284
+ const inverseField = options?.inverseField;
285
+ if ((field !== void 0 || inverseField !== void 0) && table === void 0) {
286
+ throw new Error(
287
+ `Specify \`table\` if you're customizing the \`field\` or \`inverseField\` for a many:many edge. Config: \`${JSON.stringify(options)}\``
288
+ );
289
+ }
290
+ const inverseName = options?.inverse;
291
+ this.edgeConfigs[name] = ref !== void 0 ? { name, to, cardinality, type: "field", ref } : { name, to, cardinality, type: "ref", table, field, inverseField };
292
+ if (inverseName !== void 0) {
293
+ this.edgeConfigs[inverseName] = {
294
+ name: inverseName,
295
+ to,
296
+ cardinality,
297
+ type: "ref",
298
+ inverse: name,
299
+ table
300
+ };
301
+ }
302
+ return this;
303
+ }
304
+ };
305
+ function getEntDefinitions(schema) {
306
+ const tables = schema.tables;
307
+ return Object.keys(tables).reduce(
308
+ (acc, tableName) => ({
309
+ ...acc,
310
+ [tableName]: {
311
+ defaults: tables[tableName].defaults,
312
+ edges: tables[tableName].edgeConfigs,
313
+ fields: tables[tableName].fieldConfigs
314
+ }
315
+ }),
316
+ {}
317
+ );
318
+ }
319
+ // Annotate the CommonJS export names for ESM import in node:
320
+ 0 && (module.exports = {
321
+ defineEnt,
322
+ defineEntSchema,
323
+ getEntDefinitions
324
+ });
325
+ //# sourceMappingURL=schema.js.map