pqb 0.43.1 → 0.43.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +87 -33
- package/dist/index.js +563 -392
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +564 -393
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExpressionTypeMethod, Expression, RawSQLBase, emptyObject, isTemplateLiteralArgs, ColumnTypeBase, setColumnData, pushColumnData, templateLiteralSQLToCode, quoteObjectKey, toArray, emptyArray, singleQuote, addCode, singleQuoteArray, objectHasValues, toSnakeCase, columnDefaultArgumentToCode, columnErrorMessagesToCode, getValueKey, addValue, isExpression, joinTruthy, stringDataToCode, getDefaultLanguage, dateDataToCode, returnArg as returnArg$1, noop, pushOrNewArrayToObject, arrayDataToCode, numberDataToCode, logColors, applyTransforms, callWithThis, setParserToQuery,
|
|
1
|
+
import { ExpressionTypeMethod, Expression, RawSQLBase, emptyObject, isTemplateLiteralArgs, ColumnTypeBase, setColumnData, pushColumnData, templateLiteralSQLToCode, quoteObjectKey, toArray, emptyArray, singleQuote, addCode, singleQuoteArray, objectHasValues, toSnakeCase, columnDefaultArgumentToCode, columnErrorMessagesToCode, getValueKey, addValue, isExpression, joinTruthy, stringDataToCode, getDefaultLanguage, dateDataToCode, returnArg as returnArg$1, noop, pushOrNewArrayToObject, arrayDataToCode, numberDataToCode, logColors, applyTransforms, callWithThis, setParserToQuery, pushOrNewArray, isRawSQL, setDefaultNowFn, setDefaultLanguage, setCurrentColumnName, makeTimestampsHelpers, setAdapterConnectRetry, isObjectEmpty, ValExpression, applyMixins, snakeCaseKey } from 'orchid-core';
|
|
2
2
|
import pg from 'pg';
|
|
3
3
|
import { inspect } from 'node:util';
|
|
4
4
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
@@ -1245,11 +1245,13 @@ class TextColumn extends TextBaseColumn {
|
|
|
1245
1245
|
return textColumnToCode(this, ctx, key);
|
|
1246
1246
|
}
|
|
1247
1247
|
}
|
|
1248
|
+
const byteaParse = (val) => typeof val === "string" ? Buffer.from(val.slice(2), "hex") : val;
|
|
1248
1249
|
class ByteaColumn extends ColumnType {
|
|
1249
1250
|
constructor(schema) {
|
|
1250
1251
|
super(schema, schema.buffer());
|
|
1251
1252
|
this.dataType = "bytea";
|
|
1252
1253
|
this.operators = Operators.text;
|
|
1254
|
+
setColumnDefaultParse(this, byteaParse);
|
|
1253
1255
|
}
|
|
1254
1256
|
toCode(ctx, key) {
|
|
1255
1257
|
return columnCode(this, ctx, key, `bytea()`);
|
|
@@ -4466,7 +4468,7 @@ function maybeWrappedThen(resolve, reject) {
|
|
|
4466
4468
|
let afterHooks;
|
|
4467
4469
|
let afterCommitHooks;
|
|
4468
4470
|
if (q.type) {
|
|
4469
|
-
if (q.type === "insert") {
|
|
4471
|
+
if (q.type === "insert" || q.type === "upsert") {
|
|
4470
4472
|
beforeHooks = q.beforeCreate;
|
|
4471
4473
|
afterHooks = q.afterCreate;
|
|
4472
4474
|
afterCommitHooks = q.afterCreateCommit;
|
|
@@ -4544,14 +4546,18 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4544
4546
|
if (log) {
|
|
4545
4547
|
logData = log.beforeQuery(sql);
|
|
4546
4548
|
}
|
|
4547
|
-
queryResult = await
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4549
|
+
queryResult = await execQuery(
|
|
4550
|
+
adapter,
|
|
4551
|
+
queryMethodByReturnType[tempReturnType],
|
|
4552
|
+
sql
|
|
4553
|
+
);
|
|
4551
4554
|
if (log) {
|
|
4552
4555
|
log.afterQuery(sql, logData);
|
|
4553
4556
|
sql = void 0;
|
|
4554
4557
|
}
|
|
4558
|
+
if (query.patchResult) {
|
|
4559
|
+
await query.patchResult(q, hookSelect, queryResult);
|
|
4560
|
+
}
|
|
4555
4561
|
result = query.handleResult(q, tempReturnType, queryResult);
|
|
4556
4562
|
} else {
|
|
4557
4563
|
const queryMethod = queryMethodByReturnType[tempReturnType];
|
|
@@ -4565,7 +4571,7 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4565
4571
|
if (log) {
|
|
4566
4572
|
logData = log.beforeQuery(sql);
|
|
4567
4573
|
}
|
|
4568
|
-
const result2 = await adapter
|
|
4574
|
+
const result2 = await execQuery(adapter, queryMethod, sql);
|
|
4569
4575
|
if (queryResult) {
|
|
4570
4576
|
queryResult.rowCount += result2.rowCount;
|
|
4571
4577
|
queryResult.rows.push(...result2.rows);
|
|
@@ -4583,7 +4589,7 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4583
4589
|
if (log) log.afterQuery(commitSql$1, logData);
|
|
4584
4590
|
}
|
|
4585
4591
|
if (query.patchResult) {
|
|
4586
|
-
await query.patchResult(q, queryResult);
|
|
4592
|
+
await query.patchResult(q, hookSelect, queryResult);
|
|
4587
4593
|
}
|
|
4588
4594
|
result = query.handleResult(q, tempReturnType, queryResult);
|
|
4589
4595
|
}
|
|
@@ -4711,6 +4717,17 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4711
4717
|
return reject?.(error);
|
|
4712
4718
|
}
|
|
4713
4719
|
};
|
|
4720
|
+
const execQuery = (adapter, method, sql) => {
|
|
4721
|
+
return adapter[method](sql).then(
|
|
4722
|
+
(result) => {
|
|
4723
|
+
if (result.rowCount && !result.rows.length) {
|
|
4724
|
+
result.rows.length = result.rowCount;
|
|
4725
|
+
result.rows.fill({});
|
|
4726
|
+
}
|
|
4727
|
+
return result;
|
|
4728
|
+
}
|
|
4729
|
+
);
|
|
4730
|
+
};
|
|
4714
4731
|
const assignError = (to, from) => {
|
|
4715
4732
|
to.message = from.message;
|
|
4716
4733
|
to.length = from.length;
|
|
@@ -5650,6 +5667,306 @@ function queryJson(self, coalesce) {
|
|
|
5650
5667
|
return q;
|
|
5651
5668
|
}
|
|
5652
5669
|
|
|
5670
|
+
const MAX_BINDING_PARAMS = 65536;
|
|
5671
|
+
|
|
5672
|
+
const quotedColumns = [];
|
|
5673
|
+
const makeInsertSql = (ctx, q, query, quotedAs) => {
|
|
5674
|
+
const { columns, shape, inCTE } = query;
|
|
5675
|
+
quotedColumns.length = columns.length;
|
|
5676
|
+
for (let i = 0, len = columns.length; i < len; i++) {
|
|
5677
|
+
quotedColumns[i] = `"${shape[columns[i]]?.data.name || columns[i]}"`;
|
|
5678
|
+
}
|
|
5679
|
+
let runtimeDefaults;
|
|
5680
|
+
if (q.internal.runtimeDefaultColumns) {
|
|
5681
|
+
runtimeDefaults = [];
|
|
5682
|
+
for (const key of q.internal.runtimeDefaultColumns) {
|
|
5683
|
+
if (!columns.includes(key)) {
|
|
5684
|
+
const column = shape[key];
|
|
5685
|
+
quotedColumns.push(`"${column.data.name || key}"`);
|
|
5686
|
+
runtimeDefaults.push(column.data.runtimeDefault);
|
|
5687
|
+
}
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5690
|
+
let values = query.values;
|
|
5691
|
+
if (quotedColumns.length === 0) {
|
|
5692
|
+
const key = Object.keys(q.shape)[0];
|
|
5693
|
+
const column = q.shape[key];
|
|
5694
|
+
quotedColumns[0] = `"${column?.data.name || key}"`;
|
|
5695
|
+
if (Array.isArray(values) && Array.isArray(values[0])) {
|
|
5696
|
+
values = values.map(() => [void 0]);
|
|
5697
|
+
}
|
|
5698
|
+
}
|
|
5699
|
+
ctx.sql.push(
|
|
5700
|
+
`INSERT INTO ${quotedAs}(${quotedColumns.join(", ")})`,
|
|
5701
|
+
null
|
|
5702
|
+
);
|
|
5703
|
+
const QueryClass = ctx.queryBuilder.constructor;
|
|
5704
|
+
if (query.onConflict) {
|
|
5705
|
+
ctx.sql.push("ON CONFLICT");
|
|
5706
|
+
const { target } = query.onConflict;
|
|
5707
|
+
if (target) {
|
|
5708
|
+
if (typeof target === "string") {
|
|
5709
|
+
ctx.sql.push(`("${shape[target]?.data.name || target}")`);
|
|
5710
|
+
} else if (Array.isArray(target)) {
|
|
5711
|
+
ctx.sql.push(
|
|
5712
|
+
`(${target.reduce(
|
|
5713
|
+
(sql, item, i) => sql + (i ? ", " : "") + `"${shape[item]?.data.name || item}"`,
|
|
5714
|
+
""
|
|
5715
|
+
)})`
|
|
5716
|
+
);
|
|
5717
|
+
} else if ("toSQL" in target) {
|
|
5718
|
+
ctx.sql.push(target.toSQL(ctx, quotedAs));
|
|
5719
|
+
} else {
|
|
5720
|
+
ctx.sql.push(`ON CONSTRAINT "${target.constraint}"`);
|
|
5721
|
+
}
|
|
5722
|
+
}
|
|
5723
|
+
if ("merge" in query.onConflict) {
|
|
5724
|
+
let sql;
|
|
5725
|
+
const { merge } = query.onConflict;
|
|
5726
|
+
if (merge) {
|
|
5727
|
+
if (typeof merge === "string") {
|
|
5728
|
+
const name = shape[merge]?.data.name || merge;
|
|
5729
|
+
sql = `DO UPDATE SET "${name}" = excluded."${name}"`;
|
|
5730
|
+
} else if ("except" in merge) {
|
|
5731
|
+
sql = mergeColumnsSql(columns, quotedColumns, target, merge.except);
|
|
5732
|
+
} else {
|
|
5733
|
+
sql = `DO UPDATE SET ${merge.reduce((sql2, item, i) => {
|
|
5734
|
+
const name = shape[item]?.data.name || item;
|
|
5735
|
+
return sql2 + (i ? ", " : "") + `"${name}" = excluded."${name}"`;
|
|
5736
|
+
}, "")}`;
|
|
5737
|
+
}
|
|
5738
|
+
} else {
|
|
5739
|
+
sql = mergeColumnsSql(columns, quotedColumns, target);
|
|
5740
|
+
}
|
|
5741
|
+
ctx.sql.push(sql);
|
|
5742
|
+
} else if (query.onConflict.set) {
|
|
5743
|
+
let sql;
|
|
5744
|
+
const { set } = query.onConflict;
|
|
5745
|
+
if (isExpression(set)) {
|
|
5746
|
+
sql = set.toSQL(ctx, quotedAs);
|
|
5747
|
+
} else {
|
|
5748
|
+
const arr = [];
|
|
5749
|
+
for (const key in set) {
|
|
5750
|
+
arr.push(
|
|
5751
|
+
`"${shape[key]?.data.name || key}" = ${addValue(
|
|
5752
|
+
ctx.values,
|
|
5753
|
+
set[key]
|
|
5754
|
+
)}`
|
|
5755
|
+
);
|
|
5756
|
+
}
|
|
5757
|
+
sql = arr.join(", ");
|
|
5758
|
+
}
|
|
5759
|
+
ctx.sql.push("DO UPDATE SET", sql);
|
|
5760
|
+
} else {
|
|
5761
|
+
ctx.sql.push("DO NOTHING");
|
|
5762
|
+
}
|
|
5763
|
+
}
|
|
5764
|
+
pushWhereStatementSql(ctx, q, query, quotedAs);
|
|
5765
|
+
let returning;
|
|
5766
|
+
if (inCTE?.selectNum) {
|
|
5767
|
+
returning = {
|
|
5768
|
+
select: inCTE.returning?.select ? "1, " + inCTE.returning.select : "1",
|
|
5769
|
+
hookSelect: inCTE.returning?.hookSelect
|
|
5770
|
+
};
|
|
5771
|
+
} else {
|
|
5772
|
+
returning = makeReturningSql(ctx, q, query, quotedAs, 2);
|
|
5773
|
+
}
|
|
5774
|
+
if (returning.select) ctx.sql.push("RETURNING", returning.select);
|
|
5775
|
+
if (query.kind === "object") {
|
|
5776
|
+
const valuesSql = [];
|
|
5777
|
+
let ctxValues = ctx.values;
|
|
5778
|
+
const restValuesLen = ctxValues.length;
|
|
5779
|
+
let currentValuesLen = restValuesLen;
|
|
5780
|
+
let batch;
|
|
5781
|
+
for (let i = 0; i < values.length; i++) {
|
|
5782
|
+
let encodedRow = encodeRow(
|
|
5783
|
+
ctx,
|
|
5784
|
+
ctxValues,
|
|
5785
|
+
q,
|
|
5786
|
+
QueryClass,
|
|
5787
|
+
values[i],
|
|
5788
|
+
runtimeDefaults,
|
|
5789
|
+
quotedAs
|
|
5790
|
+
);
|
|
5791
|
+
if (!inCTE) encodedRow = "(" + encodedRow + ")";
|
|
5792
|
+
if (ctxValues.length > MAX_BINDING_PARAMS) {
|
|
5793
|
+
if (ctxValues.length - currentValuesLen > MAX_BINDING_PARAMS) {
|
|
5794
|
+
throw new Error(
|
|
5795
|
+
`Too many parameters for a single insert row, max is ${MAX_BINDING_PARAMS}`
|
|
5796
|
+
);
|
|
5797
|
+
}
|
|
5798
|
+
ctx.sql[1] = (inCTE ? "SELECT " : "VALUES ") + valuesSql.join(", ");
|
|
5799
|
+
ctxValues.length = currentValuesLen;
|
|
5800
|
+
batch = pushOrNewArray(batch, {
|
|
5801
|
+
text: ctx.sql.join(" "),
|
|
5802
|
+
values: ctxValues
|
|
5803
|
+
});
|
|
5804
|
+
ctxValues = ctx.values = [];
|
|
5805
|
+
valuesSql.length = 0;
|
|
5806
|
+
i--;
|
|
5807
|
+
} else {
|
|
5808
|
+
currentValuesLen = ctxValues.length;
|
|
5809
|
+
valuesSql.push(encodedRow);
|
|
5810
|
+
}
|
|
5811
|
+
}
|
|
5812
|
+
if (batch) {
|
|
5813
|
+
ctx.sql[1] = (inCTE ? "SELECT " : "VALUES ") + valuesSql.join(", ");
|
|
5814
|
+
batch.push({
|
|
5815
|
+
text: ctx.sql.join(" "),
|
|
5816
|
+
values: ctxValues
|
|
5817
|
+
});
|
|
5818
|
+
return {
|
|
5819
|
+
hookSelect: returning.hookSelect,
|
|
5820
|
+
batch
|
|
5821
|
+
};
|
|
5822
|
+
} else {
|
|
5823
|
+
ctx.sql[1] = (inCTE ? "SELECT " : "VALUES ") + valuesSql.join(", ");
|
|
5824
|
+
}
|
|
5825
|
+
if (inCTE) {
|
|
5826
|
+
ctx.sql[1] += ' WHERE NOT EXISTS (SELECT 1 FROM "f")';
|
|
5827
|
+
}
|
|
5828
|
+
} else if (query.kind === "raw") {
|
|
5829
|
+
if (isExpression(values)) {
|
|
5830
|
+
let valuesSql = values.toSQL(ctx, quotedAs);
|
|
5831
|
+
if (runtimeDefaults) {
|
|
5832
|
+
valuesSql += `, ${runtimeDefaults.map((fn) => addValue(ctx.values, fn())).join(", ")}`;
|
|
5833
|
+
}
|
|
5834
|
+
ctx.sql[1] = `VALUES (${valuesSql})`;
|
|
5835
|
+
} else {
|
|
5836
|
+
let sql;
|
|
5837
|
+
if (runtimeDefaults) {
|
|
5838
|
+
const { values: v } = ctx;
|
|
5839
|
+
sql = values.map(
|
|
5840
|
+
(raw) => (
|
|
5841
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
5842
|
+
`(${raw.toSQL(ctx, quotedAs)}, ${runtimeDefaults.map((fn) => addValue(v, fn())).join(", ")})`
|
|
5843
|
+
)
|
|
5844
|
+
).join(", ");
|
|
5845
|
+
} else {
|
|
5846
|
+
sql = values.map((raw) => `(${raw.toSQL(ctx, quotedAs)})`).join(", ");
|
|
5847
|
+
}
|
|
5848
|
+
ctx.sql[1] = `VALUES ${sql}`;
|
|
5849
|
+
}
|
|
5850
|
+
} else {
|
|
5851
|
+
const { from, values: v } = values;
|
|
5852
|
+
const q2 = from.clone();
|
|
5853
|
+
if (v) {
|
|
5854
|
+
pushQueryValue(
|
|
5855
|
+
q2,
|
|
5856
|
+
"select",
|
|
5857
|
+
new RawSQL(
|
|
5858
|
+
encodeRow(
|
|
5859
|
+
ctx,
|
|
5860
|
+
ctx.values,
|
|
5861
|
+
q2,
|
|
5862
|
+
QueryClass,
|
|
5863
|
+
v[0],
|
|
5864
|
+
runtimeDefaults,
|
|
5865
|
+
quotedAs
|
|
5866
|
+
)
|
|
5867
|
+
)
|
|
5868
|
+
);
|
|
5869
|
+
}
|
|
5870
|
+
ctx.sql[1] = getSqlText(makeSQL(q2, { values: ctx.values }));
|
|
5871
|
+
}
|
|
5872
|
+
return {
|
|
5873
|
+
hookSelect: returning.hookSelect,
|
|
5874
|
+
text: ctx.sql.join(" "),
|
|
5875
|
+
values: ctx.values
|
|
5876
|
+
};
|
|
5877
|
+
};
|
|
5878
|
+
const mergeColumnsSql = (columns, quotedColumns2, target, except) => {
|
|
5879
|
+
const notExcluded = [];
|
|
5880
|
+
const exclude = typeof target === "string" ? [target] : Array.isArray(target) ? [...target] : [];
|
|
5881
|
+
if (except) {
|
|
5882
|
+
if (typeof except === "string") {
|
|
5883
|
+
exclude.push(except);
|
|
5884
|
+
} else {
|
|
5885
|
+
exclude.push(...except);
|
|
5886
|
+
}
|
|
5887
|
+
}
|
|
5888
|
+
for (let i = 0; i < columns.length; i++) {
|
|
5889
|
+
if (!exclude.includes(columns[i])) {
|
|
5890
|
+
notExcluded.push(quotedColumns2[i]);
|
|
5891
|
+
}
|
|
5892
|
+
}
|
|
5893
|
+
return notExcluded.length ? `DO UPDATE SET ${notExcluded.map((column) => `${column} = excluded.${column}`).join(", ")}` : "DO NOTHING";
|
|
5894
|
+
};
|
|
5895
|
+
const encodeRow = (ctx, values, q, QueryClass, row, runtimeDefaults, quotedAs) => {
|
|
5896
|
+
const arr = row.map((value) => {
|
|
5897
|
+
if (value && typeof value === "object") {
|
|
5898
|
+
if (value instanceof Expression) {
|
|
5899
|
+
return value.toSQL(ctx, quotedAs);
|
|
5900
|
+
} else if (value instanceof QueryClass) {
|
|
5901
|
+
return `(${getSqlText(joinSubQuery(q, value).toSQL(ctx))})`;
|
|
5902
|
+
}
|
|
5903
|
+
}
|
|
5904
|
+
return value === void 0 ? "DEFAULT" : addValue(values, value);
|
|
5905
|
+
});
|
|
5906
|
+
if (runtimeDefaults) {
|
|
5907
|
+
for (const fn of runtimeDefaults) {
|
|
5908
|
+
arr.push(addValue(values, fn()));
|
|
5909
|
+
}
|
|
5910
|
+
}
|
|
5911
|
+
return arr.join(", ");
|
|
5912
|
+
};
|
|
5913
|
+
const hookSelectKeys = [
|
|
5914
|
+
null,
|
|
5915
|
+
"afterUpdateSelect",
|
|
5916
|
+
"afterCreateSelect",
|
|
5917
|
+
"afterDeleteSelect"
|
|
5918
|
+
];
|
|
5919
|
+
const makeReturningSql = (ctx, q, data, quotedAs, hookSelectI, addHookSelectI) => {
|
|
5920
|
+
if (data.inCTE) {
|
|
5921
|
+
if (hookSelectI !== 2) {
|
|
5922
|
+
const returning = makeReturningSql(
|
|
5923
|
+
ctx,
|
|
5924
|
+
q,
|
|
5925
|
+
data,
|
|
5926
|
+
quotedAs,
|
|
5927
|
+
2,
|
|
5928
|
+
hookSelectI
|
|
5929
|
+
);
|
|
5930
|
+
if (returning.hookSelect) {
|
|
5931
|
+
for (const [key, value] of returning.hookSelect) {
|
|
5932
|
+
data.inCTE.targetHookSelect.set(key, value);
|
|
5933
|
+
}
|
|
5934
|
+
}
|
|
5935
|
+
return data.inCTE.returning = returning;
|
|
5936
|
+
}
|
|
5937
|
+
if (data.inCTE.returning) {
|
|
5938
|
+
return data.inCTE.returning;
|
|
5939
|
+
}
|
|
5940
|
+
}
|
|
5941
|
+
const hookSelect = hookSelectI && data[hookSelectKeys[hookSelectI]];
|
|
5942
|
+
const { select } = data;
|
|
5943
|
+
if (!q.q.hookSelect && !hookSelect?.size && !select?.length && !addHookSelectI) {
|
|
5944
|
+
return { hookSelect: hookSelect && /* @__PURE__ */ new Map() };
|
|
5945
|
+
}
|
|
5946
|
+
const otherCTEHookSelect = addHookSelectI && data[hookSelectKeys[addHookSelectI]];
|
|
5947
|
+
let tempSelect;
|
|
5948
|
+
if (q.q.hookSelect || hookSelect || otherCTEHookSelect) {
|
|
5949
|
+
tempSelect = new Map(q.q.hookSelect);
|
|
5950
|
+
if (hookSelect) {
|
|
5951
|
+
for (const column of hookSelect) {
|
|
5952
|
+
tempSelect.set(column, { select: column });
|
|
5953
|
+
}
|
|
5954
|
+
}
|
|
5955
|
+
if (otherCTEHookSelect) {
|
|
5956
|
+
for (const column of otherCTEHookSelect) {
|
|
5957
|
+
tempSelect.set(column, { select: column });
|
|
5958
|
+
}
|
|
5959
|
+
}
|
|
5960
|
+
}
|
|
5961
|
+
let sql;
|
|
5962
|
+
if (tempSelect?.size || select?.length) {
|
|
5963
|
+
sql = selectToSql(ctx, q, data, quotedAs, tempSelect, void 0, true);
|
|
5964
|
+
} else if (addHookSelectI) {
|
|
5965
|
+
sql = "1";
|
|
5966
|
+
}
|
|
5967
|
+
return { select: sql, hookSelect: tempSelect };
|
|
5968
|
+
};
|
|
5969
|
+
|
|
5653
5970
|
const pushSelectSql = (ctx, table, query, quotedAs, aliases) => {
|
|
5654
5971
|
const sql = selectToSql(
|
|
5655
5972
|
ctx,
|
|
@@ -5661,7 +5978,16 @@ const pushSelectSql = (ctx, table, query, quotedAs, aliases) => {
|
|
|
5661
5978
|
);
|
|
5662
5979
|
if (sql) ctx.sql.push(sql);
|
|
5663
5980
|
};
|
|
5664
|
-
const selectToSql = (ctx, table, query, quotedAs, hookSelect = query.hookSelect, aliases) => {
|
|
5981
|
+
const selectToSql = (ctx, table, query, quotedAs, hookSelect = query.hookSelect, aliases, skipCTE) => {
|
|
5982
|
+
if (query.inCTE && !skipCTE) {
|
|
5983
|
+
const { select } = makeReturningSql(
|
|
5984
|
+
ctx,
|
|
5985
|
+
table,
|
|
5986
|
+
query,
|
|
5987
|
+
quotedAs
|
|
5988
|
+
);
|
|
5989
|
+
return query.inCTE.selectNum ? select ? "0, " + select : "0" : select || "";
|
|
5990
|
+
}
|
|
5665
5991
|
let selected;
|
|
5666
5992
|
const list = [];
|
|
5667
5993
|
if (query.select) {
|
|
@@ -6005,371 +6331,116 @@ const pushFromAndAs = (ctx, table, data, quotedAs) => {
|
|
|
6005
6331
|
let fn;
|
|
6006
6332
|
let query;
|
|
6007
6333
|
if ("query" in source) {
|
|
6008
|
-
fn = "websearch_to_tsquery";
|
|
6009
|
-
query = source.query;
|
|
6010
|
-
} else if ("plainQuery" in source) {
|
|
6011
|
-
fn = "plainto_tsquery";
|
|
6012
|
-
query = source.plainQuery;
|
|
6013
|
-
} else if ("phraseQuery" in source) {
|
|
6014
|
-
fn = "phraseto_tsquery";
|
|
6015
|
-
query = source.phraseQuery;
|
|
6016
|
-
} else {
|
|
6017
|
-
fn = "to_tsquery";
|
|
6018
|
-
query = source.tsQuery;
|
|
6019
|
-
}
|
|
6020
|
-
let querySql;
|
|
6021
|
-
if (typeof query === "string") {
|
|
6022
|
-
ctx.values.push(query);
|
|
6023
|
-
querySql = `$${ctx.values.length}`;
|
|
6024
|
-
} else {
|
|
6025
|
-
querySql = `${query.toSQL(ctx, quotedAs)}`;
|
|
6026
|
-
}
|
|
6027
|
-
sql += `, ${fn}(${lang}, ${querySql}) "${as}"`;
|
|
6028
|
-
}
|
|
6029
|
-
ctx.sql.push(sql);
|
|
6030
|
-
};
|
|
6031
|
-
const getFrom = (ctx, table, data, quotedAs) => {
|
|
6032
|
-
if (data.from) {
|
|
6033
|
-
const { from } = data;
|
|
6034
|
-
if (Array.isArray(from)) {
|
|
6035
|
-
return from.map((item) => fromToSql(ctx, data, item, quotedAs)).join(", ");
|
|
6036
|
-
}
|
|
6037
|
-
return fromToSql(ctx, data, from, quotedAs);
|
|
6038
|
-
}
|
|
6039
|
-
let sql = quoteSchemaAndTable(data.schema, table.table);
|
|
6040
|
-
if (data.only) sql = `ONLY ${sql}`;
|
|
6041
|
-
return sql;
|
|
6042
|
-
};
|
|
6043
|
-
const fromToSql = (ctx, data, from, quotedAs) => {
|
|
6044
|
-
let only;
|
|
6045
|
-
let sql;
|
|
6046
|
-
if (typeof from === "object") {
|
|
6047
|
-
if (isExpression(from)) {
|
|
6048
|
-
sql = from.toSQL(ctx, quotedAs);
|
|
6049
|
-
} else {
|
|
6050
|
-
only = from.q.only;
|
|
6051
|
-
if (!from.table) {
|
|
6052
|
-
sql = `(${getSqlText(makeSQL(from, ctx))})`;
|
|
6053
|
-
} else if (!checkIfASimpleQuery(from)) {
|
|
6054
|
-
sql = `(${getSqlText(makeSQL(from, ctx))})`;
|
|
6055
|
-
} else {
|
|
6056
|
-
sql = quoteSchemaAndTable(from.q.schema, from.table);
|
|
6057
|
-
}
|
|
6058
|
-
}
|
|
6059
|
-
} else {
|
|
6060
|
-
sql = quoteSchemaAndTable(data.schema, from);
|
|
6061
|
-
}
|
|
6062
|
-
return (only === void 0 ? data.only : only) ? `ONLY ${sql}` : sql;
|
|
6063
|
-
};
|
|
6064
|
-
const getSearchLang = (ctx, data, source, quotedAs) => {
|
|
6065
|
-
return source.langSQL ?? (source.langSQL = "languageColumn" in source ? columnToSql(ctx, data, data.shape, source.languageColumn, quotedAs) : isRawSQL(source.language) ? source.language.toSQL(ctx) : addValue(ctx.values, source.language || data.language || "english"));
|
|
6066
|
-
};
|
|
6067
|
-
const getSearchText = (ctx, data, source, quotedAs, forHeadline) => {
|
|
6068
|
-
let sql = source.textSQL;
|
|
6069
|
-
if (sql) return sql;
|
|
6070
|
-
if ("in" in source) {
|
|
6071
|
-
if (typeof source.in === "string") {
|
|
6072
|
-
sql = columnToSql(ctx, data, data.shape, source.in, quotedAs);
|
|
6073
|
-
} else if (Array.isArray(source.in)) {
|
|
6074
|
-
sql = `concat_ws(' ', ${source.in.map((column) => columnToSql(ctx, data, data.shape, column, quotedAs)).join(", ")})`;
|
|
6075
|
-
} else {
|
|
6076
|
-
sql = [];
|
|
6077
|
-
for (const key in source.in) {
|
|
6078
|
-
sql.push(columnToSql(ctx, data, data.shape, key, quotedAs));
|
|
6079
|
-
}
|
|
6080
|
-
}
|
|
6081
|
-
} else if ("vector" in source) {
|
|
6082
|
-
if (forHeadline) {
|
|
6083
|
-
throw new Error(
|
|
6084
|
-
"Cannot use a search based on a vector column for a search headline"
|
|
6085
|
-
);
|
|
6086
|
-
}
|
|
6087
|
-
sql = columnToSql(ctx, data, data.shape, source.vector, quotedAs);
|
|
6088
|
-
} else {
|
|
6089
|
-
if (typeof source.text === "string") {
|
|
6090
|
-
sql = addValue(ctx.values, source.text);
|
|
6091
|
-
} else {
|
|
6092
|
-
sql = source.text.toSQL(ctx, quotedAs);
|
|
6093
|
-
}
|
|
6094
|
-
}
|
|
6095
|
-
return source.textSQL = sql;
|
|
6096
|
-
};
|
|
6097
|
-
const getTsVector = (ctx, data, lang, source, quotedAs) => {
|
|
6098
|
-
const text = getSearchText(ctx, data, source, quotedAs);
|
|
6099
|
-
if ("in" in source) {
|
|
6100
|
-
if (typeof source.in === "string" || Array.isArray(source.in)) {
|
|
6101
|
-
return `to_tsvector(${lang}, ${text})`;
|
|
6102
|
-
} else {
|
|
6103
|
-
let tsVector = "";
|
|
6104
|
-
let i = 0;
|
|
6105
|
-
for (const key in source.in) {
|
|
6106
|
-
tsVector = (tsVector ? `${tsVector} || ` : "") + `setweight(to_tsvector(${lang}, ${text[i++]}), ${addValue(
|
|
6107
|
-
ctx.values,
|
|
6108
|
-
source.in[key]
|
|
6109
|
-
)})`;
|
|
6110
|
-
}
|
|
6111
|
-
return tsVector;
|
|
6112
|
-
}
|
|
6113
|
-
} else if ("vector" in source) {
|
|
6114
|
-
return text;
|
|
6115
|
-
} else {
|
|
6116
|
-
return `to_tsvector(${lang}, ${text})`;
|
|
6117
|
-
}
|
|
6118
|
-
};
|
|
6119
|
-
|
|
6120
|
-
const MAX_BINDING_PARAMS = 65536;
|
|
6121
|
-
|
|
6122
|
-
const quotedColumns = [];
|
|
6123
|
-
const makeInsertSql = (ctx, q, query, quotedAs) => {
|
|
6124
|
-
const { columns, shape } = query;
|
|
6125
|
-
quotedColumns.length = columns.length;
|
|
6126
|
-
for (let i = 0, len = columns.length; i < len; i++) {
|
|
6127
|
-
quotedColumns[i] = `"${shape[columns[i]]?.data.name || columns[i]}"`;
|
|
6128
|
-
}
|
|
6129
|
-
let runtimeDefaults;
|
|
6130
|
-
if (q.internal.runtimeDefaultColumns) {
|
|
6131
|
-
runtimeDefaults = [];
|
|
6132
|
-
for (const key of q.internal.runtimeDefaultColumns) {
|
|
6133
|
-
if (!columns.includes(key)) {
|
|
6134
|
-
const column = shape[key];
|
|
6135
|
-
quotedColumns.push(`"${column.data.name || key}"`);
|
|
6136
|
-
runtimeDefaults.push(column.data.runtimeDefault);
|
|
6137
|
-
}
|
|
6138
|
-
}
|
|
6139
|
-
}
|
|
6140
|
-
let values = query.values;
|
|
6141
|
-
if (quotedColumns.length === 0) {
|
|
6142
|
-
const key = Object.keys(q.shape)[0];
|
|
6143
|
-
const column = q.shape[key];
|
|
6144
|
-
quotedColumns[0] = `"${column?.data.name || key}"`;
|
|
6145
|
-
if (Array.isArray(values) && Array.isArray(values[0])) {
|
|
6146
|
-
values = values.map(() => [void 0]);
|
|
6147
|
-
}
|
|
6148
|
-
}
|
|
6149
|
-
ctx.sql.push(
|
|
6150
|
-
`INSERT INTO ${quotedAs}(${quotedColumns.join(", ")})`,
|
|
6151
|
-
null
|
|
6152
|
-
);
|
|
6153
|
-
const QueryClass = ctx.queryBuilder.constructor;
|
|
6154
|
-
if (query.onConflict) {
|
|
6155
|
-
ctx.sql.push("ON CONFLICT");
|
|
6156
|
-
const { target } = query.onConflict;
|
|
6157
|
-
if (target) {
|
|
6158
|
-
if (typeof target === "string") {
|
|
6159
|
-
ctx.sql.push(`("${shape[target]?.data.name || target}")`);
|
|
6160
|
-
} else if (Array.isArray(target)) {
|
|
6161
|
-
ctx.sql.push(
|
|
6162
|
-
`(${target.reduce(
|
|
6163
|
-
(sql, item, i) => sql + (i ? ", " : "") + `"${shape[item]?.data.name || item}"`,
|
|
6164
|
-
""
|
|
6165
|
-
)})`
|
|
6166
|
-
);
|
|
6167
|
-
} else if ("toSQL" in target) {
|
|
6168
|
-
ctx.sql.push(target.toSQL(ctx, quotedAs));
|
|
6169
|
-
} else {
|
|
6170
|
-
ctx.sql.push(`ON CONSTRAINT "${target.constraint}"`);
|
|
6171
|
-
}
|
|
6172
|
-
}
|
|
6173
|
-
if ("merge" in query.onConflict) {
|
|
6174
|
-
let sql;
|
|
6175
|
-
const { merge } = query.onConflict;
|
|
6176
|
-
if (merge) {
|
|
6177
|
-
if (typeof merge === "string") {
|
|
6178
|
-
const name = shape[merge]?.data.name || merge;
|
|
6179
|
-
sql = `DO UPDATE SET "${name}" = excluded."${name}"`;
|
|
6180
|
-
} else if ("except" in merge) {
|
|
6181
|
-
sql = mergeColumnsSql(columns, quotedColumns, target, merge.except);
|
|
6182
|
-
} else {
|
|
6183
|
-
sql = `DO UPDATE SET ${merge.reduce((sql2, item, i) => {
|
|
6184
|
-
const name = shape[item]?.data.name || item;
|
|
6185
|
-
return sql2 + (i ? ", " : "") + `"${name}" = excluded."${name}"`;
|
|
6186
|
-
}, "")}`;
|
|
6187
|
-
}
|
|
6188
|
-
} else {
|
|
6189
|
-
sql = mergeColumnsSql(columns, quotedColumns, target);
|
|
6190
|
-
}
|
|
6191
|
-
ctx.sql.push(sql);
|
|
6192
|
-
} else if (query.onConflict.set) {
|
|
6193
|
-
let sql;
|
|
6194
|
-
const { set } = query.onConflict;
|
|
6195
|
-
if (isExpression(set)) {
|
|
6196
|
-
sql = set.toSQL(ctx, quotedAs);
|
|
6197
|
-
} else {
|
|
6198
|
-
const arr = [];
|
|
6199
|
-
for (const key in set) {
|
|
6200
|
-
arr.push(
|
|
6201
|
-
`"${shape[key]?.data.name || key}" = ${addValue(
|
|
6202
|
-
ctx.values,
|
|
6203
|
-
set[key]
|
|
6204
|
-
)}`
|
|
6205
|
-
);
|
|
6206
|
-
}
|
|
6207
|
-
sql = arr.join(", ");
|
|
6208
|
-
}
|
|
6209
|
-
ctx.sql.push("DO UPDATE SET", sql);
|
|
6334
|
+
fn = "websearch_to_tsquery";
|
|
6335
|
+
query = source.query;
|
|
6336
|
+
} else if ("plainQuery" in source) {
|
|
6337
|
+
fn = "plainto_tsquery";
|
|
6338
|
+
query = source.plainQuery;
|
|
6339
|
+
} else if ("phraseQuery" in source) {
|
|
6340
|
+
fn = "phraseto_tsquery";
|
|
6341
|
+
query = source.phraseQuery;
|
|
6210
6342
|
} else {
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
}
|
|
6214
|
-
pushWhereStatementSql(ctx, q, query, quotedAs);
|
|
6215
|
-
const hookSelect = pushReturningSql(
|
|
6216
|
-
ctx,
|
|
6217
|
-
q,
|
|
6218
|
-
query,
|
|
6219
|
-
quotedAs,
|
|
6220
|
-
query.afterCreateSelect
|
|
6221
|
-
);
|
|
6222
|
-
if (query.kind === "object") {
|
|
6223
|
-
const valuesSql = [];
|
|
6224
|
-
let ctxValues = ctx.values;
|
|
6225
|
-
const restValuesLen = ctxValues.length;
|
|
6226
|
-
let currentValuesLen = restValuesLen;
|
|
6227
|
-
let batch;
|
|
6228
|
-
for (let i = 0; i < values.length; i++) {
|
|
6229
|
-
const encodedRow = `(${encodeRow(
|
|
6230
|
-
ctx,
|
|
6231
|
-
ctxValues,
|
|
6232
|
-
q,
|
|
6233
|
-
QueryClass,
|
|
6234
|
-
values[i],
|
|
6235
|
-
runtimeDefaults,
|
|
6236
|
-
quotedAs
|
|
6237
|
-
)})`;
|
|
6238
|
-
if (ctxValues.length > MAX_BINDING_PARAMS) {
|
|
6239
|
-
if (ctxValues.length - currentValuesLen > MAX_BINDING_PARAMS) {
|
|
6240
|
-
throw new Error(
|
|
6241
|
-
`Too many parameters for a single insert row, max is ${MAX_BINDING_PARAMS}`
|
|
6242
|
-
);
|
|
6243
|
-
}
|
|
6244
|
-
ctx.sql[1] = `VALUES ${valuesSql.join(",")}`;
|
|
6245
|
-
ctxValues.length = currentValuesLen;
|
|
6246
|
-
batch = pushOrNewArray(batch, {
|
|
6247
|
-
text: ctx.sql.join(" "),
|
|
6248
|
-
values: ctxValues
|
|
6249
|
-
});
|
|
6250
|
-
ctxValues = ctx.values = [];
|
|
6251
|
-
valuesSql.length = 0;
|
|
6252
|
-
i--;
|
|
6253
|
-
} else {
|
|
6254
|
-
currentValuesLen = ctxValues.length;
|
|
6255
|
-
valuesSql.push(encodedRow);
|
|
6256
|
-
}
|
|
6343
|
+
fn = "to_tsquery";
|
|
6344
|
+
query = source.tsQuery;
|
|
6257
6345
|
}
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
values: ctxValues
|
|
6263
|
-
});
|
|
6264
|
-
return {
|
|
6265
|
-
hookSelect,
|
|
6266
|
-
batch
|
|
6267
|
-
};
|
|
6346
|
+
let querySql;
|
|
6347
|
+
if (typeof query === "string") {
|
|
6348
|
+
ctx.values.push(query);
|
|
6349
|
+
querySql = `$${ctx.values.length}`;
|
|
6268
6350
|
} else {
|
|
6269
|
-
|
|
6351
|
+
querySql = `${query.toSQL(ctx, quotedAs)}`;
|
|
6270
6352
|
}
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6353
|
+
sql += `, ${fn}(${lang}, ${querySql}) "${as}"`;
|
|
6354
|
+
}
|
|
6355
|
+
ctx.sql.push(sql);
|
|
6356
|
+
};
|
|
6357
|
+
const getFrom = (ctx, table, data, quotedAs) => {
|
|
6358
|
+
if (data.from) {
|
|
6359
|
+
const { from } = data;
|
|
6360
|
+
if (Array.isArray(from)) {
|
|
6361
|
+
return from.map((item) => fromToSql(ctx, data, item, quotedAs)).join(", ");
|
|
6362
|
+
}
|
|
6363
|
+
return fromToSql(ctx, data, from, quotedAs);
|
|
6364
|
+
}
|
|
6365
|
+
let sql = quoteSchemaAndTable(data.schema, table.table);
|
|
6366
|
+
if (data.only) sql = `ONLY ${sql}`;
|
|
6367
|
+
return sql;
|
|
6368
|
+
};
|
|
6369
|
+
const fromToSql = (ctx, data, from, quotedAs) => {
|
|
6370
|
+
let only;
|
|
6371
|
+
let sql;
|
|
6372
|
+
if (typeof from === "object") {
|
|
6373
|
+
if (isExpression(from)) {
|
|
6374
|
+
sql = from.toSQL(ctx, quotedAs);
|
|
6278
6375
|
} else {
|
|
6279
|
-
|
|
6280
|
-
if (
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
6285
|
-
`(${raw.toSQL(ctx, quotedAs)}, ${runtimeDefaults.map((fn) => addValue(v, fn())).join(", ")})`
|
|
6286
|
-
)
|
|
6287
|
-
).join(", ");
|
|
6376
|
+
only = from.q.only;
|
|
6377
|
+
if (!from.table) {
|
|
6378
|
+
sql = `(${getSqlText(makeSQL(from, ctx))})`;
|
|
6379
|
+
} else if (!checkIfASimpleQuery(from)) {
|
|
6380
|
+
sql = `(${getSqlText(makeSQL(from, ctx))})`;
|
|
6288
6381
|
} else {
|
|
6289
|
-
sql =
|
|
6382
|
+
sql = quoteSchemaAndTable(from.q.schema, from.table);
|
|
6290
6383
|
}
|
|
6291
|
-
ctx.sql[1] = `VALUES ${sql}`;
|
|
6292
6384
|
}
|
|
6293
6385
|
} else {
|
|
6294
|
-
|
|
6295
|
-
const q2 = from.clone();
|
|
6296
|
-
if (v) {
|
|
6297
|
-
pushQueryValue(
|
|
6298
|
-
q2,
|
|
6299
|
-
"select",
|
|
6300
|
-
new RawSQL(
|
|
6301
|
-
encodeRow(
|
|
6302
|
-
ctx,
|
|
6303
|
-
ctx.values,
|
|
6304
|
-
q2,
|
|
6305
|
-
QueryClass,
|
|
6306
|
-
v[0],
|
|
6307
|
-
runtimeDefaults,
|
|
6308
|
-
quotedAs
|
|
6309
|
-
)
|
|
6310
|
-
)
|
|
6311
|
-
);
|
|
6312
|
-
}
|
|
6313
|
-
ctx.sql[1] = getSqlText(makeSQL(q2, { values: ctx.values }));
|
|
6386
|
+
sql = quoteSchemaAndTable(data.schema, from);
|
|
6314
6387
|
}
|
|
6315
|
-
return {
|
|
6316
|
-
hookSelect,
|
|
6317
|
-
text: ctx.sql.join(" "),
|
|
6318
|
-
values: ctx.values
|
|
6319
|
-
};
|
|
6388
|
+
return (only === void 0 ? data.only : only) ? `ONLY ${sql}` : sql;
|
|
6320
6389
|
};
|
|
6321
|
-
const
|
|
6322
|
-
|
|
6323
|
-
const exclude = typeof target === "string" ? [target] : Array.isArray(target) ? [...target] : [];
|
|
6324
|
-
if (except) {
|
|
6325
|
-
if (typeof except === "string") {
|
|
6326
|
-
exclude.push(except);
|
|
6327
|
-
} else {
|
|
6328
|
-
exclude.push(...except);
|
|
6329
|
-
}
|
|
6330
|
-
}
|
|
6331
|
-
for (let i = 0; i < columns.length; i++) {
|
|
6332
|
-
if (!exclude.includes(columns[i])) {
|
|
6333
|
-
notExcluded.push(quotedColumns2[i]);
|
|
6334
|
-
}
|
|
6335
|
-
}
|
|
6336
|
-
return notExcluded.length ? `DO UPDATE SET ${notExcluded.map((column) => `${column} = excluded.${column}`).join(", ")}` : "DO NOTHING";
|
|
6390
|
+
const getSearchLang = (ctx, data, source, quotedAs) => {
|
|
6391
|
+
return source.langSQL ?? (source.langSQL = "languageColumn" in source ? columnToSql(ctx, data, data.shape, source.languageColumn, quotedAs) : isRawSQL(source.language) ? source.language.toSQL(ctx) : addValue(ctx.values, source.language || data.language || "english"));
|
|
6337
6392
|
};
|
|
6338
|
-
const
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6393
|
+
const getSearchText = (ctx, data, source, quotedAs, forHeadline) => {
|
|
6394
|
+
let sql = source.textSQL;
|
|
6395
|
+
if (sql) return sql;
|
|
6396
|
+
if ("in" in source) {
|
|
6397
|
+
if (typeof source.in === "string") {
|
|
6398
|
+
sql = columnToSql(ctx, data, data.shape, source.in, quotedAs);
|
|
6399
|
+
} else if (Array.isArray(source.in)) {
|
|
6400
|
+
sql = `concat_ws(' ', ${source.in.map((column) => columnToSql(ctx, data, data.shape, column, quotedAs)).join(", ")})`;
|
|
6401
|
+
} else {
|
|
6402
|
+
sql = [];
|
|
6403
|
+
for (const key in source.in) {
|
|
6404
|
+
sql.push(columnToSql(ctx, data, data.shape, key, quotedAs));
|
|
6345
6405
|
}
|
|
6346
6406
|
}
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6407
|
+
} else if ("vector" in source) {
|
|
6408
|
+
if (forHeadline) {
|
|
6409
|
+
throw new Error(
|
|
6410
|
+
"Cannot use a search based on a vector column for a search headline"
|
|
6411
|
+
);
|
|
6412
|
+
}
|
|
6413
|
+
sql = columnToSql(ctx, data, data.shape, source.vector, quotedAs);
|
|
6414
|
+
} else {
|
|
6415
|
+
if (typeof source.text === "string") {
|
|
6416
|
+
sql = addValue(ctx.values, source.text);
|
|
6417
|
+
} else {
|
|
6418
|
+
sql = source.text.toSQL(ctx, quotedAs);
|
|
6352
6419
|
}
|
|
6353
6420
|
}
|
|
6354
|
-
return
|
|
6421
|
+
return source.textSQL = sql;
|
|
6355
6422
|
};
|
|
6356
|
-
const
|
|
6357
|
-
const
|
|
6358
|
-
if (
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6423
|
+
const getTsVector = (ctx, data, lang, source, quotedAs) => {
|
|
6424
|
+
const text = getSearchText(ctx, data, source, quotedAs);
|
|
6425
|
+
if ("in" in source) {
|
|
6426
|
+
if (typeof source.in === "string" || Array.isArray(source.in)) {
|
|
6427
|
+
return `to_tsvector(${lang}, ${text})`;
|
|
6428
|
+
} else {
|
|
6429
|
+
let tsVector = "";
|
|
6430
|
+
let i = 0;
|
|
6431
|
+
for (const key in source.in) {
|
|
6432
|
+
tsVector = (tsVector ? `${tsVector} || ` : "") + `setweight(to_tsvector(${lang}, ${text[i++]}), ${addValue(
|
|
6433
|
+
ctx.values,
|
|
6434
|
+
source.in[key]
|
|
6435
|
+
)})`;
|
|
6365
6436
|
}
|
|
6437
|
+
return tsVector;
|
|
6366
6438
|
}
|
|
6367
|
-
|
|
6368
|
-
return
|
|
6369
|
-
} else
|
|
6370
|
-
|
|
6439
|
+
} else if ("vector" in source) {
|
|
6440
|
+
return text;
|
|
6441
|
+
} else {
|
|
6442
|
+
return `to_tsvector(${lang}, ${text})`;
|
|
6371
6443
|
}
|
|
6372
|
-
return;
|
|
6373
6444
|
};
|
|
6374
6445
|
|
|
6375
6446
|
const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
@@ -6380,12 +6451,11 @@ const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
|
6380
6451
|
if (!query.select) {
|
|
6381
6452
|
query.select = countSelect;
|
|
6382
6453
|
}
|
|
6383
|
-
const hookSelect =
|
|
6454
|
+
const hookSelect = pushUpdateReturning(
|
|
6384
6455
|
ctx,
|
|
6385
6456
|
table,
|
|
6386
6457
|
query,
|
|
6387
6458
|
quotedAs,
|
|
6388
|
-
query.afterUpdateSelect,
|
|
6389
6459
|
"SELECT"
|
|
6390
6460
|
);
|
|
6391
6461
|
ctx.sql.push(`FROM ${quotedTable}`);
|
|
@@ -6400,7 +6470,21 @@ const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
|
6400
6470
|
ctx.sql.push("SET");
|
|
6401
6471
|
ctx.sql.push(set.join(", "));
|
|
6402
6472
|
pushWhereStatementSql(ctx, table, query, quotedAs);
|
|
6403
|
-
return
|
|
6473
|
+
return pushUpdateReturning(ctx, table, query, quotedAs, "RETURNING");
|
|
6474
|
+
};
|
|
6475
|
+
const pushUpdateReturning = (ctx, table, query, quotedAs, keyword) => {
|
|
6476
|
+
const { inCTE } = query;
|
|
6477
|
+
const { select, hookSelect } = makeReturningSql(
|
|
6478
|
+
ctx,
|
|
6479
|
+
table,
|
|
6480
|
+
query,
|
|
6481
|
+
quotedAs,
|
|
6482
|
+
1,
|
|
6483
|
+
inCTE && 2
|
|
6484
|
+
);
|
|
6485
|
+
const s = inCTE?.selectNum ? select ? "0, " + select : "0" : select;
|
|
6486
|
+
if (s) ctx.sql.push(keyword, s);
|
|
6487
|
+
return hookSelect;
|
|
6404
6488
|
};
|
|
6405
6489
|
const processData = (ctx, table, set, data, quotedAs) => {
|
|
6406
6490
|
let append;
|
|
@@ -6483,7 +6567,9 @@ const pushDeleteSql = (ctx, table, query, quotedAs) => {
|
|
|
6483
6567
|
ctx.sql.push("WHERE", conditions);
|
|
6484
6568
|
}
|
|
6485
6569
|
}
|
|
6486
|
-
|
|
6570
|
+
const returning = makeReturningSql(ctx, table, query, quotedAs, 3);
|
|
6571
|
+
if (returning.select) ctx.sql.push("RETURNING", returning.select);
|
|
6572
|
+
return returning.hookSelect;
|
|
6487
6573
|
};
|
|
6488
6574
|
|
|
6489
6575
|
const pushTruncateSql = (ctx, table, query) => {
|
|
@@ -6562,7 +6648,7 @@ const makeSQL = (table, options) => {
|
|
|
6562
6648
|
if (query.with) {
|
|
6563
6649
|
pushWithSql(ctx, query.with);
|
|
6564
6650
|
}
|
|
6565
|
-
if (query.type) {
|
|
6651
|
+
if (query.type && query.type !== "upsert") {
|
|
6566
6652
|
const tableName = table.table ?? query.as;
|
|
6567
6653
|
if (!tableName) throw new Error(`Table is missing for ${query.type}`);
|
|
6568
6654
|
if (query.type === "truncate") {
|
|
@@ -6598,10 +6684,11 @@ const makeSQL = (table, options) => {
|
|
|
6598
6684
|
}
|
|
6599
6685
|
const quotedAs = (query.as || table.table) && `"${query.as || table.table}"`;
|
|
6600
6686
|
if (query.union) {
|
|
6601
|
-
|
|
6687
|
+
const s = getSqlText(makeSQL(query.union.b, { values }));
|
|
6688
|
+
sql.push(query.union.p ? s : `(${s})`);
|
|
6602
6689
|
for (const u of query.union.u) {
|
|
6603
|
-
const
|
|
6604
|
-
sql.push(`${u.k}
|
|
6690
|
+
const s2 = isExpression(u.a) ? u.a.toSQL(ctx, quotedAs) : getSqlText(makeSQL(u.a, { values }));
|
|
6691
|
+
sql.push(`${u.k} ${u.p ? s2 : "(" + s2 + ")"}`);
|
|
6605
6692
|
}
|
|
6606
6693
|
} else {
|
|
6607
6694
|
sql.push("SELECT");
|
|
@@ -9987,12 +10074,13 @@ class MergeQueryMethods {
|
|
|
9987
10074
|
}
|
|
9988
10075
|
}
|
|
9989
10076
|
|
|
9990
|
-
const _queryUnion = (base, args, k) => {
|
|
10077
|
+
const _queryUnion = (base, args, k, p, m) => {
|
|
9991
10078
|
const q = base.baseQuery.clone();
|
|
9992
10079
|
const u = args.map(
|
|
9993
10080
|
(a) => ({
|
|
9994
10081
|
a: typeof a === "function" ? a(q) : a,
|
|
9995
|
-
k
|
|
10082
|
+
k,
|
|
10083
|
+
m
|
|
9996
10084
|
})
|
|
9997
10085
|
);
|
|
9998
10086
|
const union = q.q.union = base.q.union;
|
|
@@ -10001,7 +10089,8 @@ const _queryUnion = (base, args, k) => {
|
|
|
10001
10089
|
} else {
|
|
10002
10090
|
q.q.union = {
|
|
10003
10091
|
b: base,
|
|
10004
|
-
u
|
|
10092
|
+
u,
|
|
10093
|
+
p
|
|
10005
10094
|
};
|
|
10006
10095
|
}
|
|
10007
10096
|
return q;
|
|
@@ -10279,7 +10368,7 @@ const _queryUpdate = (query, arg) => {
|
|
|
10279
10368
|
}
|
|
10280
10369
|
const { queries } = ctx;
|
|
10281
10370
|
if (queries) {
|
|
10282
|
-
q.patchResult = async (_, queryResult) => {
|
|
10371
|
+
q.patchResult = async (_, _h, queryResult) => {
|
|
10283
10372
|
await Promise.all(queries.map(callWithThis, queryResult));
|
|
10284
10373
|
if (ctx.collect) {
|
|
10285
10374
|
const t = query.baseQuery.clone();
|
|
@@ -10868,26 +10957,80 @@ class SearchMethods {
|
|
|
10868
10957
|
|
|
10869
10958
|
function orCreate(query, data, updateData, mergeData) {
|
|
10870
10959
|
const { q } = query;
|
|
10871
|
-
q.
|
|
10872
|
-
q.
|
|
10960
|
+
q.returnsOne = true;
|
|
10961
|
+
if (!q.select) {
|
|
10962
|
+
q.returnType = "void";
|
|
10963
|
+
}
|
|
10873
10964
|
const { handleResult } = q;
|
|
10874
10965
|
let result;
|
|
10875
10966
|
let created = false;
|
|
10876
10967
|
q.handleResult = (q2, t, r, s) => {
|
|
10877
10968
|
return created ? result : handleResult(q2, t, r, s);
|
|
10878
10969
|
};
|
|
10879
|
-
q.
|
|
10970
|
+
q.hookSelect ?? (q.hookSelect = /* @__PURE__ */ new Map());
|
|
10971
|
+
q.patchResult = async (q2, hookSelect, queryResult) => {
|
|
10972
|
+
var _a, _b;
|
|
10880
10973
|
if (queryResult.rowCount === 0) {
|
|
10881
10974
|
if (typeof data === "function") {
|
|
10882
10975
|
data = data(updateData);
|
|
10883
10976
|
}
|
|
10884
10977
|
if (mergeData) data = { ...mergeData, ...data };
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10978
|
+
let hasAfterCallback = q2.q.afterCreate;
|
|
10979
|
+
let hasAfterCommitCallback = q2.q.afterCreateCommit;
|
|
10980
|
+
if (updateData) {
|
|
10981
|
+
hasAfterCallback = hasAfterCallback || q2.q.afterUpdate;
|
|
10982
|
+
hasAfterCommitCallback = hasAfterCommitCallback || q2.q.afterUpdateCommit;
|
|
10983
|
+
}
|
|
10984
|
+
const inCTE = {
|
|
10985
|
+
selectNum: !!(hasAfterCallback || hasAfterCommitCallback),
|
|
10986
|
+
targetHookSelect: hookSelect
|
|
10889
10987
|
};
|
|
10890
|
-
|
|
10988
|
+
q2 = q2.clone();
|
|
10989
|
+
q2.q.inCTE = inCTE;
|
|
10990
|
+
const c = q2.create(data);
|
|
10991
|
+
c.q.select = q2.q.select;
|
|
10992
|
+
let q22 = q2.queryBuilder.with("f", q2).with("c", c);
|
|
10993
|
+
q22.q.returnsOne = true;
|
|
10994
|
+
queryFrom(q22, "f");
|
|
10995
|
+
q22 = _queryUnion(
|
|
10996
|
+
q22,
|
|
10997
|
+
[q2.queryBuilder.from("c")],
|
|
10998
|
+
"UNION ALL",
|
|
10999
|
+
true,
|
|
11000
|
+
true
|
|
11001
|
+
);
|
|
11002
|
+
let afterHooks;
|
|
11003
|
+
let afterCommitHooks;
|
|
11004
|
+
q22.q.handleResult = (a, t, r, s) => {
|
|
11005
|
+
if (hasAfterCallback || hasAfterCommitCallback) {
|
|
11006
|
+
const fieldName = r.fields[0].name;
|
|
11007
|
+
if (r.rows[0][fieldName]) {
|
|
11008
|
+
afterHooks = q2.q.afterCreate;
|
|
11009
|
+
afterCommitHooks = q2.q.afterCreateCommit;
|
|
11010
|
+
} else {
|
|
11011
|
+
afterHooks = q2.q.afterUpdate;
|
|
11012
|
+
afterCommitHooks = q2.q.afterUpdateCommit;
|
|
11013
|
+
}
|
|
11014
|
+
delete r.rows[0][fieldName];
|
|
11015
|
+
}
|
|
11016
|
+
result = handleResult(a, t, r, s);
|
|
11017
|
+
return a.q.hookSelect ? result.map((row) => ({ ...row })) : result;
|
|
11018
|
+
};
|
|
11019
|
+
q22.q.log = q2.q.log;
|
|
11020
|
+
q22.q.logger = q2.q.logger;
|
|
11021
|
+
q22.q.type = "upsert";
|
|
11022
|
+
q22.q.beforeCreate = q2.q.beforeCreate;
|
|
11023
|
+
if (hasAfterCallback) {
|
|
11024
|
+
((_a = q22.q).afterCreate ?? (_a.afterCreate = [])).push(
|
|
11025
|
+
(data2, query2) => afterHooks && Promise.all([...afterHooks].map((fn) => fn(data2, query2)))
|
|
11026
|
+
);
|
|
11027
|
+
}
|
|
11028
|
+
if (hasAfterCommitCallback) {
|
|
11029
|
+
((_b = q22.q).afterCreateCommit ?? (_b.afterCreateCommit = [])).push(
|
|
11030
|
+
(data2, query2) => afterCommitHooks && Promise.all([...afterCommitHooks].map((fn) => fn(data2, query2)))
|
|
11031
|
+
);
|
|
11032
|
+
}
|
|
11033
|
+
await q22;
|
|
10891
11034
|
created = true;
|
|
10892
11035
|
} else if (queryResult.rowCount > 1) {
|
|
10893
11036
|
throw new MoreThanOneRowError(
|
|
@@ -10900,9 +11043,7 @@ function orCreate(query, data, updateData, mergeData) {
|
|
|
10900
11043
|
}
|
|
10901
11044
|
class QueryUpsertOrCreate {
|
|
10902
11045
|
/**
|
|
10903
|
-
* `upsert` tries to update
|
|
10904
|
-
*
|
|
10905
|
-
* It will implicitly wrap queries in a transaction if it was not wrapped yet.
|
|
11046
|
+
* `upsert` tries to update a single record, and then it creates the record if it doesn't yet exist.
|
|
10906
11047
|
*
|
|
10907
11048
|
* `find` or `findBy` must precede `upsert` because it does not work with multiple updates.
|
|
10908
11049
|
*
|
|
@@ -10913,7 +11054,7 @@ class QueryUpsertOrCreate {
|
|
|
10913
11054
|
*
|
|
10914
11055
|
* `data` and `update` objects are of the same type that's expected by `update` method, `create` object is of type of `create` method argument.
|
|
10915
11056
|
*
|
|
10916
|
-
*
|
|
11057
|
+
* No values are returned by default, place `select` or `selectAll` before `upsert` to specify returning columns.
|
|
10917
11058
|
*
|
|
10918
11059
|
* ```ts
|
|
10919
11060
|
* await User.selectAll()
|
|
@@ -10990,6 +11131,9 @@ class QueryUpsertOrCreate {
|
|
|
10990
11131
|
* });
|
|
10991
11132
|
* ```
|
|
10992
11133
|
*
|
|
11134
|
+
* `upsert` works in the exact same way as [orCreate](#orCreate), but with `UPDATE` statement instead of `SELECT`.
|
|
11135
|
+
* it also performs a single query if the record exists, and two queries if there is no record yet.
|
|
11136
|
+
*
|
|
10993
11137
|
* @param data - `update` property for the data to update, `create` property for the data to create
|
|
10994
11138
|
*/
|
|
10995
11139
|
upsert(data) {
|
|
@@ -11004,22 +11148,16 @@ class QueryUpsertOrCreate {
|
|
|
11004
11148
|
if (!isObjectEmpty(updateData)) {
|
|
11005
11149
|
_queryUpdate(q, updateData);
|
|
11006
11150
|
}
|
|
11007
|
-
|
|
11008
|
-
if (!c.q.select) {
|
|
11009
|
-
c.q.returnType = "void";
|
|
11010
|
-
}
|
|
11011
|
-
return c;
|
|
11151
|
+
return orCreate(q, data.create, updateData, mergeData);
|
|
11012
11152
|
}
|
|
11013
11153
|
/**
|
|
11014
11154
|
* `orCreate` creates a record only if it was not found by conditions.
|
|
11015
11155
|
*
|
|
11016
|
-
* It will implicitly wrap queries in a transaction if it was not wrapped yet.
|
|
11017
|
-
*
|
|
11018
11156
|
* `find` or `findBy` must precede `orCreate`.
|
|
11019
11157
|
*
|
|
11020
11158
|
* It is accepting the same argument as `create` commands.
|
|
11021
11159
|
*
|
|
11022
|
-
*
|
|
11160
|
+
* No result is returned by default, place `get`, `select`, or `selectAll` before `orCreate` to specify returning columns.
|
|
11023
11161
|
*
|
|
11024
11162
|
* ```ts
|
|
11025
11163
|
* const user = await User.selectAll()
|
|
@@ -11030,7 +11168,7 @@ class QueryUpsertOrCreate {
|
|
|
11030
11168
|
* });
|
|
11031
11169
|
* ```
|
|
11032
11170
|
*
|
|
11033
|
-
* The data
|
|
11171
|
+
* The data can be returned from a function, it won't be called if the record was found:
|
|
11034
11172
|
*
|
|
11035
11173
|
* ```ts
|
|
11036
11174
|
* const user = await User.selectAll()
|
|
@@ -11041,6 +11179,35 @@ class QueryUpsertOrCreate {
|
|
|
11041
11179
|
* }));
|
|
11042
11180
|
* ```
|
|
11043
11181
|
*
|
|
11182
|
+
* `orCreate` works by performing just a single query in the case if the record exists, and one additional query when the record does not exist.
|
|
11183
|
+
*
|
|
11184
|
+
* At first, it performs a "find" query, the query cost is exact same as if you didn't use `orCreate`.
|
|
11185
|
+
*
|
|
11186
|
+
* Then, if the record wasn't found, it performs a single query with CTE expressions to try finding it again, for the case it was already created just a moment before,
|
|
11187
|
+
* and then it creates the record if it's still not found. Using such CTE allows to skip using transactions, while still conforming to atomicity.
|
|
11188
|
+
*
|
|
11189
|
+
* ```sql
|
|
11190
|
+
* -- first query
|
|
11191
|
+
* SELECT * FROM "table" WHERE "key" = 'value'
|
|
11192
|
+
*
|
|
11193
|
+
* -- the record could have been created in between these two queries
|
|
11194
|
+
*
|
|
11195
|
+
* -- second query
|
|
11196
|
+
* WITH find_row AS (
|
|
11197
|
+
* SELECT * FROM "table" WHERE "key" = 'value'
|
|
11198
|
+
* )
|
|
11199
|
+
* WITH insert_row AS (
|
|
11200
|
+
* INSERT INTO "table" ("key")
|
|
11201
|
+
* SELECT 'value'
|
|
11202
|
+
* -- skip the insert if the row already exists
|
|
11203
|
+
* WHERE NOT EXISTS (SELECT 1 FROM find_row)
|
|
11204
|
+
* RETURNING *
|
|
11205
|
+
* )
|
|
11206
|
+
* SELECT * FROM find_row
|
|
11207
|
+
* UNION ALL
|
|
11208
|
+
* SELECT * FROM insert_row
|
|
11209
|
+
* ```
|
|
11210
|
+
*
|
|
11044
11211
|
* @param data - the same data as for `create`, it may be returned from a callback
|
|
11045
11212
|
*/
|
|
11046
11213
|
orCreate(data) {
|
|
@@ -11279,16 +11446,17 @@ class ColumnRefExpression extends Expression {
|
|
|
11279
11446
|
}
|
|
11280
11447
|
}
|
|
11281
11448
|
class RefExpression extends Expression {
|
|
11282
|
-
constructor(value,
|
|
11449
|
+
constructor(value, query, ref) {
|
|
11283
11450
|
super();
|
|
11284
|
-
this.q = q;
|
|
11285
11451
|
this.ref = ref;
|
|
11286
11452
|
this.result = { value };
|
|
11287
|
-
q.expr = this;
|
|
11453
|
+
(this.q = query.q).expr = this;
|
|
11454
|
+
this.table = query.table;
|
|
11288
11455
|
Object.assign(this, value.operators);
|
|
11289
11456
|
}
|
|
11290
|
-
makeSQL(ctx
|
|
11291
|
-
|
|
11457
|
+
makeSQL(ctx) {
|
|
11458
|
+
const as = this.q.as || this.table;
|
|
11459
|
+
return columnToSql(ctx, this.q, this.q.shape, this.ref, as && `"${as}"`);
|
|
11292
11460
|
}
|
|
11293
11461
|
}
|
|
11294
11462
|
class OrExpression extends Expression {
|
|
@@ -11384,7 +11552,7 @@ class ExpressionMethods {
|
|
|
11384
11552
|
} else {
|
|
11385
11553
|
column = shape[arg];
|
|
11386
11554
|
}
|
|
11387
|
-
return new RefExpression(column, q
|
|
11555
|
+
return new RefExpression(column, q, arg);
|
|
11388
11556
|
}
|
|
11389
11557
|
val(value) {
|
|
11390
11558
|
return new ValExpression(value);
|
|
@@ -12099,6 +12267,9 @@ class QueryMethods {
|
|
|
12099
12267
|
narrowType() {
|
|
12100
12268
|
return () => this;
|
|
12101
12269
|
}
|
|
12270
|
+
if(condition, fn) {
|
|
12271
|
+
return condition ? fn(this) : this;
|
|
12272
|
+
}
|
|
12102
12273
|
queryRelated(relName, params) {
|
|
12103
12274
|
return this.relations[relName].relationConfig.queryRelated(
|
|
12104
12275
|
params
|