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.js
CHANGED
|
@@ -812,8 +812,10 @@ const columnExcludesToCode = (items) => {
|
|
|
812
812
|
}
|
|
813
813
|
return code;
|
|
814
814
|
};
|
|
815
|
-
const columnCheckToCode = (ctx,
|
|
816
|
-
return
|
|
815
|
+
const columnCheckToCode = (ctx, checks) => {
|
|
816
|
+
return checks.map(
|
|
817
|
+
({ sql, name }) => `.check(${sql.toCode(ctx.t)}${name ? `, '${name}'` : ""})`
|
|
818
|
+
).join("");
|
|
817
819
|
};
|
|
818
820
|
const identityToCode = (identity, dataType) => {
|
|
819
821
|
const code = [];
|
|
@@ -897,8 +899,8 @@ const columnCode = (type, ctx, key, code) => {
|
|
|
897
899
|
}
|
|
898
900
|
}
|
|
899
901
|
if (data.comment) orchidCore.addCode(code, `.comment(${orchidCore.singleQuote(data.comment)})`);
|
|
900
|
-
if (data.
|
|
901
|
-
orchidCore.addCode(code, columnCheckToCode(ctx, data.
|
|
902
|
+
if (data.checks) {
|
|
903
|
+
orchidCore.addCode(code, columnCheckToCode(ctx, data.checks));
|
|
902
904
|
}
|
|
903
905
|
if (data.errors) {
|
|
904
906
|
for (const part of orchidCore.columnErrorMessagesToCode(data.errors)) {
|
|
@@ -1245,11 +1247,13 @@ class TextColumn extends TextBaseColumn {
|
|
|
1245
1247
|
return textColumnToCode(this, ctx, key);
|
|
1246
1248
|
}
|
|
1247
1249
|
}
|
|
1250
|
+
const byteaParse = (val) => typeof val === "string" ? Buffer.from(val.slice(2), "hex") : val;
|
|
1248
1251
|
class ByteaColumn extends ColumnType {
|
|
1249
1252
|
constructor(schema) {
|
|
1250
1253
|
super(schema, schema.buffer());
|
|
1251
1254
|
this.dataType = "bytea";
|
|
1252
1255
|
this.operators = Operators.text;
|
|
1256
|
+
setColumnDefaultParse(this, byteaParse);
|
|
1253
1257
|
}
|
|
1254
1258
|
toCode(ctx, key) {
|
|
1255
1259
|
return columnCode(this, ctx, key, `bytea()`);
|
|
@@ -4466,7 +4470,7 @@ function maybeWrappedThen(resolve, reject) {
|
|
|
4466
4470
|
let afterHooks;
|
|
4467
4471
|
let afterCommitHooks;
|
|
4468
4472
|
if (q.type) {
|
|
4469
|
-
if (q.type === "insert") {
|
|
4473
|
+
if (q.type === "insert" || q.type === "upsert") {
|
|
4470
4474
|
beforeHooks = q.beforeCreate;
|
|
4471
4475
|
afterHooks = q.afterCreate;
|
|
4472
4476
|
afterCommitHooks = q.afterCreateCommit;
|
|
@@ -4544,14 +4548,18 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4544
4548
|
if (log) {
|
|
4545
4549
|
logData = log.beforeQuery(sql);
|
|
4546
4550
|
}
|
|
4547
|
-
queryResult = await
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
+
queryResult = await execQuery(
|
|
4552
|
+
adapter,
|
|
4553
|
+
queryMethodByReturnType[tempReturnType],
|
|
4554
|
+
sql
|
|
4555
|
+
);
|
|
4551
4556
|
if (log) {
|
|
4552
4557
|
log.afterQuery(sql, logData);
|
|
4553
4558
|
sql = void 0;
|
|
4554
4559
|
}
|
|
4560
|
+
if (query.patchResult) {
|
|
4561
|
+
await query.patchResult(q, hookSelect, queryResult);
|
|
4562
|
+
}
|
|
4555
4563
|
result = query.handleResult(q, tempReturnType, queryResult);
|
|
4556
4564
|
} else {
|
|
4557
4565
|
const queryMethod = queryMethodByReturnType[tempReturnType];
|
|
@@ -4565,7 +4573,7 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4565
4573
|
if (log) {
|
|
4566
4574
|
logData = log.beforeQuery(sql);
|
|
4567
4575
|
}
|
|
4568
|
-
const result2 = await adapter
|
|
4576
|
+
const result2 = await execQuery(adapter, queryMethod, sql);
|
|
4569
4577
|
if (queryResult) {
|
|
4570
4578
|
queryResult.rowCount += result2.rowCount;
|
|
4571
4579
|
queryResult.rows.push(...result2.rows);
|
|
@@ -4583,7 +4591,7 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4583
4591
|
if (log) log.afterQuery(commitSql$1, logData);
|
|
4584
4592
|
}
|
|
4585
4593
|
if (query.patchResult) {
|
|
4586
|
-
await query.patchResult(q, queryResult);
|
|
4594
|
+
await query.patchResult(q, hookSelect, queryResult);
|
|
4587
4595
|
}
|
|
4588
4596
|
result = query.handleResult(q, tempReturnType, queryResult);
|
|
4589
4597
|
}
|
|
@@ -4711,6 +4719,17 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4711
4719
|
return reject?.(error);
|
|
4712
4720
|
}
|
|
4713
4721
|
};
|
|
4722
|
+
const execQuery = (adapter, method, sql) => {
|
|
4723
|
+
return adapter[method](sql).then(
|
|
4724
|
+
(result) => {
|
|
4725
|
+
if (result.rowCount && !result.rows.length) {
|
|
4726
|
+
result.rows.length = result.rowCount;
|
|
4727
|
+
result.rows.fill({});
|
|
4728
|
+
}
|
|
4729
|
+
return result;
|
|
4730
|
+
}
|
|
4731
|
+
);
|
|
4732
|
+
};
|
|
4714
4733
|
const assignError = (to, from) => {
|
|
4715
4734
|
to.message = from.message;
|
|
4716
4735
|
to.length = from.length;
|
|
@@ -5650,6 +5669,306 @@ function queryJson(self, coalesce) {
|
|
|
5650
5669
|
return q;
|
|
5651
5670
|
}
|
|
5652
5671
|
|
|
5672
|
+
const MAX_BINDING_PARAMS = 65536;
|
|
5673
|
+
|
|
5674
|
+
const quotedColumns = [];
|
|
5675
|
+
const makeInsertSql = (ctx, q, query, quotedAs) => {
|
|
5676
|
+
const { columns, shape, inCTE } = query;
|
|
5677
|
+
quotedColumns.length = columns.length;
|
|
5678
|
+
for (let i = 0, len = columns.length; i < len; i++) {
|
|
5679
|
+
quotedColumns[i] = `"${shape[columns[i]]?.data.name || columns[i]}"`;
|
|
5680
|
+
}
|
|
5681
|
+
let runtimeDefaults;
|
|
5682
|
+
if (q.internal.runtimeDefaultColumns) {
|
|
5683
|
+
runtimeDefaults = [];
|
|
5684
|
+
for (const key of q.internal.runtimeDefaultColumns) {
|
|
5685
|
+
if (!columns.includes(key)) {
|
|
5686
|
+
const column = shape[key];
|
|
5687
|
+
quotedColumns.push(`"${column.data.name || key}"`);
|
|
5688
|
+
runtimeDefaults.push(column.data.runtimeDefault);
|
|
5689
|
+
}
|
|
5690
|
+
}
|
|
5691
|
+
}
|
|
5692
|
+
let values = query.values;
|
|
5693
|
+
if (quotedColumns.length === 0) {
|
|
5694
|
+
const key = Object.keys(q.shape)[0];
|
|
5695
|
+
const column = q.shape[key];
|
|
5696
|
+
quotedColumns[0] = `"${column?.data.name || key}"`;
|
|
5697
|
+
if (Array.isArray(values) && Array.isArray(values[0])) {
|
|
5698
|
+
values = values.map(() => [void 0]);
|
|
5699
|
+
}
|
|
5700
|
+
}
|
|
5701
|
+
ctx.sql.push(
|
|
5702
|
+
`INSERT INTO ${quotedAs}(${quotedColumns.join(", ")})`,
|
|
5703
|
+
null
|
|
5704
|
+
);
|
|
5705
|
+
const QueryClass = ctx.queryBuilder.constructor;
|
|
5706
|
+
if (query.onConflict) {
|
|
5707
|
+
ctx.sql.push("ON CONFLICT");
|
|
5708
|
+
const { target } = query.onConflict;
|
|
5709
|
+
if (target) {
|
|
5710
|
+
if (typeof target === "string") {
|
|
5711
|
+
ctx.sql.push(`("${shape[target]?.data.name || target}")`);
|
|
5712
|
+
} else if (Array.isArray(target)) {
|
|
5713
|
+
ctx.sql.push(
|
|
5714
|
+
`(${target.reduce(
|
|
5715
|
+
(sql, item, i) => sql + (i ? ", " : "") + `"${shape[item]?.data.name || item}"`,
|
|
5716
|
+
""
|
|
5717
|
+
)})`
|
|
5718
|
+
);
|
|
5719
|
+
} else if ("toSQL" in target) {
|
|
5720
|
+
ctx.sql.push(target.toSQL(ctx, quotedAs));
|
|
5721
|
+
} else {
|
|
5722
|
+
ctx.sql.push(`ON CONSTRAINT "${target.constraint}"`);
|
|
5723
|
+
}
|
|
5724
|
+
}
|
|
5725
|
+
if ("merge" in query.onConflict) {
|
|
5726
|
+
let sql;
|
|
5727
|
+
const { merge } = query.onConflict;
|
|
5728
|
+
if (merge) {
|
|
5729
|
+
if (typeof merge === "string") {
|
|
5730
|
+
const name = shape[merge]?.data.name || merge;
|
|
5731
|
+
sql = `DO UPDATE SET "${name}" = excluded."${name}"`;
|
|
5732
|
+
} else if ("except" in merge) {
|
|
5733
|
+
sql = mergeColumnsSql(columns, quotedColumns, target, merge.except);
|
|
5734
|
+
} else {
|
|
5735
|
+
sql = `DO UPDATE SET ${merge.reduce((sql2, item, i) => {
|
|
5736
|
+
const name = shape[item]?.data.name || item;
|
|
5737
|
+
return sql2 + (i ? ", " : "") + `"${name}" = excluded."${name}"`;
|
|
5738
|
+
}, "")}`;
|
|
5739
|
+
}
|
|
5740
|
+
} else {
|
|
5741
|
+
sql = mergeColumnsSql(columns, quotedColumns, target);
|
|
5742
|
+
}
|
|
5743
|
+
ctx.sql.push(sql);
|
|
5744
|
+
} else if (query.onConflict.set) {
|
|
5745
|
+
let sql;
|
|
5746
|
+
const { set } = query.onConflict;
|
|
5747
|
+
if (orchidCore.isExpression(set)) {
|
|
5748
|
+
sql = set.toSQL(ctx, quotedAs);
|
|
5749
|
+
} else {
|
|
5750
|
+
const arr = [];
|
|
5751
|
+
for (const key in set) {
|
|
5752
|
+
arr.push(
|
|
5753
|
+
`"${shape[key]?.data.name || key}" = ${orchidCore.addValue(
|
|
5754
|
+
ctx.values,
|
|
5755
|
+
set[key]
|
|
5756
|
+
)}`
|
|
5757
|
+
);
|
|
5758
|
+
}
|
|
5759
|
+
sql = arr.join(", ");
|
|
5760
|
+
}
|
|
5761
|
+
ctx.sql.push("DO UPDATE SET", sql);
|
|
5762
|
+
} else {
|
|
5763
|
+
ctx.sql.push("DO NOTHING");
|
|
5764
|
+
}
|
|
5765
|
+
}
|
|
5766
|
+
pushWhereStatementSql(ctx, q, query, quotedAs);
|
|
5767
|
+
let returning;
|
|
5768
|
+
if (inCTE?.selectNum) {
|
|
5769
|
+
returning = {
|
|
5770
|
+
select: inCTE.returning?.select ? "1, " + inCTE.returning.select : "1",
|
|
5771
|
+
hookSelect: inCTE.returning?.hookSelect
|
|
5772
|
+
};
|
|
5773
|
+
} else {
|
|
5774
|
+
returning = makeReturningSql(ctx, q, query, quotedAs, 2);
|
|
5775
|
+
}
|
|
5776
|
+
if (returning.select) ctx.sql.push("RETURNING", returning.select);
|
|
5777
|
+
if (query.kind === "object") {
|
|
5778
|
+
const valuesSql = [];
|
|
5779
|
+
let ctxValues = ctx.values;
|
|
5780
|
+
const restValuesLen = ctxValues.length;
|
|
5781
|
+
let currentValuesLen = restValuesLen;
|
|
5782
|
+
let batch;
|
|
5783
|
+
for (let i = 0; i < values.length; i++) {
|
|
5784
|
+
let encodedRow = encodeRow(
|
|
5785
|
+
ctx,
|
|
5786
|
+
ctxValues,
|
|
5787
|
+
q,
|
|
5788
|
+
QueryClass,
|
|
5789
|
+
values[i],
|
|
5790
|
+
runtimeDefaults,
|
|
5791
|
+
quotedAs
|
|
5792
|
+
);
|
|
5793
|
+
if (!inCTE) encodedRow = "(" + encodedRow + ")";
|
|
5794
|
+
if (ctxValues.length > MAX_BINDING_PARAMS) {
|
|
5795
|
+
if (ctxValues.length - currentValuesLen > MAX_BINDING_PARAMS) {
|
|
5796
|
+
throw new Error(
|
|
5797
|
+
`Too many parameters for a single insert row, max is ${MAX_BINDING_PARAMS}`
|
|
5798
|
+
);
|
|
5799
|
+
}
|
|
5800
|
+
ctx.sql[1] = (inCTE ? "SELECT " : "VALUES ") + valuesSql.join(", ");
|
|
5801
|
+
ctxValues.length = currentValuesLen;
|
|
5802
|
+
batch = orchidCore.pushOrNewArray(batch, {
|
|
5803
|
+
text: ctx.sql.join(" "),
|
|
5804
|
+
values: ctxValues
|
|
5805
|
+
});
|
|
5806
|
+
ctxValues = ctx.values = [];
|
|
5807
|
+
valuesSql.length = 0;
|
|
5808
|
+
i--;
|
|
5809
|
+
} else {
|
|
5810
|
+
currentValuesLen = ctxValues.length;
|
|
5811
|
+
valuesSql.push(encodedRow);
|
|
5812
|
+
}
|
|
5813
|
+
}
|
|
5814
|
+
if (batch) {
|
|
5815
|
+
ctx.sql[1] = (inCTE ? "SELECT " : "VALUES ") + valuesSql.join(", ");
|
|
5816
|
+
batch.push({
|
|
5817
|
+
text: ctx.sql.join(" "),
|
|
5818
|
+
values: ctxValues
|
|
5819
|
+
});
|
|
5820
|
+
return {
|
|
5821
|
+
hookSelect: returning.hookSelect,
|
|
5822
|
+
batch
|
|
5823
|
+
};
|
|
5824
|
+
} else {
|
|
5825
|
+
ctx.sql[1] = (inCTE ? "SELECT " : "VALUES ") + valuesSql.join(", ");
|
|
5826
|
+
}
|
|
5827
|
+
if (inCTE) {
|
|
5828
|
+
ctx.sql[1] += ' WHERE NOT EXISTS (SELECT 1 FROM "f")';
|
|
5829
|
+
}
|
|
5830
|
+
} else if (query.kind === "raw") {
|
|
5831
|
+
if (orchidCore.isExpression(values)) {
|
|
5832
|
+
let valuesSql = values.toSQL(ctx, quotedAs);
|
|
5833
|
+
if (runtimeDefaults) {
|
|
5834
|
+
valuesSql += `, ${runtimeDefaults.map((fn) => orchidCore.addValue(ctx.values, fn())).join(", ")}`;
|
|
5835
|
+
}
|
|
5836
|
+
ctx.sql[1] = `VALUES (${valuesSql})`;
|
|
5837
|
+
} else {
|
|
5838
|
+
let sql;
|
|
5839
|
+
if (runtimeDefaults) {
|
|
5840
|
+
const { values: v } = ctx;
|
|
5841
|
+
sql = values.map(
|
|
5842
|
+
(raw) => (
|
|
5843
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
5844
|
+
`(${raw.toSQL(ctx, quotedAs)}, ${runtimeDefaults.map((fn) => orchidCore.addValue(v, fn())).join(", ")})`
|
|
5845
|
+
)
|
|
5846
|
+
).join(", ");
|
|
5847
|
+
} else {
|
|
5848
|
+
sql = values.map((raw) => `(${raw.toSQL(ctx, quotedAs)})`).join(", ");
|
|
5849
|
+
}
|
|
5850
|
+
ctx.sql[1] = `VALUES ${sql}`;
|
|
5851
|
+
}
|
|
5852
|
+
} else {
|
|
5853
|
+
const { from, values: v } = values;
|
|
5854
|
+
const q2 = from.clone();
|
|
5855
|
+
if (v) {
|
|
5856
|
+
pushQueryValue(
|
|
5857
|
+
q2,
|
|
5858
|
+
"select",
|
|
5859
|
+
new RawSQL(
|
|
5860
|
+
encodeRow(
|
|
5861
|
+
ctx,
|
|
5862
|
+
ctx.values,
|
|
5863
|
+
q2,
|
|
5864
|
+
QueryClass,
|
|
5865
|
+
v[0],
|
|
5866
|
+
runtimeDefaults,
|
|
5867
|
+
quotedAs
|
|
5868
|
+
)
|
|
5869
|
+
)
|
|
5870
|
+
);
|
|
5871
|
+
}
|
|
5872
|
+
ctx.sql[1] = getSqlText(makeSQL(q2, { values: ctx.values }));
|
|
5873
|
+
}
|
|
5874
|
+
return {
|
|
5875
|
+
hookSelect: returning.hookSelect,
|
|
5876
|
+
text: ctx.sql.join(" "),
|
|
5877
|
+
values: ctx.values
|
|
5878
|
+
};
|
|
5879
|
+
};
|
|
5880
|
+
const mergeColumnsSql = (columns, quotedColumns2, target, except) => {
|
|
5881
|
+
const notExcluded = [];
|
|
5882
|
+
const exclude = typeof target === "string" ? [target] : Array.isArray(target) ? [...target] : [];
|
|
5883
|
+
if (except) {
|
|
5884
|
+
if (typeof except === "string") {
|
|
5885
|
+
exclude.push(except);
|
|
5886
|
+
} else {
|
|
5887
|
+
exclude.push(...except);
|
|
5888
|
+
}
|
|
5889
|
+
}
|
|
5890
|
+
for (let i = 0; i < columns.length; i++) {
|
|
5891
|
+
if (!exclude.includes(columns[i])) {
|
|
5892
|
+
notExcluded.push(quotedColumns2[i]);
|
|
5893
|
+
}
|
|
5894
|
+
}
|
|
5895
|
+
return notExcluded.length ? `DO UPDATE SET ${notExcluded.map((column) => `${column} = excluded.${column}`).join(", ")}` : "DO NOTHING";
|
|
5896
|
+
};
|
|
5897
|
+
const encodeRow = (ctx, values, q, QueryClass, row, runtimeDefaults, quotedAs) => {
|
|
5898
|
+
const arr = row.map((value) => {
|
|
5899
|
+
if (value && typeof value === "object") {
|
|
5900
|
+
if (value instanceof orchidCore.Expression) {
|
|
5901
|
+
return value.toSQL(ctx, quotedAs);
|
|
5902
|
+
} else if (value instanceof QueryClass) {
|
|
5903
|
+
return `(${getSqlText(joinSubQuery(q, value).toSQL(ctx))})`;
|
|
5904
|
+
}
|
|
5905
|
+
}
|
|
5906
|
+
return value === void 0 ? "DEFAULT" : orchidCore.addValue(values, value);
|
|
5907
|
+
});
|
|
5908
|
+
if (runtimeDefaults) {
|
|
5909
|
+
for (const fn of runtimeDefaults) {
|
|
5910
|
+
arr.push(orchidCore.addValue(values, fn()));
|
|
5911
|
+
}
|
|
5912
|
+
}
|
|
5913
|
+
return arr.join(", ");
|
|
5914
|
+
};
|
|
5915
|
+
const hookSelectKeys = [
|
|
5916
|
+
null,
|
|
5917
|
+
"afterUpdateSelect",
|
|
5918
|
+
"afterCreateSelect",
|
|
5919
|
+
"afterDeleteSelect"
|
|
5920
|
+
];
|
|
5921
|
+
const makeReturningSql = (ctx, q, data, quotedAs, hookSelectI, addHookSelectI) => {
|
|
5922
|
+
if (data.inCTE) {
|
|
5923
|
+
if (hookSelectI !== 2) {
|
|
5924
|
+
const returning = makeReturningSql(
|
|
5925
|
+
ctx,
|
|
5926
|
+
q,
|
|
5927
|
+
data,
|
|
5928
|
+
quotedAs,
|
|
5929
|
+
2,
|
|
5930
|
+
hookSelectI
|
|
5931
|
+
);
|
|
5932
|
+
if (returning.hookSelect) {
|
|
5933
|
+
for (const [key, value] of returning.hookSelect) {
|
|
5934
|
+
data.inCTE.targetHookSelect.set(key, value);
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
return data.inCTE.returning = returning;
|
|
5938
|
+
}
|
|
5939
|
+
if (data.inCTE.returning) {
|
|
5940
|
+
return data.inCTE.returning;
|
|
5941
|
+
}
|
|
5942
|
+
}
|
|
5943
|
+
const hookSelect = hookSelectI && data[hookSelectKeys[hookSelectI]];
|
|
5944
|
+
const { select } = data;
|
|
5945
|
+
if (!q.q.hookSelect && !hookSelect?.size && !select?.length && !addHookSelectI) {
|
|
5946
|
+
return { hookSelect: hookSelect && /* @__PURE__ */ new Map() };
|
|
5947
|
+
}
|
|
5948
|
+
const otherCTEHookSelect = addHookSelectI && data[hookSelectKeys[addHookSelectI]];
|
|
5949
|
+
let tempSelect;
|
|
5950
|
+
if (q.q.hookSelect || hookSelect || otherCTEHookSelect) {
|
|
5951
|
+
tempSelect = new Map(q.q.hookSelect);
|
|
5952
|
+
if (hookSelect) {
|
|
5953
|
+
for (const column of hookSelect) {
|
|
5954
|
+
tempSelect.set(column, { select: column });
|
|
5955
|
+
}
|
|
5956
|
+
}
|
|
5957
|
+
if (otherCTEHookSelect) {
|
|
5958
|
+
for (const column of otherCTEHookSelect) {
|
|
5959
|
+
tempSelect.set(column, { select: column });
|
|
5960
|
+
}
|
|
5961
|
+
}
|
|
5962
|
+
}
|
|
5963
|
+
let sql;
|
|
5964
|
+
if (tempSelect?.size || select?.length) {
|
|
5965
|
+
sql = selectToSql(ctx, q, data, quotedAs, tempSelect, void 0, true);
|
|
5966
|
+
} else if (addHookSelectI) {
|
|
5967
|
+
sql = "1";
|
|
5968
|
+
}
|
|
5969
|
+
return { select: sql, hookSelect: tempSelect };
|
|
5970
|
+
};
|
|
5971
|
+
|
|
5653
5972
|
const pushSelectSql = (ctx, table, query, quotedAs, aliases) => {
|
|
5654
5973
|
const sql = selectToSql(
|
|
5655
5974
|
ctx,
|
|
@@ -5661,7 +5980,16 @@ const pushSelectSql = (ctx, table, query, quotedAs, aliases) => {
|
|
|
5661
5980
|
);
|
|
5662
5981
|
if (sql) ctx.sql.push(sql);
|
|
5663
5982
|
};
|
|
5664
|
-
const selectToSql = (ctx, table, query, quotedAs, hookSelect = query.hookSelect, aliases) => {
|
|
5983
|
+
const selectToSql = (ctx, table, query, quotedAs, hookSelect = query.hookSelect, aliases, skipCTE) => {
|
|
5984
|
+
if (query.inCTE && !skipCTE) {
|
|
5985
|
+
const { select } = makeReturningSql(
|
|
5986
|
+
ctx,
|
|
5987
|
+
table,
|
|
5988
|
+
query,
|
|
5989
|
+
quotedAs
|
|
5990
|
+
);
|
|
5991
|
+
return query.inCTE.selectNum ? select ? "0, " + select : "0" : select || "";
|
|
5992
|
+
}
|
|
5665
5993
|
let selected;
|
|
5666
5994
|
const list = [];
|
|
5667
5995
|
if (query.select) {
|
|
@@ -6005,371 +6333,116 @@ const pushFromAndAs = (ctx, table, data, quotedAs) => {
|
|
|
6005
6333
|
let fn;
|
|
6006
6334
|
let query;
|
|
6007
6335
|
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 (orchidCore.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) : orchidCore.isRawSQL(source.language) ? source.language.toSQL(ctx) : orchidCore.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 = orchidCore.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++]}), ${orchidCore.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 (orchidCore.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}" = ${orchidCore.addValue(
|
|
6202
|
-
ctx.values,
|
|
6203
|
-
set[key]
|
|
6204
|
-
)}`
|
|
6205
|
-
);
|
|
6206
|
-
}
|
|
6207
|
-
sql = arr.join(", ");
|
|
6208
|
-
}
|
|
6209
|
-
ctx.sql.push("DO UPDATE SET", sql);
|
|
6336
|
+
fn = "websearch_to_tsquery";
|
|
6337
|
+
query = source.query;
|
|
6338
|
+
} else if ("plainQuery" in source) {
|
|
6339
|
+
fn = "plainto_tsquery";
|
|
6340
|
+
query = source.plainQuery;
|
|
6341
|
+
} else if ("phraseQuery" in source) {
|
|
6342
|
+
fn = "phraseto_tsquery";
|
|
6343
|
+
query = source.phraseQuery;
|
|
6210
6344
|
} 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 = orchidCore.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
|
-
}
|
|
6345
|
+
fn = "to_tsquery";
|
|
6346
|
+
query = source.tsQuery;
|
|
6257
6347
|
}
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
values: ctxValues
|
|
6263
|
-
});
|
|
6264
|
-
return {
|
|
6265
|
-
hookSelect,
|
|
6266
|
-
batch
|
|
6267
|
-
};
|
|
6348
|
+
let querySql;
|
|
6349
|
+
if (typeof query === "string") {
|
|
6350
|
+
ctx.values.push(query);
|
|
6351
|
+
querySql = `$${ctx.values.length}`;
|
|
6268
6352
|
} else {
|
|
6269
|
-
|
|
6353
|
+
querySql = `${query.toSQL(ctx, quotedAs)}`;
|
|
6270
6354
|
}
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6355
|
+
sql += `, ${fn}(${lang}, ${querySql}) "${as}"`;
|
|
6356
|
+
}
|
|
6357
|
+
ctx.sql.push(sql);
|
|
6358
|
+
};
|
|
6359
|
+
const getFrom = (ctx, table, data, quotedAs) => {
|
|
6360
|
+
if (data.from) {
|
|
6361
|
+
const { from } = data;
|
|
6362
|
+
if (Array.isArray(from)) {
|
|
6363
|
+
return from.map((item) => fromToSql(ctx, data, item, quotedAs)).join(", ");
|
|
6364
|
+
}
|
|
6365
|
+
return fromToSql(ctx, data, from, quotedAs);
|
|
6366
|
+
}
|
|
6367
|
+
let sql = quoteSchemaAndTable(data.schema, table.table);
|
|
6368
|
+
if (data.only) sql = `ONLY ${sql}`;
|
|
6369
|
+
return sql;
|
|
6370
|
+
};
|
|
6371
|
+
const fromToSql = (ctx, data, from, quotedAs) => {
|
|
6372
|
+
let only;
|
|
6373
|
+
let sql;
|
|
6374
|
+
if (typeof from === "object") {
|
|
6375
|
+
if (orchidCore.isExpression(from)) {
|
|
6376
|
+
sql = from.toSQL(ctx, quotedAs);
|
|
6278
6377
|
} 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) => orchidCore.addValue(v, fn())).join(", ")})`
|
|
6286
|
-
)
|
|
6287
|
-
).join(", ");
|
|
6378
|
+
only = from.q.only;
|
|
6379
|
+
if (!from.table) {
|
|
6380
|
+
sql = `(${getSqlText(makeSQL(from, ctx))})`;
|
|
6381
|
+
} else if (!checkIfASimpleQuery(from)) {
|
|
6382
|
+
sql = `(${getSqlText(makeSQL(from, ctx))})`;
|
|
6288
6383
|
} else {
|
|
6289
|
-
sql =
|
|
6384
|
+
sql = quoteSchemaAndTable(from.q.schema, from.table);
|
|
6290
6385
|
}
|
|
6291
|
-
ctx.sql[1] = `VALUES ${sql}`;
|
|
6292
6386
|
}
|
|
6293
6387
|
} 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 }));
|
|
6388
|
+
sql = quoteSchemaAndTable(data.schema, from);
|
|
6314
6389
|
}
|
|
6315
|
-
return {
|
|
6316
|
-
hookSelect,
|
|
6317
|
-
text: ctx.sql.join(" "),
|
|
6318
|
-
values: ctx.values
|
|
6319
|
-
};
|
|
6390
|
+
return (only === void 0 ? data.only : only) ? `ONLY ${sql}` : sql;
|
|
6320
6391
|
};
|
|
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";
|
|
6392
|
+
const getSearchLang = (ctx, data, source, quotedAs) => {
|
|
6393
|
+
return source.langSQL ?? (source.langSQL = "languageColumn" in source ? columnToSql(ctx, data, data.shape, source.languageColumn, quotedAs) : orchidCore.isRawSQL(source.language) ? source.language.toSQL(ctx) : orchidCore.addValue(ctx.values, source.language || data.language || "english"));
|
|
6337
6394
|
};
|
|
6338
|
-
const
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6395
|
+
const getSearchText = (ctx, data, source, quotedAs, forHeadline) => {
|
|
6396
|
+
let sql = source.textSQL;
|
|
6397
|
+
if (sql) return sql;
|
|
6398
|
+
if ("in" in source) {
|
|
6399
|
+
if (typeof source.in === "string") {
|
|
6400
|
+
sql = columnToSql(ctx, data, data.shape, source.in, quotedAs);
|
|
6401
|
+
} else if (Array.isArray(source.in)) {
|
|
6402
|
+
sql = `concat_ws(' ', ${source.in.map((column) => columnToSql(ctx, data, data.shape, column, quotedAs)).join(", ")})`;
|
|
6403
|
+
} else {
|
|
6404
|
+
sql = [];
|
|
6405
|
+
for (const key in source.in) {
|
|
6406
|
+
sql.push(columnToSql(ctx, data, data.shape, key, quotedAs));
|
|
6345
6407
|
}
|
|
6346
6408
|
}
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6409
|
+
} else if ("vector" in source) {
|
|
6410
|
+
if (forHeadline) {
|
|
6411
|
+
throw new Error(
|
|
6412
|
+
"Cannot use a search based on a vector column for a search headline"
|
|
6413
|
+
);
|
|
6414
|
+
}
|
|
6415
|
+
sql = columnToSql(ctx, data, data.shape, source.vector, quotedAs);
|
|
6416
|
+
} else {
|
|
6417
|
+
if (typeof source.text === "string") {
|
|
6418
|
+
sql = orchidCore.addValue(ctx.values, source.text);
|
|
6419
|
+
} else {
|
|
6420
|
+
sql = source.text.toSQL(ctx, quotedAs);
|
|
6352
6421
|
}
|
|
6353
6422
|
}
|
|
6354
|
-
return
|
|
6423
|
+
return source.textSQL = sql;
|
|
6355
6424
|
};
|
|
6356
|
-
const
|
|
6357
|
-
const
|
|
6358
|
-
if (
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6425
|
+
const getTsVector = (ctx, data, lang, source, quotedAs) => {
|
|
6426
|
+
const text = getSearchText(ctx, data, source, quotedAs);
|
|
6427
|
+
if ("in" in source) {
|
|
6428
|
+
if (typeof source.in === "string" || Array.isArray(source.in)) {
|
|
6429
|
+
return `to_tsvector(${lang}, ${text})`;
|
|
6430
|
+
} else {
|
|
6431
|
+
let tsVector = "";
|
|
6432
|
+
let i = 0;
|
|
6433
|
+
for (const key in source.in) {
|
|
6434
|
+
tsVector = (tsVector ? `${tsVector} || ` : "") + `setweight(to_tsvector(${lang}, ${text[i++]}), ${orchidCore.addValue(
|
|
6435
|
+
ctx.values,
|
|
6436
|
+
source.in[key]
|
|
6437
|
+
)})`;
|
|
6365
6438
|
}
|
|
6439
|
+
return tsVector;
|
|
6366
6440
|
}
|
|
6367
|
-
|
|
6368
|
-
return
|
|
6369
|
-
} else
|
|
6370
|
-
|
|
6441
|
+
} else if ("vector" in source) {
|
|
6442
|
+
return text;
|
|
6443
|
+
} else {
|
|
6444
|
+
return `to_tsvector(${lang}, ${text})`;
|
|
6371
6445
|
}
|
|
6372
|
-
return;
|
|
6373
6446
|
};
|
|
6374
6447
|
|
|
6375
6448
|
const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
@@ -6380,12 +6453,11 @@ const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
|
6380
6453
|
if (!query.select) {
|
|
6381
6454
|
query.select = countSelect;
|
|
6382
6455
|
}
|
|
6383
|
-
const hookSelect =
|
|
6456
|
+
const hookSelect = pushUpdateReturning(
|
|
6384
6457
|
ctx,
|
|
6385
6458
|
table,
|
|
6386
6459
|
query,
|
|
6387
6460
|
quotedAs,
|
|
6388
|
-
query.afterUpdateSelect,
|
|
6389
6461
|
"SELECT"
|
|
6390
6462
|
);
|
|
6391
6463
|
ctx.sql.push(`FROM ${quotedTable}`);
|
|
@@ -6400,7 +6472,21 @@ const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
|
6400
6472
|
ctx.sql.push("SET");
|
|
6401
6473
|
ctx.sql.push(set.join(", "));
|
|
6402
6474
|
pushWhereStatementSql(ctx, table, query, quotedAs);
|
|
6403
|
-
return
|
|
6475
|
+
return pushUpdateReturning(ctx, table, query, quotedAs, "RETURNING");
|
|
6476
|
+
};
|
|
6477
|
+
const pushUpdateReturning = (ctx, table, query, quotedAs, keyword) => {
|
|
6478
|
+
const { inCTE } = query;
|
|
6479
|
+
const { select, hookSelect } = makeReturningSql(
|
|
6480
|
+
ctx,
|
|
6481
|
+
table,
|
|
6482
|
+
query,
|
|
6483
|
+
quotedAs,
|
|
6484
|
+
1,
|
|
6485
|
+
inCTE && 2
|
|
6486
|
+
);
|
|
6487
|
+
const s = inCTE?.selectNum ? select ? "0, " + select : "0" : select;
|
|
6488
|
+
if (s) ctx.sql.push(keyword, s);
|
|
6489
|
+
return hookSelect;
|
|
6404
6490
|
};
|
|
6405
6491
|
const processData = (ctx, table, set, data, quotedAs) => {
|
|
6406
6492
|
let append;
|
|
@@ -6483,7 +6569,9 @@ const pushDeleteSql = (ctx, table, query, quotedAs) => {
|
|
|
6483
6569
|
ctx.sql.push("WHERE", conditions);
|
|
6484
6570
|
}
|
|
6485
6571
|
}
|
|
6486
|
-
|
|
6572
|
+
const returning = makeReturningSql(ctx, table, query, quotedAs, 3);
|
|
6573
|
+
if (returning.select) ctx.sql.push("RETURNING", returning.select);
|
|
6574
|
+
return returning.hookSelect;
|
|
6487
6575
|
};
|
|
6488
6576
|
|
|
6489
6577
|
const pushTruncateSql = (ctx, table, query) => {
|
|
@@ -6562,7 +6650,7 @@ const makeSQL = (table, options) => {
|
|
|
6562
6650
|
if (query.with) {
|
|
6563
6651
|
pushWithSql(ctx, query.with);
|
|
6564
6652
|
}
|
|
6565
|
-
if (query.type) {
|
|
6653
|
+
if (query.type && query.type !== "upsert") {
|
|
6566
6654
|
const tableName = table.table ?? query.as;
|
|
6567
6655
|
if (!tableName) throw new Error(`Table is missing for ${query.type}`);
|
|
6568
6656
|
if (query.type === "truncate") {
|
|
@@ -6598,10 +6686,11 @@ const makeSQL = (table, options) => {
|
|
|
6598
6686
|
}
|
|
6599
6687
|
const quotedAs = (query.as || table.table) && `"${query.as || table.table}"`;
|
|
6600
6688
|
if (query.union) {
|
|
6601
|
-
|
|
6689
|
+
const s = getSqlText(makeSQL(query.union.b, { values }));
|
|
6690
|
+
sql.push(query.union.p ? s : `(${s})`);
|
|
6602
6691
|
for (const u of query.union.u) {
|
|
6603
|
-
const
|
|
6604
|
-
sql.push(`${u.k}
|
|
6692
|
+
const s2 = orchidCore.isExpression(u.a) ? u.a.toSQL(ctx, quotedAs) : getSqlText(makeSQL(u.a, { values }));
|
|
6693
|
+
sql.push(`${u.k} ${u.p ? s2 : "(" + s2 + ")"}`);
|
|
6605
6694
|
}
|
|
6606
6695
|
} else {
|
|
6607
6696
|
sql.push("SELECT");
|
|
@@ -9987,12 +10076,13 @@ class MergeQueryMethods {
|
|
|
9987
10076
|
}
|
|
9988
10077
|
}
|
|
9989
10078
|
|
|
9990
|
-
const _queryUnion = (base, args, k) => {
|
|
10079
|
+
const _queryUnion = (base, args, k, p, m) => {
|
|
9991
10080
|
const q = base.baseQuery.clone();
|
|
9992
10081
|
const u = args.map(
|
|
9993
10082
|
(a) => ({
|
|
9994
10083
|
a: typeof a === "function" ? a(q) : a,
|
|
9995
|
-
k
|
|
10084
|
+
k,
|
|
10085
|
+
m
|
|
9996
10086
|
})
|
|
9997
10087
|
);
|
|
9998
10088
|
const union = q.q.union = base.q.union;
|
|
@@ -10001,7 +10091,8 @@ const _queryUnion = (base, args, k) => {
|
|
|
10001
10091
|
} else {
|
|
10002
10092
|
q.q.union = {
|
|
10003
10093
|
b: base,
|
|
10004
|
-
u
|
|
10094
|
+
u,
|
|
10095
|
+
p
|
|
10005
10096
|
};
|
|
10006
10097
|
}
|
|
10007
10098
|
return q;
|
|
@@ -10279,7 +10370,7 @@ const _queryUpdate = (query, arg) => {
|
|
|
10279
10370
|
}
|
|
10280
10371
|
const { queries } = ctx;
|
|
10281
10372
|
if (queries) {
|
|
10282
|
-
q.patchResult = async (_, queryResult) => {
|
|
10373
|
+
q.patchResult = async (_, _h, queryResult) => {
|
|
10283
10374
|
await Promise.all(queries.map(orchidCore.callWithThis, queryResult));
|
|
10284
10375
|
if (ctx.collect) {
|
|
10285
10376
|
const t = query.baseQuery.clone();
|
|
@@ -10868,26 +10959,80 @@ class SearchMethods {
|
|
|
10868
10959
|
|
|
10869
10960
|
function orCreate(query, data, updateData, mergeData) {
|
|
10870
10961
|
const { q } = query;
|
|
10871
|
-
q.
|
|
10872
|
-
q.
|
|
10962
|
+
q.returnsOne = true;
|
|
10963
|
+
if (!q.select) {
|
|
10964
|
+
q.returnType = "void";
|
|
10965
|
+
}
|
|
10873
10966
|
const { handleResult } = q;
|
|
10874
10967
|
let result;
|
|
10875
10968
|
let created = false;
|
|
10876
10969
|
q.handleResult = (q2, t, r, s) => {
|
|
10877
10970
|
return created ? result : handleResult(q2, t, r, s);
|
|
10878
10971
|
};
|
|
10879
|
-
q.
|
|
10972
|
+
q.hookSelect ?? (q.hookSelect = /* @__PURE__ */ new Map());
|
|
10973
|
+
q.patchResult = async (q2, hookSelect, queryResult) => {
|
|
10974
|
+
var _a, _b;
|
|
10880
10975
|
if (queryResult.rowCount === 0) {
|
|
10881
10976
|
if (typeof data === "function") {
|
|
10882
10977
|
data = data(updateData);
|
|
10883
10978
|
}
|
|
10884
10979
|
if (mergeData) data = { ...mergeData, ...data };
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10980
|
+
let hasAfterCallback = q2.q.afterCreate;
|
|
10981
|
+
let hasAfterCommitCallback = q2.q.afterCreateCommit;
|
|
10982
|
+
if (updateData) {
|
|
10983
|
+
hasAfterCallback = hasAfterCallback || q2.q.afterUpdate;
|
|
10984
|
+
hasAfterCommitCallback = hasAfterCommitCallback || q2.q.afterUpdateCommit;
|
|
10985
|
+
}
|
|
10986
|
+
const inCTE = {
|
|
10987
|
+
selectNum: !!(hasAfterCallback || hasAfterCommitCallback),
|
|
10988
|
+
targetHookSelect: hookSelect
|
|
10889
10989
|
};
|
|
10890
|
-
|
|
10990
|
+
q2 = q2.clone();
|
|
10991
|
+
q2.q.inCTE = inCTE;
|
|
10992
|
+
const c = q2.create(data);
|
|
10993
|
+
c.q.select = q2.q.select;
|
|
10994
|
+
let q22 = q2.queryBuilder.with("f", q2).with("c", c);
|
|
10995
|
+
q22.q.returnsOne = true;
|
|
10996
|
+
queryFrom(q22, "f");
|
|
10997
|
+
q22 = _queryUnion(
|
|
10998
|
+
q22,
|
|
10999
|
+
[q2.queryBuilder.from("c")],
|
|
11000
|
+
"UNION ALL",
|
|
11001
|
+
true,
|
|
11002
|
+
true
|
|
11003
|
+
);
|
|
11004
|
+
let afterHooks;
|
|
11005
|
+
let afterCommitHooks;
|
|
11006
|
+
q22.q.handleResult = (a, t, r, s) => {
|
|
11007
|
+
if (hasAfterCallback || hasAfterCommitCallback) {
|
|
11008
|
+
const fieldName = r.fields[0].name;
|
|
11009
|
+
if (r.rows[0][fieldName]) {
|
|
11010
|
+
afterHooks = q2.q.afterCreate;
|
|
11011
|
+
afterCommitHooks = q2.q.afterCreateCommit;
|
|
11012
|
+
} else {
|
|
11013
|
+
afterHooks = q2.q.afterUpdate;
|
|
11014
|
+
afterCommitHooks = q2.q.afterUpdateCommit;
|
|
11015
|
+
}
|
|
11016
|
+
delete r.rows[0][fieldName];
|
|
11017
|
+
}
|
|
11018
|
+
result = handleResult(a, t, r, s);
|
|
11019
|
+
return a.q.hookSelect ? result.map((row) => ({ ...row })) : result;
|
|
11020
|
+
};
|
|
11021
|
+
q22.q.log = q2.q.log;
|
|
11022
|
+
q22.q.logger = q2.q.logger;
|
|
11023
|
+
q22.q.type = "upsert";
|
|
11024
|
+
q22.q.beforeCreate = q2.q.beforeCreate;
|
|
11025
|
+
if (hasAfterCallback) {
|
|
11026
|
+
((_a = q22.q).afterCreate ?? (_a.afterCreate = [])).push(
|
|
11027
|
+
(data2, query2) => afterHooks && Promise.all([...afterHooks].map((fn) => fn(data2, query2)))
|
|
11028
|
+
);
|
|
11029
|
+
}
|
|
11030
|
+
if (hasAfterCommitCallback) {
|
|
11031
|
+
((_b = q22.q).afterCreateCommit ?? (_b.afterCreateCommit = [])).push(
|
|
11032
|
+
(data2, query2) => afterCommitHooks && Promise.all([...afterCommitHooks].map((fn) => fn(data2, query2)))
|
|
11033
|
+
);
|
|
11034
|
+
}
|
|
11035
|
+
await q22;
|
|
10891
11036
|
created = true;
|
|
10892
11037
|
} else if (queryResult.rowCount > 1) {
|
|
10893
11038
|
throw new MoreThanOneRowError(
|
|
@@ -10900,9 +11045,7 @@ function orCreate(query, data, updateData, mergeData) {
|
|
|
10900
11045
|
}
|
|
10901
11046
|
class QueryUpsertOrCreate {
|
|
10902
11047
|
/**
|
|
10903
|
-
* `upsert` tries to update
|
|
10904
|
-
*
|
|
10905
|
-
* It will implicitly wrap queries in a transaction if it was not wrapped yet.
|
|
11048
|
+
* `upsert` tries to update a single record, and then it creates the record if it doesn't yet exist.
|
|
10906
11049
|
*
|
|
10907
11050
|
* `find` or `findBy` must precede `upsert` because it does not work with multiple updates.
|
|
10908
11051
|
*
|
|
@@ -10913,7 +11056,7 @@ class QueryUpsertOrCreate {
|
|
|
10913
11056
|
*
|
|
10914
11057
|
* `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
11058
|
*
|
|
10916
|
-
*
|
|
11059
|
+
* No values are returned by default, place `select` or `selectAll` before `upsert` to specify returning columns.
|
|
10917
11060
|
*
|
|
10918
11061
|
* ```ts
|
|
10919
11062
|
* await User.selectAll()
|
|
@@ -10990,6 +11133,9 @@ class QueryUpsertOrCreate {
|
|
|
10990
11133
|
* });
|
|
10991
11134
|
* ```
|
|
10992
11135
|
*
|
|
11136
|
+
* `upsert` works in the exact same way as [orCreate](#orCreate), but with `UPDATE` statement instead of `SELECT`.
|
|
11137
|
+
* it also performs a single query if the record exists, and two queries if there is no record yet.
|
|
11138
|
+
*
|
|
10993
11139
|
* @param data - `update` property for the data to update, `create` property for the data to create
|
|
10994
11140
|
*/
|
|
10995
11141
|
upsert(data) {
|
|
@@ -11004,22 +11150,16 @@ class QueryUpsertOrCreate {
|
|
|
11004
11150
|
if (!orchidCore.isObjectEmpty(updateData)) {
|
|
11005
11151
|
_queryUpdate(q, updateData);
|
|
11006
11152
|
}
|
|
11007
|
-
|
|
11008
|
-
if (!c.q.select) {
|
|
11009
|
-
c.q.returnType = "void";
|
|
11010
|
-
}
|
|
11011
|
-
return c;
|
|
11153
|
+
return orCreate(q, data.create, updateData, mergeData);
|
|
11012
11154
|
}
|
|
11013
11155
|
/**
|
|
11014
11156
|
* `orCreate` creates a record only if it was not found by conditions.
|
|
11015
11157
|
*
|
|
11016
|
-
* It will implicitly wrap queries in a transaction if it was not wrapped yet.
|
|
11017
|
-
*
|
|
11018
11158
|
* `find` or `findBy` must precede `orCreate`.
|
|
11019
11159
|
*
|
|
11020
11160
|
* It is accepting the same argument as `create` commands.
|
|
11021
11161
|
*
|
|
11022
|
-
*
|
|
11162
|
+
* No result is returned by default, place `get`, `select`, or `selectAll` before `orCreate` to specify returning columns.
|
|
11023
11163
|
*
|
|
11024
11164
|
* ```ts
|
|
11025
11165
|
* const user = await User.selectAll()
|
|
@@ -11030,7 +11170,7 @@ class QueryUpsertOrCreate {
|
|
|
11030
11170
|
* });
|
|
11031
11171
|
* ```
|
|
11032
11172
|
*
|
|
11033
|
-
* The data
|
|
11173
|
+
* The data can be returned from a function, it won't be called if the record was found:
|
|
11034
11174
|
*
|
|
11035
11175
|
* ```ts
|
|
11036
11176
|
* const user = await User.selectAll()
|
|
@@ -11041,6 +11181,35 @@ class QueryUpsertOrCreate {
|
|
|
11041
11181
|
* }));
|
|
11042
11182
|
* ```
|
|
11043
11183
|
*
|
|
11184
|
+
* `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.
|
|
11185
|
+
*
|
|
11186
|
+
* At first, it performs a "find" query, the query cost is exact same as if you didn't use `orCreate`.
|
|
11187
|
+
*
|
|
11188
|
+
* 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,
|
|
11189
|
+
* 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.
|
|
11190
|
+
*
|
|
11191
|
+
* ```sql
|
|
11192
|
+
* -- first query
|
|
11193
|
+
* SELECT * FROM "table" WHERE "key" = 'value'
|
|
11194
|
+
*
|
|
11195
|
+
* -- the record could have been created in between these two queries
|
|
11196
|
+
*
|
|
11197
|
+
* -- second query
|
|
11198
|
+
* WITH find_row AS (
|
|
11199
|
+
* SELECT * FROM "table" WHERE "key" = 'value'
|
|
11200
|
+
* )
|
|
11201
|
+
* WITH insert_row AS (
|
|
11202
|
+
* INSERT INTO "table" ("key")
|
|
11203
|
+
* SELECT 'value'
|
|
11204
|
+
* -- skip the insert if the row already exists
|
|
11205
|
+
* WHERE NOT EXISTS (SELECT 1 FROM find_row)
|
|
11206
|
+
* RETURNING *
|
|
11207
|
+
* )
|
|
11208
|
+
* SELECT * FROM find_row
|
|
11209
|
+
* UNION ALL
|
|
11210
|
+
* SELECT * FROM insert_row
|
|
11211
|
+
* ```
|
|
11212
|
+
*
|
|
11044
11213
|
* @param data - the same data as for `create`, it may be returned from a callback
|
|
11045
11214
|
*/
|
|
11046
11215
|
orCreate(data) {
|
|
@@ -11279,16 +11448,17 @@ class ColumnRefExpression extends orchidCore.Expression {
|
|
|
11279
11448
|
}
|
|
11280
11449
|
}
|
|
11281
11450
|
class RefExpression extends orchidCore.Expression {
|
|
11282
|
-
constructor(value,
|
|
11451
|
+
constructor(value, query, ref) {
|
|
11283
11452
|
super();
|
|
11284
|
-
this.q = q;
|
|
11285
11453
|
this.ref = ref;
|
|
11286
11454
|
this.result = { value };
|
|
11287
|
-
q.expr = this;
|
|
11455
|
+
(this.q = query.q).expr = this;
|
|
11456
|
+
this.table = query.table;
|
|
11288
11457
|
Object.assign(this, value.operators);
|
|
11289
11458
|
}
|
|
11290
|
-
makeSQL(ctx
|
|
11291
|
-
|
|
11459
|
+
makeSQL(ctx) {
|
|
11460
|
+
const as = this.q.as || this.table;
|
|
11461
|
+
return columnToSql(ctx, this.q, this.q.shape, this.ref, as && `"${as}"`);
|
|
11292
11462
|
}
|
|
11293
11463
|
}
|
|
11294
11464
|
class OrExpression extends orchidCore.Expression {
|
|
@@ -11384,7 +11554,7 @@ class ExpressionMethods {
|
|
|
11384
11554
|
} else {
|
|
11385
11555
|
column = shape[arg];
|
|
11386
11556
|
}
|
|
11387
|
-
return new RefExpression(column, q
|
|
11557
|
+
return new RefExpression(column, q, arg);
|
|
11388
11558
|
}
|
|
11389
11559
|
val(value) {
|
|
11390
11560
|
return new orchidCore.ValExpression(value);
|
|
@@ -12099,6 +12269,9 @@ class QueryMethods {
|
|
|
12099
12269
|
narrowType() {
|
|
12100
12270
|
return () => this;
|
|
12101
12271
|
}
|
|
12272
|
+
if(condition, fn) {
|
|
12273
|
+
return condition ? fn(this) : this;
|
|
12274
|
+
}
|
|
12102
12275
|
queryRelated(relName, params) {
|
|
12103
12276
|
return this.relations[relName].relationConfig.queryRelated(
|
|
12104
12277
|
params
|