@happyvertical/smrt-core 0.42.7 → 0.43.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.
Files changed (101) hide show
  1. package/AGENTS.md +35 -2
  2. package/agents/schema-paths.md +37 -15
  3. package/dist/cascade.d.ts +7 -6
  4. package/dist/cascade.d.ts.map +1 -1
  5. package/dist/cascade.js +19 -21
  6. package/dist/cascade.js.map +1 -1
  7. package/dist/class.d.ts +10 -0
  8. package/dist/class.d.ts.map +1 -1
  9. package/dist/class.js +21 -0
  10. package/dist/class.js.map +1 -1
  11. package/dist/decorators/index.d.ts +50 -15
  12. package/dist/decorators/index.d.ts.map +1 -1
  13. package/dist/decorators/index.js +23 -11
  14. package/dist/decorators/index.js.map +1 -1
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +2 -1
  18. package/dist/manifest/static-manifest.d.ts.map +1 -1
  19. package/dist/manifest/static-manifest.js +17 -1
  20. package/dist/manifest/static-manifest.js.map +1 -1
  21. package/dist/manifest/store.js +1 -1
  22. package/dist/manifest/store.js.map +1 -1
  23. package/dist/manifest.json +20 -1
  24. package/dist/migrations/differ.d.ts +2 -0
  25. package/dist/migrations/differ.d.ts.map +1 -1
  26. package/dist/migrations/differ.js +103 -0
  27. package/dist/migrations/differ.js.map +1 -1
  28. package/dist/migrations/generator.d.ts.map +1 -1
  29. package/dist/migrations/generator.js +26 -2
  30. package/dist/migrations/generator.js.map +1 -1
  31. package/dist/migrations/orchestrate.d.ts.map +1 -1
  32. package/dist/migrations/orchestrate.js +4 -1
  33. package/dist/migrations/orchestrate.js.map +1 -1
  34. package/dist/object.d.ts +4 -4
  35. package/dist/object.js +4 -4
  36. package/dist/object.js.map +1 -1
  37. package/dist/registry/schema-builder.d.ts +6 -0
  38. package/dist/registry/schema-builder.d.ts.map +1 -1
  39. package/dist/registry/schema-builder.js +80 -8
  40. package/dist/registry/schema-builder.js.map +1 -1
  41. package/dist/registry.d.ts +5 -7
  42. package/dist/registry.d.ts.map +1 -1
  43. package/dist/registry.js +6 -8
  44. package/dist/registry.js.map +1 -1
  45. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  46. package/dist/scanner/manifest-generator.js +64 -18
  47. package/dist/scanner/manifest-generator.js.map +1 -1
  48. package/dist/scanner/types.d.ts +7 -1
  49. package/dist/scanner/types.d.ts.map +1 -1
  50. package/dist/scanner/types.js.map +1 -1
  51. package/dist/schema/ddl/base-strategy.d.ts.map +1 -1
  52. package/dist/schema/ddl/base-strategy.js +2 -0
  53. package/dist/schema/ddl/base-strategy.js.map +1 -1
  54. package/dist/schema/ddl/duckdb-strategy.d.ts +1 -0
  55. package/dist/schema/ddl/duckdb-strategy.d.ts.map +1 -1
  56. package/dist/schema/ddl/duckdb-strategy.js +23 -1
  57. package/dist/schema/ddl/duckdb-strategy.js.map +1 -1
  58. package/dist/schema/ddl/postgres-strategy.js +1 -1
  59. package/dist/schema/foreign-key-ddl.d.ts +16 -0
  60. package/dist/schema/foreign-key-ddl.d.ts.map +1 -0
  61. package/dist/schema/foreign-key-ddl.js +85 -0
  62. package/dist/schema/foreign-key-ddl.js.map +1 -0
  63. package/dist/schema/foreign-key-planner.d.ts +18 -0
  64. package/dist/schema/foreign-key-planner.d.ts.map +1 -0
  65. package/dist/schema/foreign-key-planner.js +109 -0
  66. package/dist/schema/foreign-key-planner.js.map +1 -0
  67. package/dist/schema/foreign-key-policy.d.ts +21 -0
  68. package/dist/schema/foreign-key-policy.d.ts.map +1 -0
  69. package/dist/schema/foreign-key-policy.js +41 -0
  70. package/dist/schema/foreign-key-policy.js.map +1 -0
  71. package/dist/schema/generator.d.ts +3 -0
  72. package/dist/schema/generator.d.ts.map +1 -1
  73. package/dist/schema/generator.js +65 -13
  74. package/dist/schema/generator.js.map +1 -1
  75. package/dist/schema/index.d.ts +3 -0
  76. package/dist/schema/index.d.ts.map +1 -1
  77. package/dist/schema/index.js +4 -1
  78. package/dist/schema/manifest-schema.d.ts.map +1 -1
  79. package/dist/schema/manifest-schema.js +21 -3
  80. package/dist/schema/manifest-schema.js.map +1 -1
  81. package/dist/schema/schema-aggregator.d.ts +7 -1
  82. package/dist/schema/schema-aggregator.d.ts.map +1 -1
  83. package/dist/schema/schema-aggregator.js +54 -9
  84. package/dist/schema/schema-aggregator.js.map +1 -1
  85. package/dist/schema/schema-manager.d.ts +1 -6
  86. package/dist/schema/schema-manager.d.ts.map +1 -1
  87. package/dist/schema/schema-manager.js +26 -30
  88. package/dist/schema/schema-manager.js.map +1 -1
  89. package/dist/schema/types.d.ts +12 -5
  90. package/dist/schema/types.d.ts.map +1 -1
  91. package/dist/schema/utils.d.ts +1 -1
  92. package/dist/schema/utils.d.ts.map +1 -1
  93. package/dist/schema/utils.js +15 -1
  94. package/dist/schema/utils.js.map +1 -1
  95. package/dist/schema.js +4 -1
  96. package/dist/smrt-knowledge.json +18 -8
  97. package/dist/testing/database.d.ts +11 -1
  98. package/dist/testing/database.d.ts.map +1 -1
  99. package/dist/testing/database.js +80 -9
  100. package/dist/testing/database.js.map +1 -1
  101. package/package.json +4 -4
