@dbsp/core 1.5.0 → 1.6.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
@@ -1665,7 +1665,7 @@ function isManyToMany(rel) {
1665
1665
  }
1666
1666
 
1667
1667
  // src/planner.ts
1668
- import { toColumnList } from "@dbsp/types";
1668
+ import { resolveJsonAggOrderKey, toColumnList } from "@dbsp/types";
1669
1669
 
1670
1670
  // src/dx/errors.ts
1671
1671
  var ExecutionError = class _ExecutionError extends Error {
@@ -2410,12 +2410,6 @@ function isSubquerySelectedColumnNonNullable(existsIntent, sourceTable, model) {
2410
2410
  if (!column) return false;
2411
2411
  return !column.nullable;
2412
2412
  }
2413
- function resolveTargetJsonAggOrderKey(model, targetTable) {
2414
- const table = model.getTable(targetTable);
2415
- if (!table) return { columns: [], fallback: false };
2416
- const pkColumns = toColumnList(table.primaryKey);
2417
- return pkColumns.length > 0 ? { columns: pkColumns, fallback: false } : { columns: table.columns.map((col2) => col2.name), fallback: true };
2418
- }
2419
2413
  function optimizeInToExists(where, sourceTable, model, negated = false) {
2420
2414
  switch (where.kind) {
2421
2415
  case "in": {
@@ -2744,7 +2738,8 @@ function processInclude(include, sourceTable, model, state, opts, intentPath, de
2744
2738
  const explicitJoinType = includeStrategy === "join" ? include.join ?? cascadedJoinType : void 0;
2745
2739
  const includeDecisionId = generateDecisionId(state, "include-strategy");
2746
2740
  const parentKey = relation.type === "belongsTo" ? relation.targetKey : relation.sourceKey;
2747
- const targetOrder = resolveTargetJsonAggOrderKey(model, relation.target);
2741
+ const targetTable = model.getTable(relation.target);
2742
+ const targetOrder = targetTable ? resolveJsonAggOrderKey(targetTable) : void 0;
2748
2743
  state.decisions.push({
2749
2744
  id: includeDecisionId,
2750
2745
  type: "include-strategy",
@@ -2760,10 +2755,10 @@ function processInclude(include, sourceTable, model, state, opts, intentPath, de
2760
2755
  foreignKey: relation.foreignKey
2761
2756
  },
2762
2757
  ...parentKey !== void 0 && { parentKey },
2763
- ...targetOrder.columns.length > 0 && {
2764
- targetPrimaryKey: targetOrder.columns
2758
+ ...targetOrder && targetOrder.columns.length > 0 && {
2759
+ targetOrderKey: targetOrder.columns
2765
2760
  },
2766
- ...targetOrder.fallback && { orderByFallback: true }
2761
+ ...targetOrder?.fallback && { orderByFallback: true }
2767
2762
  },
2768
2763
  choice: includeStrategy,
2769
2764
  // Embed joinType so the adapter's join handler can use it directly
@@ -6257,7 +6252,7 @@ import {
6257
6252
  NqlLexer,
6258
6253
  compile as nqlCompile
6259
6254
  } from "@dbsp/nql";
6260
- import { toColumnList as toColumnList2 } from "@dbsp/types";
6255
+ import { resolveJsonAggOrderKey as resolveJsonAggOrderKey2 } from "@dbsp/types";
6261
6256
  import {
6262
6257
  explainUnsupportedNqlBindingIncludeHop,
6263
6258
  getTrustedNqlRelationFilterFields,
@@ -6411,7 +6406,11 @@ function virtualRelationIncludeShape(relation) {
6411
6406
  type: relationType,
6412
6407
  foreignKey,
6413
6408
  source: relation.sourceTable,
6414
- target: relation.targetTable
6409
+ target: relation.targetTable,
6410
+ ...relation.through !== void 0 && { through: relation.through },
6411
+ ...relation.throughTargetColumn !== void 0 && {
6412
+ otherKey: relation.throughTargetColumn
6413
+ }
6415
6414
  };
6416
6415
  }
6417
6416
  var BINDING_INCLUDE_NODE_ONLY_RELATION = {
@@ -6457,7 +6456,8 @@ function trustedBindingRelationColumnIsAdmitted(column) {
6457
6456
  if (trusted.cardinality === "one") {
6458
6457
  return !isDotted || trusted.hops.length > 0;
6459
6458
  }
6460
- return trusted.cardinality === "many" && trusted.relationType === "hasMany" && !isDotted && trusted.hops.length === 0;
6459
+ const hasCompleteManyToManyProof = (trusted.relationType === "manyToMany" || trusted.relationType === "belongsToMany") && trusted.through !== void 0 && trusted.throughSourceColumn !== void 0 && trusted.throughTargetColumn !== void 0;
6460
+ return trusted.cardinality === "many" && (trusted.relationType === "hasMany" || hasCompleteManyToManyProof) && !isDotted && trusted.hops.length === 0;
6461
6461
  }
6462
6462
  function assertProvenBindingInclude(bindingName, include, provenRelations) {
6463
6463
  const proven = provenRelations.get(include.relation);
@@ -6519,7 +6519,8 @@ function createBindingIncludeDecision(intent, include, relation, index, model) {
6519
6519
  const relationType = relation.relationType;
6520
6520
  const foreignKey = relationType === "belongsTo" ? relation.sourceColumn : relation.targetColumn;
6521
6521
  const parentKey = relationType === "belongsTo" ? relation.targetColumn : relation.sourceColumn;
6522
- const targetOrder = resolveTargetJsonAggOrderKey2(model, relation.targetTable);
6522
+ const targetTable = model.getTable(relation.targetTable);
6523
+ const targetOrder = targetTable ? resolveJsonAggOrderKey2(targetTable) : void 0;
6523
6524
  return {
6524
6525
  id: `binding-include-${index}`,
6525
6526
  type: "include-strategy",
@@ -6530,10 +6531,10 @@ function createBindingIncludeDecision(intent, include, relation, index, model) {
6530
6531
  relationType,
6531
6532
  foreignKey,
6532
6533
  parentKey,
6533
- ...targetOrder.columns.length > 0 && {
6534
- targetPrimaryKey: targetOrder.columns
6534
+ ...targetOrder && targetOrder.columns.length > 0 && {
6535
+ targetOrderKey: targetOrder.columns
6535
6536
  },
6536
- ...targetOrder.fallback && { orderByFallback: true },
6537
+ ...targetOrder?.fallback && { orderByFallback: true },
6537
6538
  includeAlias: include.relation,
6538
6539
  intentPath: `include[${index}]`
6539
6540
  },
@@ -6549,12 +6550,6 @@ function parentKeyForRelation(relation) {
6549
6550
  if (relation.type === "belongsTo") return relation.targetKey;
6550
6551
  return relation.sourceKey;
6551
6552
  }
6552
- function resolveTargetJsonAggOrderKey2(model, targetTable) {
6553
- const table = model.getTable(targetTable);
6554
- if (!table) return { columns: [], fallback: false };
6555
- const pkColumns = toColumnList2(table.primaryKey);
6556
- return pkColumns.length > 0 ? { columns: pkColumns, fallback: false } : { columns: table.columns.map((col2) => col2.name), fallback: true };
6557
- }
6558
6553
  function assertSupportedBindingIncludeHop(bindingName, rootIncludeRelation, relationName, relation, include, reasonPrefix = "") {
6559
6554
  const unsupportedReason = explainUnsupportedNqlBindingIncludeHop(
6560
6555
  relationName,
@@ -6653,10 +6648,11 @@ function createBindingTailIncludeDecisions(bindingName, include, firstHopRelatio
6653
6648
  const baseContext = { ...decision.context };
6654
6649
  delete baseContext.foreignKey;
6655
6650
  delete baseContext.parentKey;
6656
- delete baseContext.targetPrimaryKey;
6651
+ delete baseContext.targetOrderKey;
6657
6652
  delete baseContext.orderByFallback;
6658
6653
  const parentKey = parentKeyForRelation(relation);
6659
- const targetOrder = resolveTargetJsonAggOrderKey2(model, relation.target);
6654
+ const targetTable = model.getTable(relation.target);
6655
+ const targetOrder = targetTable ? resolveJsonAggOrderKey2(targetTable) : void 0;
6660
6656
  return {
6661
6657
  ...decision,
6662
6658
  id: `binding-include-${includeIndex}-tail-${tailIndex}`,
@@ -6674,10 +6670,10 @@ function createBindingTailIncludeDecisions(bindingName, include, firstHopRelatio
6674
6670
  // Leave parentKey absent when RelationIR does not specify it so the
6675
6671
  // adapter applies the same defaultPkColumnName fallback as real-table includes.
6676
6672
  ...parentKey !== void 0 && { parentKey },
6677
- ...targetOrder.columns.length > 0 && {
6678
- targetPrimaryKey: targetOrder.columns
6673
+ ...targetOrder && targetOrder.columns.length > 0 && {
6674
+ targetOrderKey: targetOrder.columns
6679
6675
  },
6680
- ...targetOrder.fallback && { orderByFallback: true },
6676
+ ...targetOrder?.fallback && { orderByFallback: true },
6681
6677
  intentPath: rebaseBindingTailIntentPath(
6682
6678
  decision.context.intentPath,
6683
6679
  includeIndex
@@ -6698,6 +6694,13 @@ function createBindingFinalPlan(intent, bundle, model, dialectCapabilities) {
6698
6694
  );
6699
6695
  }
6700
6696
  const proven = provenIncludes.get(include.relation);
6697
+ if (!proven) {
6698
+ throw bindingFinalIncludeError(
6699
+ intent.from,
6700
+ include.relation,
6701
+ "include relation proof was not emitted by the binding compiler"
6702
+ );
6703
+ }
6701
6704
  const firstHopDecision = createBindingIncludeDecision(
6702
6705
  intent,
6703
6706
  include,
@@ -6848,6 +6851,14 @@ function assembleNqlTemplate(strings, values) {
6848
6851
  function hasMutationBindingBodies(bundle) {
6849
6852
  return (bundle.mutationBindings?.size ?? 0) > 0;
6850
6853
  }
6854
+ function hasSnapshotReadBindingSteps(bundle) {
6855
+ return bundle.nqlProgramSequence?.some(
6856
+ (step) => step.kind === "query" && step.snapshot === true
6857
+ ) ?? false;
6858
+ }
6859
+ function hasExecutableNqlProgramSequence(bundle) {
6860
+ return hasMutationBindingBodies(bundle) || hasSnapshotReadBindingSteps(bundle);
6861
+ }
6851
6862
  function requireMutationBindingColumns(bundle, bindName) {
6852
6863
  const columns = bundle.bindingOutputSchemas?.get(bindName)?.columns;
6853
6864
  if (columns === void 0 || columns.length === 0) {
@@ -6911,6 +6922,7 @@ function orderedSequenceStepToProgramStep(step) {
6911
6922
  intent: step.query,
6912
6923
  ...step.bindName !== void 0 && { bindName: step.bindName },
6913
6924
  final: step.final,
6925
+ ...step.snapshot === true && { snapshot: true },
6914
6926
  ...dependencyStep.bindingDependencies !== void 0 && {
6915
6927
  bindingDependencies: dependencyStep.bindingDependencies
6916
6928
  }
@@ -6926,15 +6938,32 @@ function orderedSequenceStepToProgramStep(step) {
6926
6938
  }
6927
6939
  };
6928
6940
  }
6941
+ var structuredCloneFn = globalThis.structuredClone;
6942
+ function hasCustomSnapshotPrototype(value) {
6943
+ if (value === null || typeof value !== "object") return false;
6944
+ const prototype = Object.getPrototypeOf(value);
6945
+ return prototype !== Object.prototype && prototype !== null && prototype !== Array.prototype && prototype !== Date.prototype && prototype !== Map.prototype && prototype !== Set.prototype;
6946
+ }
6947
+ function cloneMutationSnapshotColumnValue(value) {
6948
+ if (hasCustomSnapshotPrototype(value) || structuredCloneFn === void 0) {
6949
+ return value;
6950
+ }
6951
+ try {
6952
+ return structuredCloneFn(value);
6953
+ } catch {
6954
+ return value;
6955
+ }
6956
+ }
6929
6957
  function snapshotMutationRows(rows) {
6930
6958
  return rows.map((row) => {
6931
- if (Array.isArray(row)) {
6932
- return [...row];
6959
+ if (row === null || typeof row !== "object") {
6960
+ return cloneMutationSnapshotColumnValue(row);
6933
6961
  }
6934
- if (row !== null && typeof row === "object") {
6935
- return { ...row };
6962
+ const snapshot = { ...row };
6963
+ for (const key of Reflect.ownKeys(snapshot)) {
6964
+ snapshot[key] = cloneMutationSnapshotColumnValue(snapshot[key]);
6936
6965
  }
6937
- return row;
6966
+ return snapshot;
6938
6967
  });
6939
6968
  }
6940
6969
  function assertNqlProgramSteps(compiledIntent, steps) {
@@ -6958,6 +6987,13 @@ function assertNqlProgramSteps(compiledIntent, steps) {
6958
6987
  }
6959
6988
  const seenBindNames = /* @__PURE__ */ new Set();
6960
6989
  for (const step of steps) {
6990
+ if (step.kind === "query" && step.snapshot === true) {
6991
+ if (step.bindName === void 0 || step.final) {
6992
+ throw new Error(
6993
+ "NQL program sequence query snapshots must be named non-final statements."
6994
+ );
6995
+ }
6996
+ }
6961
6997
  if (step.bindName === void 0) continue;
6962
6998
  if (seenBindNames.has(step.bindName)) {
6963
6999
  throw new Error(
@@ -7063,6 +7099,18 @@ function filterOptionalMapByBindingDependencies(source, bindingDependencies) {
7063
7099
  const filtered = filterMapByBindingDependencies(source, bindingDependencies);
7064
7100
  return filtered.size > 0 ? filtered : void 0;
7065
7101
  }
7102
+ function runtimeSourceBindingNames(sourceBundle) {
7103
+ const names = /* @__PURE__ */ new Set();
7104
+ for (const name of sourceBundle.mutationBindings?.keys() ?? []) {
7105
+ names.add(name);
7106
+ }
7107
+ for (const step of sourceBundle.nqlProgramSequence ?? []) {
7108
+ if (step.kind === "query" && step.snapshot === true && step.bindName !== void 0) {
7109
+ names.add(step.bindName);
7110
+ }
7111
+ }
7112
+ return names.size > 0 ? names : void 0;
7113
+ }
7066
7114
  function filterMapByRuntimeBindingDependencies(source, runtimeSourceBindings, bindingDependencies) {
7067
7115
  if (source === void 0) return /* @__PURE__ */ new Map();
7068
7116
  if (bindingDependencies === void 0 || runtimeSourceBindings === void 0 || runtimeSourceBindings.size === 0) {
@@ -7202,7 +7250,7 @@ var NqlBuilderImpl = class {
7202
7250
  }
7203
7251
  dump(meta) {
7204
7252
  const compiledIntent = this.compile();
7205
- if (hasMutationBindingBodies(compiledIntent.bundle)) {
7253
+ if (hasExecutableNqlProgramSequence(compiledIntent.bundle)) {
7206
7254
  return this.dumpNqlProgramSequence(compiledIntent, meta);
7207
7255
  }
7208
7256
  if (compiledIntent.kind === "mutation") {
@@ -7285,7 +7333,7 @@ var NqlBuilderImpl = class {
7285
7333
  createNqlStatementBundle(statement, bindings, runtimeBindings, sourceBundle, bindingDependencies, planReport) {
7286
7334
  const statementBindings = filterMapByRuntimeBindingDependencies(
7287
7335
  bindings,
7288
- sourceBundle.mutationBindings,
7336
+ runtimeSourceBindingNames(sourceBundle),
7289
7337
  bindingDependencies
7290
7338
  );
7291
7339
  const statementRuntimeBindings = filterMapByBindingDependencies(
@@ -7425,6 +7473,28 @@ var NqlBuilderImpl = class {
7425
7473
  if (step.final) {
7426
7474
  finalRows = rows.transformedRows;
7427
7475
  }
7476
+ } else if (step.snapshot === true && step.bindName !== void 0) {
7477
+ const statementBundle = this.createNqlStatementBundle(
7478
+ { query: step.intent },
7479
+ priorBindings,
7480
+ runtimeBindings,
7481
+ sourceBundle,
7482
+ step.bindingDependencies
7483
+ );
7484
+ const compiled = txAdapter.compile(
7485
+ statementBundle,
7486
+ this.nqlBundleCompileOptions()
7487
+ );
7488
+ const rows = await txAdapter.execute(compiled);
7489
+ runtimeBindings.set(
7490
+ step.bindName,
7491
+ createRuntimeBinding(
7492
+ sourceBundle,
7493
+ step.bindName,
7494
+ snapshotMutationRows(rows),
7495
+ txAdapter.dbCasing
7496
+ )
7497
+ );
7428
7498
  } else if (step.final) {
7429
7499
  const planReport = isBindingFinalQuery(compiledIntent.bundle) && compiledIntent.kind === "query" ? createBindingFinalPlan(
7430
7500
  step.intent,
@@ -7516,6 +7586,12 @@ var NqlBuilderImpl = class {
7516
7586
  sql: compiled.sql,
7517
7587
  params: compiled.parameters
7518
7588
  });
7589
+ if (step.snapshot === true && step.bindName !== void 0) {
7590
+ runtimeBindings.set(step.bindName, {
7591
+ columns: requireMutationBindingColumns(sourceBundle, step.bindName),
7592
+ rows: []
7593
+ });
7594
+ }
7519
7595
  }
7520
7596
  if (step.bindName !== void 0) {
7521
7597
  const boundQuery = sourceBundle.bindings?.get(step.bindName);
@@ -7595,7 +7671,7 @@ var NqlBuilderImpl = class {
7595
7671
  );
7596
7672
  }
7597
7673
  const compiledIntent = this.compile();
7598
- if (hasMutationBindingBodies(compiledIntent.bundle)) {
7674
+ if (hasExecutableNqlProgramSequence(compiledIntent.bundle)) {
7599
7675
  return this.executeNqlProgramSequence(compiledIntent, adapter);
7600
7676
  }
7601
7677
  if (compiledIntent.kind === "mutation") {
@@ -7940,7 +8016,7 @@ async function cursorPaginate(builder, options) {
7940
8016
  }
7941
8017
 
7942
8018
  // src/dx/result-hydrator.ts
7943
- import { toColumnList as toColumnList3 } from "@dbsp/types";
8019
+ import { toColumnList as toColumnList2 } from "@dbsp/types";
7944
8020
 
7945
8021
  // src/dx/relation-paths.ts
7946
8022
  function nonEmptyString(value) {
@@ -8317,7 +8393,7 @@ var ResultHydrator = class {
8317
8393
  * Get the foreign key column name from relation metadata.
8318
8394
  */
8319
8395
  getForeignKeyColumn(foreignKey) {
8320
- const columns = toColumnList3(foreignKey);
8396
+ const columns = toColumnList2(foreignKey);
8321
8397
  if (columns.length === 0) {
8322
8398
  return "parent_id";
8323
8399
  }
@@ -8418,7 +8494,7 @@ var ResultHydrator = class {
8418
8494
  * case (slower but collision-safe for any value content).
8419
8495
  */
8420
8496
  extractKeyValue(obj, key) {
8421
- const columns = toColumnList3(key);
8497
+ const columns = toColumnList2(key);
8422
8498
  if (columns.length === 0) {
8423
8499
  return void 0;
8424
8500
  }
@@ -8436,7 +8512,7 @@ var ResultHydrator = class {
8436
8512
  return parts.join(COMPOSITE_KEY_SEP);
8437
8513
  }
8438
8514
  extractQueryKeyValue(obj, key) {
8439
- const columns = toColumnList3(key);
8515
+ const columns = toColumnList2(key);
8440
8516
  if (columns.length === 0) {
8441
8517
  return void 0;
8442
8518
  }
@@ -10867,6 +10943,7 @@ function rangeContainedBy(fieldOrColumn, valueOrRange, rangeType = "daterange")
10867
10943
  }
10868
10944
 
10869
10945
  // src/dx/schema-bridge.ts
10946
+ import { buildRelationKeyFields, toColumnList as toColumnList3 } from "@dbsp/types";
10870
10947
  import * as v from "valibot";
10871
10948
  function generatedTypeToColumnType(genType) {
10872
10949
  switch (genType) {
@@ -10919,6 +10996,37 @@ function mapRelationType2(kind) {
10919
10996
  return "belongsToMany";
10920
10997
  }
10921
10998
  }
10999
+ function sourceTableFromQualifiedName(qualifiedName) {
11000
+ const dotIndex = qualifiedName.indexOf(".");
11001
+ return dotIndex > 0 ? qualifiedName.slice(0, dotIndex) : qualifiedName;
11002
+ }
11003
+ function relationNameFromQualifiedName(qualifiedName) {
11004
+ const dotIndex = qualifiedName.indexOf(".");
11005
+ return dotIndex > 0 ? qualifiedName.slice(dotIndex + 1) : qualifiedName;
11006
+ }
11007
+ function columnListsEqual(left, right) {
11008
+ const leftColumns = toColumnList3(left);
11009
+ const rightColumns = toColumnList3(right);
11010
+ return leftColumns.length === rightColumns.length && leftColumns.every((column, index) => column === rightColumns[index]);
11011
+ }
11012
+ function generatedReferencedColumns(key) {
11013
+ const columns = toColumnList3(key);
11014
+ return columns.length > 0 ? columns : ["id"];
11015
+ }
11016
+ function findRelationForeignKey(sourceTable, genRelation, tables) {
11017
+ switch (genRelation.kind) {
11018
+ case "belongsTo":
11019
+ return tables.get(sourceTable)?.foreignKeys.find(
11020
+ (fk) => fk.references.table === genRelation.target && columnListsEqual(fk.columns, genRelation.foreignKey)
11021
+ );
11022
+ case "hasMany":
11023
+ return tables.get(genRelation.target)?.foreignKeys.find(
11024
+ (fk) => fk.references.table === sourceTable && columnListsEqual(fk.columns, genRelation.foreignKey)
11025
+ );
11026
+ case "manyToMany":
11027
+ return void 0;
11028
+ }
11029
+ }
10922
11030
  function isGeneratedTableWithConfig(table) {
10923
11031
  const columns = table.columns;
10924
11032
  return typeof columns === "object" && columns !== null && typeof columns.type !== "string";
@@ -11046,10 +11154,9 @@ function buildTableIRFromDefinition(tableName, genTable, fkAutoIndex) {
11046
11154
  }
11047
11155
  });
11048
11156
  }
11049
- function buildRelationIR(qualifiedName, genRelation, hints) {
11050
- const dotIndex = qualifiedName.indexOf(".");
11051
- const sourceTable = dotIndex > 0 ? qualifiedName.slice(0, dotIndex) : qualifiedName;
11052
- const relationName = dotIndex > 0 ? qualifiedName.slice(dotIndex + 1) : qualifiedName;
11157
+ function buildRelationIR(qualifiedName, genRelation, hints, relationFk) {
11158
+ const sourceTable = sourceTableFromQualifiedName(qualifiedName);
11159
+ const relationName = relationNameFromQualifiedName(qualifiedName);
11053
11160
  const hint = hints[qualifiedName];
11054
11161
  const relCardinality = genRelation.kind === "hasMany" ? genRelation.cardinality : void 0;
11055
11162
  const cardinality = hint?.cardinality === "one" ? "one" : relCardinality === "one" ? "one" : genRelation.kind === "belongsTo" ? "one" : "many";
@@ -11073,14 +11180,38 @@ function buildRelationIR(qualifiedName, genRelation, hints) {
11073
11180
  case "belongsTo":
11074
11181
  return {
11075
11182
  ...baseRelation,
11076
- foreignKey: genRelation.foreignKey,
11077
- ...genRelation.targetKey ? { targetKey: genRelation.targetKey } : {}
11183
+ ...buildRelationKeyFields(
11184
+ relationFk ?? {
11185
+ columns: genRelation.foreignKey,
11186
+ references: {
11187
+ table: genRelation.target,
11188
+ columns: generatedReferencedColumns(genRelation.targetKey)
11189
+ }
11190
+ },
11191
+ "belongsTo",
11192
+ {
11193
+ foreignKeyShape: genRelation.foreignKey,
11194
+ ...genRelation.targetKey !== void 0 ? { referencedKeyShape: genRelation.targetKey } : {}
11195
+ }
11196
+ )
11078
11197
  };
11079
11198
  case "hasMany":
11080
11199
  return {
11081
11200
  ...baseRelation,
11082
- foreignKey: genRelation.foreignKey,
11083
- ...genRelation.sourceKey ? { sourceKey: genRelation.sourceKey } : {}
11201
+ ...buildRelationKeyFields(
11202
+ relationFk ?? {
11203
+ columns: genRelation.foreignKey,
11204
+ references: {
11205
+ table: sourceTable,
11206
+ columns: generatedReferencedColumns(genRelation.sourceKey)
11207
+ }
11208
+ },
11209
+ "inverse",
11210
+ {
11211
+ foreignKeyShape: genRelation.foreignKey,
11212
+ ...genRelation.sourceKey !== void 0 ? { referencedKeyShape: genRelation.sourceKey } : {}
11213
+ }
11214
+ )
11084
11215
  };
11085
11216
  case "manyToMany":
11086
11217
  return {
@@ -11102,9 +11233,15 @@ function buildModelFromSchema(schema2) {
11102
11233
  );
11103
11234
  }
11104
11235
  for (const [qualifiedName, genRelation] of Object.entries(schema2.relations)) {
11236
+ const sourceTable = sourceTableFromQualifiedName(qualifiedName);
11105
11237
  relations.set(
11106
11238
  qualifiedName,
11107
- buildRelationIR(qualifiedName, genRelation, schema2.hints)
11239
+ buildRelationIR(
11240
+ qualifiedName,
11241
+ genRelation,
11242
+ schema2.hints,
11243
+ findRelationForeignKey(sourceTable, genRelation, tables)
11244
+ )
11108
11245
  );
11109
11246
  }
11110
11247
  return new ModelIRImpl(tables, relations);