@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 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?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';
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?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';
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?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';
4262
- readonly onUpdate?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION';
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
- return adapter.listIndexes(tableName, schemaName, options);
10334
- }
10335
- const sql2 = `SELECT indexname AS name, indexdef AS definition, (SELECT indisunique FROM pg_index WHERE indexrelid = (SELECT oid FROM pg_class WHERE relname = indexname)) AS unique, CASE WHEN indexdef LIKE '%USING %' THEN split_part(indexdef, 'USING ', 2) ELSE 'btree' END AS method FROM pg_indexes WHERE tablename = '${tableName.replace(/'/g, "''")}' ` + (schemaName ? `AND schemaname = '${schemaName.replace(/'/g, "''")}' ` : "") + `ORDER BY indexname`;
10336
- if ("executeRaw" in adapter && typeof adapter.executeRaw === "function") {
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
- if (adapter.executeDDL) await adapter.executeDDL(sql2);
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
- v.picklist(["CASCADE", "SET NULL", "RESTRICT", "NO ACTION"])
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 } : {},