@@ -0,0 +1,109 @@
1
+ import { quoteIdentifier } from "./sql-identifiers.js";
2
+ import { foreignKeyConstraintName, renderForeignKeyConstraint, schemaDependenciesForEngine, schemaForeignKeys, schemaForeignKeysForEngine } from "./foreign-key-ddl.js";
3
+ //#region src/schema/foreign-key-planner.ts
4
+ /** Render the inverse of a PostgreSQL deferred ADD CONSTRAINT statement. */
5
+ function renderDeferredForeignKeyDrop(table, foreignKey) {
6
+ return `ALTER TABLE ${quoteIdentifier(table)} DROP CONSTRAINT IF EXISTS ${quoteIdentifier(foreignKeyConstraintName(table, foreignKey))};`;
7
+ }
8
+ function stronglyConnectedComponents(names, dependencies) {
9
+ let nextIndex = 0;
10
+ const indexes = /* @__PURE__ */ new Map();
11
+ const lowLinks = /* @__PURE__ */ new Map();
12
+ const stack = [];
13
+ const onStack = /* @__PURE__ */ new Set();
14
+ const componentByName = /* @__PURE__ */ new Map();
15
+ let component = 0;
16
+ const visit = (name) => {
17
+ indexes.set(name, nextIndex);
18
+ lowLinks.set(name, nextIndex);
19
+ nextIndex++;
20
+ stack.push(name);
21
+ onStack.add(name);
22
+ for (const dependency of dependencies.get(name) || []) if (!indexes.has(dependency)) {
23
+ visit(dependency);
24
+ lowLinks.set(name, Math.min(lowLinks.get(name) ?? 0, lowLinks.get(dependency) ?? 0));
25
+ } else if (onStack.has(dependency)) lowLinks.set(name, Math.min(lowLinks.get(name) ?? 0, indexes.get(dependency) ?? 0));
26
+ if (lowLinks.get(name) !== indexes.get(name)) return;
27
+ while (stack.length > 0) {
28
+ const member = stack.pop();
29
+ onStack.delete(member);
30
+ componentByName.set(member, component);
31
+ if (member === name) break;
32
+ }
33
+ component++;
34
+ };
35
+ for (const name of names) if (!indexes.has(name)) visit(name);
36
+ return componentByName;
37
+ }
38
+ function omitForeignKeys(schema, omitted) {
39
+ if (omitted.size === 0) return schema;
40
+ const columns = Object.fromEntries(Object.entries(schema.columns).map(([name, definition]) => [name, omitted.has(name) ? {
41
+ ...definition,
42
+ foreignKey: void 0
43
+ } : definition]));
44
+ return {
45
+ ...schema,
46
+ columns,
47
+ foreignKeys: schemaForeignKeys(schema).filter((foreignKey) => !omitted.has(foreignKey.column))
48
+ };
49
+ }
50
+ /** Deterministically order new tables and define safe behavior for FK cycles. */
51
+ function planForeignKeyCreation(input, engine) {
52
+ const byName = new Map([...input].sort((a, b) => a.tableName.localeCompare(b.tableName)).map((schema) => [schema.tableName, schema]));
53
+ const names = [...byName.keys()];
54
+ const dependencies = /* @__PURE__ */ new Map();
55
+ for (const [name, schema] of byName) {
56
+ for (const foreignKey of schemaForeignKeysForEngine(schema, engine)) renderForeignKeyConstraint(name, foreignKey);
57
+ dependencies.set(name, Array.from(new Set(schemaDependenciesForEngine(schema, engine).filter((target) => target !== name && byName.has(target)))).sort());
58
+ }
59
+ const components = stronglyConnectedComponents(names, dependencies);
60
+ const componentSizes = /* @__PURE__ */ new Map();
61
+ for (const id of components.values()) componentSizes.set(id, (componentSizes.get(id) || 0) + 1);
62
+ const isMutualCycle = (source, target) => {
63
+ const component = components.get(source);
64
+ return source !== target && component !== void 0 && component === components.get(target) && (componentSizes.get(component) || 0) > 1;
65
+ };
66
+ if (engine === "duckdb" || engine === "json") for (const [source, schema] of byName) for (const foreignKey of schemaForeignKeysForEngine(schema, engine)) {
67
+ if (source === foreignKey.referencesTable) throw new Error(`[DDL:${engine}] Foreign key ${source}.${foreignKey.column} is self-referential; DuckDB cannot insert self-referencing foreign keys safely.`);
68
+ if (foreignKey.onDelete === "CASCADE" || foreignKey.onDelete === "SET NULL") throw new Error(`[DDL:${engine}] Foreign key ${source}.${foreignKey.column} uses ON DELETE ${foreignKey.onDelete}, which DuckDB does not support. Use PostgreSQL/SQLite or keep this relationship app-side only with @crossPackageRef.`);
69
+ if (foreignKey.onUpdate !== void 0) throw new Error(`[DDL:${engine}] Foreign key ${source}.${foreignKey.column} uses ON UPDATE ${foreignKey.onUpdate}, which DuckDB does not support. DuckDB cannot preserve SMRT's ON UPDATE CASCADE contract; use PostgreSQL/SQLite or keep this relationship app-side only with @crossPackageRef.`);
70
+ if (isMutualCycle(source, foreignKey.referencesTable)) throw new Error(`[DDL:${engine}] Foreign-key cycle ${source}.${foreignKey.column} -> ${foreignKey.referencesTable}.${foreignKey.referencesColumn} cannot be created safely because DuckDB does not support ALTER TABLE ADD CONSTRAINT.`);
71
+ }
72
+ const visited = /* @__PURE__ */ new Set();
73
+ const visiting = /* @__PURE__ */ new Set();
74
+ const orderedNames = [];
75
+ const visit = (name) => {
76
+ if (visited.has(name) || visiting.has(name)) return;
77
+ visiting.add(name);
78
+ for (const dependency of dependencies.get(name) || []) visit(dependency);
79
+ visiting.delete(name);
80
+ visited.add(name);
81
+ orderedNames.push(name);
82
+ };
83
+ for (const name of names) visit(name);
84
+ const deferred = [];
85
+ const schemas = orderedNames.map((name) => {
86
+ const schema = byName.get(name);
87
+ if (engine !== "postgres") return schema;
88
+ const omitted = /* @__PURE__ */ new Set();
89
+ for (const foreignKey of schemaForeignKeysForEngine(schema, engine)) if (isMutualCycle(name, foreignKey.referencesTable)) {
90
+ omitted.add(foreignKey.column);
91
+ deferred.push({
92
+ table: name,
93
+ foreignKey
94
+ });
95
+ }
96
+ return omitForeignKeys(schema, omitted);
97
+ });
98
+ deferred.sort((a, b) => `${a.table}.${a.foreignKey.column}`.localeCompare(`${b.table}.${b.foreignKey.column}`));
99
+ return {
100
+ schemas,
101
+ cyclicTables: names.filter((name) => (componentSizes.get(components.get(name) ?? -1) || 0) > 1),
102
+ deferredConstraints: deferred,
103
+ deferredStatements: deferred.map(({ table, foreignKey }) => `ALTER TABLE ${quoteIdentifier(table)} ADD ${renderForeignKeyConstraint(table, foreignKey)};`)
104
+ };
105
+ }
106
+ //#endregion
107
+ export { planForeignKeyCreation, renderDeferredForeignKeyDrop };
108
+
109
+ //# sourceMappingURL=foreign-key-planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"foreign-key-planner.js","names":[],"sources":["../../src/schema/foreign-key-planner.ts"],"sourcesContent":["import type { DatabaseEngine } from './ddl/types.js';\nimport {\n foreignKeyConstraintName,\n renderForeignKeyConstraint,\n schemaDependenciesForEngine,\n schemaForeignKeys,\n schemaForeignKeysForEngine,\n} from './foreign-key-ddl.js';\nimport { quoteIdentifier } from './sql-identifiers.js';\nimport type { ForeignKeyDefinition, SchemaDefinition } from './types.js';\n\nexport interface ForeignKeyCreationPlan {\n schemas: SchemaDefinition[];\n deferredStatements: string[];\n /** Tables participating in a multi-table strongly connected component. */\n cyclicTables: string[];\n /** PostgreSQL constraints omitted from CREATE TABLE and added afterward. */\n deferredConstraints: Array<{\n table: string;\n foreignKey: ForeignKeyDefinition;\n }>;\n}\n\n/** Render the inverse of a PostgreSQL deferred ADD CONSTRAINT statement. */\nexport function renderDeferredForeignKeyDrop(\n table: string,\n foreignKey: ForeignKeyDefinition,\n): string {\n return `ALTER TABLE ${quoteIdentifier(table)} DROP CONSTRAINT IF EXISTS ${quoteIdentifier(\n foreignKeyConstraintName(table, foreignKey),\n )};`;\n}\n\nfunction stronglyConnectedComponents(\n names: string[],\n dependencies: Map<string, string[]>,\n): Map<string, number> {\n let nextIndex = 0;\n const indexes = new Map<string, number>();\n const lowLinks = new Map<string, number>();\n const stack: string[] = [];\n const onStack = new Set<string>();\n const componentByName = new Map<string, number>();\n let component = 0;\n\n const visit = (name: string): void => {\n indexes.set(name, nextIndex);\n lowLinks.set(name, nextIndex);\n nextIndex++;\n stack.push(name);\n onStack.add(name);\n\n for (const dependency of dependencies.get(name) || []) {\n if (!indexes.has(dependency)) {\n visit(dependency);\n lowLinks.set(\n name,\n Math.min(lowLinks.get(name) ?? 0, lowLinks.get(dependency) ?? 0),\n );\n } else if (onStack.has(dependency)) {\n lowLinks.set(\n name,\n Math.min(lowLinks.get(name) ?? 0, indexes.get(dependency) ?? 0),\n );\n }\n }\n\n if (lowLinks.get(name) !== indexes.get(name)) return;\n while (stack.length > 0) {\n const member = stack.pop() as string;\n onStack.delete(member);\n componentByName.set(member, component);\n if (member === name) break;\n }\n component++;\n };\n\n for (const name of names) {\n if (!indexes.has(name)) visit(name);\n }\n return componentByName;\n}\n\nfunction omitForeignKeys(\n schema: SchemaDefinition,\n omitted: Set<string>,\n): SchemaDefinition {\n if (omitted.size === 0) return schema;\n const columns = Object.fromEntries(\n Object.entries(schema.columns).map(([name, definition]) => [\n name,\n omitted.has(name) ? { ...definition, foreignKey: undefined } : definition,\n ]),\n );\n return {\n ...schema,\n columns,\n foreignKeys: schemaForeignKeys(schema).filter(\n (foreignKey) => !omitted.has(foreignKey.column),\n ),\n };\n}\n\n/** Deterministically order new tables and define safe behavior for FK cycles. */\nexport function planForeignKeyCreation(\n input: readonly SchemaDefinition[],\n engine: DatabaseEngine,\n): ForeignKeyCreationPlan {\n const byName = new Map(\n [...input]\n .sort((a, b) => a.tableName.localeCompare(b.tableName))\n .map((schema) => [schema.tableName, schema]),\n );\n const names = [...byName.keys()];\n const dependencies = new Map<string, string[]>();\n for (const [name, schema] of byName) {\n for (const foreignKey of schemaForeignKeysForEngine(schema, engine)) {\n // Validate externally supplied manifest actions before a dry-run can\n // report an executable plan.\n renderForeignKeyConstraint(name, foreignKey);\n }\n dependencies.set(\n name,\n Array.from(\n new Set(\n schemaDependenciesForEngine(schema, engine).filter(\n (target) => target !== name && byName.has(target),\n ),\n ),\n ).sort(),\n );\n }\n\n const components = stronglyConnectedComponents(names, dependencies);\n const componentSizes = new Map<number, number>();\n for (const id of components.values()) {\n componentSizes.set(id, (componentSizes.get(id) || 0) + 1);\n }\n const isMutualCycle = (source: string, target: string): boolean => {\n const component = components.get(source);\n return (\n source !== target &&\n component !== undefined &&\n component === components.get(target) &&\n (componentSizes.get(component) || 0) > 1\n );\n };\n\n if (engine === 'duckdb' || engine === 'json') {\n for (const [source, schema] of byName) {\n for (const foreignKey of schemaForeignKeysForEngine(schema, engine)) {\n if (source === foreignKey.referencesTable) {\n throw new Error(\n `[DDL:${engine}] Foreign key ${source}.${foreignKey.column} is self-referential; DuckDB cannot insert self-referencing foreign keys safely.`,\n );\n }\n if (\n foreignKey.onDelete === 'CASCADE' ||\n foreignKey.onDelete === 'SET NULL'\n ) {\n throw new Error(\n `[DDL:${engine}] Foreign key ${source}.${foreignKey.column} uses ON DELETE ${foreignKey.onDelete}, which DuckDB does not support. Use PostgreSQL/SQLite or keep this relationship app-side only with @crossPackageRef.`,\n );\n }\n if (foreignKey.onUpdate !== undefined) {\n throw new Error(\n `[DDL:${engine}] Foreign key ${source}.${foreignKey.column} uses ON UPDATE ${foreignKey.onUpdate}, which DuckDB does not support. DuckDB cannot preserve SMRT's ON UPDATE CASCADE contract; use PostgreSQL/SQLite or keep this relationship app-side only with @crossPackageRef.`,\n );\n }\n if (isMutualCycle(source, foreignKey.referencesTable)) {\n throw new Error(\n `[DDL:${engine}] Foreign-key cycle ${source}.${foreignKey.column} -> ${foreignKey.referencesTable}.${foreignKey.referencesColumn} cannot be created safely because DuckDB does not support ALTER TABLE ADD CONSTRAINT.`,\n );\n }\n }\n }\n }\n\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const orderedNames: string[] = [];\n const visit = (name: string): void => {\n if (visited.has(name) || visiting.has(name)) return;\n visiting.add(name);\n for (const dependency of dependencies.get(name) || []) visit(dependency);\n visiting.delete(name);\n visited.add(name);\n orderedNames.push(name);\n };\n for (const name of names) visit(name);\n\n const deferred: Array<{ table: string; foreignKey: ForeignKeyDefinition }> =\n [];\n const schemas = orderedNames.map((name) => {\n const schema = byName.get(name) as SchemaDefinition;\n if (engine !== 'postgres') return schema;\n const omitted = new Set<string>();\n for (const foreignKey of schemaForeignKeysForEngine(schema, engine)) {\n if (isMutualCycle(name, foreignKey.referencesTable)) {\n omitted.add(foreignKey.column);\n deferred.push({ table: name, foreignKey });\n }\n }\n return omitForeignKeys(schema, omitted);\n });\n\n deferred.sort((a, b) =>\n `${a.table}.${a.foreignKey.column}`.localeCompare(\n `${b.table}.${b.foreignKey.column}`,\n ),\n );\n return {\n schemas,\n cyclicTables: names.filter(\n (name) => (componentSizes.get(components.get(name) ?? -1) || 0) > 1,\n ),\n deferredConstraints: deferred,\n deferredStatements: deferred.map(\n ({ table, foreignKey }) =>\n `ALTER TABLE ${quoteIdentifier(table)} ADD ${renderForeignKeyConstraint(table, foreignKey)};`,\n ),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { ForeignKeyAction } from './types.js';
2
+ /** Normalize decorator action spelling into the SQL vocabulary. */
3
+ export declare function normalizeForeignKeyAction(value: unknown): ForeignKeyAction | undefined;
4
+ /** Validate an externally supplied action rather than interpolating raw SQL. */
5
+ export declare function requireForeignKeyAction(value: unknown, context: string): ForeignKeyAction;
6
+ /**
7
+ * Resolve the one delete policy shared by app-side cascade and database DDL.
8
+ *
9
+ * A same-package reference that identifies the referencing row defaults to
10
+ * CASCADE. Tenant ids are scope markers rather than ownership edges, and all
11
+ * other references default to SQL NO ACTION.
12
+ */
13
+ export declare function resolveForeignKeyDeleteAction(options: {
14
+ declared?: unknown;
15
+ isConflictColumn: boolean;
16
+ isTenantIdField: boolean;
17
+ }): {
18
+ action: ForeignKeyAction;
19
+ declared: boolean;
20
+ };
21
+ //# sourceMappingURL=foreign-key-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"foreign-key-policy.d.ts","sourceRoot":"","sources":["../../src/schema/foreign-key-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AASnD,mEAAmE;AACnE,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,GACb,gBAAgB,GAAG,SAAS,CAM9B;AAED,gFAAgF;AAChF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,MAAM,GACd,gBAAgB,CAQlB;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;CAC1B,GAAG;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAelD"}
@@ -0,0 +1,41 @@
1
+ //#region src/schema/foreign-key-policy.ts
2
+ var FOREIGN_KEY_ACTIONS = /* @__PURE__ */ new Set([
3
+ "CASCADE",
4
+ "SET NULL",
5
+ "RESTRICT",
6
+ "NO ACTION"
7
+ ]);
8
+ /** Normalize decorator action spelling into the SQL vocabulary. */
9
+ function normalizeForeignKeyAction(value) {
10
+ if (typeof value !== "string") return void 0;
11
+ const normalized = value.trim().toUpperCase().replace(/_/g, " ");
12
+ return FOREIGN_KEY_ACTIONS.has(normalized) ? normalized : void 0;
13
+ }
14
+ /** Validate an externally supplied action rather than interpolating raw SQL. */
15
+ function requireForeignKeyAction(value, context) {
16
+ const normalized = normalizeForeignKeyAction(value);
17
+ if (!normalized) throw new Error(`Invalid foreign-key action ${JSON.stringify(value)} for ${context}. Expected CASCADE, SET NULL, RESTRICT, or NO ACTION.`);
18
+ return normalized;
19
+ }
20
+ /**
21
+ * Resolve the one delete policy shared by app-side cascade and database DDL.
22
+ *
23
+ * A same-package reference that identifies the referencing row defaults to
24
+ * CASCADE. Tenant ids are scope markers rather than ownership edges, and all
25
+ * other references default to SQL NO ACTION.
26
+ */
27
+ function resolveForeignKeyDeleteAction(options) {
28
+ const declaredAction = options.declared === void 0 ? void 0 : requireForeignKeyAction(options.declared, "ON DELETE");
29
+ if (declaredAction) return {
30
+ action: declaredAction,
31
+ declared: true
32
+ };
33
+ return {
34
+ action: !options.isTenantIdField && options.isConflictColumn ? "CASCADE" : "NO ACTION",
35
+ declared: false
36
+ };
37
+ }
38
+ //#endregion
39
+ export { normalizeForeignKeyAction, requireForeignKeyAction, resolveForeignKeyDeleteAction };
40
+
41
+ //# sourceMappingURL=foreign-key-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"foreign-key-policy.js","names":[],"sources":["../../src/schema/foreign-key-policy.ts"],"sourcesContent":["import type { ForeignKeyAction } from './types.js';\n\nconst FOREIGN_KEY_ACTIONS = new Set<ForeignKeyAction>([\n 'CASCADE',\n 'SET NULL',\n 'RESTRICT',\n 'NO ACTION',\n]);\n\n/** Normalize decorator action spelling into the SQL vocabulary. */\nexport function normalizeForeignKeyAction(\n value: unknown,\n): ForeignKeyAction | undefined {\n if (typeof value !== 'string') return undefined;\n const normalized = value.trim().toUpperCase().replace(/_/g, ' ');\n return FOREIGN_KEY_ACTIONS.has(normalized as ForeignKeyAction)\n ? (normalized as ForeignKeyAction)\n : undefined;\n}\n\n/** Validate an externally supplied action rather than interpolating raw SQL. */\nexport function requireForeignKeyAction(\n value: unknown,\n context: string,\n): ForeignKeyAction {\n const normalized = normalizeForeignKeyAction(value);\n if (!normalized) {\n throw new Error(\n `Invalid foreign-key action ${JSON.stringify(value)} for ${context}. Expected CASCADE, SET NULL, RESTRICT, or NO ACTION.`,\n );\n }\n return normalized;\n}\n\n/**\n * Resolve the one delete policy shared by app-side cascade and database DDL.\n *\n * A same-package reference that identifies the referencing row defaults to\n * CASCADE. Tenant ids are scope markers rather than ownership edges, and all\n * other references default to SQL NO ACTION.\n */\nexport function resolveForeignKeyDeleteAction(options: {\n declared?: unknown;\n isConflictColumn: boolean;\n isTenantIdField: boolean;\n}): { action: ForeignKeyAction; declared: boolean } {\n const declaredAction =\n options.declared === undefined\n ? undefined\n : requireForeignKeyAction(options.declared, 'ON DELETE');\n if (declaredAction) {\n return { action: declaredAction, declared: true };\n }\n return {\n action:\n !options.isTenantIdField && options.isConflictColumn\n ? 'CASCADE'\n : 'NO ACTION',\n declared: false,\n };\n}\n"],"mappings":";AAEA,IAAM,sCAAsB,IAAI,IAAsB;CACpD;CACA;CACA;CACA;AACF,CAAC;;AAGD,SAAgB,0BACd,OAC8B;CAC9B,IAAI,OAAO,UAAU,UAAU,OAAO,KAAA;CACtC,MAAM,aAAa,MAAM,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,MAAM,GAAG;CAC/D,OAAO,oBAAoB,IAAI,UAA8B,IACxD,aACD,KAAA;AACN;;AAGA,SAAgB,wBACd,OACA,SACkB;CAClB,MAAM,aAAa,0BAA0B,KAAK;CAClD,IAAI,CAAC,YACH,MAAM,IAAI,MACR,8BAA8B,KAAK,UAAU,KAAK,EAAE,OAAO,QAAQ,sDACrE;CAEF,OAAO;AACT;;;;;;;;AASA,SAAgB,8BAA8B,SAIM;CAClD,MAAM,iBACJ,QAAQ,aAAa,KAAA,IACjB,KAAA,IACA,wBAAwB,QAAQ,UAAU,WAAW;CAC3D,IAAI,gBACF,OAAO;EAAE,QAAQ;EAAgB,UAAU;CAAK;CAElD,OAAO;EACL,QACE,CAAC,QAAQ,mBAAmB,QAAQ,mBAChC,YACA;EACN,UAAU;CACZ;AACF"}
@@ -57,7 +57,9 @@ type SchemaGeneratorConfig = {
57
57
  };
