@danceroutine/tango-schema 1.11.1 → 1.11.2
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/chunk-D7D4PA-g.js +13 -0
- package/dist/domain/index.d.ts +2 -13
- package/dist/domain/index.js +7 -1
- package/dist/domain/index.js.map +1 -0
- package/dist/index-Bhh0b304.d.ts +246 -0
- package/dist/index-DXFf5XNn.d.ts +747 -0
- package/dist/index.d.ts +3 -9
- package/dist/index.js +3 -4
- package/dist/model/index.d.ts +3 -25
- package/dist/model/index.js +2 -3
- package/dist/{model-upj6jxaK.js → model-aRAusQPz.js} +199 -175
- package/dist/model-aRAusQPz.js.map +1 -0
- package/package.json +3 -3
- package/dist/domain/DeleteReferentialAction.d.ts +0 -1
- package/dist/domain/Field.d.ts +0 -20
- package/dist/domain/FieldType.d.ts +0 -2
- package/dist/domain/IndexDef.d.ts +0 -6
- package/dist/domain/Model.d.ts +0 -35
- package/dist/domain/ModelMetadata.d.ts +0 -16
- package/dist/domain/ModelWriteHooks.d.ts +0 -96
- package/dist/domain/RelationDef.d.ts +0 -7
- package/dist/domain/RelationType.d.ts +0 -2
- package/dist/domain/UpdateReferentialAction.d.ts +0 -1
- package/dist/domain/internal/InternalFieldType.d.ts +0 -10
- package/dist/domain/internal/InternalReferentialAction.d.ts +0 -6
- package/dist/domain/internal/InternalRelationType.d.ts +0 -5
- package/dist/domain/internal/zod/hasConstructorName.d.ts +0 -1
- package/dist/domain/internal/zod/index.d.ts +0 -13
- package/dist/domain/internal/zod/isDate.d.ts +0 -1
- package/dist/domain/internal/zod/isZodArray.d.ts +0 -2
- package/dist/domain/internal/zod/isZodBoolean.d.ts +0 -2
- package/dist/domain/internal/zod/isZodDate.d.ts +0 -2
- package/dist/domain/internal/zod/isZodDefault.d.ts +0 -2
- package/dist/domain/internal/zod/isZodNullable.d.ts +0 -2
- package/dist/domain/internal/zod/isZodNumber.d.ts +0 -2
- package/dist/domain/internal/zod/isZodObject.d.ts +0 -2
- package/dist/domain/internal/zod/isZodOptional.d.ts +0 -2
- package/dist/domain/internal/zod/isZodString.d.ts +0 -2
- package/dist/domain-Cufz6y1q.js +0 -7
- package/dist/domain-Cufz6y1q.js.map +0 -1
- package/dist/model/Model.d.ts +0 -11
- package/dist/model/ModelAugmentorRegistry.d.ts +0 -11
- package/dist/model/ModelDefinition.d.ts +0 -23
- package/dist/model/constraints/Constraints.d.ts +0 -19
- package/dist/model/constraints/Indexes.d.ts +0 -4
- package/dist/model/constraints/index.d.ts +0 -6
- package/dist/model/decorators/Decorators.d.ts +0 -83
- package/dist/model/decorators/domain/DecoratedFieldKind.d.ts +0 -6
- package/dist/model/decorators/domain/ModelRef.d.ts +0 -11
- package/dist/model/decorators/domain/RelationDecoratedSchema.d.ts +0 -24
- package/dist/model/decorators/domain/RelationDecoratorConfig.d.ts +0 -39
- package/dist/model/decorators/domain/TangoFieldMeta.d.ts +0 -89
- package/dist/model/decorators/domain/ZodTypeAny.d.ts +0 -2
- package/dist/model/decorators/index.d.ts +0 -13
- package/dist/model/fields/FieldMetadataStore.d.ts +0 -4
- package/dist/model/fields/FinalizedStorageArtifacts.d.ts +0 -11
- package/dist/model/fields/inferFieldsFromSchema.d.ts +0 -15
- package/dist/model/internal/InternalSchemaModel.d.ts +0 -29
- package/dist/model/meta/Meta.d.ts +0 -22
- package/dist/model/meta/index.d.ts +0 -5
- package/dist/model/registry/GeneratedRelationRegistryArtifact.d.ts +0 -10
- package/dist/model/registry/ModelRegistry.d.ts +0 -129
- package/dist/model/registry/ResolvedRelationGraphArtifactFactory.d.ts +0 -13
- package/dist/model/registry/ResolvedRelationGraphSnapshot.d.ts +0 -110
- package/dist/model/registry/index.d.ts +0 -8
- package/dist/model/relations/ImplicitManyToManyIdentifier.d.ts +0 -45
- package/dist/model/relations/ImplicitManyToManyThroughFactory.d.ts +0 -14
- package/dist/model/relations/NormalizedRelationStorageDescriptor.d.ts +0 -36
- package/dist/model/relations/RelationBuilder.d.ts +0 -19
- package/dist/model/relations/RelationDescriptorNormalizer.d.ts +0 -30
- package/dist/model/relations/RelationSpec.d.ts +0 -48
- package/dist/model/relations/ResolvedRelationGraph.d.ts +0 -49
- package/dist/model/relations/ResolvedRelationGraphBuilder.d.ts +0 -54
- package/dist/model/relations/SchemaNaming.d.ts +0 -12
- package/dist/model/relations/index.d.ts +0 -13
- package/dist/model-upj6jxaK.js.map +0 -1
- package/dist/resolveSchemaModuleEntrypoint.d.ts +0 -20
|
@@ -1,23 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { t as __exportAll } from "./chunk-D7D4PA-g.js";
|
|
2
|
+
import { getLogger } from "@danceroutine/tango-core";
|
|
3
|
+
import { z } from "zod";
|
|
3
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
-
import { existsSync,
|
|
5
|
-
import { dirname, extname, resolve
|
|
6
|
-
import { createHash
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { dirname, extname, resolve } from "node:path";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
7
8
|
import { fileURLToPath } from "node:url";
|
|
8
|
-
|
|
9
|
-
//#region rolldown:runtime
|
|
10
|
-
var __defProp = Object.defineProperty;
|
|
11
|
-
var __export = (target, all) => {
|
|
12
|
-
for (var name in all) __defProp(target, name, {
|
|
13
|
-
get: all[name],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
//#endregion
|
|
19
9
|
//#region src/model/fields/FieldMetadataStore.ts
|
|
20
|
-
const fieldMetadataStore = new WeakMap();
|
|
10
|
+
const fieldMetadataStore = /* @__PURE__ */ new WeakMap();
|
|
21
11
|
function getFieldMetadata(schema) {
|
|
22
12
|
return fieldMetadataStore.get(schema);
|
|
23
13
|
}
|
|
@@ -28,7 +18,6 @@ function setFieldMetadata(schema, meta) {
|
|
|
28
18
|
...meta
|
|
29
19
|
});
|
|
30
20
|
}
|
|
31
|
-
|
|
32
21
|
//#endregion
|
|
33
22
|
//#region src/model/decorators/domain/ModelRef.ts
|
|
34
23
|
function createTypedModelRef(key) {
|
|
@@ -37,7 +26,6 @@ function createTypedModelRef(key) {
|
|
|
37
26
|
function isTypedModelRef(value) {
|
|
38
27
|
return typeof value === "object" && value !== null && typeof value.key === "string";
|
|
39
28
|
}
|
|
40
|
-
|
|
41
29
|
//#endregion
|
|
42
30
|
//#region src/model/decorators/domain/DecoratedFieldKind.ts
|
|
43
31
|
const InternalDecoratedFieldKind = {
|
|
@@ -45,7 +33,6 @@ const InternalDecoratedFieldKind = {
|
|
|
45
33
|
ONE_TO_ONE: "oneToOne",
|
|
46
34
|
MANY_TO_MANY: "manyToMany"
|
|
47
35
|
};
|
|
48
|
-
|
|
49
36
|
//#endregion
|
|
50
37
|
//#region src/model/decorators/Decorators.ts
|
|
51
38
|
function isZodType(value) {
|
|
@@ -55,11 +42,11 @@ function decorate(schema, meta) {
|
|
|
55
42
|
setFieldMetadata(schema, meta);
|
|
56
43
|
return schema;
|
|
57
44
|
}
|
|
58
|
-
const warnedDecoratorKinds = new Set();
|
|
45
|
+
const warnedDecoratorKinds = /* @__PURE__ */ new Set();
|
|
59
46
|
function warnDeprecatedSchemaOverload(kind, replacement) {
|
|
60
47
|
if (warnedDecoratorKinds.has(kind)) return;
|
|
61
48
|
warnedDecoratorKinds.add(kind);
|
|
62
|
-
getLogger
|
|
49
|
+
getLogger("tango.schema.decorators").warn(`Deprecated positional schema overload used for t.${kind}(...). Prefer ${replacement} instead.`);
|
|
63
50
|
}
|
|
64
51
|
function maybeDecorator(schemaOrUndefined, meta) {
|
|
65
52
|
if (schemaOrUndefined) return decorate(schemaOrUndefined, meta);
|
|
@@ -105,6 +92,7 @@ function errorMessages(schema, map) {
|
|
|
105
92
|
return decorate(schema, { errorMessages: map });
|
|
106
93
|
}
|
|
107
94
|
var FieldDecoratorBuilderImpl = class {
|
|
95
|
+
schema;
|
|
108
96
|
constructor(schema) {
|
|
109
97
|
this.schema = schema;
|
|
110
98
|
}
|
|
@@ -155,8 +143,8 @@ function applyRelationMetadata(schema, meta, config) {
|
|
|
155
143
|
});
|
|
156
144
|
}
|
|
157
145
|
function toReferentialOptions(config) {
|
|
158
|
-
if (!config) return
|
|
159
|
-
if (config.column ===
|
|
146
|
+
if (!config) return;
|
|
147
|
+
if (config.column === void 0 && config.onDelete === void 0 && config.onUpdate === void 0) return;
|
|
160
148
|
return {
|
|
161
149
|
column: config.column,
|
|
162
150
|
onDelete: config.onDelete,
|
|
@@ -178,14 +166,13 @@ function foreignKey(target, schemaOrOptions, maybeOptions) {
|
|
|
178
166
|
});
|
|
179
167
|
}
|
|
180
168
|
const config = schemaOrOptions;
|
|
181
|
-
|
|
182
|
-
return applyRelationMetadata(schema, {
|
|
169
|
+
return applyRelationMetadata(config?.field ?? z.number().int(), {
|
|
183
170
|
relationKind: InternalDecoratedFieldKind.FOREIGN_KEY,
|
|
184
171
|
references: {
|
|
185
172
|
target,
|
|
186
173
|
options: toReferentialOptions(config)
|
|
187
174
|
},
|
|
188
|
-
notNull: config?.field ?
|
|
175
|
+
notNull: config?.field ? void 0 : true
|
|
189
176
|
}, config);
|
|
190
177
|
}
|
|
191
178
|
function oneToOne(target, schemaOrOptions, maybeOptions) {
|
|
@@ -201,15 +188,14 @@ function oneToOne(target, schemaOrOptions, maybeOptions) {
|
|
|
201
188
|
});
|
|
202
189
|
}
|
|
203
190
|
const config = schemaOrOptions;
|
|
204
|
-
|
|
205
|
-
return applyRelationMetadata(schema, {
|
|
191
|
+
return applyRelationMetadata(config?.field ?? z.number().int(), {
|
|
206
192
|
relationKind: InternalDecoratedFieldKind.ONE_TO_ONE,
|
|
207
193
|
unique: true,
|
|
208
194
|
references: {
|
|
209
195
|
target,
|
|
210
196
|
options: toReferentialOptions(config)
|
|
211
197
|
},
|
|
212
|
-
notNull: config?.field ?
|
|
198
|
+
notNull: config?.field ? void 0 : true
|
|
213
199
|
}, config);
|
|
214
200
|
}
|
|
215
201
|
function manyToMany(target, schemaOrConfig) {
|
|
@@ -220,12 +206,10 @@ function manyToMany(target, schemaOrConfig) {
|
|
|
220
206
|
references: { target }
|
|
221
207
|
});
|
|
222
208
|
}
|
|
223
|
-
if (schemaOrConfig?.relatedName !==
|
|
209
|
+
if (schemaOrConfig?.relatedName !== void 0) throw new Error("t.manyToMany(...) does not support relatedName yet.");
|
|
224
210
|
const config = schemaOrConfig;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const schema = config?.field ?? z$1.array(z$1.number().int());
|
|
228
|
-
return applyRelationMetadata(schema, {
|
|
211
|
+
if ((config?.through !== void 0 || config?.throughSourceFieldName !== void 0 || config?.throughTargetFieldName !== void 0) && !(config?.through && config.throughSourceFieldName && config.throughTargetFieldName)) throw new Error("t.manyToMany(...) through config requires through, throughSourceFieldName, and throughTargetFieldName.");
|
|
212
|
+
return applyRelationMetadata(config?.field ?? z.array(z.number().int()), {
|
|
229
213
|
relationKind: InternalDecoratedFieldKind.MANY_TO_MANY,
|
|
230
214
|
references: {
|
|
231
215
|
target,
|
|
@@ -254,18 +238,15 @@ const Decorators = {
|
|
|
254
238
|
oneToOne,
|
|
255
239
|
manyToMany
|
|
256
240
|
};
|
|
257
|
-
|
|
258
241
|
//#endregion
|
|
259
242
|
//#region src/model/decorators/index.ts
|
|
260
|
-
var decorators_exports = {
|
|
261
|
-
__export(decorators_exports, {
|
|
243
|
+
var decorators_exports = /* @__PURE__ */ __exportAll({
|
|
262
244
|
Decorators: () => Decorators,
|
|
263
245
|
InternalDecoratedFieldKind: () => InternalDecoratedFieldKind,
|
|
264
246
|
createTypedModelRef: () => createTypedModelRef,
|
|
265
247
|
isTypedModelRef: () => isTypedModelRef,
|
|
266
248
|
t: () => Decorators
|
|
267
249
|
});
|
|
268
|
-
|
|
269
250
|
//#endregion
|
|
270
251
|
//#region src/model/meta/Meta.ts
|
|
271
252
|
const Meta = {
|
|
@@ -306,15 +287,12 @@ const Meta = {
|
|
|
306
287
|
}), {});
|
|
307
288
|
}
|
|
308
289
|
};
|
|
309
|
-
|
|
310
290
|
//#endregion
|
|
311
291
|
//#region src/model/meta/index.ts
|
|
312
|
-
var meta_exports = {
|
|
313
|
-
__export(meta_exports, {
|
|
292
|
+
var meta_exports = /* @__PURE__ */ __exportAll({
|
|
314
293
|
Meta: () => Meta,
|
|
315
294
|
m: () => Meta
|
|
316
295
|
});
|
|
317
|
-
|
|
318
296
|
//#endregion
|
|
319
297
|
//#region src/model/constraints/Constraints.ts
|
|
320
298
|
const Constraints = {
|
|
@@ -339,7 +317,6 @@ const Constraints = {
|
|
|
339
317
|
};
|
|
340
318
|
}
|
|
341
319
|
};
|
|
342
|
-
|
|
343
320
|
//#endregion
|
|
344
321
|
//#region src/model/constraints/Indexes.ts
|
|
345
322
|
const Indexes = { index(on, options) {
|
|
@@ -351,17 +328,14 @@ const Indexes = { index(on, options) {
|
|
|
351
328
|
where: options?.where
|
|
352
329
|
};
|
|
353
330
|
} };
|
|
354
|
-
|
|
355
331
|
//#endregion
|
|
356
332
|
//#region src/model/constraints/index.ts
|
|
357
|
-
var constraints_exports = {
|
|
358
|
-
__export(constraints_exports, {
|
|
333
|
+
var constraints_exports = /* @__PURE__ */ __exportAll({
|
|
359
334
|
Constraints: () => Constraints,
|
|
360
335
|
Indexes: () => Indexes,
|
|
361
336
|
c: () => Constraints,
|
|
362
337
|
i: () => Indexes
|
|
363
338
|
});
|
|
364
|
-
|
|
365
339
|
//#endregion
|
|
366
340
|
//#region src/domain/internal/InternalFieldType.ts
|
|
367
341
|
const InternalFieldType = {
|
|
@@ -374,73 +348,61 @@ const InternalFieldType = {
|
|
|
374
348
|
JSONB: "jsonb",
|
|
375
349
|
UUID: "uuid"
|
|
376
350
|
};
|
|
377
|
-
|
|
378
351
|
//#endregion
|
|
379
352
|
//#region src/domain/internal/zod/isDate.ts
|
|
380
353
|
function isDate(value) {
|
|
381
|
-
return value !== null && value !==
|
|
354
|
+
return value !== null && value !== void 0 && Object.prototype.toString.call(value) === "[object Date]";
|
|
382
355
|
}
|
|
383
|
-
|
|
384
356
|
//#endregion
|
|
385
357
|
//#region src/domain/internal/zod/hasConstructorName.ts
|
|
386
358
|
function hasConstructorName(value, name) {
|
|
387
359
|
return !!value && typeof value === "object" && value.constructor?.name === name;
|
|
388
360
|
}
|
|
389
|
-
|
|
390
361
|
//#endregion
|
|
391
362
|
//#region src/domain/internal/zod/isZodArray.ts
|
|
392
363
|
function isZodArray(value) {
|
|
393
364
|
return hasConstructorName(value, "ZodArray");
|
|
394
365
|
}
|
|
395
|
-
|
|
396
366
|
//#endregion
|
|
397
367
|
//#region src/domain/internal/zod/isZodBoolean.ts
|
|
398
368
|
function isZodBoolean(value) {
|
|
399
369
|
return hasConstructorName(value, "ZodBoolean");
|
|
400
370
|
}
|
|
401
|
-
|
|
402
371
|
//#endregion
|
|
403
372
|
//#region src/domain/internal/zod/isZodDate.ts
|
|
404
373
|
function isZodDate(value) {
|
|
405
374
|
return hasConstructorName(value, "ZodDate");
|
|
406
375
|
}
|
|
407
|
-
|
|
408
376
|
//#endregion
|
|
409
377
|
//#region src/domain/internal/zod/isZodDefault.ts
|
|
410
378
|
function isZodDefault(value) {
|
|
411
379
|
return hasConstructorName(value, "ZodDefault");
|
|
412
380
|
}
|
|
413
|
-
|
|
414
381
|
//#endregion
|
|
415
382
|
//#region src/domain/internal/zod/isZodNullable.ts
|
|
416
383
|
function isZodNullable(value) {
|
|
417
384
|
return hasConstructorName(value, "ZodNullable");
|
|
418
385
|
}
|
|
419
|
-
|
|
420
386
|
//#endregion
|
|
421
387
|
//#region src/domain/internal/zod/isZodNumber.ts
|
|
422
388
|
function isZodNumber(value) {
|
|
423
389
|
return hasConstructorName(value, "ZodNumber");
|
|
424
390
|
}
|
|
425
|
-
|
|
426
391
|
//#endregion
|
|
427
392
|
//#region src/domain/internal/zod/isZodObject.ts
|
|
428
393
|
function isZodObject(value) {
|
|
429
394
|
return hasConstructorName(value, "ZodObject");
|
|
430
395
|
}
|
|
431
|
-
|
|
432
396
|
//#endregion
|
|
433
397
|
//#region src/domain/internal/zod/isZodOptional.ts
|
|
434
398
|
function isZodOptional(value) {
|
|
435
399
|
return hasConstructorName(value, "ZodOptional");
|
|
436
400
|
}
|
|
437
|
-
|
|
438
401
|
//#endregion
|
|
439
402
|
//#region src/domain/internal/zod/isZodString.ts
|
|
440
403
|
function isZodString(value) {
|
|
441
404
|
return hasConstructorName(value, "ZodString");
|
|
442
405
|
}
|
|
443
|
-
|
|
444
406
|
//#endregion
|
|
445
407
|
//#region src/model/fields/inferFieldsFromSchema.ts
|
|
446
408
|
/**
|
|
@@ -451,75 +413,74 @@ function isZodString(value) {
|
|
|
451
413
|
*/
|
|
452
414
|
function inferField(name, zodType, meta, registry, resolveReferenceTarget) {
|
|
453
415
|
let type;
|
|
454
|
-
let notNull
|
|
455
|
-
let defaultValue
|
|
416
|
+
let notNull = true;
|
|
417
|
+
let defaultValue = void 0;
|
|
456
418
|
let unwrapped = zodType;
|
|
457
419
|
if (isZodOptional(unwrapped)) {
|
|
458
|
-
notNull
|
|
420
|
+
notNull = false;
|
|
459
421
|
unwrapped = unwrapped.unwrap();
|
|
460
422
|
}
|
|
461
423
|
if (isZodNullable(unwrapped)) {
|
|
462
|
-
notNull
|
|
424
|
+
notNull = false;
|
|
463
425
|
unwrapped = unwrapped.unwrap();
|
|
464
426
|
}
|
|
465
427
|
if (isZodDefault(unwrapped)) {
|
|
466
428
|
const def = unwrapped._zod.def.defaultValue;
|
|
467
|
-
if (isDate(def)) defaultValue
|
|
468
|
-
else if (typeof def === "string" || typeof def === "number") defaultValue
|
|
429
|
+
if (isDate(def)) defaultValue = { now: true };
|
|
430
|
+
else if (typeof def === "string" || typeof def === "number") defaultValue = String(def);
|
|
469
431
|
unwrapped = unwrapped.removeDefault();
|
|
470
432
|
}
|
|
471
433
|
if (isZodString(unwrapped)) type = InternalFieldType.TEXT;
|
|
472
|
-
else if (isZodNumber(unwrapped))
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
else if (isZodObject(unwrapped) || isZodArray(unwrapped)) type = InternalFieldType.JSONB;
|
|
479
|
-
else return null;
|
|
480
|
-
const field$1 = {
|
|
434
|
+
else if (isZodNumber(unwrapped)) type = (unwrapped._zod.def.checks ?? []).some((c) => "format" in c._zod.def && c._zod.def.format === "safeint") ? InternalFieldType.INT : InternalFieldType.BIGINT;
|
|
435
|
+
else if (isZodBoolean(unwrapped)) type = InternalFieldType.BOOL;
|
|
436
|
+
else if (isZodDate(unwrapped)) type = InternalFieldType.TIMESTAMPTZ;
|
|
437
|
+
else if (isZodObject(unwrapped) || isZodArray(unwrapped)) type = InternalFieldType.JSONB;
|
|
438
|
+
else return null;
|
|
439
|
+
const field = {
|
|
481
440
|
name,
|
|
482
441
|
type,
|
|
483
|
-
notNull
|
|
484
|
-
default: defaultValue
|
|
442
|
+
notNull,
|
|
443
|
+
default: defaultValue
|
|
485
444
|
};
|
|
486
|
-
if (!meta) return field
|
|
487
|
-
if (meta.dbColumn) field
|
|
488
|
-
if (typeof meta.notNull === "boolean") field
|
|
489
|
-
if (meta.default !==
|
|
490
|
-
if (meta.primaryKey) field
|
|
491
|
-
if (meta.unique) field
|
|
445
|
+
if (!meta) return field;
|
|
446
|
+
if (meta.dbColumn) field.name = meta.dbColumn;
|
|
447
|
+
if (typeof meta.notNull === "boolean") field.notNull = meta.notNull;
|
|
448
|
+
if (meta.default !== void 0) field.default = meta.default;
|
|
449
|
+
if (meta.primaryKey) field.primaryKey = true;
|
|
450
|
+
if (meta.unique) field.unique = true;
|
|
492
451
|
if (meta.relationKind === InternalDecoratedFieldKind.MANY_TO_MANY) return null;
|
|
493
452
|
if (meta.references) {
|
|
494
453
|
const targetMetadata = resolveReferenceTarget ? resolveReferenceTarget(meta.references.target) : resolveReferenceTargetFromRegistry(meta.references.target, registry, meta.references.options?.column);
|
|
495
|
-
field
|
|
454
|
+
field.references = {
|
|
496
455
|
table: targetMetadata.table,
|
|
497
456
|
column: meta.references.options?.column ?? targetMetadata.pk,
|
|
498
457
|
onDelete: meta.references.options?.onDelete,
|
|
499
458
|
onUpdate: meta.references.options?.onUpdate
|
|
500
459
|
};
|
|
501
460
|
}
|
|
502
|
-
return field
|
|
461
|
+
return field;
|
|
503
462
|
}
|
|
504
463
|
function resolveReferenceTargetFromRegistry(target, registry, explicitColumn) {
|
|
505
464
|
const targetModel = registry.resolveRef(target);
|
|
506
|
-
const primaryKey
|
|
465
|
+
const primaryKey = explicitColumn ?? targetModel.metadata.fields.find((candidate) => candidate.primaryKey)?.name ?? "id";
|
|
507
466
|
return {
|
|
508
467
|
table: targetModel.metadata.table,
|
|
509
|
-
pk: primaryKey
|
|
468
|
+
pk: primaryKey
|
|
510
469
|
};
|
|
511
470
|
}
|
|
471
|
+
/**
|
|
472
|
+
* Infer Tango field metadata from a Zod object schema and any attached field decorators.
|
|
473
|
+
*/
|
|
512
474
|
function inferFieldsFromSchema(schema, options) {
|
|
513
475
|
const registry = options?.registry ?? ModelRegistry.global();
|
|
514
476
|
const shape = schema.shape;
|
|
515
477
|
const fields = [];
|
|
516
478
|
for (const [name, zodType] of Object.entries(shape)) {
|
|
517
|
-
const field
|
|
518
|
-
if (field
|
|
479
|
+
const field = inferField(name, zodType, getFieldMetadata(zodType), registry, options?.resolveReferenceTarget);
|
|
480
|
+
if (field) fields.push(field);
|
|
519
481
|
}
|
|
520
482
|
return fields;
|
|
521
483
|
}
|
|
522
|
-
|
|
523
484
|
//#endregion
|
|
524
485
|
//#region src/domain/internal/InternalRelationType.ts
|
|
525
486
|
const InternalRelationType = {
|
|
@@ -527,40 +488,63 @@ const InternalRelationType = {
|
|
|
527
488
|
BELONGS_TO: "belongsTo",
|
|
528
489
|
HAS_ONE: "hasOne"
|
|
529
490
|
};
|
|
530
|
-
|
|
531
491
|
//#endregion
|
|
532
492
|
//#region src/model/relations/RelationBuilder.ts
|
|
493
|
+
/**
|
|
494
|
+
* Public authoring DSL for model-level named relations.
|
|
495
|
+
*
|
|
496
|
+
* This is the first stage of the relations subdomain. Application code uses it
|
|
497
|
+
* inside `relations: (r) => ({ ... })` to declare stable relation names and
|
|
498
|
+
* resolve ambiguity that field decorators alone cannot express.
|
|
499
|
+
*
|
|
500
|
+
* Later internal stages normalize these authored definitions and combine them
|
|
501
|
+
* with field-authored relation metadata to build the resolved relation graph.
|
|
502
|
+
*/
|
|
533
503
|
var RelationBuilder = class {
|
|
534
504
|
/** Declare a one-to-many relation from this model to `target`. */
|
|
535
|
-
hasMany(target, foreignKey
|
|
505
|
+
hasMany(target, foreignKey) {
|
|
536
506
|
return {
|
|
537
507
|
type: InternalRelationType.HAS_MANY,
|
|
538
508
|
target,
|
|
539
|
-
foreignKey
|
|
509
|
+
foreignKey
|
|
540
510
|
};
|
|
541
511
|
}
|
|
542
512
|
/** Declare an owning relation to a parent model. */
|
|
543
|
-
belongsTo(target, foreignKey
|
|
513
|
+
belongsTo(target, foreignKey, localKey) {
|
|
544
514
|
return {
|
|
545
515
|
type: InternalRelationType.BELONGS_TO,
|
|
546
516
|
target,
|
|
547
|
-
foreignKey
|
|
517
|
+
foreignKey,
|
|
548
518
|
localKey
|
|
549
519
|
};
|
|
550
520
|
}
|
|
551
521
|
/** Declare a one-to-one relation from this model to `target`. */
|
|
552
|
-
hasOne(target, foreignKey
|
|
522
|
+
hasOne(target, foreignKey) {
|
|
553
523
|
return {
|
|
554
524
|
type: InternalRelationType.HAS_ONE,
|
|
555
525
|
target,
|
|
556
|
-
foreignKey
|
|
526
|
+
foreignKey
|
|
557
527
|
};
|
|
558
528
|
}
|
|
559
529
|
};
|
|
560
|
-
|
|
561
530
|
//#endregion
|
|
562
531
|
//#region src/model/relations/RelationDescriptorNormalizer.ts
|
|
532
|
+
/**
|
|
533
|
+
* Normalizes field-authored relation declarations from a model schema into the
|
|
534
|
+
* shared descriptor shape consumed by storage and relation finalization.
|
|
535
|
+
*
|
|
536
|
+
* This is the normalization stage of the relations subdomain. It sits between
|
|
537
|
+
* authoring and resolution:
|
|
538
|
+
*
|
|
539
|
+
* - authoring: decorators attach relation intent to schema fields
|
|
540
|
+
* - normalization: this class converts that intent into a registry-independent
|
|
541
|
+
* descriptor shape
|
|
542
|
+
* - resolution: the graph builder combines those descriptors with finalized
|
|
543
|
+
* storage artifacts and explicit relation names
|
|
544
|
+
*/
|
|
563
545
|
var RelationDescriptorNormalizer = class RelationDescriptorNormalizer {
|
|
546
|
+
sourceModelKey;
|
|
547
|
+
schema;
|
|
564
548
|
constructor(sourceModelKey, schema) {
|
|
565
549
|
this.sourceModelKey = sourceModelKey;
|
|
566
550
|
this.schema = schema;
|
|
@@ -588,7 +572,7 @@ var RelationDescriptorNormalizer = class RelationDescriptorNormalizer {
|
|
|
588
572
|
}
|
|
589
573
|
normalizeCandidate(candidate) {
|
|
590
574
|
const meta = getFieldMetadata(candidate.zodType);
|
|
591
|
-
if (!meta?.references || !meta.relationKind) return
|
|
575
|
+
if (!meta?.references || !meta.relationKind) return;
|
|
592
576
|
return {
|
|
593
577
|
edgeId: this.buildEdgeId(candidate.sourceSchemaFieldKey, meta.relationKind),
|
|
594
578
|
sourceModelKey: this.sourceModelKey,
|
|
@@ -619,9 +603,16 @@ var RelationDescriptorNormalizer = class RelationDescriptorNormalizer {
|
|
|
619
603
|
return fieldKey;
|
|
620
604
|
}
|
|
621
605
|
};
|
|
622
|
-
|
|
623
606
|
//#endregion
|
|
624
607
|
//#region src/model/relations/SchemaNaming.ts
|
|
608
|
+
/**
|
|
609
|
+
* Shared naming policy for the model and relations subdomains.
|
|
610
|
+
*
|
|
611
|
+
* These helpers are not an authoring or graph stage on their own. They are the
|
|
612
|
+
* cross-cutting policy layer used by both model construction and relation
|
|
613
|
+
* resolution when Tango derives table names, aliases, and synthesized relation
|
|
614
|
+
* names in a Django-style shape.
|
|
615
|
+
*/
|
|
625
616
|
function toSnakeCase(value) {
|
|
626
617
|
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[\s-]+/g, "_").toLowerCase();
|
|
627
618
|
}
|
|
@@ -637,7 +628,6 @@ function decapitalizeModelName(name) {
|
|
|
637
628
|
if (name.length === 0) return name;
|
|
638
629
|
return `${name[0].toLowerCase()}${name.slice(1)}`;
|
|
639
630
|
}
|
|
640
|
-
|
|
641
631
|
//#endregion
|
|
642
632
|
//#region src/model/internal/InternalSchemaModel.ts
|
|
643
633
|
const REGISTRY_OWNER_KEY = Symbol.for("tango.schema.registryOwner");
|
|
@@ -658,7 +648,7 @@ var InternalSchemaModel = class InternalSchemaModel {
|
|
|
658
648
|
static create(definition, registry) {
|
|
659
649
|
InternalSchemaModel.validateDefinition(definition);
|
|
660
650
|
const builder = new RelationBuilder();
|
|
661
|
-
const relations = definition.relations ? Object.freeze(definition.relations(builder)) :
|
|
651
|
+
const relations = definition.relations ? Object.freeze(definition.relations(builder)) : void 0;
|
|
662
652
|
const key = `${definition.namespace}/${definition.name}`;
|
|
663
653
|
const table = definition.table?.trim() || deriveTableName(definition.name);
|
|
664
654
|
const normalizedRelations = RelationDescriptorNormalizer.normalize(key, definition.schema);
|
|
@@ -710,7 +700,7 @@ var InternalSchemaModel = class InternalSchemaModel {
|
|
|
710
700
|
static validateDefinition(definition) {
|
|
711
701
|
if (!definition.namespace.trim()) throw new Error("Model.namespace is required and cannot be empty.");
|
|
712
702
|
if (!definition.name.trim()) throw new Error("Model.name is required and cannot be empty.");
|
|
713
|
-
if (definition.table !==
|
|
703
|
+
if (definition.table !== void 0 && !definition.table.trim()) throw new Error("Model.table cannot be empty when provided.");
|
|
714
704
|
}
|
|
715
705
|
static require(model) {
|
|
716
706
|
if (!InternalSchemaModel.isInternalSchemaModel(model)) throw new Error(`Model '${model.metadata.key}' is missing internal registry ownership metadata.`);
|
|
@@ -720,8 +710,7 @@ var InternalSchemaModel = class InternalSchemaModel {
|
|
|
720
710
|
return InternalSchemaModel.require(model);
|
|
721
711
|
}
|
|
722
712
|
static attachInternals(model, internals) {
|
|
723
|
-
|
|
724
|
-
Object.defineProperties(carrier, {
|
|
713
|
+
Object.defineProperties(model, {
|
|
725
714
|
[REGISTRY_OWNER_KEY]: {
|
|
726
715
|
value: internals.registry,
|
|
727
716
|
enumerable: false,
|
|
@@ -735,7 +724,7 @@ var InternalSchemaModel = class InternalSchemaModel {
|
|
|
735
724
|
writable: false
|
|
736
725
|
},
|
|
737
726
|
[EXPLICIT_FIELDS_KEY]: {
|
|
738
|
-
value: internals.explicitFields ? Object.freeze([...internals.explicitFields]) :
|
|
727
|
+
value: internals.explicitFields ? Object.freeze([...internals.explicitFields]) : void 0,
|
|
739
728
|
enumerable: false,
|
|
740
729
|
configurable: false,
|
|
741
730
|
writable: false
|
|
@@ -749,7 +738,6 @@ var InternalSchemaModel = class InternalSchemaModel {
|
|
|
749
738
|
});
|
|
750
739
|
}
|
|
751
740
|
};
|
|
752
|
-
|
|
753
741
|
//#endregion
|
|
754
742
|
//#region src/model/relations/NormalizedRelationStorageDescriptor.ts
|
|
755
743
|
const InternalNormalizedRelationOrigin = {
|
|
@@ -757,7 +745,6 @@ const InternalNormalizedRelationOrigin = {
|
|
|
757
745
|
ONE_TO_ONE: "oneToOne",
|
|
758
746
|
MANY_TO_MANY: "manyToMany"
|
|
759
747
|
};
|
|
760
|
-
|
|
761
748
|
//#endregion
|
|
762
749
|
//#region src/model/relations/RelationSpec.ts
|
|
763
750
|
const InternalRelationPublicKind = {
|
|
@@ -780,9 +767,14 @@ const InternalRelationProvenance = {
|
|
|
780
767
|
RELATIONS_API: "relations-api",
|
|
781
768
|
SYNTHESIZED_REVERSE: "synthesized-reverse"
|
|
782
769
|
};
|
|
783
|
-
|
|
784
770
|
//#endregion
|
|
785
771
|
//#region src/model/relations/ImplicitManyToManyIdentifier.ts
|
|
772
|
+
/**
|
|
773
|
+
* Single source of truth for identity of Tango-synthesized many-to-many
|
|
774
|
+
* through models. Other parts of the schema package interact with synthesized
|
|
775
|
+
* models exclusively through this class so they do not have to know the
|
|
776
|
+
* namespace or digest scheme those keys encode.
|
|
777
|
+
*/
|
|
786
778
|
var ImplicitManyToManyIdentifier = class ImplicitManyToManyIdentifier {
|
|
787
779
|
static NAMESPACE = "tango.implicit";
|
|
788
780
|
/**
|
|
@@ -834,10 +826,9 @@ var ImplicitManyToManyIdentifier = class ImplicitManyToManyIdentifier {
|
|
|
834
826
|
return modelKey.slice(prefix.length);
|
|
835
827
|
}
|
|
836
828
|
static digest(sourceModelKey, sourceSchemaFieldKey, targetModelKey, byteLength) {
|
|
837
|
-
return createHash
|
|
829
|
+
return createHash("sha256").update(`${sourceModelKey}\0${sourceSchemaFieldKey}\0${targetModelKey}`, "utf8").digest("hex").slice(0, byteLength);
|
|
838
830
|
}
|
|
839
831
|
};
|
|
840
|
-
|
|
841
832
|
//#endregion
|
|
842
833
|
//#region src/domain/internal/InternalReferentialAction.ts
|
|
843
834
|
const InternalReferentialAction = {
|
|
@@ -846,7 +837,6 @@ const InternalReferentialAction = {
|
|
|
846
837
|
RESTRICT: "RESTRICT",
|
|
847
838
|
NO_ACTION: "NO ACTION"
|
|
848
839
|
};
|
|
849
|
-
|
|
850
840
|
//#endregion
|
|
851
841
|
//#region src/model/relations/ImplicitManyToManyThroughFactory.ts
|
|
852
842
|
var ImplicitManyToManyThroughFactory = class ImplicitManyToManyThroughFactory {
|
|
@@ -941,11 +931,7 @@ var ImplicitManyToManyThroughFactory = class ImplicitManyToManyThroughFactory {
|
|
|
941
931
|
}
|
|
942
932
|
static clonePrimaryKeySchemaForForeignKey(zodType) {
|
|
943
933
|
const unwrapped = ImplicitManyToManyThroughFactory.unwrapForForeignKeyField(zodType);
|
|
944
|
-
if (isZodNumber(unwrapped))
|
|
945
|
-
const checks = unwrapped._zod.def.checks ?? [];
|
|
946
|
-
const isInt = checks.some((check) => "format" in check._zod.def && check._zod.def.format === "safeint");
|
|
947
|
-
return isInt ? z.number().int() : z.number();
|
|
948
|
-
}
|
|
934
|
+
if (isZodNumber(unwrapped)) return (unwrapped._zod.def.checks ?? []).some((check) => "format" in check._zod.def && check._zod.def.format === "safeint") ? z.number().int() : z.number();
|
|
949
935
|
if (isZodString(unwrapped)) return z.string();
|
|
950
936
|
if (isZodBoolean(unwrapped)) return z.boolean();
|
|
951
937
|
if (isZodDate(unwrapped)) return z.date();
|
|
@@ -955,10 +941,7 @@ var ImplicitManyToManyThroughFactory = class ImplicitManyToManyThroughFactory {
|
|
|
955
941
|
}
|
|
956
942
|
static readSinglePrimaryKey(model) {
|
|
957
943
|
const keys = [];
|
|
958
|
-
for (const [fieldKey
|
|
959
|
-
const meta$1 = getFieldMetadata(zodType$1);
|
|
960
|
-
if (meta$1?.primaryKey) keys.push(fieldKey$1);
|
|
961
|
-
}
|
|
944
|
+
for (const [fieldKey, zodType] of Object.entries(model.schema.shape)) if (getFieldMetadata(zodType)?.primaryKey) keys.push(fieldKey);
|
|
962
945
|
if (keys.length !== 1) throw new Error(`Implicit many-to-many requires model '${model.metadata.key}' to declare exactly one primary key field.`);
|
|
963
946
|
const fieldKey = keys[0];
|
|
964
947
|
const zodType = model.schema.shape[fieldKey];
|
|
@@ -990,7 +973,6 @@ var ImplicitManyToManyThroughFactory = class ImplicitManyToManyThroughFactory {
|
|
|
990
973
|
return candidate;
|
|
991
974
|
}
|
|
992
975
|
};
|
|
993
|
-
|
|
994
976
|
//#endregion
|
|
995
977
|
//#region src/model/relations/ResolvedRelationGraphBuilder.ts
|
|
996
978
|
const REFERENCE_CAPABILITIES = Object.freeze({
|
|
@@ -1004,10 +986,24 @@ const MANY_TO_MANY_CAPABILITIES = Object.freeze({
|
|
|
1004
986
|
hydratable: true
|
|
1005
987
|
});
|
|
1006
988
|
const RELATION_NAME_SEPARATOR = ":";
|
|
989
|
+
/**
|
|
990
|
+
* Resolution-stage builder that turns normalized relation descriptors into the
|
|
991
|
+
* registry-scoped resolved relation graph.
|
|
992
|
+
*
|
|
993
|
+
* This is the final pipeline stage in the relations subdomain. It combines:
|
|
994
|
+
*
|
|
995
|
+
* - normalized field-authored relation descriptors
|
|
996
|
+
* - explicit model-level relation names from `RelationBuilder`
|
|
997
|
+
* - finalized storage artifacts from the registry
|
|
998
|
+
*
|
|
999
|
+
* The result is the canonical named relation graph used by ORM-facing
|
|
1000
|
+
* consumers.
|
|
1001
|
+
*/
|
|
1007
1002
|
var ResolvedRelationGraphBuilder = class ResolvedRelationGraphBuilder {
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1003
|
+
options;
|
|
1004
|
+
byModel = /* @__PURE__ */ new Map();
|
|
1005
|
+
byEdgeId = /* @__PURE__ */ new Map();
|
|
1006
|
+
matchedOverrides = /* @__PURE__ */ new Set();
|
|
1011
1007
|
constructor(options) {
|
|
1012
1008
|
this.options = options;
|
|
1013
1009
|
}
|
|
@@ -1160,8 +1156,7 @@ var ResolvedRelationGraphBuilder = class ResolvedRelationGraphBuilder {
|
|
|
1160
1156
|
const reverseModelRelations = InternalSchemaModel.getExplicitRelations(targetModel) ?? {};
|
|
1161
1157
|
const reverseKind = descriptor.unique ? InternalRelationPublicKind.HAS_ONE : InternalRelationPublicKind.HAS_MANY;
|
|
1162
1158
|
return Object.entries(reverseModelRelations).find(([, relation]) => {
|
|
1163
|
-
|
|
1164
|
-
return relationTargetKey === sourceModel.metadata.key && relation.type === reverseKind && relation.foreignKey === descriptor.sourceSchemaFieldKey;
|
|
1159
|
+
return this.resolveRelationTargetKey(targetModel, relation.target) === sourceModel.metadata.key && relation.type === reverseKind && relation.foreignKey === descriptor.sourceSchemaFieldKey;
|
|
1165
1160
|
});
|
|
1166
1161
|
}
|
|
1167
1162
|
assertAllOverridesMatched(model) {
|
|
@@ -1173,9 +1168,8 @@ var ResolvedRelationGraphBuilder = class ResolvedRelationGraphBuilder {
|
|
|
1173
1168
|
}
|
|
1174
1169
|
}
|
|
1175
1170
|
addResolvedRelation(descriptor) {
|
|
1176
|
-
const modelRelations = this.byModel.get(descriptor.sourceModelKey) ?? new Map();
|
|
1177
|
-
|
|
1178
|
-
if (existing) throw new Error(`Ambiguous relation name '${descriptor.name}' on model '${descriptor.sourceModelKey}'. Add an explicit relations override.`);
|
|
1171
|
+
const modelRelations = this.byModel.get(descriptor.sourceModelKey) ?? /* @__PURE__ */ new Map();
|
|
1172
|
+
if (modelRelations.get(descriptor.name)) throw new Error(`Ambiguous relation name '${descriptor.name}' on model '${descriptor.sourceModelKey}'. Add an explicit relations override.`);
|
|
1179
1173
|
modelRelations.set(descriptor.name, descriptor);
|
|
1180
1174
|
this.byModel.set(descriptor.sourceModelKey, modelRelations);
|
|
1181
1175
|
this.byEdgeId.set(descriptor.edgeId, descriptor);
|
|
@@ -1199,16 +1193,21 @@ var ResolvedRelationGraphBuilder = class ResolvedRelationGraphBuilder {
|
|
|
1199
1193
|
return cardinality === InternalRelationCardinality.MANY ? pluralize(snake) : snake;
|
|
1200
1194
|
}
|
|
1201
1195
|
};
|
|
1202
|
-
|
|
1203
1196
|
//#endregion
|
|
1204
1197
|
//#region src/model/registry/GeneratedRelationRegistryArtifact.ts
|
|
1205
1198
|
const GENERATED_RELATION_REGISTRY_DIRNAME = ".tango";
|
|
1206
1199
|
const GENERATED_RELATION_REGISTRY_TYPES_FILENAME = "relations.generated.d.ts";
|
|
1207
1200
|
const GENERATED_RELATION_REGISTRY_METADATA_FILENAME = "relations.generated.json";
|
|
1208
1201
|
const GENERATED_RELATION_REGISTRY_METADATA_VERSION = 1;
|
|
1209
|
-
|
|
1210
1202
|
//#endregion
|
|
1211
1203
|
//#region src/model/registry/ResolvedRelationGraphArtifactFactory.ts
|
|
1204
|
+
/**
|
|
1205
|
+
* Build canonical serialized artifacts from a resolved relation graph.
|
|
1206
|
+
*
|
|
1207
|
+
* Generation, drift detection, and related tooling all need the same stable
|
|
1208
|
+
* snapshot shape and fingerprinting rules, so that work lives behind one class
|
|
1209
|
+
* instead of a pair of free functions.
|
|
1210
|
+
*/
|
|
1212
1211
|
var ResolvedRelationGraphArtifactFactory = class ResolvedRelationGraphArtifactFactory {
|
|
1213
1212
|
static createSnapshot(graph) {
|
|
1214
1213
|
return ResolvedRelationGraphBuilder.createSnapshot(graph);
|
|
@@ -1218,14 +1217,22 @@ var ResolvedRelationGraphArtifactFactory = class ResolvedRelationGraphArtifactFa
|
|
|
1218
1217
|
return createHash("sha256").update(JSON.stringify(snapshot)).digest("hex");
|
|
1219
1218
|
}
|
|
1220
1219
|
};
|
|
1221
|
-
|
|
1222
1220
|
//#endregion
|
|
1223
1221
|
//#region src/model/registry/ModelRegistry.ts
|
|
1224
1222
|
const DEFAULT_IDENTIFIER_NAME = "id";
|
|
1225
1223
|
const ACTIVE_REGISTRY_STORAGE_KEY = Symbol.for("tango.schema.activeRegistryStorage");
|
|
1224
|
+
/**
|
|
1225
|
+
* Registry that resolves Tango models by stable identity.
|
|
1226
|
+
*
|
|
1227
|
+
* The default shared registry is convenient for application bootstrapping
|
|
1228
|
+
* within one schema package instance, while dedicated instances are useful in
|
|
1229
|
+
* tests and tooling. Explicit active-registry binding stays process-shared so
|
|
1230
|
+
* tooling can construct models across separate schema package copies without
|
|
1231
|
+
* relying on the ambient default registry.
|
|
1232
|
+
*/
|
|
1226
1233
|
var ModelRegistry = class ModelRegistry {
|
|
1227
1234
|
static globalRegistry;
|
|
1228
|
-
models = new Map();
|
|
1235
|
+
models = /* @__PURE__ */ new Map();
|
|
1229
1236
|
version = 0;
|
|
1230
1237
|
storageCache;
|
|
1231
1238
|
relationGraphCache;
|
|
@@ -1307,8 +1314,7 @@ var ModelRegistry = class ModelRegistry {
|
|
|
1307
1314
|
* Register a model on this registry instance.
|
|
1308
1315
|
*/
|
|
1309
1316
|
register(model) {
|
|
1310
|
-
|
|
1311
|
-
if (owner !== this) throw new Error(`Model '${model.metadata.key}' belongs to a different registry and cannot be registered here.`);
|
|
1317
|
+
if (InternalSchemaModel.getRegistryOwner(model) !== this) throw new Error(`Model '${model.metadata.key}' belongs to a different registry and cannot be registered here.`);
|
|
1312
1318
|
const existing = this.models.get(model.metadata.key);
|
|
1313
1319
|
if (existing && existing !== model) throw new Error(`Model '${model.metadata.key}' is already registered in this registry.`);
|
|
1314
1320
|
this.models.set(model.metadata.key, model);
|
|
@@ -1338,9 +1344,9 @@ var ModelRegistry = class ModelRegistry {
|
|
|
1338
1344
|
resolveRef(ref) {
|
|
1339
1345
|
if (typeof ref === "string" || isTypedModelRef(ref)) {
|
|
1340
1346
|
const key = typeof ref === "string" ? ref : ref.key;
|
|
1341
|
-
const model
|
|
1342
|
-
if (!model
|
|
1343
|
-
return model
|
|
1347
|
+
const model = this.getByKey(key);
|
|
1348
|
+
if (!model) throw new Error(`Unable to resolve model reference '${key}'. Ensure it is registered in ModelRegistry.`);
|
|
1349
|
+
return model;
|
|
1344
1350
|
}
|
|
1345
1351
|
const model = typeof ref === "function" ? ref() : ref;
|
|
1346
1352
|
if (InternalSchemaModel.getRegistryOwner(model) !== this) throw new Error(`Model reference '${model.metadata.key}' belongs to a different registry and cannot be resolved here.`);
|
|
@@ -1355,9 +1361,9 @@ var ModelRegistry = class ModelRegistry {
|
|
|
1355
1361
|
const implicitThroughModels = ImplicitManyToManyThroughFactory.buildModels(this);
|
|
1356
1362
|
for (const model of implicitThroughModels) this.models.set(model.metadata.key, model);
|
|
1357
1363
|
if (strippedImplicit || implicitThroughModels.length > 0) this.bumpVersion();
|
|
1358
|
-
const primaryKeyByModel = new Map();
|
|
1364
|
+
const primaryKeyByModel = /* @__PURE__ */ new Map();
|
|
1359
1365
|
for (const model of this.models.values()) primaryKeyByModel.set(model.metadata.key, this.inferPrimaryKeyName(model));
|
|
1360
|
-
const byModel = new Map();
|
|
1366
|
+
const byModel = /* @__PURE__ */ new Map();
|
|
1361
1367
|
for (const model of this.models.values()) {
|
|
1362
1368
|
const explicitFields = InternalSchemaModel.getExplicitFields(model);
|
|
1363
1369
|
const inferredFields = inferFieldsFromSchema(model.schema, {
|
|
@@ -1371,12 +1377,12 @@ var ModelRegistry = class ModelRegistry {
|
|
|
1371
1377
|
}
|
|
1372
1378
|
});
|
|
1373
1379
|
const fields = this.freezeFields(this.mergeStorageFields(inferredFields, explicitFields));
|
|
1374
|
-
const primaryKey
|
|
1380
|
+
const primaryKey = fields.find((field) => field.primaryKey)?.name ?? DEFAULT_IDENTIFIER_NAME;
|
|
1375
1381
|
byModel.set(model.metadata.key, {
|
|
1376
1382
|
key: model.metadata.key,
|
|
1377
1383
|
table: model.metadata.table,
|
|
1378
1384
|
fields,
|
|
1379
|
-
pk: primaryKey
|
|
1385
|
+
pk: primaryKey
|
|
1380
1386
|
});
|
|
1381
1387
|
}
|
|
1382
1388
|
const finalized = {
|
|
@@ -1438,9 +1444,9 @@ var ModelRegistry = class ModelRegistry {
|
|
|
1438
1444
|
}
|
|
1439
1445
|
bumpVersion() {
|
|
1440
1446
|
this.version += 1;
|
|
1441
|
-
this.storageCache =
|
|
1442
|
-
this.relationGraphCache =
|
|
1443
|
-
this.lastRelationRegistryDriftCheckVersion =
|
|
1447
|
+
this.storageCache = void 0;
|
|
1448
|
+
this.relationGraphCache = void 0;
|
|
1449
|
+
this.lastRelationRegistryDriftCheckVersion = void 0;
|
|
1444
1450
|
}
|
|
1445
1451
|
stripImplicitManyToManyModels() {
|
|
1446
1452
|
let removed = false;
|
|
@@ -1451,7 +1457,7 @@ var ModelRegistry = class ModelRegistry {
|
|
|
1451
1457
|
return removed;
|
|
1452
1458
|
}
|
|
1453
1459
|
freezeFields(fields) {
|
|
1454
|
-
return Object.freeze(fields.map((field
|
|
1460
|
+
return Object.freeze(fields.map((field) => Object.freeze({ ...field })));
|
|
1455
1461
|
}
|
|
1456
1462
|
inferPrimaryKeyName(model) {
|
|
1457
1463
|
for (const [fieldKey, zodType] of Object.entries(model.schema.shape)) {
|
|
@@ -1459,12 +1465,12 @@ var ModelRegistry = class ModelRegistry {
|
|
|
1459
1465
|
if (meta?.primaryKey) return meta.dbColumn ?? fieldKey;
|
|
1460
1466
|
}
|
|
1461
1467
|
const explicitFields = InternalSchemaModel.getExplicitFields(model);
|
|
1462
|
-
if (explicitFields) return explicitFields.find((field
|
|
1468
|
+
if (explicitFields) return explicitFields.find((field) => field.primaryKey)?.name ?? DEFAULT_IDENTIFIER_NAME;
|
|
1463
1469
|
return DEFAULT_IDENTIFIER_NAME;
|
|
1464
1470
|
}
|
|
1465
1471
|
mergeStorageFields(inferredFields, explicitFields) {
|
|
1466
1472
|
if (!explicitFields?.length) return inferredFields;
|
|
1467
|
-
const mergedFields = new Map(inferredFields.map((field
|
|
1473
|
+
const mergedFields = new Map(inferredFields.map((field) => [field.name, field]));
|
|
1468
1474
|
for (const explicitField of explicitFields) mergedFields.set(explicitField.name, explicitField);
|
|
1469
1475
|
return Array.from(mergedFields.values());
|
|
1470
1476
|
}
|
|
@@ -1475,26 +1481,25 @@ var ModelRegistry = class ModelRegistry {
|
|
|
1475
1481
|
if (!expected) return;
|
|
1476
1482
|
const liveSnapshot = ResolvedRelationGraphArtifactFactory.createSnapshot(graph);
|
|
1477
1483
|
if (this.isPartialRegistrySnapshot(liveSnapshot, expected.snapshot)) return;
|
|
1478
|
-
|
|
1479
|
-
if (liveFingerprint === expected.fingerprint) return;
|
|
1484
|
+
if (ResolvedRelationGraphArtifactFactory.createFingerprint(liveSnapshot) === expected.fingerprint) return;
|
|
1480
1485
|
getLogger("tango.schema.registry").warn(`Generated relation registry drift detected. Run 'tango codegen relations' to refresh ${GENERATED_RELATION_REGISTRY_DIRNAME}/${GENERATED_RELATION_REGISTRY_METADATA_FILENAME}.`);
|
|
1481
1486
|
}
|
|
1482
1487
|
shouldCheckGeneratedRelationRegistry() {
|
|
1483
1488
|
return process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test";
|
|
1484
1489
|
}
|
|
1485
1490
|
readGeneratedRelationRegistryArtifact() {
|
|
1486
|
-
const metadataPath = resolve
|
|
1487
|
-
if (!existsSync
|
|
1491
|
+
const metadataPath = resolve(process.cwd(), GENERATED_RELATION_REGISTRY_DIRNAME, GENERATED_RELATION_REGISTRY_METADATA_FILENAME);
|
|
1492
|
+
if (!existsSync(metadataPath)) return;
|
|
1488
1493
|
try {
|
|
1489
1494
|
const parsed = JSON.parse(readFileSync(metadataPath, "utf8"));
|
|
1490
|
-
if (parsed.version !==
|
|
1495
|
+
if (parsed.version !== 1 || typeof parsed.fingerprint !== "string" || !parsed.snapshot || !Array.isArray(parsed.snapshot.models)) {
|
|
1491
1496
|
getLogger("tango.schema.registry").warn(`Ignoring malformed generated relation registry metadata at '${metadataPath}'.`);
|
|
1492
|
-
return
|
|
1497
|
+
return;
|
|
1493
1498
|
}
|
|
1494
1499
|
return parsed;
|
|
1495
1500
|
} catch (error) {
|
|
1496
1501
|
getLogger("tango.schema.registry").warn(`Unable to read generated relation registry metadata at '${metadataPath}'.`, error);
|
|
1497
|
-
return
|
|
1502
|
+
return;
|
|
1498
1503
|
}
|
|
1499
1504
|
}
|
|
1500
1505
|
isPartialRegistrySnapshot(liveSnapshot, expectedSnapshot) {
|
|
@@ -1508,10 +1513,16 @@ var ModelRegistry = class ModelRegistry {
|
|
|
1508
1513
|
return true;
|
|
1509
1514
|
}
|
|
1510
1515
|
};
|
|
1511
|
-
|
|
1512
1516
|
//#endregion
|
|
1513
1517
|
//#region src/resolveSchemaModuleEntrypoint.ts
|
|
1514
1518
|
const LOCAL_ENTRYPOINT_CANDIDATES = ["./index.ts", "./index.js"];
|
|
1519
|
+
/**
|
|
1520
|
+
* Resolve the current package root entrypoint for `@danceroutine/tango-schema`.
|
|
1521
|
+
*
|
|
1522
|
+
* Tooling loaders alias app-side `@danceroutine/tango-schema` imports back to
|
|
1523
|
+
* this path so project modules reuse the same schema package instance across
|
|
1524
|
+
* workspace-source and published-dist environments.
|
|
1525
|
+
*/
|
|
1515
1526
|
function resolveSchemaModuleEntrypoint() {
|
|
1516
1527
|
for (const relativePath of LOCAL_ENTRYPOINT_CANDIDATES) {
|
|
1517
1528
|
const absolutePath = fileURLToPath(new URL(relativePath, import.meta.url));
|
|
@@ -1519,6 +1530,17 @@ function resolveSchemaModuleEntrypoint() {
|
|
|
1519
1530
|
}
|
|
1520
1531
|
throw new Error(`Unable to resolve the @danceroutine/tango-schema entrypoint relative to '${fileURLToPath(import.meta.url)}'.`);
|
|
1521
1532
|
}
|
|
1533
|
+
/**
|
|
1534
|
+
* Return explicit Jiti alias entries for the schema package root and its
|
|
1535
|
+
* public subpaths so app modules always reuse the same schema package instance.
|
|
1536
|
+
*
|
|
1537
|
+
* @internal
|
|
1538
|
+
* Exported for Tango tooling/framework consumption only. This helper exists so
|
|
1539
|
+
* Tango loaders can force app modules to reuse the active schema package
|
|
1540
|
+
* instance during module execution. It is not intended as a stable application
|
|
1541
|
+
* API, and the alias map may be more permissive than the package exports
|
|
1542
|
+
* surface by design.
|
|
1543
|
+
*/
|
|
1522
1544
|
function createSchemaModuleAliases() {
|
|
1523
1545
|
const entrypoint = resolveSchemaModuleEntrypoint();
|
|
1524
1546
|
const packageRoot = dirname(entrypoint);
|
|
@@ -1533,29 +1555,27 @@ function createSchemaModuleAliases() {
|
|
|
1533
1555
|
"@danceroutine/tango-schema/": `${packageRoot}/`
|
|
1534
1556
|
};
|
|
1535
1557
|
}
|
|
1536
|
-
|
|
1537
1558
|
//#endregion
|
|
1538
1559
|
//#region src/model/registry/index.ts
|
|
1539
|
-
var registry_exports = {
|
|
1540
|
-
__export(registry_exports, {
|
|
1560
|
+
var registry_exports = /* @__PURE__ */ __exportAll({
|
|
1541
1561
|
GENERATED_RELATION_REGISTRY_DIRNAME: () => GENERATED_RELATION_REGISTRY_DIRNAME,
|
|
1542
1562
|
GENERATED_RELATION_REGISTRY_METADATA_FILENAME: () => GENERATED_RELATION_REGISTRY_METADATA_FILENAME,
|
|
1543
|
-
GENERATED_RELATION_REGISTRY_METADATA_VERSION: () =>
|
|
1563
|
+
GENERATED_RELATION_REGISTRY_METADATA_VERSION: () => 1,
|
|
1544
1564
|
GENERATED_RELATION_REGISTRY_TYPES_FILENAME: () => GENERATED_RELATION_REGISTRY_TYPES_FILENAME,
|
|
1545
1565
|
ModelRegistry: () => ModelRegistry,
|
|
1546
1566
|
ResolvedRelationGraphArtifactFactory: () => ResolvedRelationGraphArtifactFactory,
|
|
1547
1567
|
createSchemaModuleAliases: () => createSchemaModuleAliases,
|
|
1548
1568
|
resolveSchemaModuleEntrypoint: () => resolveSchemaModuleEntrypoint
|
|
1549
1569
|
});
|
|
1550
|
-
|
|
1551
1570
|
//#endregion
|
|
1552
1571
|
//#region src/model/relations/index.ts
|
|
1553
|
-
var relations_exports = {};
|
|
1554
|
-
__export(relations_exports, { RelationBuilder: () => RelationBuilder });
|
|
1555
|
-
|
|
1572
|
+
var relations_exports = /* @__PURE__ */ __exportAll({ RelationBuilder: () => RelationBuilder });
|
|
1556
1573
|
//#endregion
|
|
1557
1574
|
//#region src/model/ModelAugmentorRegistry.ts
|
|
1558
|
-
const modelAugmentors = new Set();
|
|
1575
|
+
const modelAugmentors = /* @__PURE__ */ new Set();
|
|
1576
|
+
/**
|
|
1577
|
+
* Register a model augmentor that runs for existing and future models.
|
|
1578
|
+
*/
|
|
1559
1579
|
function registerModelAugmentor(augmentor) {
|
|
1560
1580
|
modelAugmentors.add(augmentor);
|
|
1561
1581
|
for (const model of ModelRegistry.global().values()) augmentor(model);
|
|
@@ -1563,29 +1583,33 @@ function registerModelAugmentor(augmentor) {
|
|
|
1563
1583
|
modelAugmentors.delete(augmentor);
|
|
1564
1584
|
};
|
|
1565
1585
|
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Apply all registered augmentors to a model before it is returned publicly.
|
|
1588
|
+
*/
|
|
1566
1589
|
function applyModelAugmentors(model) {
|
|
1567
1590
|
for (const augmentor of modelAugmentors) augmentor(model);
|
|
1568
1591
|
return model;
|
|
1569
1592
|
}
|
|
1570
|
-
|
|
1571
1593
|
//#endregion
|
|
1572
1594
|
//#region src/model/Model.ts
|
|
1595
|
+
/**
|
|
1596
|
+
* Creates a model definition with metadata and schema validation.
|
|
1597
|
+
* Automatically finalizes field types through the owning model registry.
|
|
1598
|
+
*/
|
|
1573
1599
|
function Model(definition) {
|
|
1574
1600
|
const registry = definition.registry ?? ModelRegistry.active();
|
|
1575
1601
|
const model = applyModelAugmentors(InternalSchemaModel.create(definition, registry));
|
|
1576
1602
|
registry.register(model);
|
|
1577
1603
|
return model;
|
|
1578
1604
|
}
|
|
1579
|
-
|
|
1580
1605
|
//#endregion
|
|
1581
1606
|
//#region src/model/index.ts
|
|
1582
|
-
var model_exports = {
|
|
1583
|
-
__export(model_exports, {
|
|
1607
|
+
var model_exports = /* @__PURE__ */ __exportAll({
|
|
1584
1608
|
Constraints: () => Constraints,
|
|
1585
1609
|
Decorators: () => Decorators,
|
|
1586
1610
|
GENERATED_RELATION_REGISTRY_DIRNAME: () => GENERATED_RELATION_REGISTRY_DIRNAME,
|
|
1587
1611
|
GENERATED_RELATION_REGISTRY_METADATA_FILENAME: () => GENERATED_RELATION_REGISTRY_METADATA_FILENAME,
|
|
1588
|
-
GENERATED_RELATION_REGISTRY_METADATA_VERSION: () =>
|
|
1612
|
+
GENERATED_RELATION_REGISTRY_METADATA_VERSION: () => 1,
|
|
1589
1613
|
GENERATED_RELATION_REGISTRY_TYPES_FILENAME: () => GENERATED_RELATION_REGISTRY_TYPES_FILENAME,
|
|
1590
1614
|
ImplicitManyToManyIdentifier: () => ImplicitManyToManyIdentifier,
|
|
1591
1615
|
Indexes: () => Indexes,
|
|
@@ -1610,7 +1634,7 @@ __export(model_exports, {
|
|
|
1610
1634
|
resolveSchemaModuleEntrypoint: () => resolveSchemaModuleEntrypoint,
|
|
1611
1635
|
t: () => Decorators
|
|
1612
1636
|
});
|
|
1613
|
-
|
|
1614
1637
|
//#endregion
|
|
1615
|
-
export {
|
|
1616
|
-
|
|
1638
|
+
export { InternalDecoratedFieldKind as C, Decorators as S, isTypedModelRef as T, Indexes as _, registry_exports as a, Meta as b, ModelRegistry as c, GENERATED_RELATION_REGISTRY_METADATA_FILENAME as d, GENERATED_RELATION_REGISTRY_METADATA_VERSION as f, constraints_exports as g, RelationBuilder as h, relations_exports as i, ResolvedRelationGraphArtifactFactory as l, ImplicitManyToManyIdentifier as m, Model as n, createSchemaModuleAliases as o, GENERATED_RELATION_REGISTRY_TYPES_FILENAME as p, registerModelAugmentor as r, resolveSchemaModuleEntrypoint as s, model_exports as t, GENERATED_RELATION_REGISTRY_DIRNAME as u, Constraints as v, createTypedModelRef as w, decorators_exports as x, meta_exports as y };
|
|
1639
|
+
|
|
1640
|
+
//# sourceMappingURL=model-aRAusQPz.js.map
|