pqb 0.56.3 → 0.56.5

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
@@ -4235,14 +4235,7 @@ const throwIfJoinLateral = (q, method) => {
4235
4235
  };
4236
4236
  const saveAliasedShape = (q, as, key) => {
4237
4237
  const shapes = q.q[key];
4238
- if (shapes?.[as]) {
4239
- let suffix = 2;
4240
- let name;
4241
- while (shapes[name = `${as}${suffix}`]) {
4242
- suffix++;
4243
- }
4244
- as = name;
4245
- }
4238
+ as = orchidCore.getFreeAlias(shapes, as);
4246
4239
  setQueryObjectValueImmutable(q, key, as, orchidCore.emptyObject);
4247
4240
  return as;
4248
4241
  };
@@ -6354,15 +6347,26 @@ const pushWithSql = (ctx, items) => {
6354
6347
  const sql = withToSql(ctx, items);
6355
6348
  if (sql) ctx.sql.push("WITH", sql);
6356
6349
  };
6350
+ const pushOrAppendWithSql = (ctx, query, items) => {
6351
+ const sql = withToSql(ctx, items);
6352
+ if (sql) {
6353
+ if (query.with) {
6354
+ ctx.sql[ctx.sql.length - 1] += ",";
6355
+ } else {
6356
+ ctx.sql.push("WITH");
6357
+ }
6358
+ ctx.sql.push(sql);
6359
+ }
6360
+ };
6357
6361
 