58
58
  getDescendants(baseClassName: string): string[];
59
59
  getAllFields(className: string): Promise<Map<string, RegistryField>>;
60
+ getFields?(className: string): Map<string, RegistryField>;
60
61
  getSTIBase?(className: string): string | null;
62
+ getTableName?(className: string): string | undefined;
61
63
  };
62
64
  };
63
65
  export declare class SchemaGenerator {
@@ -71,6 +73,7 @@ export declare class SchemaGenerator {
71
73
  private shouldEmitDefault;
72
74
  private getRegistryTargetIdColumnType;
73
75
  private reconcileRegistryForeignKeyColumnTypes;
76
+ private applyRegistryForeignKeys;
74
77
  /**
75
78
  * Whether an existing index already leads with `leadingColumns`, in order.
76
79
  *
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/schema/generator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/schema/generator.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { resolveForeignKeyDeleteAction } from "./foreign-key-policy.js";
1
2
  import { classnameToTablename } from "../utils/naming.js";
2
3
  import { formatDefaultValue, quoteIdentifier, quoteStringLiteral } from "./sql-identifiers.js";
3
4
  import { assertIdentifierFits, enforceIdentifierLimits } from "./index-utils.js";
@@ -9,6 +10,10 @@ import { createHash } from "node:crypto";
9
10
  * Schema generator for SMRT objects
10
11
  * Converts AST field definitions to database schema definitions
11
12
  */
13
+ function getForeignKeyConstraintEngines(field) {
14
+ const constraint = field._meta?.constraint;
15
+ return typeof constraint === "object" ? [...constraint.engines] : void 0;
16
+ }
12
17
  var SchemaGenerator = class {
13
18
  /**
14
19
  * Convert field type to SQL data type
@@ -67,6 +72,45 @@ var SchemaGenerator = class {
67
72
  };
68
73
  }
69
74
  }
75
+ applyRegistryForeignKeys(columns, fields, conflictColumns, registry) {
76
+ const conflictSet = new Set(conflictColumns);
77
+ for (const [fieldName, field] of fields.entries()) {
78
+ if (field.type !== "foreignKey" || !field.related) continue;
79
+ const columnName = this.toSnakeCase(fieldName);
80
+ const column = columns[columnName];
81
+ if (!column) continue;
82
+ if (field._meta?.constraint === false) {
83
+ column.foreignKey = void 0;
84
+ continue;
85
+ }
86
+ const isTenantIdField = field.__tenancy?.isTenantIdField === true || field._meta?.__tenancy?.isTenantIdField === true;
87
+ if (isTenantIdField) {
88
+ column.foreignKey = void 0;
89
+ continue;
90
+ }
91
+ const [targetName, declaredTargetColumn] = field.related.split(".");
92
+ const targetBase = registry?.getSTIBase?.(targetName) || targetName;
93
+ const registeredTargetTable = registry?.getTableName?.(targetBase);
94
+ if (registry && !registeredTargetTable) {
95
+ column.foreignKey = void 0;
96
+ continue;
97
+ }
98
+ const targetColumn = declaredTargetColumn || Array.from(registry?.getFields?.(targetBase)?.entries() || []).find(([, targetField]) => targetField._meta?.primaryKey === true)?.[0] || "id";
99
+ const targetTable = registeredTargetTable || this.classNameToTableName(targetBase);
100
+ const { action } = resolveForeignKeyDeleteAction({
101
+ declared: field._meta?.onDelete,
102
+ isConflictColumn: conflictSet.has(columnName),
103
+ isTenantIdField
104
+ });
105
+ column.foreignKey = {
106
+ table: targetTable,
107
+ column: this.toSnakeCase(targetColumn),
108
+ onDelete: action,
109
+ onUpdate: "CASCADE",
110
+ ...getForeignKeyConstraintEngines(field) ? { engines: getForeignKeyConstraintEngines(field) } : {}
111
+ };
112
+ }
113
+ }
70
114
  /**
71
115
  * Whether an existing index already leads with `leadingColumns`, in order.
72
116
  *
@@ -483,7 +527,8 @@ var SchemaGenerator = class {
483
527
  referencesTable: columnDef.foreignKey.table,
484
528
  referencesColumn: columnDef.foreignKey.column,
485
529
  onDelete: columnDef.foreignKey.onDelete,
486
- onUpdate: columnDef.foreignKey.onUpdate
530
+ onUpdate: columnDef.foreignKey.onUpdate,
531
+ ...columnDef.foreignKey.engines ? { engines: columnDef.foreignKey.engines } : {}
487
532
  });
488
533
  return foreignKeys;
489
534
  }
@@ -570,14 +615,15 @@ var SchemaGenerator = class {
570
615
  description: field._meta?.description
571
616
  };
572
617
  if (field._meta?.default !== void 0 && this.shouldEmitDefault(field, field._meta.default)) columnDef.defaultValue = field._meta.default;
573
- if (field.type === "foreignKey") {
618
+ if (field.type === "foreignKey" && field._meta?.constraint !== false && field._meta?.__tenancy?.isTenantIdField !== true) {
574
619
  const relatedName = field.related;
575
620
  const onDeleteAction = field._meta?.onDelete;
576
621
  if (relatedName) columnDef.foreignKey = {
577
622
  table: this.classNameToTableName(relatedName),
578
623
  column: "id",
579
624
  onDelete: onDeleteAction || "CASCADE",
580
- onUpdate: "CASCADE"
625
+ onUpdate: "CASCADE",
626
+ ...getForeignKeyConstraintEngines(field) ? { engines: getForeignKeyConstraintEngines(field) } : {}
581
627
  };
582
628
  }
583
629
  if ((field._meta?.indexed === true || field.indexed === true) && !columnDef.foreignKey && !columnDef.unique && !columnDef.primaryKey) indexedColumns.add(this.toSnakeCase(fieldName));
@@ -596,9 +642,11 @@ var SchemaGenerator = class {
596
642
  description: "Last update timestamp"
597
643
  };
598
644
  this.reconcileRegistryForeignKeyColumnTypes(columns, fields, config?.registry);
645
+ const resolvedConflict = this.resolveConflictTarget("cti", columns, config);
646
+ this.applyRegistryForeignKeys(columns, fields, resolvedConflict.conflictColumns, config?.registry);
599
647
  const indexes = [];
600
648
  if (!hasCustomPK) {
601
- const { conflictColumns, tenantColumn } = this.resolveConflictTarget("cti", columns, config);
649
+ const { conflictColumns, tenantColumn } = resolvedConflict;
602
650
  if (!this.conflictColumnsArePrimaryKey(conflictColumns, columns)) indexes.push({
603
651
  name: conflictIndexName(tableName, conflictColumns, tenantColumn),
604
652
  columns: conflictColumns,
@@ -623,7 +671,7 @@ var SchemaGenerator = class {
623
671
  indexes,
624
672
  triggers: [],
625
673
  foreignKeys: this.extractForeignKeys(columns),
626
- dependencies: [],
674
+ dependencies: this.extractForeignKeys(columns).map((foreignKey) => foreignKey.referencesTable).filter((dependency) => dependency !== tableName),
627
675
  version: createHash("sha256").update(JSON.stringify(columns)).digest("hex").substring(0, 8),
628
676
  packageName: "runtime",
629
677
  baseClass: "SmrtObject"
@@ -755,14 +803,15 @@ var SchemaGenerator = class {
755
803
  description: field._meta?.description
756
804
  };
757
805
  if (field._meta?.default !== void 0 && this.shouldEmitDefault(field, field._meta.default)) columnDef.defaultValue = field._meta.default;
758
- if (field.type === "foreignKey") {
806
+ if (field.type === "foreignKey" && field._meta?.constraint !== false && field._meta?.__tenancy?.isTenantIdField !== true) {
759
807
  const relatedName = field.related;
760
808
  const onDeleteAction = field._meta?.onDelete;
761
809
  if (relatedName) columnDef.foreignKey = {
762
810
  table: this.classNameToTableName(relatedName),
763
811
  column: "id",
764
812
  onDelete: onDeleteAction || "CASCADE",
765
- onUpdate: "CASCADE"
813
+ onUpdate: "CASCADE",
814
+ ...getForeignKeyConstraintEngines(field) ? { engines: getForeignKeyConstraintEngines(field) } : {}
766
815
  };
767
816
  }
768
817
  if ((field._meta?.indexed === true || field.indexed === true) && !columnDef.foreignKey) indexedStiColumns.add(columnName);
@@ -781,9 +830,11 @@ var SchemaGenerator = class {
781
830
  defaultValue: "current_timestamp",
782
831
  description: "Last update timestamp"
783
832
  };
833
+ const resolvedConflict = this.resolveConflictTarget("sti", columns, config);
784
834
  for (const className of allClassNames) {
785
835
  const classFields = await ObjectRegistry.getAllFields(className);
786
836
  this.reconcileRegistryForeignKeyColumnTypes(columns, classFields, ObjectRegistry);
837
+ this.applyRegistryForeignKeys(columns, classFields, resolvedConflict.conflictColumns, ObjectRegistry);
787
838
  }
788
839
  const indexes = [];
789
840
  this.emitStiConflictIndex(indexes, columns, tableName, config);
@@ -819,7 +870,7 @@ var SchemaGenerator = class {
819
870
  indexes,
820
871
  triggers: [],
821
872
  foreignKeys: this.extractForeignKeys(columns),
822
- dependencies: [],
873
+ dependencies: this.extractForeignKeys(columns).map((foreignKey) => foreignKey.referencesTable).filter((dependency) => dependency !== tableName),
823
874
  version: createHash("sha256").update(JSON.stringify({
824
875
  columns,
825
876
  baseClassName,
@@ -949,8 +1000,8 @@ var SchemaGenerator = class {
949
1000
  jsonPath: idx.jsonPath
950
1001
  })),
951
1002
  triggers: [],
952
- foreignKeys: [],
953
- dependencies: [],
1003
+ foreignKeys: this.extractForeignKeys(this.convertManifestColumnsToSchemaColumns(columns)),
1004
+ dependencies: this.extractForeignKeys(this.convertManifestColumnsToSchemaColumns(columns)).map((foreignKey) => foreignKey.referencesTable).filter((dependency) => dependency !== tableName),
954
1005
  version: "",
955
1006
  packageName: ""
956
1007
  };
@@ -1046,8 +1097,8 @@ var SchemaGenerator = class {
1046
1097
  jsonPath: idx.jsonPath
1047
1098
  })),
1048
1099
  triggers: [],
1049
- foreignKeys: [],
1050
- dependencies: [],
1100
+ foreignKeys: this.extractForeignKeys(this.convertManifestColumnsToSchemaColumns(columns)),
1101
+ dependencies: this.extractForeignKeys(this.convertManifestColumnsToSchemaColumns(columns)).map((foreignKey) => foreignKey.referencesTable).filter((dependency) => dependency !== tableName),
1051
1102
  version: "",
1052
1103
  packageName: ""
1053
1104
  };
@@ -1108,7 +1159,8 @@ var SchemaGenerator = class {
1108
1159
  referenceKind: col.referenceKind,
1109
1160
  notNull: col.notNull,
1110
1161
  unique: col.unique,
1111
- defaultValue: col.default
1162
+ defaultValue: col.default,
1163
+ foreignKey: col.foreignKey ? { ...col.foreignKey } : void 0
1112
1164
  };
1113
1165
  return columns;
1114
1166
  }