@dbsp/core 1.10.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,
@@ -669,6 +687,13 @@ var SchemaValidationError = class extends Error {
669
687
  table;
670
688
  column;
671
689
  };
690
+ function validateSchemaIndexOptions(tableName, idx) {
691
+ if (idx.nullsNotDistinct === true && idx.unique !== true) {
692
+ throw new SchemaValidationError(
693
+ `Index "${idx.name ?? `idx_${tableName}_${idx.columns.join("_")}`}" on "${tableName}" cannot use nullsNotDistinct unless unique is true`
694
+ );
695
+ }
696
+ }
672
697
  function schemaToModelIR(definition, constraints, extras, options) {
673
698
  if (typeof options?.defaultPkColumnName === "string" && options.defaultPkColumnName.trim().length === 0) {
674
699
  throw new SchemaValidationError(
@@ -721,21 +746,21 @@ function validateRefs(definition, tableNames) {
721
746
  for (const [tableName, tableDef] of Object.entries(definition)) {
722
747
  for (const [columnName, columnDef] of Object.entries(tableDef)) {
723
748
  if (isRef(columnDef)) {
724
- if (!tableSet.has(columnDef.target)) {
749
+ if (!hasExternalSchema2(columnDef.options.schema) && !tableSet.has(columnDef.target)) {
725
750
  throw new SchemaValidationError(
726
751
  `Foreign key '${columnName}' references non-existent table '${columnDef.target}'`,
727
752
  tableName,
728
753
  columnName
729
754
  );
730
755
  }
731
- if (columnDef.target === tableName && !columnDef.options.roles) {
756
+ if (!hasExternalSchema2(columnDef.options.schema) && columnDef.target === tableName && !columnDef.options.roles) {
732
757
  throw new SchemaValidationError(
733
758
  `Self-referential FK '${columnName}' must have 'roles' option with parent/children names`,
734
759
  tableName,
735
760
  columnName
736
761
  );
737
762
  }
738
- if (columnDef.target !== tableName && columnDef.options.roles) {
763
+ if ((hasExternalSchema2(columnDef.options.schema) || columnDef.target !== tableName) && columnDef.options.roles) {
739
764
  throw new SchemaValidationError(
740
765
  `'roles' option is only valid for self-referential FKs, but '${columnName}' references '${columnDef.target}'`,
741
766
  tableName,
@@ -751,14 +776,6 @@ function validateFkTargets(tables) {
751
776
  const tableMap = new Map(tables.map((t) => [t.name, t]));
752
777
  for (const table of tables) {
753
778
  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
779
  for (const srcCol of fk.columns) {
763
780
  if (!table.columns.some((c) => c.name === srcCol)) {
764
781
  throw new SchemaValidationError(
@@ -782,6 +799,15 @@ function validateFkTargets(tables) {
782
799
  fk.columns[0]
783
800
  );
784
801
  }
802
+ if (hasExternalSchema2(fk.references.schema)) continue;
803
+ const target = tableMap.get(fk.references.table);
804
+ if (!target) {
805
+ throw new SchemaValidationError(
806
+ `Foreign key in '${table.name}' references non-existent table '${fk.references.table}'`,
807
+ table.name,
808
+ fk.columns[0]
809
+ );
810
+ }
785
811
  for (const refCol of fk.references.columns) {
786
812
  if (!target.columns.some((c) => c.name === refCol)) {
787
813
  throw new SchemaValidationError(
@@ -955,6 +981,14 @@ function getReferencedColumnType(targetDef, referencedCol, definition, visited)
955
981
  }
956
982
  function buildRefColumn(columnName, columnDef, definition) {
957
983
  const targetDef = definition[columnDef.target];
984
+ const externalSchema = normalizeReferenceSchema(columnDef.options.schema);
985
+ if (externalSchema !== void 0) {
986
+ throw new SchemaValidationError(
987
+ `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.`,
988
+ void 0,
989
+ columnName
990
+ );
991
+ }
958
992
  const targetCol = columnDef.options.references?.length === 1 ? columnDef.options.references[0] : void 0;
959
993
  const inferredType = targetCol && targetDef ? getReferencedColumnType(targetDef, targetCol, definition) ?? getTargetPkType(definition, columnDef.target) : getTargetPkType(definition, columnDef.target);
960
994
  const col2 = {
@@ -972,7 +1006,8 @@ function buildRefColumn(columnName, columnDef, definition) {
972
1006
  columns: [columnName],
973
1007
  references: {
974
1008
  table: columnDef.target,
975
- columns: columnDef.options.references ?? ["id"]
1009
+ columns: columnDef.options.references ?? ["id"],
1010
+ ...externalSchema !== void 0 ? { schema: externalSchema } : {}
976
1011
  }
977
1012
  };
978
1013
  if (columnDef.options.onDelete) fk.onDelete = columnDef.options.onDelete;
@@ -1028,7 +1063,7 @@ function buildPseudoColumns(tableName, refsByTable, finalPk) {
1028
1063
  const refs = refsByTable.get(tableName) ?? [];
1029
1064
  const pkColumn = typeof finalPk === "string" ? finalPk : finalPk?.[0] ?? "id";
1030
1065
  for (const ref3 of refs) {
1031
- if (ref3.options.roles && ref3.target === tableName) {
1066
+ if (!hasExternalSchema2(ref3.options.schema) && ref3.options.roles && ref3.target === tableName) {
1032
1067
  pseudoColumns.push(
1033
1068
  createPseudoColumnMetadata(
1034
1069
  tableName,
@@ -1067,13 +1102,18 @@ function buildTableConstraints(tableName, constraints) {
1067
1102
  }
1068
1103
  if (tableConstraints.indexes) {
1069
1104
  for (const idx of tableConstraints.indexes) {
1105
+ validateSchemaIndexOptions(tableName, idx);
1070
1106
  const indexIR = {
1071
1107
  name: idx.name ?? `idx_${tableName}_${idx.columns.join("_")}`,
1072
1108
  columns: idx.columns,
1073
1109
  unique: idx.unique ?? false
1074
1110
  };
1111
+ if (idx.nullsNotDistinct !== void 0) {
1112
+ indexIR.nullsNotDistinct = idx.nullsNotDistinct;
1113
+ }
1075
1114
  if (idx.method) indexIR.method = idx.method;
1076
1115
  if (idx.where) indexIR.where = idx.where;
1116
+ if (idx.include !== void 0) indexIR.include = idx.include;
1077
1117
  if (idx.opclass) indexIR.opclass = idx.opclass;
1078
1118
  if (idx.with) indexIR.with = idx.with;
1079
1119
  extraIndexes.push(indexIR);
@@ -1095,11 +1135,13 @@ function buildTableConstraints(tableName, constraints) {
1095
1135
  tableName
1096
1136
  );
1097
1137
  }
1138
+ const externalSchema = normalizeReferenceSchema(fkRef.options.schema);
1098
1139
  const fk = {
1099
1140
  columns: [...fkRef.options.columns],
1100
1141
  references: {
1101
1142
  table: fkRef.target,
1102
- columns: fkRef.options.references ? [...fkRef.options.references] : ["id"]
1143
+ columns: fkRef.options.references ? [...fkRef.options.references] : ["id"],
1144
+ ...externalSchema !== void 0 ? { schema: externalSchema } : {}
1103
1145
  }
1104
1146
  };
1105
1147
  if (fkRef.options.onDelete) fk.onDelete = fkRef.options.onDelete;
@@ -1147,6 +1189,7 @@ function buildRelations(_definition, refsByTable, tableNames, constraints) {
1147
1189
  for (const tableName of tableNames) {
1148
1190
  const refs = refsByTable.get(tableName) || [];
1149
1191
  for (const ref3 of refs) {
1192
+ if (hasExternalSchema2(ref3.options.schema)) continue;
1150
1193
  if (ref3.options.roles) {
1151
1194
  const roles = ref3.options.roles;
1152
1195
  relations.push({
@@ -1267,6 +1310,7 @@ function addCompositeConstraintRelations(relations, tableNames, constraints) {
1267
1310
  const foreignKeys = constraints[tableName]?.foreignKeys;
1268
1311
  if (!foreignKeys) continue;
1269
1312
  for (const fkRef of foreignKeys) {
1313
+ if (hasExternalSchema2(fkRef.options.schema)) continue;
1270
1314
  if (!tableSet.has(fkRef.target)) continue;
1271
1315
  const columns = fkRef.options.columns;
1272
1316
  if (!columns?.length) continue;
@@ -1338,38 +1382,102 @@ async function getSchemaFromDb(adapter, options) {
1338
1382
  const model = introspectionResult;
1339
1383
  const introspectedAt = introspectionResult.introspectedAt;
1340
1384
  const fkLookup = /* @__PURE__ */ new Map();
1385
+ const compositeExternalFkLookup = /* @__PURE__ */ new Map();
1341
1386
  for (const table of model.tables.values()) {
1342
1387
  const tableFks = /* @__PURE__ */ new Map();
1343
1388
  for (const fk of table.foreignKeys) {
1389
+ const externalSchema = normalizeReferenceSchema(fk.references.schema);
1390
+ if (externalSchema !== void 0 && fk.columns.length > 1) {
1391
+ const tableCompositeFks = compositeExternalFkLookup.get(table.name) ?? [];
1392
+ tableCompositeFks.push({
1393
+ ...fk,
1394
+ references: {
1395
+ ...fk.references,
1396
+ schema: externalSchema
1397
+ }
1398
+ });
1399
+ compositeExternalFkLookup.set(table.name, tableCompositeFks);
1400
+ continue;
1401
+ }
1344
1402
  const fkColumn = fk.columns[0];
1345
1403
  if (!fkColumn) continue;
1346
1404
  const column = table.columns.find((c) => c.name === fkColumn);
1347
1405
  tableFks.set(fkColumn, {
1348
1406
  target: fk.references.table,
1407
+ refs: fk.references.columns,
1408
+ ...externalSchema !== void 0 ? { schema: externalSchema } : {},
1349
1409
  nullable: column?.nullable ?? true,
1350
- unique: column?.unique ?? false
1410
+ unique: column?.unique ?? false,
1411
+ ...fk.onDelete !== void 0 ? { onDelete: fk.onDelete } : {},
1412
+ ...fk.onUpdate !== void 0 ? { onUpdate: fk.onUpdate } : {}
1351
1413
  });
1352
1414
  }
1353
1415
  fkLookup.set(table.name, tableFks);
1354
1416
  }
1355
1417
  const definition = {};
1418
+ const constraints = {};
1356
1419
  for (const table of model.tables.values()) {
1357
1420
  const tableDef = {};
1358
1421
  const tableFks = fkLookup.get(table.name) ?? /* @__PURE__ */ new Map();
1422
+ const compositeExternalFks = compositeExternalFkLookup.get(table.name) ?? [];
1359
1423
  for (const column of table.columns) {
1360
1424
  const fk = tableFks.get(column.name);
1361
1425
  if (fk) {
1426
+ if (fk.schema !== void 0) {
1427
+ const sourceColumn = {
1428
+ type: columnTypeToJsType(column.type),
1429
+ nullable: fk.nullable
1430
+ };
1431
+ if (fk.unique) sourceColumn.unique = true;
1432
+ tableDef[column.name] = sourceColumn;
1433
+ constraints[table.name] ??= {};
1434
+ const tableConstraints = constraints[table.name];
1435
+ tableConstraints.foreignKeys ??= [];
1436
+ const foreignKeys = tableConstraints.foreignKeys;
1437
+ foreignKeys.push(
1438
+ ref(fk.target, {
1439
+ schema: fk.schema,
1440
+ columns: [column.name],
1441
+ references: fk.refs,
1442
+ ...fk.onDelete !== void 0 ? { onDelete: fk.onDelete } : {},
1443
+ ...fk.onUpdate !== void 0 ? { onUpdate: fk.onUpdate } : {}
1444
+ })
1445
+ );
1446
+ continue;
1447
+ }
1448
+ const usesDefaultReferences = fk.refs.length === 1 && fk.refs[0] === "id";
1362
1449
  tableDef[column.name] = ref(fk.target, {
1363
1450
  nullable: fk.nullable,
1364
- unique: fk.unique
1451
+ unique: fk.unique,
1452
+ ...!usesDefaultReferences ? { references: fk.refs } : {},
1453
+ ...fk.onDelete !== void 0 && fk.onDelete !== "NO ACTION" ? { onDelete: fk.onDelete } : {},
1454
+ ...fk.onUpdate !== void 0 && fk.onUpdate !== "NO ACTION" ? { onUpdate: fk.onUpdate } : {}
1365
1455
  });
1366
1456
  } else {
1367
1457
  tableDef[column.name] = columnTypeToJsType(column.type);
1368
1458
  }
1369
1459
  }
1460
+ for (const fk of compositeExternalFks) {
1461
+ const externalSchema = fk.references.schema;
1462
+ if (externalSchema === void 0) continue;
1463
+ constraints[table.name] ??= {};
1464
+ const tableConstraints = constraints[table.name];
1465
+ tableConstraints.foreignKeys ??= [];
1466
+ const foreignKeys = tableConstraints.foreignKeys;
1467
+ foreignKeys.push(
1468
+ ref(fk.references.table, {
1469
+ schema: externalSchema,
1470
+ columns: fk.columns,
1471
+ references: fk.references.columns,
1472
+ ...fk.onDelete !== void 0 ? { onDelete: fk.onDelete } : {},
1473
+ ...fk.onUpdate !== void 0 ? { onUpdate: fk.onUpdate } : {}
1474
+ })
1475
+ );
1476
+ }
1370
1477
  definition[table.name] = tableDef;
1371
1478
  }
1372
1479
  const tableNames = Object.keys(definition);
1480
+ const generatedConstraints = Object.keys(constraints).length > 0 ? constraints : void 0;
1373
1481
  const tables = createTablesProxy(
1374
1482
  model,
1375
1483
  tableNames
@@ -1380,6 +1488,9 @@ async function getSchemaFromDb(adapter, options) {
1380
1488
  tableNames,
1381
1489
  tables
1382
1490
  };
1491
+ if (generatedConstraints !== void 0) {
1492
+ result.constraints = generatedConstraints;
1493
+ }
1383
1494
  if (adapter.dbCasing !== void 0) {
1384
1495
  result.dbCasing = adapter.dbCasing;
1385
1496
  }
@@ -1390,12 +1501,6 @@ async function getSchemaFromDb(adapter, options) {
1390
1501
  }
1391
1502
 
1392
1503
  // src/conventions.ts
1393
- var DEFAULT_CONVENTIONS = {
1394
- fkPattern: "{singular}Id",
1395
- pluralize: true,
1396
- timestamps: ["createdAt", "updatedAt"],
1397
- fkAutoIndex: true
1398
- };
1399
1504
  var IRREGULAR_PLURALS = {
1400
1505
  people: "person",
1401
1506
  children: "child",
@@ -1454,257 +1559,6 @@ function capitalize(name) {
1454
1559
  function decapitalize(name) {
1455
1560
  return name.charAt(0).toLowerCase() + name.slice(1);
1456
1561
  }
1457
- function getSelfRefInverseName(belongsToName) {
1458
- if (belongsToName === "parent") return "children";
1459
- return pluralize(belongsToName);
1460
- }
1461
- function detectForeignKeys(tableName, table, conventions, tableNames) {
1462
- const fks = [];
1463
- const pattern = conventions.fkPattern;
1464
- for (const [colName, colDef] of Object.entries(table)) {
1465
- if (colDef.references) {
1466
- const targetTable = colDef.references.table;
1467
- if (tableNames.has(targetTable)) {
1468
- const inferredName = colName.endsWith("Id") ? colName.slice(0, -2) : singularize(targetTable);
1469
- const isSelfRef = targetTable === tableName;
1470
- const detectedFK = {
1471
- column: colName,
1472
- targetTable,
1473
- inferredName,
1474
- explicit: true,
1475
- targetColumn: colDef.references.column ?? "id"
1476
- };
1477
- if (isSelfRef) {
1478
- detectedFK.parentRole = colDef.references.parentRole ?? inferredName;
1479
- detectedFK.childRole = colDef.references.childRole ?? getSelfRefInverseName(inferredName);
1480
- }
1481
- fks.push(detectedFK);
1482
- }
1483
- continue;
1484
- }
1485
- for (const candidateTable of tableNames) {
1486
- if (candidateTable === tableName) continue;
1487
- const singular = singularize(candidateTable);
1488
- const expectedColumn = pattern.replace("{singular}", singular);
1489
- if (colName === expectedColumn) {
1490
- fks.push({
1491
- column: colName,
1492
- targetTable: candidateTable,
1493
- inferredName: singular,
1494
- explicit: false,
1495
- targetColumn: "id"
1496
- });
1497
- break;
1498
- }
1499
- }
1500
- if (colName.endsWith("Id")) {
1501
- const prefix = colName.slice(0, -2);
1502
- const singular = singularize(tableName);
1503
- if (["parent", "manager", "supervisor", "owner", singular].includes(prefix)) {
1504
- if (!fks.some((fk) => fk.column === colName)) {
1505
- fks.push({
1506
- column: colName,
1507
- targetTable: tableName,
1508
- inferredName: prefix,
1509
- explicit: false,
1510
- targetColumn: "id",
1511
- // Auto-infer roles for convention-based self-ref FKs
1512
- parentRole: prefix,
1513
- childRole: getSelfRefInverseName(prefix)
1514
- });
1515
- }
1516
- }
1517
- }
1518
- }
1519
- return fks;
1520
- }
1521
- function isBusinessColumn(colName, colDef, timestamps) {
1522
- if (colDef.primaryKey) return false;
1523
- if (timestamps.includes(colName)) return false;
1524
- if (colDef.references) return false;
1525
- if (colName.endsWith("Id")) return false;
1526
- if (["id", "createdBy", "updatedBy", "deletedAt"].includes(colName))
1527
- return false;
1528
- return true;
1529
- }
1530
- function detectManyToMany(tables, conventions, tableNames) {
1531
- const results = [];
1532
- for (const [tableName, table] of Object.entries(tables)) {
1533
- const fks = detectForeignKeys(tableName, table, conventions, tableNames);
1534
- if (fks.length !== 2) continue;
1535
- const hasBusinessColumns = Object.entries(table).some(
1536
- ([colName, colDef]) => isBusinessColumn(colName, colDef, conventions.timestamps)
1537
- );
1538
- if (hasBusinessColumns) continue;
1539
- const fkA = fks[0];
1540
- const fkB = fks[1];
1541
- if (fkA && fkB) {
1542
- results.push({
1543
- junction: tableName,
1544
- tableA: fkA.targetTable,
1545
- tableB: fkB.targetTable,
1546
- fkA: fkA.column,
1547
- fkB: fkB.column
1548
- });
1549
- }
1550
- }
1551
- return results;
1552
- }
1553
- function inferRelationsFromSchema(tables, conventions, explicitRelations = {}) {
1554
- const result = { ...explicitRelations };
1555
- const tableNames = new Set(Object.keys(tables));
1556
- const manyToManys = detectManyToMany(tables, conventions, tableNames);
1557
- const junctionTables = new Set(manyToManys.map((m) => m.junction));
1558
- for (const m2m of manyToManys) {
1559
- const { junction, tableA, tableB, fkA, fkB } = m2m;
1560
- const relNameAtoB = conventions.pluralize ? pluralize(singularize(tableB)) : tableB;
1561
- const relNameBtoA = conventions.pluralize ? pluralize(singularize(tableA)) : tableA;
1562
- const keyAtoB = `${tableA}.${relNameAtoB}`;
1563
- const keyBtoA = `${tableB}.${relNameBtoA}`;
1564
- if (!(keyAtoB in result)) {
1565
- const rel = {
1566
- kind: "manyToMany",
1567
- target: tableB,
1568
- through: junction,
1569
- sourceFk: fkA,
1570
- targetFk: fkB
1571
- };
1572
- result[keyAtoB] = rel;
1573
- }
1574
- if (!(keyBtoA in result)) {
1575
- const rel = {
1576
- kind: "manyToMany",
1577
- target: tableA,
1578
- through: junction,
1579
- sourceFk: fkB,
1580
- targetFk: fkA
1581
- };
1582
- result[keyBtoA] = rel;
1583
- }
1584
- }
1585
- for (const [tableName, table] of Object.entries(tables)) {
1586
- if (junctionTables.has(tableName)) continue;
1587
- const fks = detectForeignKeys(tableName, table, conventions, tableNames);
1588
- for (const fk of fks) {
1589
- if (junctionTables.has(fk.targetTable)) continue;
1590
- const belongsToKey = `${tableName}.${fk.inferredName}`;
1591
- if (!(belongsToKey in result)) {
1592
- const rel = {
1593
- kind: "belongsTo",
1594
- target: fk.targetTable,
1595
- foreignKey: fk.column,
1596
- targetKey: fk.targetColumn
1597
- };
1598
- result[belongsToKey] = rel;
1599
- }
1600
- const isSelfRef = fk.targetTable === tableName;
1601
- const hasManyName = isSelfRef ? getSelfRefInverseName(fk.inferredName) : (() => {
1602
- const hasCustomAlias = fk.inferredName !== singularize(fk.targetTable);
1603
- if (hasCustomAlias) {
1604
- return conventions.pluralize ? pluralize(fk.inferredName) : fk.inferredName;
1605
- }
1606
- return conventions.pluralize ? pluralize(singularize(tableName)) : tableName;
1607
- })();
1608
- const hasManyKey = `${fk.targetTable}.${hasManyName}`;
1609
- if (!(hasManyKey in result)) {
1610
- const rel = {
1611
- kind: "hasMany",
1612
- target: tableName,
1613
- foreignKey: fk.column,
1614
- sourceKey: "id"
1615
- };
1616
- result[hasManyKey] = rel;
1617
- }
1618
- }
1619
- }
1620
- return result;
1621
- }
1622
-
1623
- // src/schema-dsl.ts
1624
- function defineSchema(tables, config) {
1625
- const relations = config?.relations ?? {};
1626
- const hints = config?.hints ?? {};
1627
- const conventions = config?.conventions ?? {};
1628
- const indexes = config?.indexes ?? {};
1629
- const defaultFilters = config?.defaultFilters ?? {};
1630
- const resolvedConventions = {
1631
- ...DEFAULT_CONVENTIONS,
1632
- ...conventions
1633
- };
1634
- const allRelations = inferRelationsFromSchema(
1635
- tables,
1636
- resolvedConventions,
1637
- relations
1638
- );
1639
- validateRelations(tables, relations);
1640
- validateHints(allRelations, hints);
1641
- validateDefaultFilters(tables, defaultFilters);
1642
- return {
1643
- tables,
1644
- relations: allRelations,
1645
- hints,
1646
- conventions: resolvedConventions,
1647
- indexes,
1648
- defaultFilters
1649
- };
1650
- }
1651
- function validateRelations(tables, relations) {
1652
- const tableNames = new Set(Object.keys(tables));
1653
- for (const [key, rel] of Object.entries(relations)) {
1654
- const sourceTable = key.split(".")[0] ?? key;
1655
- if (!tableNames.has(sourceTable)) {
1656
- throw new SchemaValidationError2(
1657
- `Relation '${key}' references non-existent source table '${sourceTable}'`
1658
- );
1659
- }
1660
- if (!tableNames.has(rel.target)) {
1661
- throw new SchemaValidationError2(
1662
- `Relation '${key}' references non-existent target table '${rel.target}'`
1663
- );
1664
- }
1665
- if (rel.kind === "manyToMany" && !tableNames.has(rel.through)) {
1666
- throw new SchemaValidationError2(
1667
- `Relation '${key}' references non-existent junction table '${rel.through}'`
1668
- );
1669
- }
1670
- }
1671
- }
1672
- function validateHints(relations, hints) {
1673
- for (const path of Object.keys(hints)) {
1674
- if (!(path in relations)) {
1675
- throw new SchemaValidationError2(
1676
- `Hint path '${path}' does not match any relation. Available: ${Object.keys(relations).join(", ")}`
1677
- );
1678
- }
1679
- }
1680
- }
1681
- function validateDefaultFilters(tables, defaultFilters) {
1682
- const tableNames = new Set(Object.keys(tables));
1683
- for (const tableName of Object.keys(defaultFilters)) {
1684
- if (!tableNames.has(tableName)) {
1685
- throw new SchemaValidationError2(
1686
- `Default filter for non-existent table '${tableName}'. Available: ${[...tableNames].join(", ")}`
1687
- );
1688
- }
1689
- }
1690
- }
1691
- var SchemaValidationError2 = class extends Error {
1692
- constructor(message) {
1693
- super(message);
1694
- this.name = "SchemaValidationError";
1695
- }
1696
- };
1697
-
1698
- // src/schema-dsl-types.ts
1699
- function isBelongsTo(rel) {
1700
- return rel.kind === "belongsTo";
1701
- }
1702
- function isHasMany(rel) {
1703
- return rel.kind === "hasMany";
1704
- }
1705
- function isManyToMany(rel) {
1706
- return rel.kind === "manyToMany";
1707
- }
1708
1562
 
1709
1563
  // src/planner.ts
1710
1564
  import { resolveJsonAggOrderKey, toColumnList } from "@dbsp/types";
@@ -6327,7 +6181,7 @@ function hydrateJsonAggIncludes(results, planReport) {
6327
6181
  if (typeof row !== "object" || row === null) {
6328
6182
  continue;
6329
6183
  }
6330
- const record2 = row;
6184
+ const record = row;
6331
6185
  for (const [relationName, info] of relationInfo) {
6332
6186
  const candidates = [relationName];
6333
6187
  if (info.includeAlias && info.includeAlias !== relationName) {
@@ -6340,17 +6194,17 @@ function hydrateJsonAggIncludes(results, planReport) {
6340
6194
  /_([a-z])/g,
6341
6195
  (_, c) => c.toUpperCase()
6342
6196
  );
6343
- if (snakeJson in record2) {
6197
+ if (snakeJson in record) {
6344
6198
  actualColumnName = snakeJson;
6345
6199
  break;
6346
6200
  }
6347
- if (camelJson in record2) {
6201
+ if (camelJson in record) {
6348
6202
  actualColumnName = camelJson;
6349
6203
  break;
6350
6204
  }
6351
6205
  }
6352
6206
  if (actualColumnName) {
6353
- const jsonValue = record2[actualColumnName];
6207
+ const jsonValue = record[actualColumnName];
6354
6208
  let parsed;
6355
6209
  if (typeof jsonValue === "string") {
6356
6210
  try {
@@ -6369,8 +6223,8 @@ function hydrateJsonAggIncludes(results, planReport) {
6369
6223
  parsed = parsed.length > 0 ? parsed[0] : null;
6370
6224
  }
6371
6225
  const outputKey = info.includeAlias ?? relationName;
6372
- record2[outputKey] = parsed;
6373
- delete record2[actualColumnName];
6226
+ record[outputKey] = parsed;
6227
+ delete record[actualColumnName];
6374
6228
  }
6375
6229
  }
6376
6230
  }
@@ -8299,12 +8153,12 @@ var ResultHydrator = class {
8299
8153
  if (typeof row !== "object" || row === null) {
8300
8154
  continue;
8301
8155
  }
8302
- const record2 = row;
8156
+ const record = row;
8303
8157
  const valuesByPath = /* @__PURE__ */ new Map();
8304
- for (const key of Object.keys(record2)) {
8158
+ for (const key of Object.keys(record)) {
8305
8159
  const info = findLongestJoinInfo(key, joinInfos);
8306
8160
  if (!info) continue;
8307
- const value = record2[key];
8161
+ const value = record[key];
8308
8162
  let entry = valuesByPath.get(info.relationPath);
8309
8163
  if (!entry) {
8310
8164
  entry = { values: {}, allNull: true };
@@ -8316,13 +8170,13 @@ var ResultHydrator = class {
8316
8170
  value
8317
8171
  );
8318
8172
  if (value !== null && value !== void 0) entry.allNull = false;
8319
- delete record2[key];
8173
+ delete record[key];
8320
8174
  }
8321
8175
  for (const info of infosByDepth) {
8322
8176
  const entry = valuesByPath.get(info.relationPath);
8323
8177
  if (!entry) continue;
8324
8178
  assignNestedValue(
8325
- record2,
8179
+ record,
8326
8180
  info.segments,
8327
8181
  entry.allNull ? null : entry.values
8328
8182
  );
@@ -8552,10 +8406,10 @@ var ResultHydrator = class {
8552
8406
  return obj[columns[0]];
8553
8407
  }
8554
8408
  const values = columns.map((k) => obj[k]);
8555
- if (values.some((v2) => v2 === void 0 || v2 === null)) {
8409
+ if (values.some((v) => v === void 0 || v === null)) {
8556
8410
  return void 0;
8557
8411
  }
8558
- const parts = values.map((v2) => String(v2));
8412
+ const parts = values.map((v) => String(v));
8559
8413
  if (parts.some((p) => p.includes(COMPOSITE_KEY_SEP))) {
8560
8414
  return JSON.stringify(parts);
8561
8415
  }
@@ -8570,7 +8424,7 @@ var ResultHydrator = class {
8570
8424
  return obj[columns[0]];
8571
8425
  }
8572
8426
  const values = columns.map((k) => obj[k]);
8573
- return values.some((v2) => v2 === void 0 || v2 === null) ? void 0 : values;
8427
+ return values.some((v) => v === void 0 || v === null) ? void 0 : values;
8574
8428
  }
8575
8429
  };
8576
8430
 
@@ -10283,7 +10137,7 @@ function generateCreateIndexSQL(tableName, schemaName, opts) {
10283
10137
  parts.push("NULLS NOT DISTINCT");
10284
10138
  }
10285
10139
  if (opts.with && Object.keys(opts.with).length > 0) {
10286
- const withClauses = Object.entries(opts.with).map(([k, v2]) => `${k} = ${v2}`).join(", ");
10140
+ const withClauses = Object.entries(opts.with).map(([k, v]) => `${k} = ${v}`).join(", ");
10287
10141
  parts.push(`WITH (${withClauses})`);
10288
10142
  }
10289
10143
  if (opts.where) parts.push(`WHERE ${opts.where}`);
@@ -10329,16 +10183,13 @@ function buildIndexAPI(tableName, schemaName, adapter, requireAdapter2) {
10329
10183
  "indexes.list() requires an adapter."
10330
10184
  );
10331
10185
  }
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;
10186
+ if (!adapter.listIndexes) {
10187
+ throw new InvalidOperationError(
10188
+ "indexes.list",
10189
+ "indexes.list() requires an adapter that implements listIndexes()."
10190
+ );
10339
10191
  }
10340
- if (adapter.executeDDL) await adapter.executeDDL(sql2);
10341
- return [];
10192
+ return adapter.listIndexes(tableName, schemaName, options);
10342
10193
  },
10343
10194
  async exists(name) {
10344
10195
  if (!adapter) {
@@ -10960,705 +10811,6 @@ function rangeContainedBy(fieldOrColumn, valueOrRange, rangeType = "daterange")
10960
10811
  };
10961
10812
  }
10962
10813
 
10963
- // src/dx/schema-bridge.ts
10964
- import { buildRelationKeyFields, toColumnList as toColumnList3 } from "@dbsp/types";
10965
- import * as v from "valibot";
10966
- function generatedTypeToColumnType(genType) {
10967
- switch (genType) {
10968
- case "string":
10969
- case "text":
10970
- return "string";
10971
- case "number":
10972
- case "decimal":
10973
- return "number";
10974
- case "integer":
10975
- return "integer";
10976
- case "bigint":
10977
- return "bigint";
10978
- case "boolean":
10979
- return "boolean";
10980
- case "date":
10981
- return "date";
10982
- case "timestamp":
10983
- case "datetime":
10984
- return "datetime";
10985
- case "json":
10986
- return "json";
10987
- case "jsonb":
10988
- return "jsonb";
10989
- case "time":
10990
- return "time";
10991
- case "uuid":
10992
- return "uuid";
10993
- case "daterange":
10994
- return "daterange";
10995
- case "tstzrange":
10996
- return "tstzrange";
10997
- case "int4range":
10998
- return "int4range";
10999
- case "tsrange":
11000
- return "tsrange";
11001
- case "int8range":
11002
- return "int8range";
11003
- case "numrange":
11004
- return "numrange";
11005
- }
11006
- }
11007
- function mapRelationType2(kind) {
11008
- switch (kind) {
11009
- case "belongsTo":
11010
- return "belongsTo";
11011
- case "hasMany":
11012
- return "hasMany";
11013
- case "manyToMany":
11014
- return "belongsToMany";
11015
- }
11016
- }
11017
- function sourceTableFromQualifiedName(qualifiedName) {
11018
- const dotIndex = qualifiedName.indexOf(".");
11019
- return dotIndex > 0 ? qualifiedName.slice(0, dotIndex) : qualifiedName;
11020
- }
11021
- function relationNameFromQualifiedName(qualifiedName) {
11022
- const dotIndex = qualifiedName.indexOf(".");
11023
- return dotIndex > 0 ? qualifiedName.slice(dotIndex + 1) : qualifiedName;
11024
- }
11025
- function columnListsEqual(left, right) {
11026
- const leftColumns = toColumnList3(left);
11027
- const rightColumns = toColumnList3(right);
11028
- return leftColumns.length === rightColumns.length && leftColumns.every((column, index) => column === rightColumns[index]);
11029
- }
11030
- function generatedReferencedColumns(key) {
11031
- const columns = toColumnList3(key);
11032
- return columns.length > 0 ? columns : ["id"];
11033
- }
11034
- function findRelationForeignKey(sourceTable, genRelation, tables) {
11035
- switch (genRelation.kind) {
11036
- case "belongsTo":
11037
- return tables.get(sourceTable)?.foreignKeys.find(
11038
- (fk) => fk.references.table === genRelation.target && columnListsEqual(fk.columns, genRelation.foreignKey)
11039
- );
11040
- case "hasMany":
11041
- return tables.get(genRelation.target)?.foreignKeys.find(
11042
- (fk) => fk.references.table === sourceTable && columnListsEqual(fk.columns, genRelation.foreignKey)
11043
- );
11044
- case "manyToMany":
11045
- return void 0;
11046
- }
11047
- }
11048
- function isGeneratedTableWithConfig(table) {
11049
- const columns = table.columns;
11050
- return typeof columns === "object" && columns !== null && typeof columns.type !== "string";
11051
- }
11052
- function buildTableIRFromDefinition(tableName, genTable, fkAutoIndex) {
11053
- const columns = [];
11054
- const foreignKeys = [];
11055
- const indexes = [];
11056
- const primaryKeys = [];
11057
- const tableColumns = isGeneratedTableWithConfig(genTable) ? genTable.columns : genTable;
11058
- const indexedColumns = /* @__PURE__ */ new Set();
11059
- for (const [colName, colDef] of Object.entries(tableColumns)) {
11060
- const col2 = {
11061
- name: colName,
11062
- type: generatedTypeToColumnType(colDef.type),
11063
- nullable: colDef.nullable ?? false,
11064
- default: colDef.default
11065
- };
11066
- if (colDef.unique !== void 0) {
11067
- col2.unique = colDef.unique;
11068
- }
11069
- if (colDef.autoIncrement !== void 0) {
11070
- col2.autoIncrement = colDef.autoIncrement;
11071
- }
11072
- columns.push(col2);
11073
- if (colDef.primaryKey) {
11074
- primaryKeys.push(colName);
11075
- }
11076
- if (colDef.references) {
11077
- const fk = {
11078
- columns: [colName],
11079
- references: {
11080
- table: colDef.references.table,
11081
- columns: [colDef.references.column ?? "id"]
11082
- }
11083
- };
11084
- if (colDef.references.onDelete) {
11085
- fk.onDelete = colDef.references.onDelete;
11086
- }
11087
- foreignKeys.push(fk);
11088
- }
11089
- if (colDef.index) {
11090
- const indexName = typeof colDef.index === "string" ? colDef.index : `idx_${tableName}_${colName}`;
11091
- indexes.push({
11092
- name: indexName,
11093
- columns: [colName],
11094
- unique: false
11095
- });
11096
- indexedColumns.add(colName);
11097
- }
11098
- if (fkAutoIndex && colDef.references && !colDef.index) {
11099
- indexes.push({
11100
- name: `idx_${tableName}_${colName}`,
11101
- columns: [colName],
11102
- unique: false
11103
- });
11104
- indexedColumns.add(colName);
11105
- }
11106
- }
11107
- const pseudoColumns = [];
11108
- for (const fk of foreignKeys) {
11109
- const fkColumn = fk.columns[0];
11110
- const targetColumn = fk.references.columns[0];
11111
- if (fk.references.table === tableName && fkColumn !== void 0 && targetColumn !== void 0) {
11112
- const colDef = tableColumns[fkColumn];
11113
- const inferredName = fkColumn.endsWith("Id") ? fkColumn.slice(0, -2) : "parent";
11114
- const parentRole = colDef?.references?.parentRole ?? inferredName;
11115
- const childRole = colDef?.references?.childRole ?? (parentRole === "parent" ? "children" : `${parentRole}s`);
11116
- pseudoColumns.push(
11117
- createPseudoColumnMetadata(
11118
- tableName,
11119
- fkColumn,
11120
- targetColumn,
11121
- parentRole,
11122
- childRole
11123
- )
11124
- );
11125
- }
11126
- }
11127
- let primaryKey;
11128
- const configuredPrimaryKey = isGeneratedTableWithConfig(genTable) ? genTable.primaryKey : void 0;
11129
- if (configuredPrimaryKey !== void 0) {
11130
- primaryKey = configuredPrimaryKey;
11131
- } else if (primaryKeys.length > 0) {
11132
- primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : primaryKeys;
11133
- } else {
11134
- const fkColumns = foreignKeys.flatMap((fk) => fk.columns);
11135
- if (fkColumns.length > 0) {
11136
- primaryKey = fkColumns.length === 1 ? fkColumns[0] : fkColumns;
11137
- } else {
11138
- const hasId = columns.some((c) => c.name === "id");
11139
- primaryKey = hasId ? "id" : void 0;
11140
- }
11141
- }
11142
- if (isGeneratedTableWithConfig(genTable)) {
11143
- for (const fk of genTable.foreignKeys ?? []) {
11144
- const foreignKey = {
11145
- columns: [...fk.columns],
11146
- references: {
11147
- table: fk.references.table,
11148
- columns: [...fk.references.columns]
11149
- }
11150
- };
11151
- if (fk.onDelete) foreignKey.onDelete = fk.onDelete;
11152
- if (fk.onUpdate) foreignKey.onUpdate = fk.onUpdate;
11153
- foreignKeys.push(foreignKey);
11154
- }
11155
- for (const index of genTable.indexes ?? []) {
11156
- indexes.push({
11157
- columns: [...index.columns],
11158
- unique: index.unique ?? false,
11159
- ...index.name !== void 0 && { name: index.name }
11160
- });
11161
- }
11162
- }
11163
- const frozenColumns = Object.freeze(columns);
11164
- return Object.freeze({
11165
- name: tableName,
11166
- columns: frozenColumns,
11167
- ...primaryKey !== void 0 ? { primaryKey } : {},
11168
- foreignKeys: Object.freeze(foreignKeys),
11169
- indexes: Object.freeze(indexes),
11170
- ...pseudoColumns.length > 0 && {
11171
- pseudoColumns: Object.freeze(pseudoColumns)
11172
- }
11173
- });
11174
- }
11175
- function buildRelationIR(qualifiedName, genRelation, hints, relationFk) {
11176
- const sourceTable = sourceTableFromQualifiedName(qualifiedName);
11177
- const relationName = relationNameFromQualifiedName(qualifiedName);
11178
- const hint = hints[qualifiedName];
11179
- const relCardinality = genRelation.kind === "hasMany" ? genRelation.cardinality : void 0;
11180
- const cardinality = hint?.cardinality === "one" ? "one" : relCardinality === "one" ? "one" : genRelation.kind === "belongsTo" ? "one" : "many";
11181
- const optionality = genRelation.kind === "belongsTo" ? "optional" : "optional";
11182
- let relationType = mapRelationType2(genRelation.kind);
11183
- if (genRelation.kind === "hasMany" && cardinality === "one") {
11184
- relationType = "hasOne";
11185
- }
11186
- const baseRelation = {
11187
- name: relationName,
11188
- source: sourceTable,
11189
- target: genRelation.target,
11190
- type: relationType,
11191
- cardinality,
11192
- optionality,
11193
- includeStrategy: genRelation.includeStrategy ?? "auto",
11194
- filterStrategy: hint?.defaultStrategy ?? "auto",
11195
- joinDefault: "auto"
11196
- };
11197
- switch (genRelation.kind) {
11198
- case "belongsTo":
11199
- return {
11200
- ...baseRelation,
11201
- ...buildRelationKeyFields(
11202
- relationFk ?? {
11203
- columns: genRelation.foreignKey,
11204
- references: {
11205
- table: genRelation.target,
11206
- columns: generatedReferencedColumns(genRelation.targetKey)
11207
- }
11208
- },
11209
- "belongsTo",
11210
- {
11211
- foreignKeyShape: genRelation.foreignKey,
11212
- ...genRelation.targetKey !== void 0 ? { referencedKeyShape: genRelation.targetKey } : {}
11213
- }
11214
- )
11215
- };
11216
- case "hasMany":
11217
- return {
11218
- ...baseRelation,
11219
- ...buildRelationKeyFields(
11220
- relationFk ?? {
11221
- columns: genRelation.foreignKey,
11222
- references: {
11223
- table: sourceTable,
11224
- columns: generatedReferencedColumns(genRelation.sourceKey)
11225
- }
11226
- },
11227
- "inverse",
11228
- {
11229
- foreignKeyShape: genRelation.foreignKey,
11230
- ...genRelation.sourceKey !== void 0 ? { referencedKeyShape: genRelation.sourceKey } : {}
11231
- }
11232
- )
11233
- };
11234
- case "manyToMany":
11235
- return {
11236
- ...baseRelation,
11237
- through: genRelation.through,
11238
- foreignKey: genRelation.sourceFk,
11239
- otherKey: genRelation.targetFk
11240
- };
11241
- }
11242
- }
11243
- function buildModelFromSchema(schema2) {
11244
- const tables = /* @__PURE__ */ new Map();
11245
- const relations = /* @__PURE__ */ new Map();
11246
- const fkAutoIndex = schema2.conventions.fkAutoIndex;
11247
- for (const [tableName, genTable] of Object.entries(schema2.tables)) {
11248
- tables.set(
11249
- tableName,
11250
- buildTableIRFromDefinition(tableName, genTable, fkAutoIndex)
11251
- );
11252
- }
11253
- for (const [qualifiedName, genRelation] of Object.entries(schema2.relations)) {
11254
- const sourceTable = sourceTableFromQualifiedName(qualifiedName);
11255
- relations.set(
11256
- qualifiedName,
11257
- buildRelationIR(
11258
- qualifiedName,
11259
- genRelation,
11260
- schema2.hints,
11261
- findRelationForeignKey(sourceTable, genRelation, tables)
11262
- )
11263
- );
11264
- }
11265
- return new ModelIRImpl(tables, relations);
11266
- }
11267
- function buildModelFromResolvedSchema(schema2) {
11268
- const generatedSchema = assertResolvedSchemaToGeneratedSchema(schema2);
11269
- return buildModelFromSchema(generatedSchema);
11270
- }
11271
- function isGeneratedSchema(value) {
11272
- if (typeof value !== "object" || value === null) {
11273
- return false;
11274
- }
11275
- const obj = value;
11276
- return typeof obj.tables === "object" && obj.tables !== null && typeof obj.relations === "object" && obj.relations !== null && typeof obj.hints === "object" && obj.hints !== null && typeof obj.conventions === "object" && obj.conventions !== null;
11277
- }
11278
- var RESOLVED_SCHEMA_ONLY_TYPES = /* @__PURE__ */ new Set(["time", "jsonb"]);
11279
- var GENERATED_SCHEMA_ONLY_TYPES = /* @__PURE__ */ new Set(["number", "datetime"]);
11280
- function hasResolvedSchemaOnlyTypes(tables) {
11281
- for (const table of Object.values(tables)) {
11282
- for (const column of Object.values(table)) {
11283
- if (column?.type && RESOLVED_SCHEMA_ONLY_TYPES.has(column.type)) {
11284
- return true;
11285
- }
11286
- }
11287
- }
11288
- return false;
11289
- }
11290
- function hasGeneratedSchemaOnlyTypes(tables) {
11291
- for (const table of Object.values(tables)) {
11292
- for (const column of Object.values(table)) {
11293
- if (column?.type && GENERATED_SCHEMA_ONLY_TYPES.has(column.type)) {
11294
- return true;
11295
- }
11296
- }
11297
- }
11298
- return false;
11299
- }
11300
- function isResolvedSchema(value) {
11301
- if (!isGeneratedSchema(value)) {
11302
- return false;
11303
- }
11304
- if (hasResolvedSchemaOnlyTypes(
11305
- value.tables
11306
- )) {
11307
- return true;
11308
- }
11309
- if (hasGeneratedSchemaOnlyTypes(
11310
- value.tables
11311
- )) {
11312
- return false;
11313
- }
11314
- return false;
11315
- }
11316
- function normalizeSchema(input) {
11317
- if (!isGeneratedSchema(input)) {
11318
- throw new Error(
11319
- "Invalid schema: must have tables, relations, hints, and conventions properties"
11320
- );
11321
- }
11322
- if (isResolvedSchema(input)) {
11323
- const result = resolvedSchemaToGeneratedSchema(input);
11324
- if (!result.success) {
11325
- const messages = result.errors.map((e) => e.message).join(", ");
11326
- throw new Error(`Schema conversion failed: ${messages}`);
11327
- }
11328
- return result.schema;
11329
- }
11330
- return input;
11331
- }
11332
- var SchemaColumnTypeSchema = v.picklist([
11333
- "uuid",
11334
- "string",
11335
- "text",
11336
- "integer",
11337
- "bigint",
11338
- "decimal",
11339
- "boolean",
11340
- "timestamp",
11341
- "date",
11342
- "time",
11343
- "json",
11344
- "jsonb",
11345
- "daterange",
11346
- "tstzrange",
11347
- "int4range",
11348
- "tsrange",
11349
- "int8range",
11350
- "numrange"
11351
- ]);
11352
- var PROTO_POLLUTION_KEYS = ["__proto__", "constructor", "prototype"];
11353
- function safeRecord(valueSchema) {
11354
- return v.pipe(
11355
- v.unknown(),
11356
- v.check((input) => {
11357
- if (typeof input !== "object" || input === null) return true;
11358
- return !Object.keys(input).some(
11359
- (k) => PROTO_POLLUTION_KEYS.includes(k)
11360
- );
11361
- }, "Schema keys must not include prototype-pollution names (__proto__, constructor, prototype)"),
11362
- v.record(v.string(), valueSchema)
11363
- );
11364
- }
11365
- var ForeignKeyReferenceSchema = v.object({
11366
- table: v.string(),
11367
- column: v.optional(v.string()),
11368
- onDelete: v.optional(
11369
- v.picklist(["CASCADE", "SET NULL", "RESTRICT", "NO ACTION"])
11370
- ),
11371
- index: v.optional(v.boolean()),
11372
- parentRole: v.optional(v.string()),
11373
- childRole: v.optional(v.string())
11374
- });
11375
- var StringOrStringArraySchema = v.union([v.string(), v.array(v.string())]);
11376
- var ColumnDefinitionSchema = v.object({
11377
- type: SchemaColumnTypeSchema,
11378
- primaryKey: v.optional(v.boolean()),
11379
- nullable: v.optional(v.boolean()),
11380
- unique: v.optional(v.boolean()),
11381
- autoIncrement: v.optional(v.boolean()),
11382
- default: v.optional(v.union([v.string(), v.number(), v.boolean()])),
11383
- references: v.optional(ForeignKeyReferenceSchema),
11384
- index: v.optional(v.union([v.boolean(), v.string()]))
11385
- });
11386
- var FlatTableDefinitionSchema = safeRecord(ColumnDefinitionSchema);
11387
- var TableDefWithConfigSchema = v.object({
11388
- columns: FlatTableDefinitionSchema,
11389
- primaryKey: v.optional(StringOrStringArraySchema),
11390
- foreignKeys: v.optional(
11391
- v.array(
11392
- v.object({
11393
- columns: v.array(v.string()),
11394
- references: v.object({
11395
- table: v.string(),
11396
- columns: v.array(v.string())
11397
- }),
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
- )
11404
- })
11405
- )
11406
- ),
11407
- indexes: v.optional(
11408
- v.array(
11409
- v.object({
11410
- columns: v.array(v.string()),
11411
- unique: v.optional(v.boolean()),
11412
- name: v.optional(v.string())
11413
- })
11414
- )
11415
- )
11416
- });
11417
- var TableDefinitionSchema = v.union([
11418
- TableDefWithConfigSchema,
11419
- FlatTableDefinitionSchema
11420
- ]);
11421
- var TablesDefinitionSchema = safeRecord(TableDefinitionSchema);
11422
- var IncludeStrategySchema = v.optional(
11423
- v.picklist(["join", "subquery", "cte", "lateral", "json_agg", "auto"])
11424
- );
11425
- var BelongsToRelationSchema = v.object({
11426
- kind: v.literal("belongsTo"),
11427
- target: v.string(),
11428
- foreignKey: StringOrStringArraySchema,
11429
- targetKey: v.optional(StringOrStringArraySchema),
11430
- includeStrategy: IncludeStrategySchema
11431
- });
11432
- var HasManyRelationSchema = v.object({
11433
- kind: v.literal("hasMany"),
11434
- target: v.string(),
11435
- foreignKey: StringOrStringArraySchema,
11436
- sourceKey: v.optional(StringOrStringArraySchema),
11437
- includeStrategy: IncludeStrategySchema
11438
- });
11439
- var ManyToManyRelationSchema = v.object({
11440
- kind: v.literal("manyToMany"),
11441
- target: v.string(),
11442
- through: v.string(),
11443
- sourceFk: v.string(),
11444
- targetFk: v.string(),
11445
- includeStrategy: IncludeStrategySchema
11446
- });
11447
- var RelationDefinitionSchema = v.variant("kind", [
11448
- BelongsToRelationSchema,
11449
- HasManyRelationSchema,
11450
- ManyToManyRelationSchema
11451
- ]);
11452
- var RelationsDefinitionSchema = safeRecord(RelationDefinitionSchema);
11453
- var HintDefinitionSchema = v.object({
11454
- defaultStrategy: v.optional(v.picklist(["exists", "join"])),
11455
- cardinality: v.optional(v.picklist(["one", "many"]))
11456
- });
11457
- var HintsDefinitionSchema = safeRecord(HintDefinitionSchema);
11458
- var ConventionsDefinitionSchema = v.object({
11459
- fkPattern: v.string(),
11460
- pluralize: v.boolean(),
11461
- timestamps: v.array(v.string()),
11462
- fkAutoIndex: v.boolean()
11463
- });
11464
- var IndexDefinitionSchema = v.object({
11465
- columns: v.array(v.string()),
11466
- unique: v.optional(v.boolean()),
11467
- name: v.optional(v.string())
11468
- });
11469
- var IndexesDefinitionSchema = safeRecord(v.array(IndexDefinitionSchema));
11470
- var ResolvedSchemaValidation = v.object({
11471
- tables: TablesDefinitionSchema,
11472
- relations: RelationsDefinitionSchema,
11473
- hints: HintsDefinitionSchema,
11474
- conventions: ConventionsDefinitionSchema,
11475
- indexes: v.optional(IndexesDefinitionSchema)
11476
- });
11477
- function mapSchemaColumnType(schemaType) {
11478
- switch (schemaType) {
11479
- case "uuid":
11480
- return "uuid";
11481
- case "string":
11482
- return "string";
11483
- case "text":
11484
- return "text";
11485
- case "integer":
11486
- return "integer";
11487
- case "bigint":
11488
- return "bigint";
11489
- case "decimal":
11490
- return "decimal";
11491
- case "boolean":
11492
- return "boolean";
11493
- case "timestamp":
11494
- return "timestamp";
11495
- case "date":
11496
- return "date";
11497
- case "time":
11498
- return "time";
11499
- case "json":
11500
- return "json";
11501
- case "jsonb":
11502
- return "jsonb";
11503
- case "daterange":
11504
- return "daterange";
11505
- case "tstzrange":
11506
- return "tstzrange";
11507
- case "int4range":
11508
- return "int4range";
11509
- case "tsrange":
11510
- return "tsrange";
11511
- case "int8range":
11512
- return "int8range";
11513
- case "numrange":
11514
- return "numrange";
11515
- }
11516
- }
11517
- function convertColumn(col2) {
11518
- const result = {
11519
- type: mapSchemaColumnType(col2.type)
11520
- };
11521
- if (col2.primaryKey !== void 0) {
11522
- result.primaryKey = col2.primaryKey;
11523
- }
11524
- if (col2.nullable !== void 0) {
11525
- result.nullable = col2.nullable;
11526
- }
11527
- if (col2.unique !== void 0) {
11528
- result.unique = col2.unique;
11529
- }
11530
- if (col2.autoIncrement !== void 0) {
11531
- result.autoIncrement = col2.autoIncrement;
11532
- }
11533
- if (col2.default !== void 0) {
11534
- result.default = col2.default;
11535
- }
11536
- if (col2.references) {
11537
- result.references = {
11538
- table: col2.references.table,
11539
- ...col2.references.column !== void 0 ? { column: col2.references.column } : {},
11540
- ...col2.references.onDelete ? { onDelete: col2.references.onDelete } : {},
11541
- ...col2.references.index !== void 0 ? { index: col2.references.index } : {},
11542
- ...col2.references.parentRole ? { parentRole: col2.references.parentRole } : {},
11543
- ...col2.references.childRole ? { childRole: col2.references.childRole } : {}
11544
- };
11545
- }
11546
- return result;
11547
- }
11548
- function convertRelation(rel) {
11549
- switch (rel.kind) {
11550
- case "belongsTo": {
11551
- const result = {
11552
- kind: "belongsTo",
11553
- target: rel.target,
11554
- foreignKey: rel.foreignKey
11555
- };
11556
- if (rel.targetKey !== void 0) {
11557
- result.targetKey = rel.targetKey;
11558
- }
11559
- if (rel.includeStrategy !== void 0) {
11560
- result.includeStrategy = rel.includeStrategy;
11561
- }
11562
- return result;
11563
- }
11564
- case "hasMany": {
11565
- const result = {
11566
- kind: "hasMany",
11567
- target: rel.target,
11568
- foreignKey: rel.foreignKey
11569
- };
11570
- if (rel.sourceKey !== void 0) {
11571
- result.sourceKey = rel.sourceKey;
11572
- }
11573
- if (rel.includeStrategy !== void 0) {
11574
- result.includeStrategy = rel.includeStrategy;
11575
- }
11576
- return result;
11577
- }
11578
- case "manyToMany": {
11579
- const result = {
11580
- kind: "manyToMany",
11581
- target: rel.target,
11582
- through: rel.through,
11583
- sourceFk: rel.sourceFk,
11584
- targetFk: rel.targetFk
11585
- };
11586
- if (rel.includeStrategy !== void 0) {
11587
- result.includeStrategy = rel.includeStrategy;
11588
- }
11589
- return result;
11590
- }
11591
- }
11592
- }
11593
- function convertHint(hint) {
11594
- const result = {};
11595
- if (hint.defaultStrategy !== void 0) {
11596
- result.defaultStrategy = hint.defaultStrategy;
11597
- }
11598
- if (hint.cardinality !== void 0) {
11599
- result.cardinality = hint.cardinality;
11600
- }
11601
- return result;
11602
- }
11603
- function resolvedSchemaToGeneratedSchema(input) {
11604
- const parseResult = v.safeParse(ResolvedSchemaValidation, input);
11605
- if (!parseResult.success) {
11606
- return {
11607
- success: false,
11608
- errors: parseResult.issues
11609
- };
11610
- }
11611
- const validated = parseResult.output;
11612
- const tables = /* @__PURE__ */ Object.create(null);
11613
- for (const [tableName, tableDef] of Object.entries(validated.tables)) {
11614
- const convertedTable = /* @__PURE__ */ Object.create(null);
11615
- const tableObj = tableDef;
11616
- const isWithConfig = Array.isArray(tableObj.primaryKey);
11617
- const columns = isWithConfig ? tableObj.columns : tableObj;
11618
- for (const [colName, colDef] of Object.entries(columns)) {
11619
- convertedTable[colName] = convertColumn(
11620
- colDef
11621
- );
11622
- }
11623
- tables[tableName] = convertedTable;
11624
- }
11625
- const relations = /* @__PURE__ */ Object.create(null);
11626
- for (const [relName, relDef] of Object.entries(validated.relations)) {
11627
- relations[relName] = convertRelation(relDef);
11628
- }
11629
- const hints = /* @__PURE__ */ Object.create(null);
11630
- for (const [hintName, hintDef] of Object.entries(validated.hints)) {
11631
- hints[hintName] = convertHint(hintDef);
11632
- }
11633
- const conventions = {
11634
- fkPattern: validated.conventions.fkPattern,
11635
- pluralize: validated.conventions.pluralize,
11636
- timestamps: validated.conventions.timestamps,
11637
- fkAutoIndex: validated.conventions.fkAutoIndex
11638
- };
11639
- return {
11640
- success: true,
11641
- schema: {
11642
- tables,
11643
- relations,
11644
- hints,
11645
- conventions
11646
- }
11647
- };
11648
- }
11649
- function assertResolvedSchemaToGeneratedSchema(input) {
11650
- const result = resolvedSchemaToGeneratedSchema(input);
11651
- if (!result.success) {
11652
- const messages = result.errors.map((e) => {
11653
- const path = e.path?.map((p) => p.key).join(".") || "root";
11654
- return `[${path}] ${e.message} (expected: ${e.expected}, received: ${e.received})`;
11655
- }).join("\n");
11656
- throw new Error(`Schema validation failed:
11657
- ${messages}`);
11658
- }
11659
- return result.schema;
11660
- }
11661
-
11662
10814
  // src/dialects/index.ts
11663
10815
  var POSTGRESQL_CAPABILITIES = {
11664
10816
  name: "postgresql",
@@ -13039,7 +12191,6 @@ export {
13039
12191
  ColumnNotFoundError,
13040
12192
  CteBuilder,
13041
12193
  CteQueryBuilder,
13042
- DEFAULT_CONVENTIONS,
13043
12194
  DEFAULT_FEATURE_CHECKERS,
13044
12195
  DUCKDB_CAPABILITIES,
13045
12196
  DeleteBuilder,
@@ -13062,12 +12213,11 @@ export {
13062
12213
  RawCteQueryBuilder,
13063
12214
  RecursiveShapeMismatchError,
13064
12215
  RelationNotFoundError,
13065
- ResolvedSchemaValidation,
13066
12216
  ResultHydrator,
13067
12217
  SQLITE_CAPABILITIES,
13068
12218
  SQL_RAW_MARKER,
13069
12219
  SchemaValidationError as SchemaError,
13070
- SchemaValidationError2 as SchemaValidationError,
12220
+ SchemaValidationError,
13071
12221
  SubqueryBuilder,
13072
12222
  SubqueryExpression,
13073
12223
  TABLE_META,
@@ -13106,7 +12256,6 @@ export {
13106
12256
  assertParamsLength,
13107
12257
  assertParamsType,
13108
12258
  assertParamsValue,
13109
- assertResolvedSchemaToGeneratedSchema,
13110
12259
  assertSQLColumn,
13111
12260
  assertSQLEquals,
13112
12261
  assertSQLJoin,
@@ -13114,8 +12263,6 @@ export {
13114
12263
  assertSuccess,
13115
12264
  assertTypeSupported,
13116
12265
  batchValues,
13117
- buildModelFromResolvedSchema,
13118
- buildModelFromSchema,
13119
12266
  capitalize,
13120
12267
  caseWhen,
13121
12268
  cast,
@@ -13137,11 +12284,8 @@ export {
13137
12284
  decapitalize,
13138
12285
  defaultLogger,
13139
12286
  defineModel,
13140
- defineSchema,
13141
12287
  denseRank,
13142
12288
  deriveRelationPathFromIntentPath,
13143
- detectForeignKeys,
13144
- detectManyToMany,
13145
12289
  distinct,
13146
12290
  emitWarning,
13147
12291
  eq,
@@ -13164,13 +12308,11 @@ export {
13164
12308
  inArray,
13165
12309
  inSubquery,
13166
12310
  inferForeignKey,
13167
- inferRelationsFromSchema,
13168
12311
  export_isAdjacencyTraversal as isAdjacencyTraversal,
13169
12312
  export_isAggregateWindowFunction as isAggregateWindowFunction,
13170
12313
  isAliasedColumn,
13171
12314
  isAllColumns,
13172
12315
  isBatchValuesRef,
13173
- isBelongsTo,
13174
12316
  isCardinalityShorthand,
13175
12317
  export_isCoalesceExpression as isCoalesceExpression,
13176
12318
  export_isColumnAliasExpression as isColumnAliasExpression,
@@ -13181,11 +12323,8 @@ export {
13181
12323
  isDistinctFrom,
13182
12324
  export_isEdgeTableTraversal as isEdgeTableTraversal,
13183
12325
  isExpressionSpec,
13184
- isGeneratedSchema,
13185
- isHasMany,
13186
12326
  export_isInsertIntent as isInsertIntent,
13187
12327
  isKnownDialect,
13188
- isManyToMany,
13189
12328
  export_isMutationIntent as isMutationIntent,
13190
12329
  isNotNull,
13191
12330
  isNull,
@@ -13200,7 +12339,6 @@ export {
13200
12339
  isRelationObjectDef,
13201
12340
  isRelationRef,
13202
12341
  isRelationTupleDef,
13203
- isResolvedSchema,
13204
12342
  export_isSelectAggregate as isSelectAggregate,
13205
12343
  export_isSelectAll as isSelectAll,
13206
12344
  export_isSelectFields as isSelectFields,
@@ -13240,7 +12378,6 @@ export {
13240
12378
  neq,
13241
12379
  none,
13242
12380
  normalizeSQL,
13243
- normalizeSchema,
13244
12381
  not,
13245
12382
  notExists,
13246
12383
  nqlRaw,
@@ -13273,7 +12410,6 @@ export {
13273
12410
  requiresDatabase,
13274
12411
  resetLogger,
13275
12412
  resolveQueryIndex,
13276
- resolvedSchemaToGeneratedSchema,
13277
12413
  rowNumber,
13278
12414
  runAssertions,
13279
12415
  schema,
@@ -13298,6 +12434,7 @@ export {
13298
12434
  validateAssertionBlocks,
13299
12435
  validateRecursiveInclude,
13300
12436
  validateRecursiveShape,
12437
+ validateSchemaIndexOptions,
13301
12438
  validateTypeName,
13302
12439
  wAvg,
13303
12440
  wCount,