6358
6362
  const makeInsertSql = (ctx, q, query, quotedAs) => {
6359
6363
  let { columns } = query;
6360
6364
  const { shape, inCTE, hookCreateSet } = query;
6361
6365
  const QueryClass = ctx.qb.constructor;
6362
- let values = query.values;
6366
+ let { insertFrom, queryColumnsCount, values } = query;
6363
6367
  let hookSetSql;
6364
6368
  if (hookCreateSet) {
6365
- ({ hookSetSql, columns, values } = processHookSet(
6369
+ ({ hookSetSql, columns, insertFrom, queryColumnsCount, values } = processHookSet(
6366
6370
  ctx,
6367
6371
  q,
6368
6372
  values,
@@ -6381,6 +6385,7 @@ const makeInsertSql = (ctx, q, query, quotedAs) => {
6381
6385
  for (const key of q.internal.runtimeDefaultColumns) {
6382
6386
  if (!columns.includes(key)) {
6383
6387
  const column = shape[key];
6388
+ columns.push(key);
6384
6389
  quotedColumns.push(`"${column.data.name || key}"`);
6385
6390
  runtimeDefaults.push(column.data.runtimeDefault);
6386
6391
  }
@@ -6398,8 +6403,22 @@ const makeInsertSql = (ctx, q, query, quotedAs) => {
6398
6403
  }
6399
6404
  const insertSql = `INSERT INTO ${quotedAs}${quotedColumns.length ? "(" + quotedColumns.join(", ") + ")" : ""}`;
6400
6405
  const hasNonSelect = ctx.hasNonSelect;
6401
- if ("from" in values && query.insertWith) {
6402
- pushWithSql(ctx, Object.values(query.insertWith).flat());
6406
+ let hasWith = !!query.with;
6407
+ if (insertFrom) {
6408
+ if (values.length < 2) {
6409
+ if (query.insertWith) {
6410
+ hasWith = true;
6411
+ pushOrAppendWithSql(ctx, query, Object.values(query.insertWith).flat());
6412
+ }
6413
+ } else {
6414
+ hasWith = true;
6415
+ pushOrAppendWithSql(ctx, query, [
6416
+ {
6417
+ n: getQueryAs(insertFrom),
6418
+ q: insertFrom
6419
+ }
6420
+ ]);
6421
+ }
6403
6422
  }
6404
6423
  const valuesPos = ctx.sql.length + 1;
6405
6424
  ctx.sql.push(insertSql, null);
@@ -6475,28 +6494,38 @@ const makeInsertSql = (ctx, q, query, quotedAs) => {
6475
6494
  );
6476
6495
  }
6477
6496
  if (returning.select) ctx.sql.push("RETURNING", returning.select);
6478
- if ("from" in values) {
6479
- const { from, values: v } = values;
6480
- const q2 = from.clone();
6481
- if (v) {
6482
- orchidCore.pushQueryValueImmutable(
6483
- q2,
6484
- "select",
6485
- new RawSQL(
6486
- encodeRow(
6487
- ctx,
6488
- ctx.values,
6489
- q2,
6490
- QueryClass,
6491
- v,
6492
- runtimeDefaults,
6493
- quotedAs
6497
+ let insertManyFromValuesAs;
6498
+ if (insertFrom) {
6499
+ if (values.length < 2) {
6500
+ const q2 = insertFrom.clone();
6501
+ if (values[0]?.length) {
6502
+ orchidCore.pushQueryValueImmutable(
6503
+ q2,
6504
+ "select",
6505
+ new RawSQL(
6506
+ encodeRow(
6507
+ ctx,
6508
+ ctx.values,
6509
+ q2,
6510
+ QueryClass,
6511
+ values[0],
6512
+ runtimeDefaults,
6513
+ quotedAs
6514
+ )
6494
6515
  )
6495
- )
6496
- );
6516
+ );
6517
+ }
6518
+ ctx.sql[valuesPos] = getSqlText(toSQL(q2, ctx));
6519
+ } else {
6520
+ insertManyFromValuesAs = query.insertValuesAs;
6521
+ const queryAs = getQueryAs(insertFrom);
6522
+ ctx.sql[valuesPos - 1] += ` SELECT "${queryAs}".*, ${columns.slice(queryColumnsCount || 0).map((key) => {
6523
+ const column = shape[key];
6524
+ return column ? `${insertManyFromValuesAs}."${column.data.name || key}"::${column.dataType}` : `${insertManyFromValuesAs}."${key}"`;
6525
+ }).join(", ")} FROM "${queryAs}",`;
6497
6526
  }
6498
- ctx.sql[valuesPos] = getSqlText(toSQL(q2, ctx));
6499
- } else {
6527
+ }
6528
+ if (!insertFrom || insertManyFromValuesAs) {
6500
6529
  const valuesSql = [];
6501
6530
  let ctxValues = ctx.values;
6502
6531
  const restValuesLen = ctxValues.length;
@@ -6505,6 +6534,8 @@ const makeInsertSql = (ctx, q, query, quotedAs) => {
6505
6534
  const { insertWith } = query;
6506
6535
  const { skipBatchCheck } = ctx;
6507
6536
  const withSqls = [];
6537
+ const startingKeyword = (insertManyFromValuesAs ? "(" : "") + (inCTE ? "SELECT " : "VALUES ");
6538
+ const valuesAppend = insertManyFromValuesAs ? `) ${insertManyFromValuesAs}(${quotedColumns.slice(queryColumnsCount || 0).join(", ")})` : "";
6508
6539
  for (let i = 0; i < values.length; i++) {
6509
6540
  const withes = insertWith?.[i];
6510
6541
  ctx.skipBatchCheck = true;
@@ -6528,11 +6559,8 @@ const makeInsertSql = (ctx, q, query, quotedAs) => {
6528
6559
  );
6529
6560
  }
6530
6561
  if (!skipBatchCheck) {
6531
- if (withSqls.length) {
6532
- ctx.sql[valuesPos - 1] = "WITH " + withSqls.join(", ") + " " + insertSql;
6533
- withSqls.length = 0;
6534
- }
6535
- ctx.sql[valuesPos] = (inCTE ? "SELECT " : "VALUES ") + valuesSql.join(", ");
6562
+ addWithSqls(ctx, hasWith, withSqls, valuesPos, insertSql);
6563
+ ctx.sql[valuesPos] = startingKeyword + valuesSql.join(", ") + valuesAppend;
6536
6564
  ctxValues.length = currentValuesLen;
6537
6565
  batch = orchidCore.pushOrNewArray(batch, {
6538
6566
  text: ctx.sql.join(" "),
@@ -6548,9 +6576,7 @@ const makeInsertSql = (ctx, q, query, quotedAs) => {
6548
6576
  if (withSql) withSqls.push(withSql);
6549
6577
  valuesSql.push(encodedRow);
6550
6578
  }
6551
- if (withSqls.length) {
6552
- ctx.sql[valuesPos - 1] = "WITH " + withSqls.join(", ") + " " + insertSql;
6553
- }
6579
+ addWithSqls(ctx, hasWith, withSqls, valuesPos, insertSql);
6554
6580
  if (batch) {
6555
6581
  if (hasNonSelect) {
6556
6582
  throw new orchidCore.OrchidOrmInternalError(
@@ -6558,7 +6584,7 @@ const makeInsertSql = (ctx, q, query, quotedAs) => {
6558
6584
  `Cannot insert many records when having a non-select sub-query`
6559
6585
  );
6560
6586
  }
6561
- ctx.sql[valuesPos] = (inCTE ? "SELECT " : "VALUES ") + valuesSql.join(", ");
6587
+ ctx.sql[valuesPos] = startingKeyword + valuesSql.join(", ") + valuesAppend;
6562
6588
  batch.push({
6563
6589
  text: ctx.sql.join(" "),
6564
6590
  values: ctxValues
@@ -6569,7 +6595,7 @@ const makeInsertSql = (ctx, q, query, quotedAs) => {
6569
6595
  batch
6570
6596
  };
6571
6597
  } else {
6572
- ctx.sql[valuesPos] = (inCTE ? "SELECT " : "VALUES ") + valuesSql.join(", ");
6598
+ ctx.sql[valuesPos] = startingKeyword + valuesSql.join(", ") + valuesAppend;
6573
6599
  }
6574
6600
  if (inCTE) {
6575
6601
  ctx.sql[valuesPos] += ' WHERE NOT EXISTS (SELECT 1 FROM "f")';
@@ -6582,6 +6608,15 @@ const makeInsertSql = (ctx, q, query, quotedAs) => {
6582
6608
  values: ctx.values
6583
6609
  };
6584
6610
  };
6611
+ const addWithSqls = (ctx, hasWith, withSqls, valuesPos, insertSql) => {
6612
+ if (withSqls.length) {
6613
+ if (hasWith) {
6614
+ ctx.sql[valuesPos - 2] += ",";
6615
+ }
6616
+ ctx.sql[valuesPos - 1] = (hasWith ? "" : "WITH ") + withSqls.join(", ") + " " + insertSql;
6617
+ withSqls.length = 0;
6618
+ }
6619
+ };
6585
6620
  const processHookSet = (ctx, q, values, hookCreateSet, columns, QueryClass, quotedAs) => {
6586
6621
  const hookSet = {};
6587
6622
  for (const item of hookCreateSet) {
@@ -6590,48 +6625,54 @@ const processHookSet = (ctx, q, values, hookCreateSet, columns, QueryClass, quot
6590
6625
  const addHookSetColumns = Object.keys(hookSet).filter(
6591
6626
  (key) => !columns.includes(key)
6592
6627
  );
6593
- if ("from" in values) {
6594
- const v = { ...values };
6595
- const newColumns = [];
6596
- const originalSelect = v.from.q.select;
6628
+ let insertFrom = q.q.insertFrom;
6629
+ if (insertFrom) {
6630
+ const newColumns = /* @__PURE__ */ new Set();
6631
+ const originalSelect = insertFrom.q.select;
6597
6632
  if (originalSelect) {
6598
- v.from = _clone(v.from);
6633
+ insertFrom = _clone(insertFrom);
6599
6634
  const select = [];
6600
6635
  for (const s of originalSelect) {
6601
6636
  if (typeof s === "string" && !hookSet[s]) {
6602
6637
  select.push(s);
6603
- newColumns.push(s);
6638
+ newColumns.add(s);
6604
6639
  } else if (typeof s === "object" && "selectAs" in s) {
6605
6640
  const filtered = {};
6606
6641
  for (const key in s.selectAs) {
6607
6642
  if (!hookSet[key]) {
6608
6643
  filtered[key] = s.selectAs[key];
6609
- newColumns.push(key);
6644
+ newColumns.add(key);
6610
6645
  }
6611
6646
  }
6612
6647
  select.push({ selectAs: filtered });
6613
6648
  }
6614
6649
  }
6615
- v.from.q.select = select;
6616
- }
6617
- let row;
6618
- if (v.values) {
6619
- const originalRow = v.values;
6620
- const valuesColumns = columns.slice(-originalRow.length);
6621
- row = [];
6622
- valuesColumns.forEach((c, i) => {
6623
- if (!hookSet[c]) {
6624
- newColumns.push(c);
6625
- row.push(originalRow[i]);
6626
- }
6650
+ insertFrom.q.select = select;
6651
+ }
6652
+ if (values.length) {
6653
+ const newValues = [];
6654
+ const valuesColumnsSet = /* @__PURE__ */ new Set();
6655
+ values.forEach((originalRow, i) => {
6656
+ const valuesColumns = columns.slice(-originalRow.length);
6657
+ const row = [];
6658
+ newValues[i] = row;
6659
+ valuesColumns.forEach((c, i2) => {
6660
+ if (!hookSet[c] && !newColumns.has(c)) {
6661
+ valuesColumnsSet.add(c);
6662
+ row.push(originalRow[i2]);
6663
+ }
6664
+ });
6627
6665
  });
6666
+ for (const valueColumn of valuesColumnsSet) {
6667
+ newColumns.add(valueColumn);
6668
+ }
6669
+ values = newValues;
6628
6670
  } else {
6629
- row = [];
6671
+ values = [[]];
6630
6672
  }
6631
- v.values = row;
6632
6673
  columns.forEach((column) => {
6633
6674
  if (column in hookSet) {
6634
- newColumns.push(column);
6675
+ newColumns.add(column);
6635
6676
  const fromHook = {
6636
6677
  fromHook: encodeValue(
6637
6678
  ctx,
@@ -6642,28 +6683,35 @@ const processHookSet = (ctx, q, values, hookCreateSet, columns, QueryClass, quot
6642
6683
  quotedAs
6643
6684
  )
6644
6685
  };
6645
- row.push(fromHook);
6686
+ for (const row of values) {
6687
+ row.push(fromHook);
6688
+ }
6646
6689
  }
6647
6690
  });
6691
+ const queryColumnsCount = insertFrom.q.select?.length;
6648
6692
  if (addHookSetColumns) {
6649
6693
  for (const key of addHookSetColumns) {
6650
- row.push({
6651
- fromHook: encodeValue(
6652
- ctx,
6653
- ctx.values,
6654
- q,
6655
- QueryClass,
6656
- hookSet[key],
6657
- quotedAs
6658
- )
6659
- });
6694
+ for (const row of values) {
6695
+ row.push({
6696
+ fromHook: encodeValue(
6697
+ ctx,
6698
+ ctx.values,
6699
+ q,
6700
+ QueryClass,
6701
+ hookSet[key],
6702
+ quotedAs
6703
+ )
6704
+ });
6705
+ }
6660
6706
  }
6661
6707
  return {
6662
6708
  columns: [...newColumns, ...addHookSetColumns],
6663
- values: v
6709
+ insertFrom,
6710
+ queryColumnsCount,
6711
+ values
6664
6712
  };
6665
6713
  }
6666
- return { columns: newColumns, values: v };
6714
+ return { columns: [...newColumns], insertFrom, queryColumnsCount, values };
6667
6715
  }
6668
6716
  columns.forEach((column, i) => {
6669
6717
  if (column in hookSet) {
@@ -6979,8 +7027,7 @@ const selectToSql = (ctx, table, query, quotedAs, hookSelect = query.hookSelect,
6979
7027
  hookSelect.delete(column);
6980
7028
  continue;
6981
7029
  }
6982
- let i = 2;
6983
- while (selected[name = `${column}${i}`]) i++;
7030
+ name = orchidCore.getFreeAlias(selected, column);
6984
7031
  item.as = name;
6985
7032
  item.temp = name;
6986
7033
  sql += ` "${name}"`;
@@ -8623,7 +8670,7 @@ class Union {
8623
8670
  }
8624
8671
  }
8625
8672
 
8626
- const addWith = (q, withStore, item, key = "with") => {
8673
+ const _addWith = (query, withStore, item, key = "with") => {
8627
8674
  if (item.q) {
8628
8675
  item.q.q.with?.forEach((item2, i, arr) => {
8629
8676
  if (item2?.q?.q.type) {
@@ -8634,7 +8681,8 @@ const addWith = (q, withStore, item, key = "with") => {
8634
8681
  if (item.q.q.insertWith) {
8635
8682
  const values = Object.values(item.q.q.insertWith).flat();
8636
8683
  item.q.q.insertWith = void 0;
8637
- q.q.with = q.q.with ? [...q.q.with, ...values] : values;
8684
+ const { q } = query;
8685
+ q.with = q.with ? [...q.with, ...values] : values;
8638
8686
  }
8639
8687
  }
8640
8688
  orchidCore.pushOrNewArrayToObjectImmutable(withStore, key, item);
@@ -8642,7 +8690,7 @@ const addWith = (q, withStore, item, key = "with") => {
8642
8690
  const moveQueryValueToWith = (q, withStore, value, withKey, set, key) => {
8643
8691
  if (value.q.type) {
8644
8692
  const as = saveAliasedShape(q, "q", "withShapes");
8645
- addWith(
8693
+ _addWith(
8646
8694
  q,
8647
8695
  withStore,
8648
8696
  {
@@ -8676,7 +8724,7 @@ class WithMethods {
8676
8724
  columns: Object.keys(query.shape)
8677
8725
  };
8678
8726
  }
8679
- addWith(q, q.q, { n: name, o: options, q: query });
8727
+ _addWith(q, q.q, { n: name, o: options, q: query });
8680
8728
  const shape = getShapeFromSelect(query, true);
8681
8729
  return setQueryObjectValueImmutable(q, "withShapes", name, {
8682
8730
  shape,
@@ -8702,7 +8750,7 @@ class WithMethods {
8702
8750
  columns: Object.keys(shape)
8703
8751
  };
8704
8752
  }
8705
- addWith(q, q.q, { n: name, o: options, q: query });
8753
+ _addWith(q, q.q, { n: name, o: options, q: query });
8706
8754
  return setQueryObjectValueImmutable(q, "withShapes", name, withConfig);
8707
8755
  }
8708
8756
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -8720,6 +8768,248 @@ class WithMethods {
8720
8768
  }
8721
8769
  }
8722
8770
 
8771
+ const insertFrom = (query, from, many, queryMany, data) => {
8772
+ const ctx = createCtx();
8773
+ const obj = data && (Array.isArray(data) ? handleManyData(query, data, ctx) : handleOneData(query, data, ctx));
8774
+ return insert(
8775
+ query,
8776
+ {
8777
+ insertFrom: from,
8778
+ columns: obj?.columns || [],
8779
+ values: obj?.values || []
8780
+ },
8781
+ many,
8782
+ queryMany
8783
+ );
8784
+ };
8785
+ const getFromSelectColumns = (q, from, obj, many) => {
8786
+ if (!many && !queryTypeWithLimitOne[from.q.returnType]) {
8787
+ throw new Error(
8788
+ "Cannot create based on a query which returns multiple records"
8789
+ );
8790
+ }
8791
+ const queryColumns = /* @__PURE__ */ new Set();
8792
+ from.q.select?.forEach((item) => {
8793
+ if (typeof item === "string") {
8794
+ const index = item.indexOf(".");
8795
+ queryColumns.add(index === -1 ? item : item.slice(index + 1));
8796
+ } else if (item && "selectAs" in item) {
8797
+ for (const column in item.selectAs) {
8798
+ queryColumns.add(column);
8799
+ }
8800
+ }
8801
+ });
8802
+ const allColumns = new Set(queryColumns);
8803
+ const queryColumnsCount = queryColumns.size;
8804
+ const allValues = [];
8805
+ if (obj?.columns) {
8806
+ for (const objectValues of obj.values) {
8807
+ const values = [];
8808
+ allValues.push(values);
8809
+ obj.columns.forEach((column, i) => {
8810
+ if (!queryColumns.has(column)) {
8811
+ allColumns.add(column);
8812
+ values.push(objectValues[i]);
8813
+ }
8814
+ });
8815
+ }
8816
+ }
8817
+ for (const key of queryColumns) {
8818
+ const column = q.shape[key];
8819
+ if (column) throwOnReadOnly$1(from, column, key);
8820
+ }
8821
+ return {
8822
+ columns: [...allColumns],
8823
+ queryColumnsCount,
8824
+ values: allValues
8825
+ };
8826
+ };
8827
+ const _queryCreateOneFrom = (q, query, data) => {
8828
+ createSelect(q);
8829
+ return insertFrom(q, query, false, false, data);
8830
+ };
8831
+ const _queryInsertOneFrom = (q, query, data) => {
8832
+ return insertFrom(q, query, false, false, data);
8833
+ };
8834
+ const _queryCreateManyFrom = (q, query, data) => {
8835
+ createSelect(q);
8836
+ return insertFrom(q, query, true, false, data);
8837
+ };
8838
+ const _queryInsertManyFrom = (q, query, data) => {
8839
+ return insertFrom(q, query, true, false, data);
8840
+ };
8841
+ const _queryCreateForEachFrom = (q, query) => {
8842
+ createSelect(q);
8843
+ return insertFrom(q, query, true, true);
8844
+ };
8845
+ const _queryInsertForEachFrom = (q, query) => {
8846
+ return insertFrom(q, query, true, true);
8847
+ };
8848
+ class QueryCreateFrom {
8849
+ /**
8850
+ * Inserts a single record based on a query that selects a single record.
8851
+ *
8852
+ * Performs a single SQL query based on `INSERT ... SELECT ... FROM`.
8853
+ *
8854
+ * See {@link createManyFrom} to insert multiple records based on a single record query,
8855
+ * and {@link createForEachFrom} to insert a record per every one found by the query.
8856
+ *
8857
+ * The first argument is a query of a **single** record, it should have `find`, `take`, or similar.
8858
+ *
8859
+ * The second optional argument is a data which will be merged with columns returned by the query.
8860
+ *
8861
+ * The data for the second argument is the same as in {@link create}.
8862
+ *
8863
+ * Columns with runtime defaults (defined with a callback) are supported here.
8864
+ * The value for such a column will be injected unless selected from a related table or provided in a data object.
8865
+ *
8866
+ * ```ts
8867
+ * const oneRecord = await db.table.createOneFrom(
8868
+ * db.relatedTable
8869
+ * // use select to map columns from one table to another
8870
+ * .select({
8871
+ * // relatedTable's id will be inserted as "relatedId"
8872
+ * relatedId: 'id',
8873
+ * })
8874
+ * .findBy({ key: 'value' }),
8875
+ * // optional argument:
8876
+ * {
8877
+ * key: 'value',
8878
+ * // supports sql, nested select, create, update, delete queries
8879
+ * fromSql: () => sql`custom sql`,
8880
+ * fromQuery: () => db.otherTable.find(id).update(data).get('column'),
8881
+ * fromRelated: (q) => q.relatedTable.create(data).get('column'),
8882
+ * },
8883
+ * );
8884
+ * ```
8885
+ *
8886
+ * The query above will produce such a SQL (omitting `from*` values):
8887
+ *
8888
+ * ```sql
8889
+ * INSERT INTO "table"("relatedId", "key")
8890
+ * SELECT "relatedTable"."id" AS "relatedId", 'value'
8891
+ * FROM "relatedTable"
8892
+ * WHERE "relatedTable"."key" = 'value'
8893
+ * LIMIT 1
8894
+ * RETURNING *
8895
+ * ```
8896
+ *
8897
+ * @param query - query to create new records from
8898
+ * @param data - additionally you can set some columns
8899
+ */
8900
+ createOneFrom(query, data) {
8901
+ return _queryCreateOneFrom(_clone(this), query, data);
8902
+ }
8903
+ /**
8904
+ * Works exactly as {@link createOneFrom}, except that it returns inserted row count by default.
8905
+ *
8906
+ * @param query - query to create new records from
8907
+ * @param data - additionally you can set some columns
8908
+ */
8909
+ insertOneFrom(query, data) {
8910
+ return _queryInsertOneFrom(_clone(this), query, data);
8911
+ }
8912
+ /**
8913
+ * Inserts multiple records based on a query that selects a single record.
8914
+ *
8915
+ * Performs a single SQL query based on `INSERT ... SELECT ... FROM`.
8916
+ *
8917
+ * See {@link createOneFrom} to insert a single record based on a single record query,
8918
+ * and {@link createForEachFrom} to insert a record per every one found by the query.
8919
+ *
8920
+ * The first argument is a query of a **single** record, it should have `find`, `take`, or similar.
8921
+ *
8922
+ * The second argument is array of objects to be merged with columns returned by the query.
8923
+ *
8924
+ * The data for the second argument is the same as in {@link createMany}.
8925
+ *
8926
+ * Columns with runtime defaults (defined with a callback) are supported here.
8927
+ * The value for such a column will be injected unless selected from a related table or provided in a data object.
8928
+ *
8929
+ * ```ts
8930
+ * const twoRecords = await db.table.createManyFrom(
8931
+ * db.relatedTable
8932
+ * // use select to map columns from one table to another
8933
+ * .select({
8934
+ * // relatedTable's id will be inserted as "relatedId"
8935
+ * relatedId: 'id',
8936
+ * })
8937
+ * .findBy({ key: 'value' }),
8938
+ * [
8939
+ * {
8940
+ * key: 'value 1',
8941
+ * // supports sql, nested select, create, update, delete queries
8942
+ * fromSql: () => sql`custom sql`,
8943
+ * fromQuery: () => db.otherTable.find(id).update(data).get('column'),
8944
+ * fromRelated: (q) => q.relatedTable.create(data).get('column'),
8945
+ * },
8946
+ * {
8947
+ * key: 'value 2',
8948
+ * },
8949
+ * ],
8950
+ * );
8951
+ * ```
8952
+ *
8953
+ * The query above will produce such a SQL (omitting `from*` values):
8954
+ *
8955
+ * ```sql
8956
+ * WITH "relatedTable" AS (
8957
+ * SELECT "relatedTable"."id" AS "relatedId", 'value'
8958
+ * FROM "relatedTable"
8959
+ * WHERE "relatedTable"."key" = 'value'
8960
+ * LIMIT 1
8961
+ * )
8962
+ * INSERT INTO "table"("relatedId", "key")
8963
+ * SELECT "relatedTable".*, v."key"::text
8964
+ * FROM "relatedTable", (VALUES ('value1'), ('value2')) v("key")
8965
+ * RETURNING *
8966
+ * ```
8967
+ *
8968
+ * @param query - query to create new records from
8969
+ * @param data - array of records to create
8970
+ */
8971
+ createManyFrom(query, data) {
8972
+ return _queryCreateManyFrom(_clone(this), query, data);
8973
+ }
8974
+ /**
8975
+ * Works exactly as {@link createManyFrom}, except that it returns inserted row count by default.
8976
+ *
8977
+ * @param query - query to create new records from
8978
+ * @param data - array of records to create
8979
+ */
8980
+ insertManyFrom(query, data) {
8981
+ return _queryInsertManyFrom(_clone(this), query, data);
8982
+ }
8983
+ /**
8984
+ * Inserts a single record per every record found in a given query.
8985
+ *
8986
+ * Performs a single SQL query based on `INSERT ... SELECT ... FROM`.
8987
+ *
8988
+ * Unlike {@link createOneFrom}, it doesn't accept second argument with data.
8989
+ *
8990
+ * Runtime defaults cannot work with it.
8991
+ *
8992
+ * ```ts
8993
+ * const manyRecords = await db.table.createForEachFrom(
8994
+ * RelatedTable.select({ relatedId: 'id' }).where({ key: 'value' }),
8995
+ * );
8996
+ * ```
8997
+ *
8998
+ * @param query - query to create new records from
8999
+ */
9000
+ createForEachFrom(query) {
9001
+ return _queryCreateForEachFrom(_clone(this), query);
9002
+ }
9003
+ /**
9004
+ * Works exactly as {@link createForEachFrom}, except that it returns inserted row count by default.
9005
+ *
9006
+ * @param query - query to create new records from
9007
+ */
9008
+ insertForEachFrom(query) {
9009
+ return _queryInsertForEachFrom(_clone(this), query);
9010
+ }
9011
+ }
9012
+
8723
9013
  const createSelect = (q) => {
8724
9014
  if (q.q.returnType === "void" || isSelectingCount(q)) {
8725
9015
  q.q.select = void 0;
@@ -8818,8 +9108,9 @@ const handleManyData = (q, data, ctx) => {
8818
9108
  };
8819
9109
  const insert = (self, {
8820
9110
  columns,
9111
+ insertFrom,
8821
9112
  values
8822
- }, many) => {
9113
+ }, many, queryMany) => {
8823
9114
  const { q } = self;
8824
9115
  if (!q.select?.length) {
8825
9116
  q.returning = true;
@@ -8828,6 +9119,28 @@ const insert = (self, {
8828
9119
  delete q.or;
8829
9120
  delete q.scopes;
8830
9121
  q.type = "insert";
9122
+ insertFrom = insertFrom ? q.insertFrom = insertFrom : q.insertFrom;
9123
+ if (insertFrom) {
9124
+ if (q.insertFrom) {
9125
+ const obj = getFromSelectColumns(
9126
+ self,
9127
+ q.insertFrom,
9128
+ {
9129
+ columns,
9130
+ values
9131
+ },
9132
+ queryMany
9133
+ );
9134
+ columns = obj.columns;
9135
+ values = obj.values;
9136
+ q.queryColumnsCount = obj.queryColumnsCount;
9137
+ }
9138
+ if (values.length > 1) {
9139
+ const insertValuesAs = orchidCore._getQueryFreeAlias(q, "v");
9140
+ orchidCore._setQueryAlias(self, "v", insertValuesAs);
9141
+ q.insertValuesAs = insertValuesAs;
9142
+ }
9143
+ }
8831
9144
  q.columns = columns;
8832
9145
  q.values = values;
8833
9146
  const { select, returnType } = q;
@@ -8843,63 +9156,20 @@ const insert = (self, {
8843
9156
  q.returnType = "pluck";
8844
9157
  }
8845
9158
  } else if (!returnType || returnType === "all") {
8846
- q.returnType = "from" in values ? values.from.q.returnType : "one";
9159
+ q.returnType = insertFrom ? insertFrom.q.returnType : "one";
8847
9160
  } else if (returnType === "pluck") {
8848
9161
  q.returnType = "valueOrThrow";
8849
9162
  }
8850
9163
  return self;
8851
9164
  };
8852
- const getFromSelectColumns = (q, from, obj, many) => {
8853
- if (!many && !queryTypeWithLimitOne[from.q.returnType]) {
8854
- throw new Error(
8855
- "Cannot create based on a query which returns multiple records"
8856
- );
8857
- }
8858
- const queryColumns = [];
8859
- from.q.select?.forEach((item) => {
8860
- if (typeof item === "string") {
8861
- const index = item.indexOf(".");
8862
- queryColumns.push(index === -1 ? item : item.slice(index + 1));
8863
- } else if (item && "selectAs" in item) {
8864
- queryColumns.push(...Object.keys(item.selectAs));
8865
- }
8866
- });
8867
- if (obj?.columns) {
8868
- queryColumns.push(...obj.columns);
8869
- }
8870
- for (const key of queryColumns) {
8871
- const column = q.shape[key];
8872
- if (column) throwOnReadOnly$1(from, column, key);
8873
- }
8874
- return queryColumns;
8875
- };
8876
- const insertFromQuery = (q, from, many, data) => {
8877
- const ctx = createCtx();
8878
- const obj = data && handleOneData(q, data, ctx);
8879
- const columns = getFromSelectColumns(q, from, obj, many);
8880
- return insert(
8881
- q,
8882
- {
8883
- columns,
8884
- values: { from, values: obj?.values[0] }
8885
- },
8886
- many
8887
- );
8888
- };
8889
9165
  const _queryCreate = (q, data) => {
8890
9166
  createSelect(q);
8891
9167
  return _queryInsert(q, data);
8892
9168
  };
8893
- const _queryInsert = (q, data) => {
9169
+ const _queryInsert = (query, data) => {
8894
9170
  const ctx = createCtx();
8895
- const obj = handleOneData(q, data, ctx);
8896
- const values = q.q.values;
8897
- if (values && "from" in values) {
8898
- obj.columns = getFromSelectColumns(q, values.from, obj);
8899
- values.values = obj.values[0];
8900
- obj.values = values;
8901
- }
8902
- return insert(q, obj);
9171
+ const obj = handleOneData(query, data, ctx);
9172
+ return insert(query, obj);
8903
9173
  };
8904
9174
  const _queryCreateMany = (q, data) => {
8905
9175
  createSelect(q);
@@ -8911,20 +9181,6 @@ const _queryInsertMany = (q, data) => {
8911
9181
  if (!data.length) result = result.none();
8912
9182
  return result;
8913
9183
  };
8914
- const _queryCreateFrom = (q, query, data) => {
8915
- createSelect(q);
8916
- return insertFromQuery(q, query, false, data);
8917
- };
8918
- const _queryInsertFrom = (q, query, data) => {
8919
- return insertFromQuery(q, query, false, data);
8920
- };
8921
- const _queryCreateManyFrom = (q, query) => {
8922
- createSelect(q);
8923
- return insertFromQuery(q, query, true);
8924
- };
8925
- const _queryInsertManyFrom = (q, query) => {
8926
- return insertFromQuery(q, query, true);
8927
- };
8928
9184
  const _queryDefaults = (q, data) => {
8929
9185
  q.q.defaults = data;
8930
9186
  return q;
@@ -9042,85 +9298,6 @@ class QueryCreate {
9042
9298
  insertMany(data) {
9043
9299
  return _queryInsertMany(_clone(this), data);
9044
9300
  }
9045
- /**
9046
- * These methods are for creating a single record, for batch creating see {@link createManyFrom}.
9047
- *
9048
- * `createFrom` is to perform the `INSERT ... SELECT ...` SQL statement, it does select and insert by performing a single query.
9049
- *
9050
- * The first argument is a query for a **single** record, it should have `find`, `take`, or similar.
9051
- *
9052
- * The second optional argument is a data which will be merged with columns returned from the select query.
9053
- *
9054
- * The data for the second argument is the same as in {@link create}.
9055
- *
9056
- * Columns with runtime defaults (defined with a callback) are supported here.
9057
- * The value for such a column will be injected unless selected from a related table or provided in a data object.
9058
- *
9059
- * ```ts
9060
- * const oneRecord = await db.table.createFrom(
9061
- * // In the select, key is a related table column, value is a column to insert as
9062
- * RelatedTable.select({ relatedId: 'id' }).findBy({ key: 'value' }),
9063
- * // optional argument:
9064
- * {
9065
- * key: 'value',
9066
- * // supports sql, nested select, create, update, delete queries
9067
- * fromSql: () => sql`custom sql`,
9068
- * fromQuery: () => db.otherTable.find(id).update(data).get('column'),
9069
- * fromRelated: (q) => q.relatedTable.create(data).get('column'),
9070
- * },
9071
- * );
9072
- * ```
9073
- *
9074
- * The query above will produce such SQL:
9075
- *
9076
- * ```sql
9077
- * INSERT INTO "table"("relatedId", "key")
9078
- * SELECT "relatedTable"."id" AS "relatedId", 'value'
9079
- * FROM "relatedTable"
9080
- * WHERE "relatedTable"."key" = 'value'
9081
- * LIMIT 1
9082
- * RETURNING *
9083
- * ```
9084
- *
9085
- * @param query - query to create new records from
9086
- * @param data - additionally you can set some columns
9087
- */
9088
- createFrom(query, data) {
9089
- return _queryCreateFrom(_clone(this), query, data);
9090
- }
9091
- /**
9092
- * Works exactly as {@link createFrom}, except that it returns inserted row count by default.
9093
- *
9094
- * @param query - query to create new records from
9095
- * @param data - additionally you can set some columns
9096
- */
9097
- insertFrom(query, data) {
9098
- return _queryInsertFrom(_clone(this), query, data);
9099
- }
9100
- /**
9101
- * Similar to `createFrom`, but intended to create many records.
9102
- *
9103
- * Unlike `createFrom`, it doesn't accept second argument with data, and runtime defaults cannot work with it.
9104
- *
9105
- * ```ts
9106
- * const manyRecords = await db.table.createManyFrom(
9107
- * RelatedTable.select({ relatedId: 'id' }).where({ key: 'value' }),
9108
- * );
9109
- * ```
9110
- *
9111
- * @param query - query to create new records from
9112
- */
9113
- createManyFrom(query) {
9114
- return _queryCreateManyFrom(_clone(this), query);
9115
- }
9116
- /**
9117
- * Works exactly as {@link createManyFrom}, except that it returns inserted row count by default.
9118
- *
9119
- * @param query - query to create new records from
9120
- */
9121
- insertManyFrom(query) {
9122
- return _queryInsertManyFrom(_clone(this), query);
9123
- }
9124
9301
  /**
9125
9302
  * `defaults` allows setting values that will be used later in `create`.
9126
9303
  *
@@ -10505,9 +10682,9 @@ class Join {
10505
10682
  }
10506
10683
  /**
10507
10684
  * This method may be useful
10508
- * for combining with [createManyFrom](/guide/create-update-delete.html#createmanyfrom-insertmanyfrom).
10685
+ * for combining with [createForEachFrom](/guide/create-update-delete.html#createForEachFrom-insertForEachFrom).
10509
10686
  *
10510
- * `createManyFrom` creates multiple record based on a selecting query:
10687
+ * `createForEachFrom` creates multiple record based on a selecting query:
10511
10688
  *
10512
10689
  * ```sql
10513
10690
  * INSERT INTO t1(c1, c2)
@@ -10521,7 +10698,7 @@ class Join {
10521
10698
  * ```ts
10522
10699
  * const data = [{ column2: 'one' }, { column2: 'two' }, { column2: 'three' }];
10523
10700
  *
10524
- * await db.table.createManyFrom(
10701
+ * await db.table.createForEachFrom(
10525
10702
  * db.otherTable
10526
10703
  * .joinData('data', (t) => ({ column2: t.text() }), data)
10527
10704
  * .select('otherTable.column1', 'data.column2'),
@@ -12618,6 +12795,7 @@ orchidCore.applyMixins(QueryMethods, [
12618
12795
  Union,
12619
12796
  JsonMethods,
12620
12797
  QueryCreate,
12798
+ QueryCreateFrom,
12621
12799
  Update,
12622
12800
  Delete,
12623
12801
  Transaction,
@@ -13307,7 +13485,6 @@ exports.MergeQueryMethods = MergeQueryMethods;
13307
13485
  exports.MoneyColumn = MoneyColumn;
13308
13486
  exports.NumberAsStringBaseColumn = NumberAsStringBaseColumn;
13309
13487
  exports.NumberBaseColumn = NumberBaseColumn;
13310
- exports.OnConflictQueryBuilder = OnConflictQueryBuilder;
13311
13488
  exports.OnMethods = OnMethods;
13312
13489
  exports.Operators = Operators;
13313
13490
  exports.OrExpression = OrExpression;
@@ -13316,7 +13493,6 @@ exports.PointColumn = PointColumn;
13316
13493
  exports.PolygonColumn = PolygonColumn;
13317
13494
  exports.PostgisGeographyPointColumn = PostgisGeographyPointColumn;
13318
13495
  exports.QueryAsMethods = QueryAsMethods;
13319
- exports.QueryCreate = QueryCreate;
13320
13496
  exports.QueryGet = QueryGet;
13321
13497
  exports.QueryHooks = QueryHooks;
13322
13498
  exports.QueryLog = QueryLog;
@@ -13351,6 +13527,7 @@ exports.VirtualColumn = VirtualColumn;
13351
13527
  exports.Where = Where;
13352
13528
  exports.WithMethods = WithMethods;
13353
13529
  exports.XMLColumn = XMLColumn;
13530
+ exports._addWith = _addWith;
13354
13531
  exports._clone = _clone;
13355
13532
  exports._getSelectableColumn = _getSelectableColumn;
13356
13533
  exports._initQueryBuilder = _initQueryBuilder;
@@ -13358,9 +13535,10 @@ exports._queryAfterSaveCommit = _queryAfterSaveCommit;
13358
13535
  exports._queryAll = _queryAll;
13359
13536
  exports._queryChangeCounter = _queryChangeCounter;
13360
13537
  exports._queryCreate = _queryCreate;
13361
- exports._queryCreateFrom = _queryCreateFrom;
13538
+ exports._queryCreateForEachFrom = _queryCreateForEachFrom;
13362
13539
  exports._queryCreateMany = _queryCreateMany;
13363
13540
  exports._queryCreateManyFrom = _queryCreateManyFrom;
13541
+ exports._queryCreateOneFrom = _queryCreateOneFrom;
13364
13542
  exports._queryDefaults = _queryDefaults;
13365
13543
  exports._queryDelete = _queryDelete;
13366
13544
  exports._queryExec = _queryExec;
@@ -13382,9 +13560,10 @@ exports._queryHookBeforeQuery = _queryHookBeforeQuery;
13382
13560
  exports._queryHookBeforeSave = _queryHookBeforeSave;
13383
13561
  exports._queryHookBeforeUpdate = _queryHookBeforeUpdate;
13384
13562
  exports._queryInsert = _queryInsert;
13385
- exports._queryInsertFrom = _queryInsertFrom;
13563
+ exports._queryInsertForEachFrom = _queryInsertForEachFrom;
13386
13564
  exports._queryInsertMany = _queryInsertMany;
13387
13565
  exports._queryInsertManyFrom = _queryInsertManyFrom;
13566
+ exports._queryInsertOneFrom = _queryInsertOneFrom;
13388
13567
  exports._queryJoinOn = _queryJoinOn;
13389
13568
  exports._queryJoinOnJsonPathEquals = _queryJoinOnJsonPathEquals;
13390
13569
  exports._queryJoinOrOn = _queryJoinOrOn;