@prisma/orm-family-sql 8.0.0-rc.18-dev.3 → 8.0.0-rc.18-dev.4

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.
@@ -1252,6 +1252,14 @@ function buildPrimaryKeyJoinOn(left, right, primaryKeyColumns) {
1252
1252
  if (primaryKeyColumns.length === 1 && firstColumn !== void 0) return EqColJoinOn.of(left.column(firstColumn), right.column(firstColumn));
1253
1253
  return AndExpr.of(primaryKeyColumns.map((column) => BinaryExpr.eq(left.column(column), right.column(column))));
1254
1254
  }
1255
+ function labeledVariantColumn(contract, variantTable, column) {
1256
+ const { namespaceId, tableName } = variantTable.storage;
1257
+ return ProjectionItem.of(variantColumnLabel(variantTable, column), variantTable.column(column), codecRefForStorageColumn(contract.storage, namespaceId, tableName, column));
1258
+ }
1259
+ function variantReturning(contract, variantTable, variantModelName, keyColumns) {
1260
+ const { namespaceId, tableName } = variantTable.storage;
1261
+ return getColumnsReadOnTable(contract, namespaceId, variantModelName, tableName).filter((column) => !keyColumns.includes(column)).map((column) => labeledVariantColumn(contract, variantTable, column));
1262
+ }
1255
1263
  function buildMtiJoins(contract, tables, polyInfo, variantValue, selectedColumnsByVariant) {
1256
1264
  const joins = [];
1257
1265
  const projection = [];
@@ -1272,7 +1280,7 @@ function buildMtiJoins(contract, tables, polyInfo, variantValue, selectedColumns
1272
1280
  for (const col of variantColumns) {
1273
1281
  if (pkColumns.includes(col)) continue;
1274
1282
  if (selectedColumnsByVariant !== void 0 && selectedVariantColumns?.has(col) !== true) continue;
1275
- projection.push(ProjectionItem.of(variantColumnLabel(variantTable, col), variantTable.column(col), codecRefForStorageColumn(contract.storage, namespaceId, tableName, col)));
1283
+ projection.push(labeledVariantColumn(contract, variantTable, col));
1276
1284
  }
1277
1285
  }
1278
1286
  return {
@@ -1610,9 +1618,12 @@ function aliasTarget(namespaceId, tableName) {
1610
1618
  tableName
1611
1619
  });
1612
1620
  }
