@dbsp/core 1.10.1 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +25 -9
- package/dist/index.js +162 -42
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -767,6 +767,8 @@ interface SelfRefRoles {
|
|
|
767
767
|
* Options for ref() foreign key declarations.
|
|
768
768
|
*/
|
|
769
769
|
interface RefOptions {
|
|
770
|
+
/** Target schema name (omit for same-schema references) */
|
|
771
|
+
schema?: string;
|
|
770
772
|
/** Is this FK nullable? → optional relation */
|
|
771
773
|
nullable?: boolean;
|
|
772
774
|
/** Is this FK unique? → 1:1 instead of 1:N */
|
|
@@ -774,7 +776,7 @@ interface RefOptions {
|
|
|
774
776
|
/** ON DELETE action */
|
|
775
777
|
onDelete?: OnDeleteAction;
|
|
776
778
|
/** ON UPDATE action */
|
|
777
|
-
onUpdate?:
|
|
779
|
+
onUpdate?: OnDeleteAction;
|
|
778
780
|
/** Local relation name (e.g., 'createdBy' for createdById column) */
|
|
779
781
|
as?: string;
|
|
780
782
|
/** Inverse relation name on target table (e.g., 'writings' instead of 'author_posts') */
|
|
@@ -952,6 +954,8 @@ interface SchemaOptions {
|
|
|
952
954
|
interface Schema<T extends SchemaDefinition> {
|
|
953
955
|
/** The raw schema definition */
|
|
954
956
|
readonly definition: T;
|
|
957
|
+
/** Table-level constraints supplied to schema() or reconstructed from introspection */
|
|
958
|
+
readonly constraints?: SchemaConstraints;
|
|
955
959
|
/** Converted ModelIR for use with ORM */
|
|
956
960
|
readonly model: ModelIR;
|
|
957
961
|
/** Table names */
|
|
@@ -1229,6 +1233,8 @@ type SchemaOnDeleteAction = 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';
|
|
|
1229
1233
|
* When present, takes priority over convention-based FK detection.
|
|
1230
1234
|
*/
|
|
1231
1235
|
interface SchemaForeignKeyReference {
|
|
1236
|
+
/** Target schema name (omit for same-schema references) */
|
|
1237
|
+
readonly schema?: string;
|
|
1232
1238
|
/** Target table name */
|
|
1233
1239
|
table: string;
|
|
1234
1240
|
/** Target column name (defaults to 'id') */
|
|
@@ -4236,9 +4242,10 @@ interface GeneratedColumn {
|
|
|
4236
4242
|
readonly autoIncrement?: boolean;
|
|
4237
4243
|
readonly default?: string;
|
|
4238
4244
|
readonly references?: {
|
|
4245
|
+
readonly schema?: string;
|
|
4239
4246
|
readonly table: string;
|
|
4240
4247
|
readonly column?: string;
|
|
4241
|
-
readonly onDelete?:
|
|
4248
|
+
readonly onDelete?: OnDeleteAction;
|
|
4242
4249
|
/** Create an index on this FK column (matches ColumnDefinitionSchema index field) */
|
|
4243
4250
|
readonly index?: boolean;
|
|
4244
4251
|
/** Role name for parent traversal in self-ref hierarchies (e.g., 'parent') */
|
|
@@ -4255,11 +4262,12 @@ interface GeneratedColumn {
|
|
|
4255
4262
|
interface GeneratedForeignKey {
|
|
4256
4263
|
readonly columns: readonly string[];
|
|
4257
4264
|
readonly references: {
|
|
4265
|
+
readonly schema?: string;
|
|
4258
4266
|
readonly table: string;
|
|
4259
4267
|
readonly columns: readonly string[];
|
|
4260
4268
|
};
|
|
4261
|
-
readonly onDelete?:
|
|
4262
|
-
readonly onUpdate?:
|
|
4269
|
+
readonly onDelete?: OnDeleteAction;
|
|
4270
|
+
readonly onUpdate?: OnDeleteAction;
|
|
4263
4271
|
}
|
|
4264
4272
|
interface GeneratedIndex {
|
|
4265
4273
|
readonly columns: readonly string[];
|
|
@@ -4476,9 +4484,10 @@ declare const ResolvedSchemaValidation: v.ObjectSchema<{
|
|
|
4476
4484
|
readonly autoIncrement: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
4477
4485
|
readonly default: v.OptionalSchema<v.UnionSchema<[v.StringSchema<undefined>, v.NumberSchema<undefined>, v.BooleanSchema<undefined>], undefined>, undefined>;
|
|
4478
4486
|
readonly references: v.OptionalSchema<v.ObjectSchema<{
|
|
4487
|
+
readonly schema: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TransformAction<string, string | undefined>]>, undefined>;
|
|
4479
4488
|
readonly table: v.StringSchema<undefined>;
|
|
4480
4489
|
readonly column: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
4481
|
-
readonly onDelete: v.OptionalSchema<v.PicklistSchema<["CASCADE", "SET NULL", "RESTRICT", "NO ACTION"], undefined>, undefined>;
|
|
4490
|
+
readonly onDelete: v.OptionalSchema<v.PicklistSchema<readonly ["CASCADE", "SET NULL", "SET DEFAULT", "RESTRICT", "NO ACTION"], undefined>, undefined>;
|
|
4482
4491
|
readonly index: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
4483
4492
|
readonly parentRole: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
4484
4493
|
readonly childRole: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -4489,11 +4498,12 @@ declare const ResolvedSchemaValidation: v.ObjectSchema<{
|
|
|
4489
4498
|
readonly foreignKeys: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
4490
4499
|
readonly columns: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
4491
4500
|
readonly references: v.ObjectSchema<{
|
|
4501
|
+
readonly schema: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TransformAction<string, string | undefined>]>, undefined>;
|
|
4492
4502
|
readonly table: v.StringSchema<undefined>;
|
|
4493
4503
|
readonly columns: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
4494
4504
|
}, undefined>;
|
|
4495
|
-
readonly onDelete: v.OptionalSchema<v.PicklistSchema<["CASCADE", "SET NULL", "RESTRICT", "NO ACTION"], undefined>, undefined>;
|
|
4496
|
-
readonly onUpdate: v.OptionalSchema<v.PicklistSchema<["CASCADE", "SET NULL", "RESTRICT", "NO ACTION"], undefined>, undefined>;
|
|
4505
|
+
readonly onDelete: v.OptionalSchema<v.PicklistSchema<readonly ["CASCADE", "SET NULL", "SET DEFAULT", "RESTRICT", "NO ACTION"], undefined>, undefined>;
|
|
4506
|
+
readonly onUpdate: v.OptionalSchema<v.PicklistSchema<readonly ["CASCADE", "SET NULL", "SET DEFAULT", "RESTRICT", "NO ACTION"], undefined>, undefined>;
|
|
4497
4507
|
}, undefined>, undefined>, undefined>;
|
|
4498
4508
|
readonly indexes: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
4499
4509
|
readonly columns: v.ArraySchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -4508,9 +4518,10 @@ declare const ResolvedSchemaValidation: v.ObjectSchema<{
|
|
|
4508
4518
|
readonly autoIncrement: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
4509
4519
|
readonly default: v.OptionalSchema<v.UnionSchema<[v.StringSchema<undefined>, v.NumberSchema<undefined>, v.BooleanSchema<undefined>], undefined>, undefined>;
|
|
4510
4520
|
readonly references: v.OptionalSchema<v.ObjectSchema<{
|
|
4521
|
+
readonly schema: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TransformAction<string, string | undefined>]>, undefined>;
|
|
4511
4522
|
readonly table: v.StringSchema<undefined>;
|
|
4512
4523
|
readonly column: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
4513
|
-
readonly onDelete: v.OptionalSchema<v.PicklistSchema<["CASCADE", "SET NULL", "RESTRICT", "NO ACTION"], undefined>, undefined>;
|
|
4524
|
+
readonly onDelete: v.OptionalSchema<v.PicklistSchema<readonly ["CASCADE", "SET NULL", "SET DEFAULT", "RESTRICT", "NO ACTION"], undefined>, undefined>;
|
|
4514
4525
|
readonly index: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
4515
4526
|
readonly parentRole: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
4516
4527
|
readonly childRole: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -4845,16 +4856,21 @@ interface OrmInstance<DB = Record<string, unknown>> {
|
|
|
4845
4856
|
* Use destructuring to get individual table references, then pass
|
|
4846
4857
|
* them to `from()` for type-safe queries.
|
|
4847
4858
|
*
|
|
4859
|
+
* Each entry also carries the runtime DDL helpers (`.truncate()`,
|
|
4860
|
+
* `.indexes.list()`, `.alterColumn()`, …) via the `TableDDL` mixin, mirroring
|
|
4861
|
+
* what `wrapTablesProxyWithDDL` produces at runtime.
|
|
4862
|
+
*
|
|
4848
4863
|
* @example
|
|
4849
4864
|
* ```typescript
|
|
4850
4865
|
* const { users, posts } = orm.tables;
|
|
4851
4866
|
* const activeUsers = await orm.from(users).where(eq(users.active, true)).all();
|
|
4867
|
+
* const indexes = await orm.tables.users.indexes.list();
|
|
4852
4868
|
* ```
|
|
4853
4869
|
*
|
|
4854
4870
|
* @since DX-040-SURFACE
|
|
4855
4871
|
*/
|
|
4856
4872
|
readonly tables: {
|
|
4857
|
-
[K in keyof DB & string]: TableRef<K, RowToColumnRefs<K, DB[K]>, any
|
|
4873
|
+
[K in keyof DB & string]: TableRef<K, RowToColumnRefs<K, DB[K]>, any> & TableDDL;
|
|
4858
4874
|
};
|
|
4859
4875
|
/**
|
|
4860
4876
|
* Start a type-safe SELECT query from a TableRef.
|
package/dist/index.js
CHANGED
|
@@ -58,6 +58,9 @@ __reExport(intent_ast_exports, types_star);
|
|
|
58
58
|
import * as types_star from "@dbsp/types";
|
|
59
59
|
|
|
60
60
|
// src/model-impl.ts
|
|
61
|
+
function hasExternalSchema(schemaName) {
|
|
62
|
+
return schemaName != null && schemaName.trim().length > 0;
|
|
63
|
+
}
|
|
61
64
|
var ModelIRImpl = class {
|
|
62
65
|
tables;
|
|
63
66
|
externalTables;
|
|
@@ -178,7 +181,7 @@ var ModelIRImpl = class {
|
|
|
178
181
|
}
|
|
179
182
|
for (const table of this.tables.values()) {
|
|
180
183
|
for (const fk of table.foreignKeys) {
|
|
181
|
-
if (!this.tables.has(fk.references.table) && !this.externalTables.has(fk.references.table)) {
|
|
184
|
+
if (!hasExternalSchema(fk.references.schema) && !this.tables.has(fk.references.table) && !this.externalTables.has(fk.references.table)) {
|
|
182
185
|
errors.push(
|
|
183
186
|
`Table "${table.name}" has FK referencing non-existent table "${fk.references.table}"`
|
|
184
187
|
);
|
|
@@ -623,11 +626,25 @@ function createTablesProxy(model, tableNames, options) {
|
|
|
623
626
|
}
|
|
624
627
|
|
|
625
628
|
// src/dx/schema.ts
|
|
629
|
+
function normalizeReferenceSchema(schemaName) {
|
|
630
|
+
if (schemaName == null) return void 0;
|
|
631
|
+
const t = schemaName.trim();
|
|
632
|
+
return t.length > 0 ? t : void 0;
|
|
633
|
+
}
|
|
634
|
+
function hasExternalSchema2(schemaName) {
|
|
635
|
+
return normalizeReferenceSchema(schemaName) !== void 0;
|
|
636
|
+
}
|
|
637
|
+
function normalizeRefOptions(options) {
|
|
638
|
+
const schemaName = normalizeReferenceSchema(options.schema);
|
|
639
|
+
if (schemaName === options.schema) return options;
|
|
640
|
+
const { schema: _schema, ...rest } = options;
|
|
641
|
+
return schemaName === void 0 ? rest : { ...rest, schema: schemaName };
|
|
642
|
+
}
|
|
626
643
|
function ref(target, options) {
|
|
627
644
|
return {
|
|
628
645
|
__brand: "ref",
|
|
629
646
|
target,
|
|
630
|
-
options: options
|
|
647
|
+
options: options ? normalizeRefOptions(options) : {}
|
|
631
648
|
};
|
|
632
649
|
}
|
|
633
650
|
function isRef(value) {
|
|
@@ -653,6 +670,7 @@ function schema(definition, constraints, options, extras) {
|
|
|
653
670
|
);
|
|
654
671
|
return {
|
|
655
672
|
definition,
|
|
673
|
+
...constraints !== void 0 ? { constraints } : {},
|
|
656
674
|
model,
|
|
657
675
|
tableNames,
|
|
658
676
|
tables,
|
|
@@ -721,21 +739,21 @@ function validateRefs(definition, tableNames) {
|
|
|
721
739
|
for (const [tableName, tableDef] of Object.entries(definition)) {
|
|
722
740
|
for (const [columnName, columnDef] of Object.entries(tableDef)) {
|
|
723
741
|
if (isRef(columnDef)) {
|
|
724
|
-
if (!tableSet.has(columnDef.target)) {
|
|
742
|
+
if (!hasExternalSchema2(columnDef.options.schema) && !tableSet.has(columnDef.target)) {
|
|
725
743
|
throw new SchemaValidationError(
|
|
726
744
|
`Foreign key '${columnName}' references non-existent table '${columnDef.target}'`,
|
|
727
745
|
tableName,
|
|
728
746
|
columnName
|
|
729
747
|
);
|
|
730
748
|
}
|
|
731
|
-
if (columnDef.target === tableName && !columnDef.options.roles) {
|
|
749
|
+
if (!hasExternalSchema2(columnDef.options.schema) && columnDef.target === tableName && !columnDef.options.roles) {
|
|
732
750
|
throw new SchemaValidationError(
|
|
733
751
|
`Self-referential FK '${columnName}' must have 'roles' option with parent/children names`,
|
|
734
752
|
tableName,
|
|
735
753
|
columnName
|
|
736
754
|
);
|
|
737
755
|
}
|
|
738
|
-
if (columnDef.target !== tableName && columnDef.options.roles) {
|
|
756
|
+
if ((hasExternalSchema2(columnDef.options.schema) || columnDef.target !== tableName) && columnDef.options.roles) {
|
|
739
757
|
throw new SchemaValidationError(
|
|
740
758
|
`'roles' option is only valid for self-referential FKs, but '${columnName}' references '${columnDef.target}'`,
|
|
741
759
|
tableName,
|
|
@@ -751,14 +769,6 @@ function validateFkTargets(tables) {
|
|
|
751
769
|
const tableMap = new Map(tables.map((t) => [t.name, t]));
|
|
752
770
|
for (const table of tables) {
|
|
753
771
|
for (const fk of table.foreignKeys) {
|
|
754
|
-
const target = tableMap.get(fk.references.table);
|
|
755
|
-
if (!target) {
|
|
756
|
-
throw new SchemaValidationError(
|
|
757
|
-
`Foreign key in '${table.name}' references non-existent table '${fk.references.table}'`,
|
|
758
|
-
table.name,
|
|
759
|
-
fk.columns[0]
|
|
760
|
-
);
|
|
761
|
-
}
|
|
762
772
|
for (const srcCol of fk.columns) {
|
|
763
773
|
if (!table.columns.some((c) => c.name === srcCol)) {
|
|
764
774
|
throw new SchemaValidationError(
|
|
@@ -782,6 +792,15 @@ function validateFkTargets(tables) {
|
|
|
782
792
|
fk.columns[0]
|
|
783
793
|
);
|
|
784
794
|
}
|
|
795
|
+
if (hasExternalSchema2(fk.references.schema)) continue;
|
|
796
|
+
const target = tableMap.get(fk.references.table);
|
|
797
|
+
if (!target) {
|
|
798
|
+
throw new SchemaValidationError(
|
|
799
|
+
`Foreign key in '${table.name}' references non-existent table '${fk.references.table}'`,
|
|
800
|
+
table.name,
|
|
801
|
+
fk.columns[0]
|
|
802
|
+
);
|
|
803
|
+
}
|
|
785
804
|
for (const refCol of fk.references.columns) {
|
|
786
805
|
if (!target.columns.some((c) => c.name === refCol)) {
|
|
787
806
|
throw new SchemaValidationError(
|
|
@@ -955,6 +974,14 @@ function getReferencedColumnType(targetDef, referencedCol, definition, visited)
|
|
|
955
974
|
}
|
|
956
975
|
function buildRefColumn(columnName, columnDef, definition) {
|
|
957
976
|
const targetDef = definition[columnDef.target];
|
|
977
|
+
const externalSchema = normalizeReferenceSchema(columnDef.options.schema);
|
|
978
|
+
if (externalSchema !== void 0) {
|
|
979
|
+
throw new SchemaValidationError(
|
|
980
|
+
`Cannot infer column type for foreign key column '${columnName}' to external table '${externalSchema}.${columnDef.target}'. Declare the source column with an explicit type and add the external foreign key at the table level with SchemaConstraints.foreignKeys.`,
|
|
981
|
+
void 0,
|
|
982
|
+
columnName
|
|
983
|
+
);
|
|
984
|
+
}
|
|
958
985
|
const targetCol = columnDef.options.references?.length === 1 ? columnDef.options.references[0] : void 0;
|
|
959
986
|
const inferredType = targetCol && targetDef ? getReferencedColumnType(targetDef, targetCol, definition) ?? getTargetPkType(definition, columnDef.target) : getTargetPkType(definition, columnDef.target);
|
|
960
987
|
const col2 = {
|
|
@@ -972,7 +999,8 @@ function buildRefColumn(columnName, columnDef, definition) {
|
|
|
972
999
|
columns: [columnName],
|
|
973
1000
|
references: {
|
|
974
1001
|
table: columnDef.target,
|
|
975
|
-
columns: columnDef.options.references ?? ["id"]
|
|
1002
|
+
columns: columnDef.options.references ?? ["id"],
|
|
1003
|
+
...externalSchema !== void 0 ? { schema: externalSchema } : {}
|
|
976
1004
|
}
|
|
977
1005
|
};
|
|
978
1006
|
if (columnDef.options.onDelete) fk.onDelete = columnDef.options.onDelete;
|
|
@@ -1028,7 +1056,7 @@ function buildPseudoColumns(tableName, refsByTable, finalPk) {
|
|
|
1028
1056
|
const refs = refsByTable.get(tableName) ?? [];
|
|
1029
1057
|
const pkColumn = typeof finalPk === "string" ? finalPk : finalPk?.[0] ?? "id";
|
|
1030
1058
|
for (const ref3 of refs) {
|
|
1031
|
-
if (ref3.options.roles && ref3.target === tableName) {
|
|
1059
|
+
if (!hasExternalSchema2(ref3.options.schema) && ref3.options.roles && ref3.target === tableName) {
|
|
1032
1060
|
pseudoColumns.push(
|
|
1033
1061
|
createPseudoColumnMetadata(
|
|
1034
1062
|
tableName,
|
|
@@ -1095,11 +1123,13 @@ function buildTableConstraints(tableName, constraints) {
|
|
|
1095
1123
|
tableName
|
|
1096
1124
|
);
|
|
1097
1125
|
}
|
|
1126
|
+
const externalSchema = normalizeReferenceSchema(fkRef.options.schema);
|
|
1098
1127
|
const fk = {
|
|
1099
1128
|
columns: [...fkRef.options.columns],
|
|
1100
1129
|
references: {
|
|
1101
1130
|
table: fkRef.target,
|
|
1102
|
-
columns: fkRef.options.references ? [...fkRef.options.references] : ["id"]
|
|
1131
|
+
columns: fkRef.options.references ? [...fkRef.options.references] : ["id"],
|
|
1132
|
+
...externalSchema !== void 0 ? { schema: externalSchema } : {}
|
|
1103
1133
|
}
|
|
1104
1134
|
};
|
|
1105
1135
|
if (fkRef.options.onDelete) fk.onDelete = fkRef.options.onDelete;
|
|
@@ -1147,6 +1177,7 @@ function buildRelations(_definition, refsByTable, tableNames, constraints) {
|
|
|
1147
1177
|
for (const tableName of tableNames) {
|
|
1148
1178
|
const refs = refsByTable.get(tableName) || [];
|
|
1149
1179
|
for (const ref3 of refs) {
|
|
1180
|
+
if (hasExternalSchema2(ref3.options.schema)) continue;
|
|
1150
1181
|
if (ref3.options.roles) {
|
|
1151
1182
|
const roles = ref3.options.roles;
|
|
1152
1183
|
relations.push({
|
|
@@ -1267,6 +1298,7 @@ function addCompositeConstraintRelations(relations, tableNames, constraints) {
|
|
|
1267
1298
|
const foreignKeys = constraints[tableName]?.foreignKeys;
|
|
1268
1299
|
if (!foreignKeys) continue;
|
|
1269
1300
|
for (const fkRef of foreignKeys) {
|
|
1301
|
+
if (hasExternalSchema2(fkRef.options.schema)) continue;
|
|
1270
1302
|
if (!tableSet.has(fkRef.target)) continue;
|
|
1271
1303
|
const columns = fkRef.options.columns;
|
|
1272
1304
|
if (!columns?.length) continue;
|
|
@@ -1338,38 +1370,102 @@ async function getSchemaFromDb(adapter, options) {
|
|
|
1338
1370
|
const model = introspectionResult;
|
|
1339
1371
|
const introspectedAt = introspectionResult.introspectedAt;
|
|
1340
1372
|
const fkLookup = /* @__PURE__ */ new Map();
|
|
1373
|
+
const compositeExternalFkLookup = /* @__PURE__ */ new Map();
|
|
1341
1374
|
for (const table of model.tables.values()) {
|
|
1342
1375
|
const tableFks = /* @__PURE__ */ new Map();
|
|
1343
1376
|
for (const fk of table.foreignKeys) {
|
|
1377
|
+
const externalSchema = normalizeReferenceSchema(fk.references.schema);
|
|
1378
|
+
if (externalSchema !== void 0 && fk.columns.length > 1) {
|
|
1379
|
+
const tableCompositeFks = compositeExternalFkLookup.get(table.name) ?? [];
|
|
1380
|
+
tableCompositeFks.push({
|
|
1381
|
+
...fk,
|
|
1382
|
+
references: {
|
|
1383
|
+
...fk.references,
|
|
1384
|
+
schema: externalSchema
|
|
1385
|
+
}
|
|
1386
|
+
});
|
|
1387
|
+
compositeExternalFkLookup.set(table.name, tableCompositeFks);
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1344
1390
|
const fkColumn = fk.columns[0];
|
|
1345
1391
|
if (!fkColumn) continue;
|
|
1346
1392
|
const column = table.columns.find((c) => c.name === fkColumn);
|
|
1347
1393
|
tableFks.set(fkColumn, {
|
|
1348
1394
|
target: fk.references.table,
|
|
1395
|
+
refs: fk.references.columns,
|
|
1396
|
+
...externalSchema !== void 0 ? { schema: externalSchema } : {},
|
|
1349
1397
|
nullable: column?.nullable ?? true,
|
|
1350
|
-
unique: column?.unique ?? false
|
|
1398
|
+
unique: column?.unique ?? false,
|
|
1399
|
+
...fk.onDelete !== void 0 ? { onDelete: fk.onDelete } : {},
|
|
1400
|
+
...fk.onUpdate !== void 0 ? { onUpdate: fk.onUpdate } : {}
|
|
1351
1401
|
});
|
|
1352
1402
|
}
|
|
1353
1403
|
fkLookup.set(table.name, tableFks);
|
|
1354
1404
|
}
|
|
1355
1405
|
const definition = {};
|
|
1406
|
+
const constraints = {};
|
|
1356
1407
|
for (const table of model.tables.values()) {
|
|
1357
1408
|
const tableDef = {};
|
|
1358
1409
|
const tableFks = fkLookup.get(table.name) ?? /* @__PURE__ */ new Map();
|
|
1410
|
+
const compositeExternalFks = compositeExternalFkLookup.get(table.name) ?? [];
|
|
1359
1411
|
for (const column of table.columns) {
|
|
1360
1412
|
const fk = tableFks.get(column.name);
|
|
1361
1413
|
if (fk) {
|
|
1414
|
+
if (fk.schema !== void 0) {
|
|
1415
|
+
const sourceColumn = {
|
|
1416
|
+
type: columnTypeToJsType(column.type),
|
|
1417
|
+
nullable: fk.nullable
|
|
1418
|
+
};
|
|
1419
|
+
if (fk.unique) sourceColumn.unique = true;
|
|
1420
|
+
tableDef[column.name] = sourceColumn;
|
|
1421
|
+
constraints[table.name] ??= {};
|
|
1422
|
+
const tableConstraints = constraints[table.name];
|
|
1423
|
+
tableConstraints.foreignKeys ??= [];
|
|
1424
|
+
const foreignKeys = tableConstraints.foreignKeys;
|
|
1425
|
+
foreignKeys.push(
|
|
1426
|
+
ref(fk.target, {
|
|
1427
|
+
schema: fk.schema,
|
|
1428
|
+
columns: [column.name],
|
|
1429
|
+
references: fk.refs,
|
|
1430
|
+
...fk.onDelete !== void 0 ? { onDelete: fk.onDelete } : {},
|
|
1431
|
+
...fk.onUpdate !== void 0 ? { onUpdate: fk.onUpdate } : {}
|
|
1432
|
+
})
|
|
1433
|
+
);
|
|
1434
|
+
continue;
|
|
1435
|
+
}
|
|
1436
|
+
const usesDefaultReferences = fk.refs.length === 1 && fk.refs[0] === "id";
|
|
1362
1437
|
tableDef[column.name] = ref(fk.target, {
|
|
1363
1438
|
nullable: fk.nullable,
|
|
1364
|
-
unique: fk.unique
|
|
1439
|
+
unique: fk.unique,
|
|
1440
|
+
...!usesDefaultReferences ? { references: fk.refs } : {},
|
|
1441
|
+
...fk.onDelete !== void 0 && fk.onDelete !== "NO ACTION" ? { onDelete: fk.onDelete } : {},
|
|
1442
|
+
...fk.onUpdate !== void 0 && fk.onUpdate !== "NO ACTION" ? { onUpdate: fk.onUpdate } : {}
|
|
1365
1443
|
});
|
|
1366
1444
|
} else {
|
|
1367
1445
|
tableDef[column.name] = columnTypeToJsType(column.type);
|
|
1368
1446
|
}
|
|
1369
1447
|
}
|
|
1448
|
+
for (const fk of compositeExternalFks) {
|
|
1449
|
+
const externalSchema = fk.references.schema;
|
|
1450
|
+
if (externalSchema === void 0) continue;
|
|
1451
|
+
constraints[table.name] ??= {};
|
|
1452
|
+
const tableConstraints = constraints[table.name];
|
|
1453
|
+
tableConstraints.foreignKeys ??= [];
|
|
1454
|
+
const foreignKeys = tableConstraints.foreignKeys;
|
|
1455
|
+
foreignKeys.push(
|
|
1456
|
+
ref(fk.references.table, {
|
|
1457
|
+
schema: externalSchema,
|
|
1458
|
+
columns: fk.columns,
|
|
1459
|
+
references: fk.references.columns,
|
|
1460
|
+
...fk.onDelete !== void 0 ? { onDelete: fk.onDelete } : {},
|
|
1461
|
+
...fk.onUpdate !== void 0 ? { onUpdate: fk.onUpdate } : {}
|
|
1462
|
+
})
|
|
1463
|
+
);
|
|
1464
|
+
}
|
|
1370
1465
|
definition[table.name] = tableDef;
|
|
1371
1466
|
}
|
|
1372
1467
|
const tableNames = Object.keys(definition);
|
|
1468
|
+
const generatedConstraints = Object.keys(constraints).length > 0 ? constraints : void 0;
|
|
1373
1469
|
const tables = createTablesProxy(
|
|
1374
1470
|
model,
|
|
1375
1471
|
tableNames
|
|
@@ -1380,6 +1476,9 @@ async function getSchemaFromDb(adapter, options) {
|
|
|
1380
1476
|
tableNames,
|
|
1381
1477
|
tables
|
|
1382
1478
|
};
|
|
1479
|
+
if (generatedConstraints !== void 0) {
|
|
1480
|
+
result.constraints = generatedConstraints;
|
|
1481
|
+
}
|
|
1383
1482
|
if (adapter.dbCasing !== void 0) {
|
|
1384
1483
|
result.dbCasing = adapter.dbCasing;
|
|
1385
1484
|
}
|
|
@@ -1464,7 +1563,7 @@ function detectForeignKeys(tableName, table, conventions, tableNames) {
|
|
|
1464
1563
|
for (const [colName, colDef] of Object.entries(table)) {
|
|
1465
1564
|
if (colDef.references) {
|
|
1466
1565
|
const targetTable = colDef.references.table;
|
|
1467
|
-
if (tableNames.has(targetTable)) {
|
|
1566
|
+
if (colDef.references.schema === void 0 && tableNames.has(targetTable)) {
|
|
1468
1567
|
const inferredName = colName.endsWith("Id") ? colName.slice(0, -2) : singularize(targetTable);
|
|
1469
1568
|
const isSelfRef = targetTable === tableName;
|
|
1470
1569
|
const detectedFK = {
|
|
@@ -10329,16 +10428,13 @@ function buildIndexAPI(tableName, schemaName, adapter, requireAdapter2) {
|
|
|
10329
10428
|
"indexes.list() requires an adapter."
|
|
10330
10429
|
);
|
|
10331
10430
|
}
|
|
10332
|
-
if (adapter.listIndexes) {
|
|
10333
|
-
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
const rows = await adapter.executeRaw(sql2, []);
|
|
10338
|
-
return rows;
|
|
10431
|
+
if (!adapter.listIndexes) {
|
|
10432
|
+
throw new InvalidOperationError(
|
|
10433
|
+
"indexes.list",
|
|
10434
|
+
"indexes.list() requires an adapter that implements listIndexes()."
|
|
10435
|
+
);
|
|
10339
10436
|
}
|
|
10340
|
-
|
|
10341
|
-
return [];
|
|
10437
|
+
return adapter.listIndexes(tableName, schemaName, options);
|
|
10342
10438
|
},
|
|
10343
10439
|
async exists(name) {
|
|
10344
10440
|
if (!adapter) {
|
|
@@ -10963,6 +11059,14 @@ function rangeContainedBy(fieldOrColumn, valueOrRange, rangeType = "daterange")
|
|
|
10963
11059
|
// src/dx/schema-bridge.ts
|
|
10964
11060
|
import { buildRelationKeyFields, toColumnList as toColumnList3 } from "@dbsp/types";
|
|
10965
11061
|
import * as v from "valibot";
|
|
11062
|
+
function normalizeReferenceSchema2(schemaName) {
|
|
11063
|
+
if (schemaName == null) return void 0;
|
|
11064
|
+
const t = schemaName.trim();
|
|
11065
|
+
return t.length > 0 ? t : void 0;
|
|
11066
|
+
}
|
|
11067
|
+
function hasExternalSchema3(schemaName) {
|
|
11068
|
+
return normalizeReferenceSchema2(schemaName) !== void 0;
|
|
11069
|
+
}
|
|
10966
11070
|
function generatedTypeToColumnType(genType) {
|
|
10967
11071
|
switch (genType) {
|
|
10968
11072
|
case "string":
|
|
@@ -11035,11 +11139,11 @@ function findRelationForeignKey(sourceTable, genRelation, tables) {
|
|
|
11035
11139
|
switch (genRelation.kind) {
|
|
11036
11140
|
case "belongsTo":
|
|
11037
11141
|
return tables.get(sourceTable)?.foreignKeys.find(
|
|
11038
|
-
(fk) => fk.references.table === genRelation.target && columnListsEqual(fk.columns, genRelation.foreignKey)
|
|
11142
|
+
(fk) => !hasExternalSchema3(fk.references.schema) && fk.references.table === genRelation.target && columnListsEqual(fk.columns, genRelation.foreignKey)
|
|
11039
11143
|
);
|
|
11040
11144
|
case "hasMany":
|
|
11041
11145
|
return tables.get(genRelation.target)?.foreignKeys.find(
|
|
11042
|
-
(fk) => fk.references.table === sourceTable && columnListsEqual(fk.columns, genRelation.foreignKey)
|
|
11146
|
+
(fk) => !hasExternalSchema3(fk.references.schema) && fk.references.table === sourceTable && columnListsEqual(fk.columns, genRelation.foreignKey)
|
|
11043
11147
|
);
|
|
11044
11148
|
case "manyToMany":
|
|
11045
11149
|
return void 0;
|
|
@@ -11074,11 +11178,13 @@ function buildTableIRFromDefinition(tableName, genTable, fkAutoIndex) {
|
|
|
11074
11178
|
primaryKeys.push(colName);
|
|
11075
11179
|
}
|
|
11076
11180
|
if (colDef.references) {
|
|
11181
|
+
const externalSchema = normalizeReferenceSchema2(colDef.references.schema);
|
|
11077
11182
|
const fk = {
|
|
11078
11183
|
columns: [colName],
|
|
11079
11184
|
references: {
|
|
11080
11185
|
table: colDef.references.table,
|
|
11081
|
-
columns: [colDef.references.column ?? "id"]
|
|
11186
|
+
columns: [colDef.references.column ?? "id"],
|
|
11187
|
+
...externalSchema !== void 0 ? { schema: externalSchema } : {}
|
|
11082
11188
|
}
|
|
11083
11189
|
};
|
|
11084
11190
|
if (colDef.references.onDelete) {
|
|
@@ -11108,7 +11214,7 @@ function buildTableIRFromDefinition(tableName, genTable, fkAutoIndex) {
|
|
|
11108
11214
|
for (const fk of foreignKeys) {
|
|
11109
11215
|
const fkColumn = fk.columns[0];
|
|
11110
11216
|
const targetColumn = fk.references.columns[0];
|
|
11111
|
-
if (fk.references.table === tableName && fkColumn !== void 0 && targetColumn !== void 0) {
|
|
11217
|
+
if (fk.references.table === tableName && !hasExternalSchema3(fk.references.schema) && fkColumn !== void 0 && targetColumn !== void 0) {
|
|
11112
11218
|
const colDef = tableColumns[fkColumn];
|
|
11113
11219
|
const inferredName = fkColumn.endsWith("Id") ? fkColumn.slice(0, -2) : "parent";
|
|
11114
11220
|
const parentRole = colDef?.references?.parentRole ?? inferredName;
|
|
@@ -11141,11 +11247,13 @@ function buildTableIRFromDefinition(tableName, genTable, fkAutoIndex) {
|
|
|
11141
11247
|
}
|
|
11142
11248
|
if (isGeneratedTableWithConfig(genTable)) {
|
|
11143
11249
|
for (const fk of genTable.foreignKeys ?? []) {
|
|
11250
|
+
const externalSchema = normalizeReferenceSchema2(fk.references.schema);
|
|
11144
11251
|
const foreignKey = {
|
|
11145
11252
|
columns: [...fk.columns],
|
|
11146
11253
|
references: {
|
|
11147
11254
|
table: fk.references.table,
|
|
11148
|
-
columns: [...fk.references.columns]
|
|
11255
|
+
columns: [...fk.references.columns],
|
|
11256
|
+
...externalSchema !== void 0 ? { schema: externalSchema } : {}
|
|
11149
11257
|
}
|
|
11150
11258
|
};
|
|
11151
11259
|
if (fk.onDelete) foreignKey.onDelete = fk.onDelete;
|
|
@@ -11362,12 +11470,25 @@ function safeRecord(valueSchema) {
|
|
|
11362
11470
|
v.record(v.string(), valueSchema)
|
|
11363
11471
|
);
|
|
11364
11472
|
}
|
|
11473
|
+
var OptionalReferenceSchemaNameSchema = v.optional(
|
|
11474
|
+
v.pipe(
|
|
11475
|
+
v.string(),
|
|
11476
|
+
v.transform((schemaName) => normalizeReferenceSchema2(schemaName))
|
|
11477
|
+
)
|
|
11478
|
+
);
|
|
11479
|
+
var ForeignKeyActionValues = [
|
|
11480
|
+
"CASCADE",
|
|
11481
|
+
"SET NULL",
|
|
11482
|
+
"SET DEFAULT",
|
|
11483
|
+
"RESTRICT",
|
|
11484
|
+
"NO ACTION"
|
|
11485
|
+
];
|
|
11486
|
+
var ForeignKeyActionSchema = v.picklist(ForeignKeyActionValues);
|
|
11365
11487
|
var ForeignKeyReferenceSchema = v.object({
|
|
11488
|
+
schema: OptionalReferenceSchemaNameSchema,
|
|
11366
11489
|
table: v.string(),
|
|
11367
11490
|
column: v.optional(v.string()),
|
|
11368
|
-
onDelete: v.optional(
|
|
11369
|
-
v.picklist(["CASCADE", "SET NULL", "RESTRICT", "NO ACTION"])
|
|
11370
|
-
),
|
|
11491
|
+
onDelete: v.optional(ForeignKeyActionSchema),
|
|
11371
11492
|
index: v.optional(v.boolean()),
|
|
11372
11493
|
parentRole: v.optional(v.string()),
|
|
11373
11494
|
childRole: v.optional(v.string())
|
|
@@ -11392,15 +11513,12 @@ var TableDefWithConfigSchema = v.object({
|
|
|
11392
11513
|
v.object({
|
|
11393
11514
|
columns: v.array(v.string()),
|
|
11394
11515
|
references: v.object({
|
|
11516
|
+
schema: OptionalReferenceSchemaNameSchema,
|
|
11395
11517
|
table: v.string(),
|
|
11396
11518
|
columns: v.array(v.string())
|
|
11397
11519
|
}),
|
|
11398
|
-
onDelete: v.optional(
|
|
11399
|
-
|
|
11400
|
-
),
|
|
11401
|
-
onUpdate: v.optional(
|
|
11402
|
-
v.picklist(["CASCADE", "SET NULL", "RESTRICT", "NO ACTION"])
|
|
11403
|
-
)
|
|
11520
|
+
onDelete: v.optional(ForeignKeyActionSchema),
|
|
11521
|
+
onUpdate: v.optional(ForeignKeyActionSchema)
|
|
11404
11522
|
})
|
|
11405
11523
|
)
|
|
11406
11524
|
),
|
|
@@ -11534,8 +11652,10 @@ function convertColumn(col2) {
|
|
|
11534
11652
|
result.default = col2.default;
|
|
11535
11653
|
}
|
|
11536
11654
|
if (col2.references) {
|
|
11655
|
+
const externalSchema = normalizeReferenceSchema2(col2.references.schema);
|
|
11537
11656
|
result.references = {
|
|
11538
11657
|
table: col2.references.table,
|
|
11658
|
+
...externalSchema !== void 0 ? { schema: externalSchema } : {},
|
|
11539
11659
|
...col2.references.column !== void 0 ? { column: col2.references.column } : {},
|
|
11540
11660
|
...col2.references.onDelete ? { onDelete: col2.references.onDelete } : {},
|
|
11541
11661
|
...col2.references.index !== void 0 ? { index: col2.references.index } : {},
|