pqb 0.43.0 → 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 +93 -37
- package/dist/index.js +569 -396
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +570 -397
- 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';
|
|
@@ -810,8 +810,10 @@ const columnExcludesToCode = (items) => {
|
|
|
810
810
|
}
|
|
811
811
|
return code;
|
|
812
812
|
};
|
|
813
|
-
const columnCheckToCode = (ctx,
|
|
814
|
-
return
|
|
813
|
+
const columnCheckToCode = (ctx, checks) => {
|
|
814
|
+
return checks.map(
|
|
815
|
+
({ sql, name }) => `.check(${sql.toCode(ctx.t)}${name ? `, '${name}'` : ""})`
|
|
816
|
+
).join("");
|
|
815
817
|
};
|
|
816
818
|
const identityToCode = (identity, dataType) => {
|
|
817
819
|
const code = [];
|
|
@@ -895,8 +897,8 @@ const columnCode = (type, ctx, key, code) => {
|
|
|
895
897
|
}
|
|
896
898
|
}
|
|
897
899
|
if (data.comment) addCode(code, `.comment(${singleQuote(data.comment)})`);
|
|
898
|
-
if (data.
|
|
899
|
-
addCode(code, columnCheckToCode(ctx, data.
|
|
900
|
+
if (data.checks) {
|
|
901
|
+
addCode(code, columnCheckToCode(ctx, data.checks));
|
|
900
902
|
}
|
|
901
903
|
if (data.errors) {
|
|
902
904
|
for (const part of columnErrorMessagesToCode(data.errors)) {
|
|
@@ -1243,11 +1245,13 @@ class TextColumn extends TextBaseColumn {
|
|
|
1243
1245
|
return textColumnToCode(this, ctx, key);
|
|
1244
1246
|
}
|
|
1245
1247
|
}
|
|
1248
|
+
const byteaParse = (val) => typeof val === "string" ? Buffer.from(val.slice(2), "hex") : val;
|
|
1246
1249
|
class ByteaColumn extends ColumnType {
|
|
1247
1250
|
constructor(schema) {
|
|
1248
1251
|
super(schema, schema.buffer());
|
|
1249
1252
|
this.dataType = "bytea";
|
|
1250
1253
|
this.operators = Operators.text;
|
|
1254
|
+
setColumnDefaultParse(this, byteaParse);
|
|
1251
1255
|
}
|
|
1252
1256
|
toCode(ctx, key) {
|
|
1253
1257
|
return columnCode(this, ctx, key, `bytea()`);
|
|
@@ -4464,7 +4468,7 @@ function maybeWrappedThen(resolve, reject) {
|
|
|
4464
4468
|
let afterHooks;
|
|
4465
4469
|
let afterCommitHooks;
|
|
4466
4470
|
if (q.type) {
|
|
4467
|
-
if (q.type === "insert") {
|
|
4471
|
+
if (q.type === "insert" || q.type === "upsert") {
|
|
4468
4472
|
beforeHooks = q.beforeCreate;
|
|
4469
4473
|
afterHooks = q.afterCreate;
|
|
4470
4474
|
afterCommitHooks = q.afterCreateCommit;
|
|
@@ -4542,14 +4546,18 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4542
4546
|
if (log) {
|
|
4543
4547
|
logData = log.beforeQuery(sql);
|
|
4544
4548
|
}
|
|
4545
|
-
queryResult = await
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
+
queryResult = await execQuery(
|
|
4550
|
+
adapter,
|
|
4551
|
+
queryMethodByReturnType[tempReturnType],
|
|
4552
|
+
sql
|
|
4553
|
+
);
|
|
4549
4554
|
if (log) {
|
|
4550
4555
|
log.afterQuery(sql, logData);
|
|
4551
4556
|
sql = void 0;
|
|
4552
4557
|
}
|
|
4558
|
+
if (query.patchResult) {
|
|
4559
|
+
await query.patchResult(q, hookSelect, queryResult);
|
|
4560
|
+
}
|
|
4553
4561
|
result = query.handleResult(q, tempReturnType, queryResult);
|
|
4554
4562
|
} else {
|
|
4555
4563
|
const queryMethod = queryMethodByReturnType[tempReturnType];
|
|
@@ -4563,7 +4571,7 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4563
4571
|
if (log) {
|
|
4564
4572
|
logData = log.beforeQuery(sql);
|
|
4565
4573
|
}
|
|
4566
|
-
const result2 = await adapter
|
|
4574
|
+
const result2 = await execQuery(adapter, queryMethod, sql);
|
|
4567
4575
|
if (queryResult) {
|
|
4568
4576
|
queryResult.rowCount += result2.rowCount;
|
|
4569
4577
|
queryResult.rows.push(...result2.rows);
|
|
@@ -4581,7 +4589,7 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4581
4589
|
if (log) log.afterQuery(commitSql$1, logData);
|
|
4582
4590
|
}
|
|
4583
4591
|
if (query.patchResult) {
|
|
4584
|
-
await query.patchResult(q, queryResult);
|
|
4592
|
+
await query.patchResult(q, hookSelect, queryResult);
|
|
4585
4593
|
}
|
|
4586
4594
|
result = query.handleResult(q, tempReturnType, queryResult);
|
|
4587
4595
|
}
|
|
@@ -4709,6 +4717,17 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4709
4717
|
return reject?.(error);
|
|
4710
4718
|
}
|
|
4711
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
|
+
};
|
|
4712
4731
|
const assignError = (to, from) => {
|
|
4713
4732
|
to.message = from.message;
|
|
4714
4733
|
to.length = from.length;
|
|
@@ -5648,6 +5667,306 @@ function queryJson(self, coalesce) {
|
|
|
5648
5667
|
return q;
|
|
5649
5668
|
}
|
|
5650
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
|
+
|
|
5651
5970
|
const pushSelectSql = (ctx, table, query, quotedAs, aliases) => {
|
|
5652
5971
|
const sql = selectToSql(
|
|
5653
5972
|
ctx,
|
|
@@ -5659,7 +5978,16 @@ const pushSelectSql = (ctx, table, query, quotedAs, aliases) => {
|
|
|
5659
5978
|
);
|
|
5660
5979
|
if (sql) ctx.sql.push(sql);
|
|
5661
5980
|
};
|
|
5662
|
-
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
|
+
}
|
|
5663
5991
|
let selected;
|
|
5664
5992
|
const list = [];
|
|
5665
5993
|
if (query.select) {
|
|
@@ -6003,371 +6331,116 @@ const pushFromAndAs = (ctx, table, data, quotedAs) => {
|
|
|
6003
6331
|
let fn;
|
|
6004
6332
|
let query;
|
|
6005
6333
|
if ("query" in source) {
|
|
6006
|
-
fn = "websearch_to_tsquery";
|
|
6007
|
-
query = source.query;
|
|
6008
|
-
} else if ("plainQuery" in source) {
|
|
6009
|
-
fn = "plainto_tsquery";
|
|
6010
|
-
query = source.plainQuery;
|
|
6011
|
-
} else if ("phraseQuery" in source) {
|
|
6012
|
-
fn = "phraseto_tsquery";
|
|
6013
|
-
query = source.phraseQuery;
|
|
6014
|
-
} else {
|
|
6015
|
-
fn = "to_tsquery";
|
|
6016
|
-
query = source.tsQuery;
|
|
6017
|
-
}
|
|
6018
|
-
let querySql;
|
|
6019
|
-
if (typeof query === "string") {
|
|
6020
|
-
ctx.values.push(query);
|
|
6021
|
-
querySql = `$${ctx.values.length}`;
|
|
6022
|
-
} else {
|
|
6023
|
-
querySql = `${query.toSQL(ctx, quotedAs)}`;
|
|
6024
|
-
}
|
|
6025
|
-
sql += `, ${fn}(${lang}, ${querySql}) "${as}"`;
|
|
6026
|
-
}
|
|
6027
|
-
ctx.sql.push(sql);
|
|
6028
|
-
};
|
|
6029
|
-
const getFrom = (ctx, table, data, quotedAs) => {
|
|
6030
|
-
if (data.from) {
|
|
6031
|
-
const { from } = data;
|
|
6032
|
-
if (Array.isArray(from)) {
|
|
6033
|
-
return from.map((item) => fromToSql(ctx, data, item, quotedAs)).join(", ");
|
|
6034
|
-
}
|
|
6035
|
-
return fromToSql(ctx, data, from, quotedAs);
|
|
6036
|
-
}
|
|
6037
|
-
let sql = quoteSchemaAndTable(data.schema, table.table);
|
|
6038
|
-
if (data.only) sql = `ONLY ${sql}`;
|
|
6039
|
-
return sql;
|
|
6040
|
-
};
|
|
6041
|
-
const fromToSql = (ctx, data, from, quotedAs) => {
|
|
6042
|
-
let only;
|
|
6043
|
-
let sql;
|
|
6044
|
-
if (typeof from === "object") {
|
|
6045
|
-
if (isExpression(from)) {
|
|
6046
|
-
sql = from.toSQL(ctx, quotedAs);
|
|
6047
|
-
} else {
|
|
6048
|
-
only = from.q.only;
|
|
6049
|
-
if (!from.table) {
|
|
6050
|
-
sql = `(${getSqlText(makeSQL(from, ctx))})`;
|
|
6051
|
-
} else if (!checkIfASimpleQuery(from)) {
|
|
6052
|
-
sql = `(${getSqlText(makeSQL(from, ctx))})`;
|
|
6053
|
-
} else {
|
|
6054
|
-
sql = quoteSchemaAndTable(from.q.schema, from.table);
|
|
6055
|
-
}
|
|
6056
|
-
}
|
|
6057
|
-
} else {
|
|
6058
|
-
sql = quoteSchemaAndTable(data.schema, from);
|
|
6059
|
-
}
|
|
6060
|
-
return (only === void 0 ? data.only : only) ? `ONLY ${sql}` : sql;
|
|
6061
|
-
};
|
|
6062
|
-
const getSearchLang = (ctx, data, source, quotedAs) => {
|
|
6063
|
-
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"));
|
|
6064
|
-
};
|
|
6065
|
-
const getSearchText = (ctx, data, source, quotedAs, forHeadline) => {
|
|
6066
|
-
let sql = source.textSQL;
|
|
6067
|
-
if (sql) return sql;
|
|
6068
|
-
if ("in" in source) {
|
|
6069
|
-
if (typeof source.in === "string") {
|
|
6070
|
-
sql = columnToSql(ctx, data, data.shape, source.in, quotedAs);
|
|
6071
|
-
} else if (Array.isArray(source.in)) {
|
|
6072
|
-
sql = `concat_ws(' ', ${source.in.map((column) => columnToSql(ctx, data, data.shape, column, quotedAs)).join(", ")})`;
|
|
6073
|
-
} else {
|
|
6074
|
-
sql = [];
|
|
6075
|
-
for (const key in source.in) {
|
|
6076
|
-
sql.push(columnToSql(ctx, data, data.shape, key, quotedAs));
|
|
6077
|
-
}
|
|
6078
|
-
}
|
|
6079
|
-
} else if ("vector" in source) {
|
|
6080
|
-
if (forHeadline) {
|
|
6081
|
-
throw new Error(
|
|
6082
|
-
"Cannot use a search based on a vector column for a search headline"
|
|
6083
|
-
);
|
|
6084
|
-
}
|
|
6085
|
-
sql = columnToSql(ctx, data, data.shape, source.vector, quotedAs);
|
|
6086
|
-
} else {
|
|
6087
|
-
if (typeof source.text === "string") {
|
|
6088
|
-
sql = addValue(ctx.values, source.text);
|
|
6089
|
-
} else {
|
|
6090
|
-
sql = source.text.toSQL(ctx, quotedAs);
|
|
6091
|
-
}
|
|
6092
|
-
}
|
|
6093
|
-
return source.textSQL = sql;
|
|
6094
|
-
};
|
|
6095
|
-
const getTsVector = (ctx, data, lang, source, quotedAs) => {
|
|
6096
|
-
const text = getSearchText(ctx, data, source, quotedAs);
|
|
6097
|
-
if ("in" in source) {
|
|
6098
|
-
if (typeof source.in === "string" || Array.isArray(source.in)) {
|
|
6099
|
-
return `to_tsvector(${lang}, ${text})`;
|
|
6100
|
-
} else {
|
|
6101
|
-
let tsVector = "";
|
|
6102
|
-
let i = 0;
|
|
6103
|
-
for (const key in source.in) {
|
|
6104
|
-
tsVector = (tsVector ? `${tsVector} || ` : "") + `setweight(to_tsvector(${lang}, ${text[i++]}), ${addValue(
|
|
6105
|
-
ctx.values,
|
|
6106
|
-
source.in[key]
|
|
6107
|
-
)})`;
|
|
6108
|
-
}
|
|
6109
|
-
return tsVector;
|
|
6110
|
-
}
|
|
6111
|
-
} else if ("vector" in source) {
|
|
6112
|
-
return text;
|
|
6113
|
-
} else {
|
|
6114
|
-
return `to_tsvector(${lang}, ${text})`;
|
|
6115
|
-
}
|
|
6116
|
-
};
|
|
6117
|
-
|
|
6118
|
-
const MAX_BINDING_PARAMS = 65536;
|
|
6119
|
-
|
|
6120
|
-
const quotedColumns = [];
|
|
6121
|
-
const makeInsertSql = (ctx, q, query, quotedAs) => {
|
|
6122
|
-
const { columns, shape } = query;
|
|
6123
|
-
quotedColumns.length = columns.length;
|
|
6124
|
-
for (let i = 0, len = columns.length; i < len; i++) {
|
|
6125
|
-
quotedColumns[i] = `"${shape[columns[i]]?.data.name || columns[i]}"`;
|
|
6126
|
-
}
|
|
6127
|
-
let runtimeDefaults;
|
|
6128
|
-
if (q.internal.runtimeDefaultColumns) {
|
|
6129
|
-
runtimeDefaults = [];
|
|
6130
|
-
for (const key of q.internal.runtimeDefaultColumns) {
|
|
6131
|
-
if (!columns.includes(key)) {
|
|
6132
|
-
const column = shape[key];
|
|
6133
|
-
quotedColumns.push(`"${column.data.name || key}"`);
|
|
6134
|
-
runtimeDefaults.push(column.data.runtimeDefault);
|
|
6135
|
-
}
|
|
6136
|
-
}
|
|
6137
|
-
}
|
|
6138
|
-
let values = query.values;
|
|
6139
|
-
if (quotedColumns.length === 0) {
|
|
6140
|
-
const key = Object.keys(q.shape)[0];
|
|
6141
|
-
const column = q.shape[key];
|
|
6142
|
-
quotedColumns[0] = `"${column?.data.name || key}"`;
|
|
6143
|
-
if (Array.isArray(values) && Array.isArray(values[0])) {
|
|
6144
|
-
values = values.map(() => [void 0]);
|
|
6145
|
-
}
|
|
6146
|
-
}
|
|
6147
|
-
ctx.sql.push(
|
|
6148
|
-
`INSERT INTO ${quotedAs}(${quotedColumns.join(", ")})`,
|
|
6149
|
-
null
|
|
6150
|
-
);
|
|
6151
|
-
const QueryClass = ctx.queryBuilder.constructor;
|
|
6152
|
-
if (query.onConflict) {
|
|
6153
|
-
ctx.sql.push("ON CONFLICT");
|
|
6154
|
-
const { target } = query.onConflict;
|
|
6155
|
-
if (target) {
|
|
6156
|
-
if (typeof target === "string") {
|
|
6157
|
-
ctx.sql.push(`("${shape[target]?.data.name || target}")`);
|
|
6158
|
-
} else if (Array.isArray(target)) {
|
|
6159
|
-
ctx.sql.push(
|
|
6160
|
-
`(${target.reduce(
|
|
6161
|
-
(sql, item, i) => sql + (i ? ", " : "") + `"${shape[item]?.data.name || item}"`,
|
|
6162
|
-
""
|
|
6163
|
-
)})`
|
|
6164
|
-
);
|
|
6165
|
-
} else if ("toSQL" in target) {
|
|
6166
|
-
ctx.sql.push(target.toSQL(ctx, quotedAs));
|
|
6167
|
-
} else {
|
|
6168
|
-
ctx.sql.push(`ON CONSTRAINT "${target.constraint}"`);
|
|
6169
|
-
}
|
|
6170
|
-
}
|
|
6171
|
-
if ("merge" in query.onConflict) {
|
|
6172
|
-
let sql;
|
|
6173
|
-
const { merge } = query.onConflict;
|
|
6174
|
-
if (merge) {
|
|
6175
|
-
if (typeof merge === "string") {
|
|
6176
|
-
const name = shape[merge]?.data.name || merge;
|
|
6177
|
-
sql = `DO UPDATE SET "${name}" = excluded."${name}"`;
|
|
6178
|
-
} else if ("except" in merge) {
|
|
6179
|
-
sql = mergeColumnsSql(columns, quotedColumns, target, merge.except);
|
|
6180
|
-
} else {
|
|
6181
|
-
sql = `DO UPDATE SET ${merge.reduce((sql2, item, i) => {
|
|
6182
|
-
const name = shape[item]?.data.name || item;
|
|
6183
|
-
return sql2 + (i ? ", " : "") + `"${name}" = excluded."${name}"`;
|
|
6184
|
-
}, "")}`;
|
|
6185
|
-
}
|
|
6186
|
-
} else {
|
|
6187
|
-
sql = mergeColumnsSql(columns, quotedColumns, target);
|
|
6188
|
-
}
|
|
6189
|
-
ctx.sql.push(sql);
|
|
6190
|
-
} else if (query.onConflict.set) {
|
|
6191
|
-
let sql;
|
|
6192
|
-
const { set } = query.onConflict;
|
|
6193
|
-
if (isExpression(set)) {
|
|
6194
|
-
sql = set.toSQL(ctx, quotedAs);
|
|
6195
|
-
} else {
|
|
6196
|
-
const arr = [];
|
|
6197
|
-
for (const key in set) {
|
|
6198
|
-
arr.push(
|
|
6199
|
-
`"${shape[key]?.data.name || key}" = ${addValue(
|
|
6200
|
-
ctx.values,
|
|
6201
|
-
set[key]
|
|
6202
|
-
)}`
|
|
6203
|
-
);
|
|
6204
|
-
}
|
|
6205
|
-
sql = arr.join(", ");
|
|
6206
|
-
}
|
|
6207
|
-
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;
|
|
6208
6342
|
} else {
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
}
|
|
6212
|
-
pushWhereStatementSql(ctx, q, query, quotedAs);
|
|
6213
|
-
const hookSelect = pushReturningSql(
|
|
6214
|
-
ctx,
|
|
6215
|
-
q,
|
|
6216
|
-
query,
|
|
6217
|
-
quotedAs,
|
|
6218
|
-
query.afterCreateSelect
|
|
6219
|
-
);
|
|
6220
|
-
if (query.kind === "object") {
|
|
6221
|
-
const valuesSql = [];
|
|
6222
|
-
let ctxValues = ctx.values;
|
|
6223
|
-
const restValuesLen = ctxValues.length;
|
|
6224
|
-
let currentValuesLen = restValuesLen;
|
|
6225
|
-
let batch;
|
|
6226
|
-
for (let i = 0; i < values.length; i++) {
|
|
6227
|
-
const encodedRow = `(${encodeRow(
|
|
6228
|
-
ctx,
|
|
6229
|
-
ctxValues,
|
|
6230
|
-
q,
|
|
6231
|
-
QueryClass,
|
|
6232
|
-
values[i],
|
|
6233
|
-
runtimeDefaults,
|
|
6234
|
-
quotedAs
|
|
6235
|
-
)})`;
|
|
6236
|
-
if (ctxValues.length > MAX_BINDING_PARAMS) {
|
|
6237
|
-
if (ctxValues.length - currentValuesLen > MAX_BINDING_PARAMS) {
|
|
6238
|
-
throw new Error(
|
|
6239
|
-
`Too many parameters for a single insert row, max is ${MAX_BINDING_PARAMS}`
|
|
6240
|
-
);
|
|
6241
|
-
}
|
|
6242
|
-
ctx.sql[1] = `VALUES ${valuesSql.join(",")}`;
|
|
6243
|
-
ctxValues.length = currentValuesLen;
|
|
6244
|
-
batch = pushOrNewArray(batch, {
|
|
6245
|
-
text: ctx.sql.join(" "),
|
|
6246
|
-
values: ctxValues
|
|
6247
|
-
});
|
|
6248
|
-
ctxValues = ctx.values = [];
|
|
6249
|
-
valuesSql.length = 0;
|
|
6250
|
-
i--;
|
|
6251
|
-
} else {
|
|
6252
|
-
currentValuesLen = ctxValues.length;
|
|
6253
|
-
valuesSql.push(encodedRow);
|
|
6254
|
-
}
|
|
6343
|
+
fn = "to_tsquery";
|
|
6344
|
+
query = source.tsQuery;
|
|
6255
6345
|
}
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
values: ctxValues
|
|
6261
|
-
});
|
|
6262
|
-
return {
|
|
6263
|
-
hookSelect,
|
|
6264
|
-
batch
|
|
6265
|
-
};
|
|
6346
|
+
let querySql;
|
|
6347
|
+
if (typeof query === "string") {
|
|
6348
|
+
ctx.values.push(query);
|
|
6349
|
+
querySql = `$${ctx.values.length}`;
|
|
6266
6350
|
} else {
|
|
6267
|
-
|
|
6351
|
+
querySql = `${query.toSQL(ctx, quotedAs)}`;
|
|
6268
6352
|
}
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
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);
|
|
6276
6375
|
} else {
|
|
6277
|
-
|
|
6278
|
-
if (
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
6283
|
-
`(${raw.toSQL(ctx, quotedAs)}, ${runtimeDefaults.map((fn) => addValue(v, fn())).join(", ")})`
|
|
6284
|
-
)
|
|
6285
|
-
).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))})`;
|
|
6286
6381
|
} else {
|
|
6287
|
-
sql =
|
|
6382
|
+
sql = quoteSchemaAndTable(from.q.schema, from.table);
|
|
6288
6383
|
}
|
|
6289
|
-
ctx.sql[1] = `VALUES ${sql}`;
|
|
6290
6384
|
}
|
|
6291
6385
|
} else {
|
|
6292
|
-
|
|
6293
|
-
const q2 = from.clone();
|
|
6294
|
-
if (v) {
|
|
6295
|
-
pushQueryValue(
|
|
6296
|
-
q2,
|
|
6297
|
-
"select",
|
|
6298
|
-
new RawSQL(
|
|
6299
|
-
encodeRow(
|
|
6300
|
-
ctx,
|
|
6301
|
-
ctx.values,
|
|
6302
|
-
q2,
|
|
6303
|
-
QueryClass,
|
|
6304
|
-
v[0],
|
|
6305
|
-
runtimeDefaults,
|
|
6306
|
-
quotedAs
|
|
6307
|
-
)
|
|
6308
|
-
)
|
|
6309
|
-
);
|
|
6310
|
-
}
|
|
6311
|
-
ctx.sql[1] = getSqlText(makeSQL(q2, { values: ctx.values }));
|
|
6386
|
+
sql = quoteSchemaAndTable(data.schema, from);
|
|
6312
6387
|
}
|
|
6313
|
-
return {
|
|
6314
|
-
hookSelect,
|
|
6315
|
-
text: ctx.sql.join(" "),
|
|
6316
|
-
values: ctx.values
|
|
6317
|
-
};
|
|
6388
|
+
return (only === void 0 ? data.only : only) ? `ONLY ${sql}` : sql;
|
|
6318
6389
|
};
|
|
6319
|
-
const
|
|
6320
|
-
|
|
6321
|
-
const exclude = typeof target === "string" ? [target] : Array.isArray(target) ? [...target] : [];
|
|
6322
|
-
if (except) {
|
|
6323
|
-
if (typeof except === "string") {
|
|
6324
|
-
exclude.push(except);
|
|
6325
|
-
} else {
|
|
6326
|
-
exclude.push(...except);
|
|
6327
|
-
}
|
|
6328
|
-
}
|
|
6329
|
-
for (let i = 0; i < columns.length; i++) {
|
|
6330
|
-
if (!exclude.includes(columns[i])) {
|
|
6331
|
-
notExcluded.push(quotedColumns2[i]);
|
|
6332
|
-
}
|
|
6333
|
-
}
|
|
6334
|
-
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"));
|
|
6335
6392
|
};
|
|
6336
|
-
const
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
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));
|
|
6343
6405
|
}
|
|
6344
6406
|
}
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
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);
|
|
6350
6419
|
}
|
|
6351
6420
|
}
|
|
6352
|
-
return
|
|
6421
|
+
return source.textSQL = sql;
|
|
6353
6422
|
};
|
|
6354
|
-
const
|
|
6355
|
-
const
|
|
6356
|
-
if (
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
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
|
+
)})`;
|
|
6363
6436
|
}
|
|
6437
|
+
return tsVector;
|
|
6364
6438
|
}
|
|
6365
|
-
|
|
6366
|
-
return
|
|
6367
|
-
} else
|
|
6368
|
-
|
|
6439
|
+
} else if ("vector" in source) {
|
|
6440
|
+
return text;
|
|
6441
|
+
} else {
|
|
6442
|
+
return `to_tsvector(${lang}, ${text})`;
|
|
6369
6443
|
}
|
|
6370
|
-
return;
|
|
6371
6444
|
};
|
|
6372
6445
|
|
|
6373
6446
|
const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
@@ -6378,12 +6451,11 @@ const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
|
6378
6451
|
if (!query.select) {
|
|
6379
6452
|
query.select = countSelect;
|
|
6380
6453
|
}
|
|
6381
|
-
const hookSelect =
|
|
6454
|
+
const hookSelect = pushUpdateReturning(
|
|
6382
6455
|
ctx,
|
|
6383
6456
|
table,
|
|
6384
6457
|
query,
|
|
6385
6458
|
quotedAs,
|
|
6386
|
-
query.afterUpdateSelect,
|
|
6387
6459
|
"SELECT"
|
|
6388
6460
|
);
|
|
6389
6461
|
ctx.sql.push(`FROM ${quotedTable}`);
|
|
@@ -6398,7 +6470,21 @@ const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
|
6398
6470
|
ctx.sql.push("SET");
|
|
6399
6471
|
ctx.sql.push(set.join(", "));
|
|
6400
6472
|
pushWhereStatementSql(ctx, table, query, quotedAs);
|
|
6401
|
-
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;
|
|
6402
6488
|
};
|
|
6403
6489
|
const processData = (ctx, table, set, data, quotedAs) => {
|
|
6404
6490
|
let append;
|
|
@@ -6481,7 +6567,9 @@ const pushDeleteSql = (ctx, table, query, quotedAs) => {
|
|
|
6481
6567
|
ctx.sql.push("WHERE", conditions);
|
|
6482
6568
|
}
|
|
6483
6569
|
}
|
|
6484
|
-
|
|
6570
|
+
const returning = makeReturningSql(ctx, table, query, quotedAs, 3);
|
|
6571
|
+
if (returning.select) ctx.sql.push("RETURNING", returning.select);
|
|
6572
|
+
return returning.hookSelect;
|
|
6485
6573
|
};
|
|
6486
6574
|
|
|
6487
6575
|
const pushTruncateSql = (ctx, table, query) => {
|
|
@@ -6560,7 +6648,7 @@ const makeSQL = (table, options) => {
|
|
|
6560
6648
|
if (query.with) {
|
|
6561
6649
|
pushWithSql(ctx, query.with);
|
|
6562
6650
|
}
|
|
6563
|
-
if (query.type) {
|
|
6651
|
+
if (query.type && query.type !== "upsert") {
|
|
6564
6652
|
const tableName = table.table ?? query.as;
|
|
6565
6653
|
if (!tableName) throw new Error(`Table is missing for ${query.type}`);
|
|
6566
6654
|
if (query.type === "truncate") {
|
|
@@ -6596,10 +6684,11 @@ const makeSQL = (table, options) => {
|
|
|
6596
6684
|
}
|
|
6597
6685
|
const quotedAs = (query.as || table.table) && `"${query.as || table.table}"`;
|
|
6598
6686
|
if (query.union) {
|
|
6599
|
-
|
|
6687
|
+
const s = getSqlText(makeSQL(query.union.b, { values }));
|
|
6688
|
+
sql.push(query.union.p ? s : `(${s})`);
|
|
6600
6689
|
for (const u of query.union.u) {
|
|
6601
|
-
const
|
|
6602
|
-
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 + ")"}`);
|
|
6603
6692
|
}
|
|
6604
6693
|
} else {
|
|
6605
6694
|
sql.push("SELECT");
|
|
@@ -9985,12 +10074,13 @@ class MergeQueryMethods {
|
|
|
9985
10074
|
}
|
|
9986
10075
|
}
|
|
9987
10076
|
|
|
9988
|
-
const _queryUnion = (base, args, k) => {
|
|
10077
|
+
const _queryUnion = (base, args, k, p, m) => {
|
|
9989
10078
|
const q = base.baseQuery.clone();
|
|
9990
10079
|
const u = args.map(
|
|
9991
10080
|
(a) => ({
|
|
9992
10081
|
a: typeof a === "function" ? a(q) : a,
|
|
9993
|
-
k
|
|
10082
|
+
k,
|
|
10083
|
+
m
|
|
9994
10084
|
})
|
|
9995
10085
|
);
|
|
9996
10086
|
const union = q.q.union = base.q.union;
|
|
@@ -9999,7 +10089,8 @@ const _queryUnion = (base, args, k) => {
|
|
|
9999
10089
|
} else {
|
|
10000
10090
|
q.q.union = {
|
|
10001
10091
|
b: base,
|
|
10002
|
-
u
|
|
10092
|
+
u,
|
|
10093
|
+
p
|
|
10003
10094
|
};
|
|
10004
10095
|
}
|
|
10005
10096
|
return q;
|
|
@@ -10277,7 +10368,7 @@ const _queryUpdate = (query, arg) => {
|
|
|
10277
10368
|
}
|
|
10278
10369
|
const { queries } = ctx;
|
|
10279
10370
|
if (queries) {
|
|
10280
|
-
q.patchResult = async (_, queryResult) => {
|
|
10371
|
+
q.patchResult = async (_, _h, queryResult) => {
|
|
10281
10372
|
await Promise.all(queries.map(callWithThis, queryResult));
|
|
10282
10373
|
if (ctx.collect) {
|
|
10283
10374
|
const t = query.baseQuery.clone();
|
|
@@ -10866,26 +10957,80 @@ class SearchMethods {
|
|
|
10866
10957
|
|
|
10867
10958
|
function orCreate(query, data, updateData, mergeData) {
|
|
10868
10959
|
const { q } = query;
|
|
10869
|
-
q.
|
|
10870
|
-
q.
|
|
10960
|
+
q.returnsOne = true;
|
|
10961
|
+
if (!q.select) {
|
|
10962
|
+
q.returnType = "void";
|
|
10963
|
+
}
|
|
10871
10964
|
const { handleResult } = q;
|
|
10872
10965
|
let result;
|
|
10873
10966
|
let created = false;
|
|
10874
10967
|
q.handleResult = (q2, t, r, s) => {
|
|
10875
10968
|
return created ? result : handleResult(q2, t, r, s);
|
|
10876
10969
|
};
|
|
10877
|
-
q.
|
|
10970
|
+
q.hookSelect ?? (q.hookSelect = /* @__PURE__ */ new Map());
|
|
10971
|
+
q.patchResult = async (q2, hookSelect, queryResult) => {
|
|
10972
|
+
var _a, _b;
|
|
10878
10973
|
if (queryResult.rowCount === 0) {
|
|
10879
10974
|
if (typeof data === "function") {
|
|
10880
10975
|
data = data(updateData);
|
|
10881
10976
|
}
|
|
10882
10977
|
if (mergeData) data = { ...mergeData, ...data };
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
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
|
|
10887
10987
|
};
|
|
10888
|
-
|
|
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;
|
|
10889
11034
|
created = true;
|
|
10890
11035
|
} else if (queryResult.rowCount > 1) {
|
|
10891
11036
|
throw new MoreThanOneRowError(
|
|
@@ -10898,9 +11043,7 @@ function orCreate(query, data, updateData, mergeData) {
|
|
|
10898
11043
|
}
|
|
10899
11044
|
class QueryUpsertOrCreate {
|
|
10900
11045
|
/**
|
|
10901
|
-
* `upsert` tries to update
|
|
10902
|
-
*
|
|
10903
|
-
* 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.
|
|
10904
11047
|
*
|
|
10905
11048
|
* `find` or `findBy` must precede `upsert` because it does not work with multiple updates.
|
|
10906
11049
|
*
|
|
@@ -10911,7 +11054,7 @@ class QueryUpsertOrCreate {
|
|
|
10911
11054
|
*
|
|
10912
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.
|
|
10913
11056
|
*
|
|
10914
|
-
*
|
|
11057
|
+
* No values are returned by default, place `select` or `selectAll` before `upsert` to specify returning columns.
|
|
10915
11058
|
*
|
|
10916
11059
|
* ```ts
|
|
10917
11060
|
* await User.selectAll()
|
|
@@ -10988,6 +11131,9 @@ class QueryUpsertOrCreate {
|
|
|
10988
11131
|
* });
|
|
10989
11132
|
* ```
|
|
10990
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
|
+
*
|
|
10991
11137
|
* @param data - `update` property for the data to update, `create` property for the data to create
|
|
10992
11138
|
*/
|
|
10993
11139
|
upsert(data) {
|
|
@@ -11002,22 +11148,16 @@ class QueryUpsertOrCreate {
|
|
|
11002
11148
|
if (!isObjectEmpty(updateData)) {
|
|
11003
11149
|
_queryUpdate(q, updateData);
|
|
11004
11150
|
}
|
|
11005
|
-
|
|
11006
|
-
if (!c.q.select) {
|
|
11007
|
-
c.q.returnType = "void";
|
|
11008
|
-
}
|
|
11009
|
-
return c;
|
|
11151
|
+
return orCreate(q, data.create, updateData, mergeData);
|
|
11010
11152
|
}
|
|
11011
11153
|
/**
|
|
11012
11154
|
* `orCreate` creates a record only if it was not found by conditions.
|
|
11013
11155
|
*
|
|
11014
|
-
* It will implicitly wrap queries in a transaction if it was not wrapped yet.
|
|
11015
|
-
*
|
|
11016
11156
|
* `find` or `findBy` must precede `orCreate`.
|
|
11017
11157
|
*
|
|
11018
11158
|
* It is accepting the same argument as `create` commands.
|
|
11019
11159
|
*
|
|
11020
|
-
*
|
|
11160
|
+
* No result is returned by default, place `get`, `select`, or `selectAll` before `orCreate` to specify returning columns.
|
|
11021
11161
|
*
|
|
11022
11162
|
* ```ts
|
|
11023
11163
|
* const user = await User.selectAll()
|
|
@@ -11028,7 +11168,7 @@ class QueryUpsertOrCreate {
|
|
|
11028
11168
|
* });
|
|
11029
11169
|
* ```
|
|
11030
11170
|
*
|
|
11031
|
-
* The data
|
|
11171
|
+
* The data can be returned from a function, it won't be called if the record was found:
|
|
11032
11172
|
*
|
|
11033
11173
|
* ```ts
|
|
11034
11174
|
* const user = await User.selectAll()
|
|
@@ -11039,6 +11179,35 @@ class QueryUpsertOrCreate {
|
|
|
11039
11179
|
* }));
|
|
11040
11180
|
* ```
|
|
11041
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
|
+
*
|
|
11042
11211
|
* @param data - the same data as for `create`, it may be returned from a callback
|
|
11043
11212
|
*/
|
|
11044
11213
|
orCreate(data) {
|
|
@@ -11277,16 +11446,17 @@ class ColumnRefExpression extends Expression {
|
|
|
11277
11446
|
}
|
|
11278
11447
|
}
|
|
11279
11448
|
class RefExpression extends Expression {
|
|
11280
|
-
constructor(value,
|
|
11449
|
+
constructor(value, query, ref) {
|
|
11281
11450
|
super();
|
|
11282
|
-
this.q = q;
|
|
11283
11451
|
this.ref = ref;
|
|
11284
11452
|
this.result = { value };
|
|
11285
|
-
q.expr = this;
|
|
11453
|
+
(this.q = query.q).expr = this;
|
|
11454
|
+
this.table = query.table;
|
|
11286
11455
|
Object.assign(this, value.operators);
|
|
11287
11456
|
}
|
|
11288
|
-
makeSQL(ctx
|
|
11289
|
-
|
|
11457
|
+
makeSQL(ctx) {
|
|
11458
|
+
const as = this.q.as || this.table;
|
|
11459
|
+
return columnToSql(ctx, this.q, this.q.shape, this.ref, as && `"${as}"`);
|
|
11290
11460
|
}
|
|
11291
11461
|
}
|
|
11292
11462
|
class OrExpression extends Expression {
|
|
@@ -11382,7 +11552,7 @@ class ExpressionMethods {
|
|
|
11382
11552
|
} else {
|
|
11383
11553
|
column = shape[arg];
|
|
11384
11554
|
}
|
|
11385
|
-
return new RefExpression(column, q
|
|
11555
|
+
return new RefExpression(column, q, arg);
|
|
11386
11556
|
}
|
|
11387
11557
|
val(value) {
|
|
11388
11558
|
return new ValExpression(value);
|
|
@@ -12097,6 +12267,9 @@ class QueryMethods {
|
|
|
12097
12267
|
narrowType() {
|
|
12098
12268
|
return () => this;
|
|
12099
12269
|
}
|
|
12270
|
+
if(condition, fn) {
|
|
12271
|
+
return condition ? fn(this) : this;
|
|
12272
|
+
}
|
|
12100
12273
|
queryRelated(relName, params) {
|
|
12101
12274
|
return this.relations[relName].relationConfig.queryRelated(
|
|
12102
12275
|
params
|