1613
- function projectTableColumns(contract, target, columns) {
1621
+ function projectTableColumn(contract, target, column) {
1614
1622
  const { namespaceId, tableName } = target.storage;
1615
- return columns.map((column) => ProjectionItem.of(column, target.column(column), codecRefForStorageColumn(contract.storage, namespaceId, tableName, column)));
1623
+ return ProjectionItem.of(column, target.column(column), codecRefForStorageColumn(contract.storage, namespaceId, tableName, column));
1624
+ }
1625
+ function projectTableColumns(contract, target, columns) {
1626
+ return columns.map((column) => projectTableColumn(contract, target, column));
1616
1627
  }
1617
1628
  function returningProjection(contract, modelName, target, returningColumns) {
1618
1629
  const { namespaceId, tableName } = target.storage;
@@ -1672,17 +1683,19 @@ function conflictSkipClause(target, conflictSkip) {
1672
1683
  if (conflictSkip.columns.length === 0) return InsertOnConflict.doNothing();
1673
1684
  return InsertOnConflict.on(conflictSkip.columns.map((column) => target.column(column))).doNothing();
1674
1685
  }
1686
+ function insertAst(contract, target, rows, conflictSkip) {
1687
+ const { namespaceId, tableName } = target.storage;
1688
+ const { rows: normalizedRows } = normalizeInsertRows(contract, namespaceId, tableName, rows);
1689
+ return InsertAst.into(target.tableSource(contract)).withRows(normalizedRows).withOnConflict(conflictSkipClause(target, conflictSkip));
1690
+ }
1675
1691
  function compileInsertReturning(contract, namespaceId, modelName, tableName, rows, returningColumns, conflictSkip) {
1676
1692
  const target = aliasTarget(namespaceId, tableName);
1677
- const { rows: normalizedRows } = normalizeInsertRows(contract, namespaceId, tableName, rows);
1678
- const ast = InsertAst.into(target.tableSource(contract)).withRows(normalizedRows).withOnConflict(conflictSkipClause(target, conflictSkip)).withReturning(returningProjection(contract, modelName, target, returningColumns));
1693
+ const ast = insertAst(contract, target, rows, conflictSkip).withReturning(returningProjection(contract, modelName, target, returningColumns));
1679
1694
  const { params } = deriveParamsFromAst(ast);
1680
1695
  return buildOrmQueryPlan(contract, ast, params);
1681
1696
  }
1682
1697
  function compileInsertCount(contract, namespaceId, tableName, rows, conflictSkip) {
1683
- const target = aliasTarget(namespaceId, tableName);
1684
- const { rows: normalizedRows } = normalizeInsertRows(contract, namespaceId, tableName, rows);
1685
- const ast = InsertAst.into(target.tableSource(contract)).withRows(normalizedRows).withOnConflict(conflictSkipClause(target, conflictSkip));
1698
+ const ast = insertAst(contract, aliasTarget(namespaceId, tableName), rows, conflictSkip);
1686
1699
  const { params } = deriveParamsFromAst(ast);
1687
1700
  return buildOrmQueryPlan(contract, ast, params);
1688
1701
  }
@@ -1718,31 +1731,15 @@ function groupRowsByColumnSignature(rows) {
1718
1731
  if (currentGroup.length > 0) groups.push(currentGroup);
1719
1732
  return groups;
1720
1733
  }
1721
- function compileInsertReturningSplit(contract, namespaceId, modelName, tableName, rows, returningColumns, conflictSkip) {
1722
- if (rows.length === 0) throw ormError("ORM.MUTATION_DATA_MISSING", "create() requires at least one row", { meta: {
1723
- method: "create",
1724
- namespaceId,
1725
- tableName
1726
- } });
1727
- return groupRowsByColumnSignature(rows).map((group) => compileInsertReturning(contract, namespaceId, modelName, tableName, group, returningColumns, conflictSkip));
1728
- }
1729
- function compileInsertCountSplit(contract, namespaceId, tableName, rows, conflictSkip) {
1730
- if (rows.length === 0) throw ormError("ORM.MUTATION_DATA_MISSING", "createAndCount() requires at least one row", { meta: {
1731
- method: "createAndCount",
1732
- namespaceId,
1733
- tableName
1734
- } });
1735
- return groupRowsByColumnSignature(rows).map((group) => compileInsertCount(contract, namespaceId, tableName, group, conflictSkip));
1736
- }
1737
- function compileUpsertReturning(contract, namespaceId, modelName, tableName, createValues, updateValues, conflictColumns, returningColumns) {
1734
+ function upsertAst(contract, target, createValues, conflictColumns, updateSet) {
1735
+ const { namespaceId, tableName } = target.storage;
1738
1736
  const createAssignments = toParamAssignments(contract, namespaceId, tableName, createValues);
1739
- const updateAssignments = Object.keys(updateValues).length > 0 ? toParamAssignments(contract, namespaceId, tableName, updateValues) : void 0;
1740
- const target = aliasTarget(namespaceId, tableName);
1741
1737
  const conflictTarget = InsertOnConflict.on(conflictColumns.map((column) => target.column(column)));
1742
- const onConflict = updateAssignments ? conflictTarget.doUpdateSet(updateAssignments.assignments) : conflictTarget.doNothing();
1743
- const ast = InsertAst.into(target.tableSource(contract)).withRows([createAssignments.assignments]).withOnConflict(onConflict).withReturning(returningProjection(contract, modelName, target, returningColumns));
1744
- const { params } = deriveParamsFromAst(ast);
1745
- return buildOrmQueryPlan(contract, ast, params);
1738
+ return InsertAst.into(target.tableSource(contract)).withRows([createAssignments.assignments]).withOnConflict(updateSet === void 0 ? conflictTarget.doNothing() : conflictTarget.doUpdateSet(updateSet));
1739
+ }
1740
+ function updateAssignments(contract, target, values) {
1741
+ const { namespaceId, tableName } = target.storage;
1742
+ return toParamAssignments(contract, namespaceId, tableName, values).assignments;
1746
1743
  }
1747
1744
  function updateAst(contract, tables, setValues, where) {
1748
1745
  const { root } = tables;
@@ -2630,46 +2627,6 @@ function consumeIncludeRows(context, state, namespaceId, modelName, rows) {
2630
2627
  * include query can't observe an already-deleted row, so delete reads
2631
2628
  * its snapshot before issuing the DELETE (see `collection.ts`).
2632
2629
  */
2633
- function reloadMutationRowsByIdentities(options) {
2634
- const { context, runtime, tables, modelName, namespaceId, identityRows, selectedFields, includes } = options;
2635
- const { contract } = context;
2636
- const { tableName } = tables.root.storage;
2637
- if (identityRows.length === 0) return emptyResult();
2638
- const identityColumns = resolveRowIdentityColumns(contract, namespaceId, tableName);
2639
- if (identityColumns.length === 0) throw ormError("ORM.ROW_IDENTITY_MISSING", `Cannot load includes for the mutation result on model "${modelName}": table "${tableName}" has no primary key or unique constraint to key the include read-back on.`, { meta: {
2640
- model: modelName,
2641
- table: tableName
2642
- } });
2643
- const identityFilter = buildIdentityInFilter(contract, tables.root, identityColumns, identityRows);
2644
- if (!identityFilter) return emptyResult();
2645
- return dispatchCollectionRows({
2646
- context,
2647
- runtime,
2648
- state: {
2649
- ...emptyState(tables),
2650
- filters: [identityFilter],
2651
- selectedFields,
2652
- includes
2653
- },
2654
- modelName,
2655
- namespaceId
2656
- });
2657
- }
2658
- function emptyResult() {
2659
- return new AsyncIterableResult((async function* () {})());
2660
- }
2661
- function buildIdentityInFilter(contract, table, identityColumns, identityRows) {
2662
- const { storage } = table;
2663
- const [singleColumn, ...rest] = identityColumns;
2664
- if (singleColumn !== void 0 && rest.length === 0) {
2665
- const values = identityRows.map((row) => row[singleColumn]).filter((value) => value !== void 0);
2666
- if (values.length === 0) return;
2667
- return BinaryExpr.in(table.column(singleColumn), ListExpression.of(values.map((value) => paramRefForStorageColumn(contract, storage, singleColumn, value))));
2668
- }
2669
- if (identityRows.length === 0) return;
2670
- const tuples = identityRows.map((row) => AndExpr.of(identityColumns.map((column) => BinaryExpr.eq(table.column(column), paramRefForStorageColumn(contract, storage, column, row[column])))));
2671
- return OrExpr.of(tuples);
2672
- }
2673
2630
  /**
2674
2631
  * Decode a single-query include payload from a parent row's raw cell
2675
2632
  * into the model-shaped value that downstream consumers see. Recurses
@@ -2928,91 +2885,6 @@ function parseIncludePayload(value) {
2928
2885
  return [];
2929
2886
  }
2930
2887
  }
2931
- function createMutationRowMapper(contract, namespaceId, modelName, tables, variantValue) {
2932
- const polyInfo = resolvePolymorphismInfo(contract, namespaceId, modelName);
2933
- return polyInfo ? (row) => mapPolymorphicRow(contract, namespaceId, modelName, polyInfo, tables, row, variantValue) : (row) => mapStorageRowToModelFields(contract, namespaceId, modelName, row);
2934
- }
2935
- function dispatchMutationRows(options) {
2936
- const { context, runtime, compiled, tables, modelName, namespaceId, variantValue, includes, selectedFields, hiddenColumns, mapRow } = options;
2937
- const { contract } = context;
2938
- const mapStorageRow = createMutationRowMapper(contract, namespaceId, modelName, tables, variantValue);
2939
- if (includes.length === 0) return mapResultRows(queryPlanRows(runtime, compiled), (rawRow) => {
2940
- const mapped = mapStorageRow(rawRow);
2941
- if (hiddenColumns.length > 0) stripHiddenMappedFields(contract, namespaceId, modelName, mapped, hiddenColumns);
2942
- return mapRow(mapped);
2943
- });
2944
- const generator = async function* () {
2945
- const identityRows = await queryPlanRows(runtime, compiled).toArray();
2946
- yield* reloadMutationRowsByIdentities({
2947
- context,
2948
- runtime,
2949
- tables,
2950
- modelName,
2951
- namespaceId,
2952
- identityRows,
2953
- selectedFields,
2954
- includes
2955
- });
2956
- };
2957
- return new AsyncIterableResult(generator());
2958
- }
2959
- function dispatchSplitMutationRows(options) {
2960
- const { context, runtime, plans, tables, modelName, namespaceId, variantValue, includes, selectedFields, hiddenColumns, mapRow } = options;
2961
- const { contract } = context;
2962
- const mapStorageRow = createMutationRowMapper(contract, namespaceId, modelName, tables, variantValue);
2963
- const generator = async function* () {
2964
- if (includes.length > 0) {
2965
- const identityRows = [];
2966
- for (const plan of plans) identityRows.push(...await queryPlanRows(runtime, plan).toArray());
2967
- yield* reloadMutationRowsByIdentities({
2968
- context,
2969
- runtime,
2970
- tables,
2971
- modelName,
2972
- namespaceId,
2973
- identityRows,
2974
- selectedFields,
2975
- includes
2976
- });
2977
- return;
2978
- }
2979
- for (const plan of plans) for await (const rawRow of queryPlanRows(runtime, plan)) {
2980
- const mapped = mapStorageRow(rawRow);
2981
- if (hiddenColumns.length > 0) stripHiddenMappedFields(contract, namespaceId, modelName, mapped, hiddenColumns);
2982
- yield mapRow(mapped);
2983
- }
2984
- };
2985
- return new AsyncIterableResult(generator());
2986
- }
2987
- async function executeMutationReturningSingleRow(options) {
2988
- const { context, runtime, compiled, tables, modelName, namespaceId, variantValue, includes, selectedFields, hiddenColumns, mapRow, operation, onMissingRowMessage } = options;
2989
- const { contract } = context;
2990
- const mapStorageRow = createMutationRowMapper(contract, namespaceId, modelName, tables, variantValue);
2991
- if (includes.length === 0) {
2992
- const first = (await queryPlanRows(runtime, compiled).toArray())[0];
2993
- if (!first) return null;
2994
- const mapped = mapStorageRow(first);
2995
- if (hiddenColumns.length > 0) stripHiddenMappedFields(contract, namespaceId, modelName, mapped, hiddenColumns);
2996
- return mapRow(mapped);
2997
- }
2998
- const identityRows = await queryPlanRows(runtime, compiled).toArray();
2999
- if (identityRows.length === 0) return null;
3000
- for await (const row of reloadMutationRowsByIdentities({
3001
- context,
3002
- runtime,
3003
- tables,
3004
- modelName,
3005
- namespaceId,
3006
- identityRows,
3007
- selectedFields,
3008
- includes
3009
- })) return row;
3010
- throw ormError("ORM.MUTATION_ROW_MISSING", onMissingRowMessage, { meta: {
3011
- operation,
3012
- model: modelName,
3013
- tableName: tables.root.storage.tableName
3014
- } });
3015
- }
3016
2888
  /** The filter expression of a condition: a condition from `fns` becomes its AST. */
3017
2889
  function conditionExpr(condition) {
3018
2890
  return isFunctionCondition(condition) ? condition.buildAst() : condition;
@@ -4593,15 +4465,37 @@ function getRelationDefinitions(contract, namespaceId, modelName) {
4593
4465
  function toFieldName(contract, namespaceId, modelName, columnName) {
4594
4466
  return fieldOfColumn(getModelColumnFields(contract, namespaceId, modelName), modelName, columnName);
4595
4467
  }
4468
+ var Node = class {};
4469
+ function executeStatement$1(ast, run) {
4470
+ return ast.kind === "select" || ast.returning !== void 0 ? run.query(ast) : run.execute(ast);
4471
+ }
4472
+ function rowsResult(rows) {
4473
+ const generator = async function* () {
4474
+ yield* rows;
4475
+ };
4476
+ return new AsyncIterableResult(generator());
4477
+ }
4478
+ var CrossJoin = class extends Node {
4479
+ constructor() {
4480
+ super();
4481
+ Object.freeze(this);
4482
+ }
4483
+ execute(inputs, _run) {
4484
+ const [left] = inputs.left;
4485
+ const [right] = inputs.right;
4486
+ if (left === void 0 || right === void 0) return rowsResult([]);
4487
+ return rowsResult([{
4488
+ ...left,
4489
+ ...right
4490
+ }]);
4491
+ }
4492
+ };
4596
4493
  function executeFiltered(ast, filter, run) {
4597
4494
  if (filter === null) return executeStatement$1(ast, run);
4598
- if (filter.some((conditions) => conditions.length === 0)) return noRows();
4495
+ if (filter.some((conditions) => conditions.length === 0)) return rowsResult([]);
4599
4496
  const where = combineWhereExprs([...ast.where === void 0 ? [] : [ast.where], ...filter.map(anyOf)]);
4600
4497
  return executeStatement$1(ast.withWhere(where), run);
4601
4498
  }
4602
- function executeStatement$1(ast, run) {
4603
- return ast.kind === "select" || ast.returning !== void 0 ? run.query(ast) : run.execute(ast);
4604
- }
4605
4499
  function anyOf(conditions) {
4606
4500
  const [first, ...others] = conditions;
4607
4501
  return first !== void 0 && others.length === 0 ? first : OrExpr.of(conditions);
@@ -4610,12 +4504,8 @@ function withColumns(returned, columns) {
4610
4504
  const present = new Set(returned.map((item) => item.alias));
4611
4505
  return [...returned, ...columns.filter((column) => !present.has(column.alias))];
4612
4506
  }
4613
- function noRows() {
4614
- const generator = async function* () {};
4615
- return new AsyncIterableResult(generator());
4616
- }
4617
- var Node = class {};
4618
- var Delete = class Delete extends Node {
4507
+ var StatementNode = class extends Node {};
4508
+ var Delete = class Delete extends StatementNode {
4619
4509
  ast;
4620
4510
  constructor(ast) {
4621
4511
  super();
@@ -4654,7 +4544,7 @@ var FilterData = class extends Edge {
4654
4544
  return first !== void 0 && others.length === 0 ? first : AndExpr.of(conditions);
4655
4545
  }
4656
4546
  };
4657
- var Find = class Find extends Node {
4547
+ var Find = class Find extends StatementNode {
4658
4548
  ast;
4659
4549
  constructor(ast) {
4660
4550
  super();
@@ -4694,7 +4584,8 @@ var Graph = class {
4694
4584
  reader: id,
4695
4585
  edge
4696
4586
  });
4697
- this.#nodes[edge.from] = this.#nodes[edge.from]?.withReturning(edge.columns.map(([source]) => source));
4587
+ const source = this.#nodes[edge.from];
4588
+ if (source instanceof StatementNode) this.#nodes[edge.from] = source.withReturning(edge.columns.map(([column]) => column));
4698
4589
  }
4699
4590
  return id;
4700
4591
  }
@@ -4703,7 +4594,7 @@ var Graph = class {
4703
4594
  }
4704
4595
  remove(id) {
4705
4596
  for (const edge of Object.values(this.inputsOf(id)).flat()) this.#readers[edge.from] = this.readersOf(edge.from).filter((entry) => entry.edge !== edge);
4706
- for (const { reader, edge } of this.readersOf(id)) this.#inputs[reader] = Object.fromEntries(Object.entries(this.inputsOf(reader)).map(([slot, edges]) => [slot, edges.filter((other) => other !== edge)]));
4597
+ for (const { reader, edge } of this.readersOf(id)) this.#inputs[reader] = Object.fromEntries(Object.entries(this.inputsOf(reader)).map(([name, slot]) => [name, Array.isArray(slot) ? slot.filter((other) => other !== edge) : slot]));
4707
4598
  this.#nodes[id] = void 0;
4708
4599
  this.#inputs[id] = {};
4709
4600
  this.#readers[id] = [];
@@ -4721,7 +4612,88 @@ var Graph = class {
4721
4612
  return this.#readers[id] ?? [];
4722
4613
  }
4723
4614
  };
4724
- var Update = class Update extends Node {
4615
+ var Insert = class Insert extends StatementNode {
4616
+ ast;
4617
+ constructor(ast) {
4618
+ super();
4619
+ this.ast = ast;
4620
+ Object.freeze(this);
4621
+ }
4622
+ get returns() {
4623
+ return this.ast.returning ?? [];
4624
+ }
4625
+ execute(inputs, run) {
4626
+ if (inputs.payload === null) return executeStatement$1(this.ast, run);
4627
+ if (inputs.payload.some((records) => records.length === 0)) return rowsResult([]);
4628
+ const payload = Object.assign({}, ...inputs.payload.map(([record]) => record));
4629
+ const rows = this.ast.rows.map((row) => ({
4630
+ ...row,
4631
+ ...payload
4632
+ }));
4633
+ return executeStatement$1(this.ast.withRows(rows), run);
4634
+ }
4635
+ withReturning(columns) {
4636
+ return new Insert(this.ast.withReturning(withColumns(this.returns, columns)));
4637
+ }
4638
+ };
4639
+ var InsertChunked = class InsertChunked extends StatementNode {
4640
+ asts;
4641
+ constructor(asts) {
4642
+ super();
4643
+ this.asts = Object.freeze([...asts]);
4644
+ Object.freeze(this);
4645
+ }
4646
+ get returns() {
4647
+ return this.asts[0]?.returning ?? [];
4648
+ }
4649
+ execute(_inputs, run) {
4650
+ if (this.returns.length === 0) return this.#sumOfCounts(run);
4651
+ const asts = this.asts;
4652
+ const generator = async function* () {
4653
+ for (const ast of asts) yield* run.query(ast);
4654
+ };
4655
+ return new AsyncIterableResult(generator());
4656
+ }
4657
+ withReturning(columns) {
4658
+ return new InsertChunked(this.asts.map((ast) => ast.withReturning(withColumns(ast.returning ?? [], columns))));
4659
+ }
4660
+ async #sumOfCounts(run) {
4661
+ let count = 0;
4662
+ for (const ast of this.asts) count += await run.execute(ast);
4663
+ return count;
4664
+ }
4665
+ };
4666
+ var PayloadData = class extends Edge {
4667
+ constructor(from, columns) {
4668
+ super(from, columns);
4669
+ Object.freeze(this);
4670
+ }
4671
+ output(sourceRow) {
4672
+ return Object.fromEntries(this.columns.map(([source, target]) => [target.alias, ParamRef.of(sourceRow[source.alias], {
4673
+ name: target.alias,
4674
+ ...ifDefined("codec", target.codec)
4675
+ })]));
4676
+ }
4677
+ };
4678
+ var Rows = class extends Edge {
4679
+ constructor(from, columns) {
4680
+ super(from, columns);
4681
+ Object.freeze(this);
4682
+ }
4683
+ output(sourceRow) {
4684
+ return Object.fromEntries(this.columns.map(([source]) => [source.alias, sourceRow[source.alias]]));
4685
+ }
4686
+ };
4687
+ var UnionAll = class extends Node {
4688
+ constructor() {
4689
+ super();
4690
+ Object.freeze(this);
4691
+ }
4692
+ execute(inputs, _run) {
4693
+ return rowsResult((inputs.rows ?? []).flat());
4694
+ }
4695
+ };
4696
+ var Update = class Update extends StatementNode {
4725
4697
  ast;
4726
4698
  constructor(ast) {
4727
4699
  super();
@@ -4794,6 +4766,61 @@ function deleteFirstGraph(collection) {
4794
4766
  graph.setResult(withIncludes ? find : deleted);
4795
4767
  return graph;
4796
4768
  }
4769
+ function createAllGraph(collection, rows, conflict) {
4770
+ const { context, state } = collection;
4771
+ const graph = new Graph();
4772
+ if (rows.length === 0) return graph;
4773
+ requireIdentityColumnsForIncludes(collection);
4774
+ const { contract } = context;
4775
+ const { root } = state.tables;
4776
+ const inserted = supportsDefaultInInsert(contract) ? graph.add(new Insert(insertAst(contract, root, rows, conflict)), { payload: [] }) : graph.add(new InsertChunked(groupRowsByColumnSignature(rows).map((group) => insertAst(contract, root, group, conflict))), {});
4777
+ graph.setResult(addWithIncludes(graph, collection, inserted));
4778
+ return graph;
4779
+ }
4780
+ function supportsDefaultInInsert(contract) {
4781
+ return contract.capabilities["sql"]?.["defaultInInsert"] === true;
4782
+ }
4783
+ function createAllVariantGraph(collection, variantTable, variantModelName, rows) {
4784
+ const { context, modelName, state } = collection;
4785
+ const { contract } = context;
4786
+ const { root } = state.tables;
4787
+ const graph = new Graph();
4788
+ const keyColumns = resolvePrimaryKeyColumns(contract, root.storage.namespaceId, root.storage.tableName);
4789
+ const keyPairs = keyColumns.map((column) => [projectTableColumn(contract, root, column), projectTableColumn(contract, variantTable, column)]);
4790
+ const baseColumns = returningProjection(contract, modelName, root, void 0);
4791
+ const variantColumns = variantReturning(contract, variantTable, variantModelName, keyColumns);
4792
+ const joins = rows.map((row) => {
4793
+ const baseInsert = insertAst(contract, root, [row.base], void 0).withReturning(baseColumns);
4794
+ const base = graph.add(new Insert(baseInsert), { payload: [] });
4795
+ const variantInsert = insertAst(contract, variantTable, [row.variant], void 0).withReturning(variantColumns);
4796
+ const variant = graph.add(new Insert(variantInsert), { payload: [new PayloadData(base, keyPairs)] });
4797
+ return graph.add(new CrossJoin(), {
4798
+ left: new Rows(base, sameColumns(baseColumns)),
4799
+ right: new Rows(variant, sameColumns(variantColumns))
4800
+ });
4801
+ });
4802
+ const [only, ...others] = joins;
4803
+ if (only !== void 0 && others.length === 0) graph.setResult(only);
4804
+ else if (only !== void 0) {
4805
+ const joined = sameColumns([...baseColumns, ...variantColumns]);
4806
+ graph.setResult(graph.add(new UnionAll(), { rows: joins.map((join) => new Rows(join, joined)) }));
4807
+ }
4808
+ return graph;
4809
+ }
4810
+ function sameColumns(columns) {
4811
+ return columns.map((column) => [column, column]);
4812
+ }
4813
+ function upsertGraph(collection, create, update, conflictColumns) {
4814
+ const { context, state } = collection;
4815
+ const { root } = state.tables;
4816
+ const graph = new Graph();
4817
+ requireIdentityColumnsForIncludes(collection);
4818
+ const updateSet = Object.keys(update).length > 0 ? updateAssignments(context.contract, root, update) : Object.fromEntries(conflictColumns.slice(0, 1).map((column) => [column, ColumnRef.of("excluded", column)]));
4819
+ const upsert = upsertAst(context.contract, root, create, conflictColumns, updateSet);
4820
+ const upserted = graph.add(new Insert(upsert), { payload: [] });
4821
+ graph.setResult(addWithIncludes(graph, collection, upserted));
4822
+ return graph;
4823
+ }
4797
4824
  function addWithIncludes(graph, collection, written) {
4798
4825
  const { state } = collection;
4799
4826
  if (state.includes.length === 0) return written;
@@ -4872,7 +4899,7 @@ async function executeGraph(graph, ctx, annotations) {
4872
4899
  function returnCallerColumns(graph, callerRows) {
4873
4900
  const { context, modelName, state } = callerRows;
4874
4901
  const columns = returningProjection(context.contract, modelName, state.tables.root, state.selectedFields);
4875
- for (const [id, node] of graph.nodes()) if (id === graph.result) graph.replace(id, node.withReturning(columns));
4902
+ for (const [id, node] of graph.nodes()) if (id === graph.result && node instanceof StatementNode) graph.replace(id, node.withReturning(columns));
4876
4903
  }
4877
4904
  function runAllNodes(graph, ctx, annotations, callerRows) {
4878
4905
  if (graph.nodes().length > 1) return withMutationScope(ctx.runtime, (scope) => runNodesInOrder(graph, {
@@ -4901,11 +4928,9 @@ async function runNodesInOrder(graph, ctx, annotations, callerRows) {
4901
4928
  }
4902
4929
  function inputsOf(graph, id, collected) {
4903
4930
  const outputs = {};
4904
- const slots = graph.inputsOf(id);
4905
- for (const slot in slots) {
4906
- const edges = slots[slot] ?? [];
4907
- outputs[slot] = edges.length === 0 ? null : edges.map((edge) => rowsOf(collected[edge.from]).map((row) => edge.output(row)));
4908
- }
4931
+ const outputOf = (edge) => rowsOf(collected[edge.from]).map((row) => edge.output(row));
4932
+ for (const [name, slot] of Object.entries(graph.inputsOf(id))) if (!Array.isArray(slot)) outputs[name] = outputOf(slot);
4933
+ else outputs[name] = slot.length === 0 ? null : slot.map(outputOf);
4909
4934
  return outputs;
4910
4935
  }
4911
4936
  function runOn(ctx, annotations) {
@@ -5523,40 +5548,16 @@ var CollectionBase = class CollectionBase {
5523
5548
  assertReturningCapability(this.contract, "createAll()");
5524
5549
  const rows = blindCast(data);
5525
5550
  const mtiContext = this.#resolveMtiCreateContext();
5526
- if (mtiContext) return this.#executeMtiCreate(rows, mtiContext);
5551
+ if (mtiContext) {
5552
+ const variantTable = requireVariantTable(this.state.tables, mtiContext.variant.value);
5553
+ return queryGraph(createAllVariantGraph(this.#descriptionWithoutIncludes(), variantTable, mtiContext.variant.modelName, this.#variantCreateRows(rows, mtiContext, variantTable)), this.ctx, annotationsMap, this.#descriptionWithoutIncludes());
5554
+ }
5555
+ return queryGraph(createAllGraph(this.#descriptionOptions(), this.#createValues(rows), conflictSkip), this.ctx, annotationsMap, this.#descriptionOptions());
5556
+ }
5557
+ #createValues(rows) {
5527
5558
  const mappedRows = this.#mapCreateRows(rows);
5528
5559
  applyCreateDefaults(this.ctx, this.namespaceId, this.tableName, mappedRows);
5529
- const { selectedForQuery: selectedForInsert, hiddenColumns } = this.#augmentMutationSelection();
5530
- if (this.contract.capabilities?.["sql"]?.["defaultInInsert"] !== true) {
5531
- const plans = compileInsertReturningSplit(this.contract, this.namespaceId, this.modelName, this.tableName, mappedRows, selectedForInsert, conflictSkip).map((plan) => mergeAnnotations(plan, annotationsMap));
5532
- return dispatchSplitMutationRows({
5533
- context: this.ctx.context,
5534
- runtime: this.ctx.runtime,
5535
- plans,
5536
- tables: this.state.tables,
5537
- modelName: this.modelName,
5538
- namespaceId: this.namespaceId,
5539
- variantValue: this.state.variantValue,
5540
- includes: this.state.includes,
5541
- selectedFields: this.state.selectedFields,
5542
- hiddenColumns,
5543
- mapRow: (mapped) => blindCast(mapped)
5544
- });
5545
- }
5546
- const compiled = mergeAnnotations(compileInsertReturning(this.contract, this.namespaceId, this.modelName, this.tableName, mappedRows, selectedForInsert, conflictSkip), annotationsMap);
5547
- return dispatchMutationRows({
5548
- context: this.ctx.context,
5549
- runtime: this.ctx.runtime,
5550
- compiled,
5551
- tables: this.state.tables,
5552
- modelName: this.modelName,
5553
- namespaceId: this.namespaceId,
5554
- variantValue: this.state.variantValue,
5555
- includes: this.state.includes,
5556
- selectedFields: this.state.selectedFields,
5557
- hiddenColumns,
5558
- mapRow: (mapped) => blindCast(mapped)
5559
- });
5560
+ return mappedRows;
5560
5561
  }
5561
5562
  #resolveConflictSkip(options, method) {
5562
5563
  if (options === void 0) return void 0;
@@ -5595,76 +5596,39 @@ var CollectionBase = class CollectionBase {
5595
5596
  if (!polyInfo) return null;
5596
5597
  const variant = polyInfo.variants.get(variantValue);
5597
5598
  if (!isMtiVariantInfo(variant)) return null;
5598
- const baseFieldToColumn = getModelFieldColumns(this.contract, this.namespaceId, this.modelName);
5599
- const variantFieldToColumn = getOwnFieldColumns(this.contract, variant.namespaceId, variant.modelName);
5600
- const pkColumns = resolvePrimaryKeyColumns(this.contract, this.namespaceId, this.tableName);
5601
5599
  return {
5602
5600
  polyInfo,
5603
5601
  variant,
5604
- baseFieldToColumn,
5605
- variantFieldToColumn,
5606
- mergedFieldToColumn: getModelAndVariantFieldColumns(this.contract, this.namespaceId, this.modelName, variant.value),
5607
- pkColumns
5602
+ baseFieldToColumn: getModelFieldColumns(this.contract, this.namespaceId, this.modelName),
5603
+ variantFieldToColumn: getOwnFieldColumns(this.contract, variant.namespaceId, variant.modelName),
5604
+ mergedFieldToColumn: getModelAndVariantFieldColumns(this.contract, this.namespaceId, this.modelName, variant.value)
5608
5605
  };
5609
5606
  }
5610
- #executeMtiCreate(data, mtiCtx) {
5611
- const { polyInfo, variant, baseFieldToColumn, variantFieldToColumn, mergedFieldToColumn, pkColumns } = mtiCtx;
5612
- const contract = this.contract;
5613
- const collectionCtx = this.ctx;
5614
- const runtime = collectionCtx.runtime;
5615
- const tableName = this.tableName;
5616
- const modelName = this.modelName;
5617
- const namespaceId = this.namespaceId;
5618
- const tables = this.state.tables;
5619
- const variantTable = requireVariantTable(tables, variant.value);
5607
+ #variantCreateRows(data, mtiCtx, variantTable) {
5608
+ const { polyInfo, variant, baseFieldToColumn, variantFieldToColumn, mergedFieldToColumn } = mtiCtx;
5620
5609
  const baseFieldColumns = new Set(Object.values(baseFieldToColumn));
5621
5610
  const variantFieldColumns = new Set(Object.values(variantFieldToColumn));
5622
- const generator = async function* () {
5623
- const defaultValueCache = /* @__PURE__ */ new Map();
5624
- for (const row of data) {
5625
- const allMapped = {};
5626
- for (const [fieldName, value] of Object.entries(row)) {
5627
- if (value === void 0) continue;
5628
- allMapped[columnOfCallerField(contract, variant.namespaceId, mergedFieldToColumn, variant.modelName, fieldName)] = value;
5629
- }
5630
- allMapped[polyInfo.discriminatorColumn] = variant.value;
5631
- const baseRow = {};
5632
- const variantRow = {};
5633
- for (const [col, val] of Object.entries(allMapped)) {
5634
- if (baseFieldColumns.has(col) || col === polyInfo.discriminatorColumn) baseRow[col] = val;
5635
- if (variantFieldColumns.has(col)) variantRow[col] = val;
5636
- }
5637
- yield blindCast(await withMutationScope(runtime, async (scope) => {
5638
- applyCreateDefaults(collectionCtx, namespaceId, tableName, [baseRow], defaultValueCache);
5639
- const baseCreated = (await queryPlanRows(scope, compileInsertReturning(contract, namespaceId, modelName, tableName, [baseRow], void 0)).toArray())[0];
5640
- if (!baseCreated) throw ormError("ORM.MUTATION_ROW_MISSING", `MTI base INSERT for model "${modelName}" did not return a row`, { meta: {
5641
- operation: "create",
5642
- model: modelName,
5643
- table: tableName,
5644
- phase: "mti-base"
5645
- } });
5646
- for (const pkColumn of pkColumns) variantRow[pkColumn] = baseCreated[pkColumn];
5647
- applyCreateDefaults(collectionCtx, variantTable.storage.namespaceId, variantTable.storage.tableName, [variantRow], defaultValueCache);
5648
- const variantCreated = (await queryPlanRows(scope, compileInsertReturning(contract, variantTable.storage.namespaceId, variant.modelName, variantTable.storage.tableName, [variantRow], void 0)).toArray())[0];
5649
- if (!variantCreated) throw ormError("ORM.MUTATION_ROW_MISSING", `MTI variant INSERT for model "${modelName}" into "${variant.table}" did not return a row`, { meta: {
5650
- operation: "create",
5651
- model: modelName,
5652
- table: variant.table,
5653
- phase: "mti-variant"
5654
- } });
5655
- const prefixedVariant = {};
5656
- for (const [col, val] of Object.entries(variantCreated)) {
5657
- if (pkColumns.includes(col)) continue;
5658
- prefixedVariant[variantColumnLabel(variantTable, col)] = val;
5659
- }
5660
- return mapPolymorphicRow(contract, namespaceId, modelName, polyInfo, tables, {
5661
- ...baseCreated,
5662
- ...prefixedVariant
5663
- }, variant.value);
5664
- }));
5611
+ const defaultValueCache = /* @__PURE__ */ new Map();
5612
+ return data.map((row) => {
5613
+ const allMapped = {};
5614
+ for (const [fieldName, value] of Object.entries(row)) {
5615
+ if (value === void 0) continue;
5616
+ allMapped[columnOfCallerField(this.contract, this.namespaceId, mergedFieldToColumn, variant.modelName, fieldName)] = value;
5665
5617
  }
5666
- };
5667
- return new AsyncIterableResult(generator());
5618
+ allMapped[polyInfo.discriminatorColumn] = variant.value;
5619
+ const baseRow = {};
5620
+ const variantRow = {};
5621
+ for (const [column, value] of Object.entries(allMapped)) {
5622
+ if (baseFieldColumns.has(column) || column === polyInfo.discriminatorColumn) baseRow[column] = value;
5623
+ if (variantFieldColumns.has(column)) variantRow[column] = value;
5624
+ }
5625
+ applyCreateDefaults(this.ctx, this.namespaceId, this.tableName, [baseRow], defaultValueCache);
5626
+ applyCreateDefaults(this.ctx, variantTable.storage.namespaceId, variantTable.storage.tableName, [variantRow], defaultValueCache);
5627
+ return {
5628
+ base: baseRow,
5629
+ variant: variantRow
5630
+ };
5631
+ });
5668
5632
  }
5669
5633
  #mapCreateRows(data) {
5670
5634
  const variantValue = this.state.variantValue;
@@ -5717,19 +5681,7 @@ var CollectionBase = class CollectionBase {
5717
5681
  this.#assertNotMtiVariant("createAndCount()");
5718
5682
  const annotationsMap = this.#collectAnnotationsFromMeta(configureCallback, "write", "createAndCount");
5719
5683
  const rows = blindCast(data);
5720
- const mappedRows = this.#mapCreateRows(rows);
5721
- applyCreateDefaults(this.ctx, this.namespaceId, this.tableName, mappedRows);
5722
- if (this.contract.capabilities?.["sql"]?.["defaultInInsert"] !== true) {
5723
- const plans = compileInsertCountSplit(this.contract, this.namespaceId, this.tableName, mappedRows, conflictSkip).map((plan) => mergeAnnotations(plan, annotationsMap));
5724
- let affectedRows = 0;
5725
- for (const plan of plans) {
5726
- const stats = await this.ctx.runtime.execute(plan);
5727
- affectedRows += stats.affectedRows;
5728
- }
5729
- return affectedRows;
5730
- }
5731
- const compiled = mergeAnnotations(compileInsertCount(this.contract, this.namespaceId, this.tableName, mappedRows, conflictSkip), annotationsMap);
5732
- return (await this.ctx.runtime.execute(compiled)).affectedRows;
5684
+ return (await executeGraph(createAllGraph(this.#descriptionWithoutIncludes(), this.#createValues(rows), conflictSkip), this.ctx, annotationsMap)).affectedRows;
5733
5685
  }
5734
5686
  async upsert(input, configure) {
5735
5687
  assertLockCompatible(this.state, "mutation");
@@ -5739,36 +5691,14 @@ var CollectionBase = class CollectionBase {
5739
5691
  const createValues = this.#mapCreateRows([blindCast(input.create)])[0] ?? {};
5740
5692
  applyCreateDefaults(this.ctx, this.namespaceId, this.tableName, [createValues]);
5741
5693
  const updateValues = mapModelDataToStorageRow(this.contract, this.namespaceId, this.modelName, input.update);
5742
- const hasUpdateValues = Object.keys(updateValues).length > 0;
5743
- if (hasUpdateValues) applyUpdateDefaults(this.ctx, this.namespaceId, this.tableName, updateValues);
5694
+ if (Object.keys(updateValues).length > 0) applyUpdateDefaults(this.ctx, this.namespaceId, this.tableName, updateValues);
5744
5695
  const conflictColumns = resolveUpsertConflictColumns(this.contract, this.namespaceId, this.modelName, blindCast(input.conflictOn));
5745
5696
  if (conflictColumns.length === 0) throw ormError("ORM.ARGUMENT_INVALID", `upsert() for model "${this.modelName}" requires conflict columns`, { meta: {
5746
5697
  method: "upsert",
5747
5698
  model: this.modelName
5748
5699
  } });
5749
- const { selectedForQuery: selectedForUpsert, hiddenColumns } = this.#augmentMutationSelection();
5750
- const compiled = mergeAnnotations(compileUpsertReturning(this.contract, this.namespaceId, this.modelName, this.tableName, createValues, updateValues, conflictColumns, selectedForUpsert), annotationsMap);
5751
- const row = await executeMutationReturningSingleRow({
5752
- context: this.ctx.context,
5753
- runtime: this.ctx.runtime,
5754
- compiled,
5755
- tables: this.state.tables,
5756
- modelName: this.modelName,
5757
- namespaceId: this.namespaceId,
5758
- variantValue: this.state.variantValue,
5759
- includes: this.state.includes,
5760
- selectedFields: this.state.selectedFields,
5761
- hiddenColumns,
5762
- mapRow: (mapped) => blindCast(mapped),
5763
- operation: "upsert",
5764
- onMissingRowMessage: `upsert() for model "${this.modelName}" did not return a row`
5765
- });
5700
+ const row = await consumeFirstRow(queryGraph(upsertGraph(this.#descriptionOptions(), createValues, updateValues, conflictColumns), this.ctx, annotationsMap, this.#descriptionOptions()));
5766
5701
  if (row) return row;
5767
- if (!hasUpdateValues) {
5768
- const conflictCriterion = this.#buildUpsertConflictCriterion(createValues, conflictColumns);
5769
- const existing = await this.#reloadMutationRowByCriterion(conflictCriterion, "upsert conflict");
5770
- if (existing) return existing;
5771
- }
5772
5702
  throw ormError("ORM.MUTATION_ROW_MISSING", `upsert() for model "${this.modelName}" did not return a row`, { meta: {
5773
5703
  operation: "upsert",
5774
5704
  model: this.modelName
@@ -5845,46 +5775,6 @@ var CollectionBase = class CollectionBase {
5845
5775
  if (Object.keys(values).length > 0) applyUpdateDefaults(this.ctx, this.namespaceId, this.tableName, values);
5846
5776
  return values;
5847
5777
  }
5848
- #buildUpsertConflictCriterion(createValues, conflictColumns) {
5849
- const criterion = {};
5850
- for (const columnName of conflictColumns) {
5851
- if (!(columnName in createValues)) throw ormError("ORM.ARGUMENT_INVALID", `upsert() for model "${this.modelName}" requires create value for conflict column "${columnName}"`, { meta: {
5852
- method: "upsert",
5853
- model: this.modelName,
5854
- column: columnName
5855
- } });
5856
- const fieldName = fieldOfColumn(getModelColumnFields(this.contract, this.namespaceId, this.modelName), this.modelName, columnName);
5857
- criterion[fieldName] = createValues[columnName];
5858
- }
5859
- return criterion;
5860
- }
5861
- /**
5862
- * Shape the projection for a mutation's `RETURNING` clause.
5863
- *
5864
- * Without includes, the mutation returns the caller's projection
5865
- * directly. With includes, it returns only the row identity columns
5866
- * (PK / unique): those rows are reloaded through the read path
5867
- * (`reloadMutationRowsByIdentities`), which re-selects the caller's
5868
- * projection together with the relations, so the `RETURNING` clause
5869
- * need only carry enough to key that read-back.
5870
- */
5871
- #augmentMutationSelection() {
5872
- if (this.state.includes.length > 0) {
5873
- const identityColumns = resolveRowIdentityColumns(this.contract, this.namespaceId, this.tableName);
5874
- if (identityColumns.length === 0) throw ormError("ORM.ROW_IDENTITY_MISSING", `Cannot load includes for the mutation result on model "${this.modelName}": table "${this.tableName}" has no primary key or unique constraint to key the include read-back on.`, { meta: {
5875
- model: this.modelName,
5876
- table: this.tableName
5877
- } });
5878
- return {
5879
- selectedForQuery: identityColumns,
5880
- hiddenColumns: []
5881
- };
5882
- }
5883
- return {
5884
- selectedForQuery: this.state.selectedFields,
5885
- hiddenColumns: []
5886
- };
5887
- }
5888
5778
  async #reloadMutationRowByIdentity(criterion) {
5889
5779
  return this.#reloadMutationRowByCriterion(criterion, "row identity");
5890
5780
  }