pqb 0.43.1 → 0.43.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +87 -33
- package/dist/index.js +563 -392
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +564 -393
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1247,11 +1247,13 @@ class TextColumn extends TextBaseColumn {
|
|
|
1247
1247
|
return textColumnToCode(this, ctx, key);
|
|
1248
1248
|
}
|
|
1249
1249
|
}
|
|
1250
|
+
const byteaParse = (val) => typeof val === "string" ? Buffer.from(val.slice(2), "hex") : val;
|
|
1250
1251
|
class ByteaColumn extends ColumnType {
|
|
1251
1252
|
constructor(schema) {
|
|
1252
1253
|
super(schema, schema.buffer());
|
|
1253
1254
|
this.dataType = "bytea";
|
|
1254
1255
|
this.operators = Operators.text;
|
|
1256
|
+
setColumnDefaultParse(this, byteaParse);
|
|
1255
1257
|
}
|
|
1256
1258
|
toCode(ctx, key) {
|
|
1257
1259
|
return columnCode(this, ctx, key, `bytea()`);
|
|
@@ -4468,7 +4470,7 @@ function maybeWrappedThen(resolve, reject) {
|
|
|
4468
4470
|
let afterHooks;
|
|
4469
4471
|
let afterCommitHooks;
|
|
4470
4472
|
if (q.type) {
|
|
4471
|
-
if (q.type === "insert") {
|
|
4473
|
+
if (q.type === "insert" || q.type === "upsert") {
|
|
4472
4474
|
beforeHooks = q.beforeCreate;
|
|
4473
4475
|
afterHooks = q.afterCreate;
|
|
4474
4476
|
afterCommitHooks = q.afterCreateCommit;
|
|
@@ -4546,14 +4548,18 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4546
4548
|
if (log) {
|
|
4547
4549
|
logData = log.beforeQuery(sql);
|
|
4548
4550
|
}
|
|
4549
|
-
queryResult = await
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4551
|
+
queryResult = await execQuery(
|
|
4552
|
+
adapter,
|
|
4553
|
+
queryMethodByReturnType[tempReturnType],
|
|
4554
|
+
sql
|
|
4555
|
+
);
|
|
4553
4556
|
if (log) {
|
|
4554
4557
|
log.afterQuery(sql, logData);
|
|
4555
4558
|
sql = void 0;
|
|
4556
4559
|
}
|
|
4560
|
+
if (query.patchResult) {
|
|
4561
|
+
await query.patchResult(q, hookSelect, queryResult);
|
|
4562
|
+
}
|
|
4557
4563
|
result = query.handleResult(q, tempReturnType, queryResult);
|
|
4558
4564
|
} else {
|
|
4559
4565
|
const queryMethod = queryMethodByReturnType[tempReturnType];
|
|
@@ -4567,7 +4573,7 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4567
4573
|
if (log) {
|
|
4568
4574
|
logData = log.beforeQuery(sql);
|
|
4569
4575
|
}
|
|
4570
|
-
const result2 = await adapter
|
|
4576
|
+
const result2 = await execQuery(adapter, queryMethod, sql);
|
|
4571
4577
|
if (queryResult) {
|
|
4572
4578
|
queryResult.rowCount += result2.rowCount;
|
|
4573
4579
|
queryResult.rows.push(...result2.rows);
|
|
@@ -4585,7 +4591,7 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4585
4591
|
if (log) log.afterQuery(commitSql$1, logData);
|
|
4586
4592
|
}
|
|
4587
4593
|
if (query.patchResult) {
|
|
4588
|
-
await query.patchResult(q, queryResult);
|
|
4594
|
+
await query.patchResult(q, hookSelect, queryResult);
|
|
4589
4595
|
}
|
|
4590
4596
|
result = query.handleResult(q, tempReturnType, queryResult);
|
|
4591
4597
|
}
|
|
@@ -4713,6 +4719,17 @@ const then = async (q, adapter, trx, beforeHooks, afterHooks, afterCommitHooks,
|
|
|
4713
4719
|
return reject?.(error);
|
|
4714
4720
|
}
|
|
4715
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
|
+
};
|
|
4716
4733
|
const assignError = (to, from) => {
|
|
4717
4734
|
to.message = from.message;
|
|
4718
4735
|
to.length = from.length;
|
|
@@ -5652,6 +5669,306 @@ function queryJson(self, coalesce) {
|
|
|
5652
5669
|
return q;
|
|
5653
5670
|
}
|
|
5654
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
|
+
|
|
5655
5972
|
const pushSelectSql = (ctx, table, query, quotedAs, aliases) => {
|
|
5656
5973
|
const sql = selectToSql(
|
|
5657
5974
|
ctx,
|
|
@@ -5663,7 +5980,16 @@ const pushSelectSql = (ctx, table, query, quotedAs, aliases) => {
|
|
|
5663
5980
|
);
|
|
5664
5981
|
if (sql) ctx.sql.push(sql);
|
|
5665
5982
|
};
|
|
5666
|
-
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
|
+
}
|
|
5667
5993
|
let selected;
|
|
5668
5994
|
const list = [];
|
|
5669
5995
|
if (query.select) {
|
|
@@ -6007,371 +6333,116 @@ const pushFromAndAs = (ctx, table, data, quotedAs) => {
|
|
|
6007
6333
|
let fn;
|
|
6008
6334
|
let query;
|
|
6009
6335
|
if ("query" in source) {
|
|
6010
|
-
fn = "websearch_to_tsquery";
|
|
6011
|
-
query = source.query;
|
|
6012
|
-
} else if ("plainQuery" in source) {
|
|
6013
|
-
fn = "plainto_tsquery";
|
|
6014
|
-
query = source.plainQuery;
|
|
6015
|
-
} else if ("phraseQuery" in source) {
|
|
6016
|
-
fn = "phraseto_tsquery";
|
|
6017
|
-
query = source.phraseQuery;
|
|
6018
|
-
} else {
|
|
6019
|
-
fn = "to_tsquery";
|
|
6020
|
-
query = source.tsQuery;
|
|
6021
|
-
}
|
|
6022
|
-
let querySql;
|
|
6023
|
-
if (typeof query === "string") {
|
|
6024
|
-
ctx.values.push(query);
|
|
6025
|
-
querySql = `$${ctx.values.length}`;
|
|
6026
|
-
} else {
|
|
6027
|
-
querySql = `${query.toSQL(ctx, quotedAs)}`;
|
|
6028
|
-
}
|
|
6029
|
-
sql += `, ${fn}(${lang}, ${querySql}) "${as}"`;
|
|
6030
|
-
}
|
|
6031
|
-
ctx.sql.push(sql);
|
|
6032
|
-
};
|
|
6033
|
-
const getFrom = (ctx, table, data, quotedAs) => {
|
|
6034
|
-
if (data.from) {
|
|
6035
|
-
const { from } = data;
|
|
6036
|
-
if (Array.isArray(from)) {
|
|
6037
|
-
return from.map((item) => fromToSql(ctx, data, item, quotedAs)).join(", ");
|
|
6038
|
-
}
|
|
6039
|
-
return fromToSql(ctx, data, from, quotedAs);
|
|
6040
|
-
}
|
|
6041
|
-
let sql = quoteSchemaAndTable(data.schema, table.table);
|
|
6042
|
-
if (data.only) sql = `ONLY ${sql}`;
|
|
6043
|
-
return sql;
|
|
6044
|
-
};
|
|
6045
|
-
const fromToSql = (ctx, data, from, quotedAs) => {
|
|
6046
|
-
let only;
|
|
6047
|
-
let sql;
|
|
6048
|
-
if (typeof from === "object") {
|
|
6049
|
-
if (orchidCore.isExpression(from)) {
|
|
6050
|
-
sql = from.toSQL(ctx, quotedAs);
|
|
6051
|
-
} else {
|
|
6052
|
-
only = from.q.only;
|
|
6053
|
-
if (!from.table) {
|
|
6054
|
-
sql = `(${getSqlText(makeSQL(from, ctx))})`;
|
|
6055
|
-
} else if (!checkIfASimpleQuery(from)) {
|
|
6056
|
-
sql = `(${getSqlText(makeSQL(from, ctx))})`;
|
|
6057
|
-
} else {
|
|
6058
|
-
sql = quoteSchemaAndTable(from.q.schema, from.table);
|
|
6059
|
-
}
|
|
6060
|
-
}
|
|
6061
|
-
} else {
|
|
6062
|
-
sql = quoteSchemaAndTable(data.schema, from);
|
|
6063
|
-
}
|
|
6064
|
-
return (only === void 0 ? data.only : only) ? `ONLY ${sql}` : sql;
|
|
6065
|
-
};
|
|
6066
|
-
const getSearchLang = (ctx, data, source, quotedAs) => {
|
|
6067
|
-
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"));
|
|
6068
|
-
};
|
|
6069
|
-
const getSearchText = (ctx, data, source, quotedAs, forHeadline) => {
|
|
6070
|
-
let sql = source.textSQL;
|
|
6071
|
-
if (sql) return sql;
|
|
6072
|
-
if ("in" in source) {
|
|
6073
|
-
if (typeof source.in === "string") {
|
|
6074
|
-
sql = columnToSql(ctx, data, data.shape, source.in, quotedAs);
|
|
6075
|
-
} else if (Array.isArray(source.in)) {
|
|
6076
|
-
sql = `concat_ws(' ', ${source.in.map((column) => columnToSql(ctx, data, data.shape, column, quotedAs)).join(", ")})`;
|
|
6077
|
-
} else {
|
|
6078
|
-
sql = [];
|
|
6079
|
-
for (const key in source.in) {
|
|
6080
|
-
sql.push(columnToSql(ctx, data, data.shape, key, quotedAs));
|
|
6081
|
-
}
|
|
6082
|
-
}
|
|
6083
|
-
} else if ("vector" in source) {
|
|
6084
|
-
if (forHeadline) {
|
|
6085
|
-
throw new Error(
|
|
6086
|
-
"Cannot use a search based on a vector column for a search headline"
|
|
6087
|
-
);
|
|
6088
|
-
}
|
|
6089
|
-
sql = columnToSql(ctx, data, data.shape, source.vector, quotedAs);
|
|
6090
|
-
} else {
|
|
6091
|
-
if (typeof source.text === "string") {
|
|
6092
|
-
sql = orchidCore.addValue(ctx.values, source.text);
|
|
6093
|
-
} else {
|
|
6094
|
-
sql = source.text.toSQL(ctx, quotedAs);
|
|
6095
|
-
}
|
|
6096
|
-
}
|
|
6097
|
-
return source.textSQL = sql;
|
|
6098
|
-
};
|
|
6099
|
-
const getTsVector = (ctx, data, lang, source, quotedAs) => {
|
|
6100
|
-
const text = getSearchText(ctx, data, source, quotedAs);
|
|
6101
|
-
if ("in" in source) {
|
|
6102
|
-
if (typeof source.in === "string" || Array.isArray(source.in)) {
|
|
6103
|
-
return `to_tsvector(${lang}, ${text})`;
|
|
6104
|
-
} else {
|
|
6105
|
-
let tsVector = "";
|
|
6106
|
-
let i = 0;
|
|
6107
|
-
for (const key in source.in) {
|
|
6108
|
-
tsVector = (tsVector ? `${tsVector} || ` : "") + `setweight(to_tsvector(${lang}, ${text[i++]}), ${orchidCore.addValue(
|
|
6109
|
-
ctx.values,
|
|
6110
|
-
source.in[key]
|
|
6111
|
-
)})`;
|
|
6112
|
-
}
|
|
6113
|
-
return tsVector;
|
|
6114
|
-
}
|
|
6115
|
-
} else if ("vector" in source) {
|
|
6116
|
-
return text;
|
|
6117
|
-
} else {
|
|
6118
|
-
return `to_tsvector(${lang}, ${text})`;
|
|
6119
|
-
}
|
|
6120
|
-
};
|
|
6121
|
-
|
|
6122
|
-
const MAX_BINDING_PARAMS = 65536;
|
|
6123
|
-
|
|
6124
|
-
const quotedColumns = [];
|
|
6125
|
-
const makeInsertSql = (ctx, q, query, quotedAs) => {
|
|
6126
|
-
const { columns, shape } = query;
|
|
6127
|
-
quotedColumns.length = columns.length;
|
|
6128
|
-
for (let i = 0, len = columns.length; i < len; i++) {
|
|
6129
|
-
quotedColumns[i] = `"${shape[columns[i]]?.data.name || columns[i]}"`;
|
|
6130
|
-
}
|
|
6131
|
-
let runtimeDefaults;
|
|
6132
|
-
if (q.internal.runtimeDefaultColumns) {
|
|
6133
|
-
runtimeDefaults = [];
|
|
6134
|
-
for (const key of q.internal.runtimeDefaultColumns) {
|
|
6135
|
-
if (!columns.includes(key)) {
|
|
6136
|
-
const column = shape[key];
|
|
6137
|
-
quotedColumns.push(`"${column.data.name || key}"`);
|
|
6138
|
-
runtimeDefaults.push(column.data.runtimeDefault);
|
|
6139
|
-
}
|
|
6140
|
-
}
|
|
6141
|
-
}
|
|
6142
|
-
let values = query.values;
|
|
6143
|
-
if (quotedColumns.length === 0) {
|
|
6144
|
-
const key = Object.keys(q.shape)[0];
|
|
6145
|
-
const column = q.shape[key];
|
|
6146
|
-
quotedColumns[0] = `"${column?.data.name || key}"`;
|
|
6147
|
-
if (Array.isArray(values) && Array.isArray(values[0])) {
|
|
6148
|
-
values = values.map(() => [void 0]);
|
|
6149
|
-
}
|
|
6150
|
-
}
|
|
6151
|
-
ctx.sql.push(
|
|
6152
|
-
`INSERT INTO ${quotedAs}(${quotedColumns.join(", ")})`,
|
|
6153
|
-
null
|
|
6154
|
-
);
|
|
6155
|
-
const QueryClass = ctx.queryBuilder.constructor;
|
|
6156
|
-
if (query.onConflict) {
|
|
6157
|
-
ctx.sql.push("ON CONFLICT");
|
|
6158
|
-
const { target } = query.onConflict;
|
|
6159
|
-
if (target) {
|
|
6160
|
-
if (typeof target === "string") {
|
|
6161
|
-
ctx.sql.push(`("${shape[target]?.data.name || target}")`);
|
|
6162
|
-
} else if (Array.isArray(target)) {
|
|
6163
|
-
ctx.sql.push(
|
|
6164
|
-
`(${target.reduce(
|
|
6165
|
-
(sql, item, i) => sql + (i ? ", " : "") + `"${shape[item]?.data.name || item}"`,
|
|
6166
|
-
""
|
|
6167
|
-
)})`
|
|
6168
|
-
);
|
|
6169
|
-
} else if ("toSQL" in target) {
|
|
6170
|
-
ctx.sql.push(target.toSQL(ctx, quotedAs));
|
|
6171
|
-
} else {
|
|
6172
|
-
ctx.sql.push(`ON CONSTRAINT "${target.constraint}"`);
|
|
6173
|
-
}
|
|
6174
|
-
}
|
|
6175
|
-
if ("merge" in query.onConflict) {
|
|
6176
|
-
let sql;
|
|
6177
|
-
const { merge } = query.onConflict;
|
|
6178
|
-
if (merge) {
|
|
6179
|
-
if (typeof merge === "string") {
|
|
6180
|
-
const name = shape[merge]?.data.name || merge;
|
|
6181
|
-
sql = `DO UPDATE SET "${name}" = excluded."${name}"`;
|
|
6182
|
-
} else if ("except" in merge) {
|
|
6183
|
-
sql = mergeColumnsSql(columns, quotedColumns, target, merge.except);
|
|
6184
|
-
} else {
|
|
6185
|
-
sql = `DO UPDATE SET ${merge.reduce((sql2, item, i) => {
|
|
6186
|
-
const name = shape[item]?.data.name || item;
|
|
6187
|
-
return sql2 + (i ? ", " : "") + `"${name}" = excluded."${name}"`;
|
|
6188
|
-
}, "")}`;
|
|
6189
|
-
}
|
|
6190
|
-
} else {
|
|
6191
|
-
sql = mergeColumnsSql(columns, quotedColumns, target);
|
|
6192
|
-
}
|
|
6193
|
-
ctx.sql.push(sql);
|
|
6194
|
-
} else if (query.onConflict.set) {
|
|
6195
|
-
let sql;
|
|
6196
|
-
const { set } = query.onConflict;
|
|
6197
|
-
if (orchidCore.isExpression(set)) {
|
|
6198
|
-
sql = set.toSQL(ctx, quotedAs);
|
|
6199
|
-
} else {
|
|
6200
|
-
const arr = [];
|
|
6201
|
-
for (const key in set) {
|
|
6202
|
-
arr.push(
|
|
6203
|
-
`"${shape[key]?.data.name || key}" = ${orchidCore.addValue(
|
|
6204
|
-
ctx.values,
|
|
6205
|
-
set[key]
|
|
6206
|
-
)}`
|
|
6207
|
-
);
|
|
6208
|
-
}
|
|
6209
|
-
sql = arr.join(", ");
|
|
6210
|
-
}
|
|
6211
|
-
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;
|
|
6212
6344
|
} else {
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
}
|
|
6216
|
-
pushWhereStatementSql(ctx, q, query, quotedAs);
|
|
6217
|
-
const hookSelect = pushReturningSql(
|
|
6218
|
-
ctx,
|
|
6219
|
-
q,
|
|
6220
|
-
query,
|
|
6221
|
-
quotedAs,
|
|
6222
|
-
query.afterCreateSelect
|
|
6223
|
-
);
|
|
6224
|
-
if (query.kind === "object") {
|
|
6225
|
-
const valuesSql = [];
|
|
6226
|
-
let ctxValues = ctx.values;
|
|
6227
|
-
const restValuesLen = ctxValues.length;
|
|
6228
|
-
let currentValuesLen = restValuesLen;
|
|
6229
|
-
let batch;
|
|
6230
|
-
for (let i = 0; i < values.length; i++) {
|
|
6231
|
-
const encodedRow = `(${encodeRow(
|
|
6232
|
-
ctx,
|
|
6233
|
-
ctxValues,
|
|
6234
|
-
q,
|
|
6235
|
-
QueryClass,
|
|
6236
|
-
values[i],
|
|
6237
|
-
runtimeDefaults,
|
|
6238
|
-
quotedAs
|
|
6239
|
-
)})`;
|
|
6240
|
-
if (ctxValues.length > MAX_BINDING_PARAMS) {
|
|
6241
|
-
if (ctxValues.length - currentValuesLen > MAX_BINDING_PARAMS) {
|
|
6242
|
-
throw new Error(
|
|
6243
|
-
`Too many parameters for a single insert row, max is ${MAX_BINDING_PARAMS}`
|
|
6244
|
-
);
|
|
6245
|
-
}
|
|
6246
|
-
ctx.sql[1] = `VALUES ${valuesSql.join(",")}`;
|
|
6247
|
-
ctxValues.length = currentValuesLen;
|
|
6248
|
-
batch = orchidCore.pushOrNewArray(batch, {
|
|
6249
|
-
text: ctx.sql.join(" "),
|
|
6250
|
-
values: ctxValues
|
|
6251
|
-
});
|
|
6252
|
-
ctxValues = ctx.values = [];
|
|
6253
|
-
valuesSql.length = 0;
|
|
6254
|
-
i--;
|
|
6255
|
-
} else {
|
|
6256
|
-
currentValuesLen = ctxValues.length;
|
|
6257
|
-
valuesSql.push(encodedRow);
|
|
6258
|
-
}
|
|
6345
|
+
fn = "to_tsquery";
|
|
6346
|
+
query = source.tsQuery;
|
|
6259
6347
|
}
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
values: ctxValues
|
|
6265
|
-
});
|
|
6266
|
-
return {
|
|
6267
|
-
hookSelect,
|
|
6268
|
-
batch
|
|
6269
|
-
};
|
|
6348
|
+
let querySql;
|
|
6349
|
+
if (typeof query === "string") {
|
|
6350
|
+
ctx.values.push(query);
|
|
6351
|
+
querySql = `$${ctx.values.length}`;
|
|
6270
6352
|
} else {
|
|
6271
|
-
|
|
6353
|
+
querySql = `${query.toSQL(ctx, quotedAs)}`;
|
|
6272
6354
|
}
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
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);
|
|
6280
6377
|
} else {
|
|
6281
|
-
|
|
6282
|
-
if (
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
6287
|
-
`(${raw.toSQL(ctx, quotedAs)}, ${runtimeDefaults.map((fn) => orchidCore.addValue(v, fn())).join(", ")})`
|
|
6288
|
-
)
|
|
6289
|
-
).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))})`;
|
|
6290
6383
|
} else {
|
|
6291
|
-
sql =
|
|
6384
|
+
sql = quoteSchemaAndTable(from.q.schema, from.table);
|
|
6292
6385
|
}
|
|
6293
|
-
ctx.sql[1] = `VALUES ${sql}`;
|
|
6294
6386
|
}
|
|
6295
6387
|
} else {
|
|
6296
|
-
|
|
6297
|
-
const q2 = from.clone();
|
|
6298
|
-
if (v) {
|
|
6299
|
-
pushQueryValue(
|
|
6300
|
-
q2,
|
|
6301
|
-
"select",
|
|
6302
|
-
new RawSQL(
|
|
6303
|
-
encodeRow(
|
|
6304
|
-
ctx,
|
|
6305
|
-
ctx.values,
|
|
6306
|
-
q2,
|
|
6307
|
-
QueryClass,
|
|
6308
|
-
v[0],
|
|
6309
|
-
runtimeDefaults,
|
|
6310
|
-
quotedAs
|
|
6311
|
-
)
|
|
6312
|
-
)
|
|
6313
|
-
);
|
|
6314
|
-
}
|
|
6315
|
-
ctx.sql[1] = getSqlText(makeSQL(q2, { values: ctx.values }));
|
|
6388
|
+
sql = quoteSchemaAndTable(data.schema, from);
|
|
6316
6389
|
}
|
|
6317
|
-
return {
|
|
6318
|
-
hookSelect,
|
|
6319
|
-
text: ctx.sql.join(" "),
|
|
6320
|
-
values: ctx.values
|
|
6321
|
-
};
|
|
6390
|
+
return (only === void 0 ? data.only : only) ? `ONLY ${sql}` : sql;
|
|
6322
6391
|
};
|
|
6323
|
-
const
|
|
6324
|
-
|
|
6325
|
-
const exclude = typeof target === "string" ? [target] : Array.isArray(target) ? [...target] : [];
|
|
6326
|
-
if (except) {
|
|
6327
|
-
if (typeof except === "string") {
|
|
6328
|
-
exclude.push(except);
|
|
6329
|
-
} else {
|
|
6330
|
-
exclude.push(...except);
|
|
6331
|
-
}
|
|
6332
|
-
}
|
|
6333
|
-
for (let i = 0; i < columns.length; i++) {
|
|
6334
|
-
if (!exclude.includes(columns[i])) {
|
|
6335
|
-
notExcluded.push(quotedColumns2[i]);
|
|
6336
|
-
}
|
|
6337
|
-
}
|
|
6338
|
-
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"));
|
|
6339
6394
|
};
|
|
6340
|
-
const
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
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));
|
|
6347
6407
|
}
|
|
6348
6408
|
}
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
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);
|
|
6354
6421
|
}
|
|
6355
6422
|
}
|
|
6356
|
-
return
|
|
6423
|
+
return source.textSQL = sql;
|
|
6357
6424
|
};
|
|
6358
|
-
const
|
|
6359
|
-
const
|
|
6360
|
-
if (
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
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
|
+
)})`;
|
|
6367
6438
|
}
|
|
6439
|
+
return tsVector;
|
|
6368
6440
|
}
|
|
6369
|
-
|
|
6370
|
-
return
|
|
6371
|
-
} else
|
|
6372
|
-
|
|
6441
|
+
} else if ("vector" in source) {
|
|
6442
|
+
return text;
|
|
6443
|
+
} else {
|
|
6444
|
+
return `to_tsvector(${lang}, ${text})`;
|
|
6373
6445
|
}
|
|
6374
|
-
return;
|
|
6375
6446
|
};
|
|
6376
6447
|
|
|
6377
6448
|
const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
@@ -6382,12 +6453,11 @@ const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
|
6382
6453
|
if (!query.select) {
|
|
6383
6454
|
query.select = countSelect;
|
|
6384
6455
|
}
|
|
6385
|
-
const hookSelect =
|
|
6456
|
+
const hookSelect = pushUpdateReturning(
|
|
6386
6457
|
ctx,
|
|
6387
6458
|
table,
|
|
6388
6459
|
query,
|
|
6389
6460
|
quotedAs,
|
|
6390
|
-
query.afterUpdateSelect,
|
|
6391
6461
|
"SELECT"
|
|
6392
6462
|
);
|
|
6393
6463
|
ctx.sql.push(`FROM ${quotedTable}`);
|
|
@@ -6402,7 +6472,21 @@ const pushUpdateSql = (ctx, table, query, quotedAs) => {
|
|
|
6402
6472
|
ctx.sql.push("SET");
|
|
6403
6473
|
ctx.sql.push(set.join(", "));
|
|
6404
6474
|
pushWhereStatementSql(ctx, table, query, quotedAs);
|
|
6405
|
-
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;
|
|
6406
6490
|
};
|
|
6407
6491
|
const processData = (ctx, table, set, data, quotedAs) => {
|
|
6408
6492
|
let append;
|
|
@@ -6485,7 +6569,9 @@ const pushDeleteSql = (ctx, table, query, quotedAs) => {
|
|
|
6485
6569
|
ctx.sql.push("WHERE", conditions);
|
|
6486
6570
|
}
|
|
6487
6571
|
}
|
|
6488
|
-
|
|
6572
|
+
const returning = makeReturningSql(ctx, table, query, quotedAs, 3);
|
|
6573
|
+
if (returning.select) ctx.sql.push("RETURNING", returning.select);
|
|
6574
|
+
return returning.hookSelect;
|
|
6489
6575
|
};
|
|
6490
6576
|
|
|
6491
6577
|
const pushTruncateSql = (ctx, table, query) => {
|
|
@@ -6564,7 +6650,7 @@ const makeSQL = (table, options) => {
|
|
|
6564
6650
|
if (query.with) {
|
|
6565
6651
|
pushWithSql(ctx, query.with);
|
|
6566
6652
|
}
|
|
6567
|
-
if (query.type) {
|
|
6653
|
+
if (query.type && query.type !== "upsert") {
|
|
6568
6654
|
const tableName = table.table ?? query.as;
|
|
6569
6655
|
if (!tableName) throw new Error(`Table is missing for ${query.type}`);
|
|
6570
6656
|
if (query.type === "truncate") {
|
|
@@ -6600,10 +6686,11 @@ const makeSQL = (table, options) => {
|
|
|
6600
6686
|
}
|
|
6601
6687
|
const quotedAs = (query.as || table.table) && `"${query.as || table.table}"`;
|
|
6602
6688
|
if (query.union) {
|
|
6603
|
-
|
|
6689
|
+
const s = getSqlText(makeSQL(query.union.b, { values }));
|
|
6690
|
+
sql.push(query.union.p ? s : `(${s})`);
|
|
6604
6691
|
for (const u of query.union.u) {
|
|
6605
|
-
const
|
|
6606
|
-
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 + ")"}`);
|
|
6607
6694
|
}
|
|
6608
6695
|
} else {
|
|
6609
6696
|
sql.push("SELECT");
|
|
@@ -9989,12 +10076,13 @@ class MergeQueryMethods {
|
|
|
9989
10076
|
}
|
|
9990
10077
|
}
|
|
9991
10078
|
|
|
9992
|
-
const _queryUnion = (base, args, k) => {
|
|
10079
|
+
const _queryUnion = (base, args, k, p, m) => {
|
|
9993
10080
|
const q = base.baseQuery.clone();
|
|
9994
10081
|
const u = args.map(
|
|
9995
10082
|
(a) => ({
|
|
9996
10083
|
a: typeof a === "function" ? a(q) : a,
|
|
9997
|
-
k
|
|
10084
|
+
k,
|
|
10085
|
+
m
|
|
9998
10086
|
})
|
|
9999
10087
|
);
|
|
10000
10088
|
const union = q.q.union = base.q.union;
|
|
@@ -10003,7 +10091,8 @@ const _queryUnion = (base, args, k) => {
|
|
|
10003
10091
|
} else {
|
|
10004
10092
|
q.q.union = {
|
|
10005
10093
|
b: base,
|
|
10006
|
-
u
|
|
10094
|
+
u,
|
|
10095
|
+
p
|
|
10007
10096
|
};
|
|
10008
10097
|
}
|
|
10009
10098
|
return q;
|
|
@@ -10281,7 +10370,7 @@ const _queryUpdate = (query, arg) => {
|
|
|
10281
10370
|
}
|
|
10282
10371
|
const { queries } = ctx;
|
|
10283
10372
|
if (queries) {
|
|
10284
|
-
q.patchResult = async (_, queryResult) => {
|
|
10373
|
+
q.patchResult = async (_, _h, queryResult) => {
|
|
10285
10374
|
await Promise.all(queries.map(orchidCore.callWithThis, queryResult));
|
|
10286
10375
|
if (ctx.collect) {
|
|
10287
10376
|
const t = query.baseQuery.clone();
|
|
@@ -10870,26 +10959,80 @@ class SearchMethods {
|
|
|
10870
10959
|
|
|
10871
10960
|
function orCreate(query, data, updateData, mergeData) {
|
|
10872
10961
|
const { q } = query;
|
|
10873
|
-
q.
|
|
10874
|
-
q.
|
|
10962
|
+
q.returnsOne = true;
|
|
10963
|
+
if (!q.select) {
|
|
10964
|
+
q.returnType = "void";
|
|
10965
|
+
}
|
|
10875
10966
|
const { handleResult } = q;
|
|
10876
10967
|
let result;
|
|
10877
10968
|
let created = false;
|
|
10878
10969
|
q.handleResult = (q2, t, r, s) => {
|
|
10879
10970
|
return created ? result : handleResult(q2, t, r, s);
|
|
10880
10971
|
};
|
|
10881
|
-
q.
|
|
10972
|
+
q.hookSelect ?? (q.hookSelect = /* @__PURE__ */ new Map());
|
|
10973
|
+
q.patchResult = async (q2, hookSelect, queryResult) => {
|
|
10974
|
+
var _a, _b;
|
|
10882
10975
|
if (queryResult.rowCount === 0) {
|
|
10883
10976
|
if (typeof data === "function") {
|
|
10884
10977
|
data = data(updateData);
|
|
10885
10978
|
}
|
|
10886
10979
|
if (mergeData) data = { ...mergeData, ...data };
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
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
|
|
10891
10989
|
};
|
|
10892
|
-
|
|
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;
|
|
10893
11036
|
created = true;
|
|
10894
11037
|
} else if (queryResult.rowCount > 1) {
|
|
10895
11038
|
throw new MoreThanOneRowError(
|
|
@@ -10902,9 +11045,7 @@ function orCreate(query, data, updateData, mergeData) {
|
|
|
10902
11045
|
}
|
|
10903
11046
|
class QueryUpsertOrCreate {
|
|
10904
11047
|
/**
|
|
10905
|
-
* `upsert` tries to update
|
|
10906
|
-
*
|
|
10907
|
-
* 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.
|
|
10908
11049
|
*
|
|
10909
11050
|
* `find` or `findBy` must precede `upsert` because it does not work with multiple updates.
|
|
10910
11051
|
*
|
|
@@ -10915,7 +11056,7 @@ class QueryUpsertOrCreate {
|
|
|
10915
11056
|
*
|
|
10916
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.
|
|
10917
11058
|
*
|
|
10918
|
-
*
|
|
11059
|
+
* No values are returned by default, place `select` or `selectAll` before `upsert` to specify returning columns.
|
|
10919
11060
|
*
|
|
10920
11061
|
* ```ts
|
|
10921
11062
|
* await User.selectAll()
|
|
@@ -10992,6 +11133,9 @@ class QueryUpsertOrCreate {
|
|
|
10992
11133
|
* });
|
|
10993
11134
|
* ```
|
|
10994
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
|
+
*
|
|
10995
11139
|
* @param data - `update` property for the data to update, `create` property for the data to create
|
|
10996
11140
|
*/
|
|
10997
11141
|
upsert(data) {
|
|
@@ -11006,22 +11150,16 @@ class QueryUpsertOrCreate {
|
|
|
11006
11150
|
if (!orchidCore.isObjectEmpty(updateData)) {
|
|
11007
11151
|
_queryUpdate(q, updateData);
|
|
11008
11152
|
}
|
|
11009
|
-
|
|
11010
|
-
if (!c.q.select) {
|
|
11011
|
-
c.q.returnType = "void";
|
|
11012
|
-
}
|
|
11013
|
-
return c;
|
|
11153
|
+
return orCreate(q, data.create, updateData, mergeData);
|
|
11014
11154
|
}
|
|
11015
11155
|
/**
|
|
11016
11156
|
* `orCreate` creates a record only if it was not found by conditions.
|
|
11017
11157
|
*
|
|
11018
|
-
* It will implicitly wrap queries in a transaction if it was not wrapped yet.
|
|
11019
|
-
*
|
|
11020
11158
|
* `find` or `findBy` must precede `orCreate`.
|
|
11021
11159
|
*
|
|
11022
11160
|
* It is accepting the same argument as `create` commands.
|
|
11023
11161
|
*
|
|
11024
|
-
*
|
|
11162
|
+
* No result is returned by default, place `get`, `select`, or `selectAll` before `orCreate` to specify returning columns.
|
|
11025
11163
|
*
|
|
11026
11164
|
* ```ts
|
|
11027
11165
|
* const user = await User.selectAll()
|
|
@@ -11032,7 +11170,7 @@ class QueryUpsertOrCreate {
|
|
|
11032
11170
|
* });
|
|
11033
11171
|
* ```
|
|
11034
11172
|
*
|
|
11035
|
-
* The data
|
|
11173
|
+
* The data can be returned from a function, it won't be called if the record was found:
|
|
11036
11174
|
*
|
|
11037
11175
|
* ```ts
|
|
11038
11176
|
* const user = await User.selectAll()
|
|
@@ -11043,6 +11181,35 @@ class QueryUpsertOrCreate {
|
|
|
11043
11181
|
* }));
|
|
11044
11182
|
* ```
|
|
11045
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
|
+
*
|
|
11046
11213
|
* @param data - the same data as for `create`, it may be returned from a callback
|
|
11047
11214
|
*/
|
|
11048
11215
|
orCreate(data) {
|
|
@@ -11281,16 +11448,17 @@ class ColumnRefExpression extends orchidCore.Expression {
|
|
|
11281
11448
|
}
|
|
11282
11449
|
}
|
|
11283
11450
|
class RefExpression extends orchidCore.Expression {
|
|
11284
|
-
constructor(value,
|
|
11451
|
+
constructor(value, query, ref) {
|
|
11285
11452
|
super();
|
|
11286
|
-
this.q = q;
|
|
11287
11453
|
this.ref = ref;
|
|
11288
11454
|
this.result = { value };
|
|
11289
|
-
q.expr = this;
|
|
11455
|
+
(this.q = query.q).expr = this;
|
|
11456
|
+
this.table = query.table;
|
|
11290
11457
|
Object.assign(this, value.operators);
|
|
11291
11458
|
}
|
|
11292
|
-
makeSQL(ctx
|
|
11293
|
-
|
|
11459
|
+
makeSQL(ctx) {
|
|
11460
|
+
const as = this.q.as || this.table;
|
|
11461
|
+
return columnToSql(ctx, this.q, this.q.shape, this.ref, as && `"${as}"`);
|
|
11294
11462
|
}
|
|
11295
11463
|
}
|
|
11296
11464
|
class OrExpression extends orchidCore.Expression {
|
|
@@ -11386,7 +11554,7 @@ class ExpressionMethods {
|
|
|
11386
11554
|
} else {
|
|
11387
11555
|
column = shape[arg];
|
|
11388
11556
|
}
|
|
11389
|
-
return new RefExpression(column, q
|
|
11557
|
+
return new RefExpression(column, q, arg);
|
|
11390
11558
|
}
|
|
11391
11559
|
val(value) {
|
|
11392
11560
|
return new orchidCore.ValExpression(value);
|
|
@@ -12101,6 +12269,9 @@ class QueryMethods {
|
|
|
12101
12269
|
narrowType() {
|
|
12102
12270
|
return () => this;
|
|
12103
12271
|
}
|
|
12272
|
+
if(condition, fn) {
|
|
12273
|
+
return condition ? fn(this) : this;
|
|
12274
|
+
}
|
|
12104
12275
|
queryRelated(relName, params) {
|
|
12105
12276
|
return this.relations[relName].relationConfig.queryRelated(
|
|
12106
12277
|
params
|