effect-qb 0.16.0 → 0.17.0
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/mysql.js +1661 -591
- package/dist/postgres/metadata.js +1930 -135
- package/dist/postgres.js +7808 -6718
- package/dist/sqlite.js +8360 -0
- package/package.json +6 -1
- package/src/internal/derived-table.ts +29 -3
- package/src/internal/dialect.ts +2 -0
- package/src/internal/dsl-mutation-runtime.ts +173 -4
- package/src/internal/dsl-plan-runtime.ts +165 -20
- package/src/internal/dsl-query-runtime.ts +60 -6
- package/src/internal/dsl-transaction-ddl-runtime.ts +72 -2
- package/src/internal/executor.ts +47 -9
- package/src/internal/expression-ast.ts +3 -2
- package/src/internal/grouping-key.ts +141 -1
- package/src/internal/implication-runtime.ts +2 -1
- package/src/internal/json/types.ts +155 -40
- package/src/internal/predicate/context.ts +14 -1
- package/src/internal/predicate/key.ts +19 -2
- package/src/internal/predicate/runtime.ts +27 -3
- package/src/internal/query.ts +252 -30
- package/src/internal/renderer.ts +35 -2
- package/src/internal/runtime/driver-value-mapping.ts +58 -0
- package/src/internal/runtime/normalize.ts +62 -38
- package/src/internal/runtime/schema.ts +5 -3
- package/src/internal/runtime/value.ts +153 -30
- package/src/internal/table-options.ts +108 -1
- package/src/internal/table.ts +87 -29
- package/src/mysql/column.ts +18 -2
- package/src/mysql/datatypes/index.ts +21 -0
- package/src/mysql/errors/catalog.ts +5 -5
- package/src/mysql/errors/normalize.ts +2 -2
- package/src/mysql/internal/dsl.ts +736 -218
- package/src/mysql/internal/renderer.ts +2 -1
- package/src/mysql/internal/sql-expression-renderer.ts +486 -130
- package/src/mysql/query.ts +9 -2
- package/src/mysql/table.ts +38 -12
- package/src/postgres/column.ts +4 -2
- package/src/postgres/errors/normalize.ts +2 -2
- package/src/postgres/executor.ts +48 -5
- package/src/postgres/function/core.ts +19 -1
- package/src/postgres/internal/dsl.ts +683 -240
- package/src/postgres/internal/renderer.ts +2 -1
- package/src/postgres/internal/schema-ddl.ts +2 -1
- package/src/postgres/internal/schema-model.ts +6 -3
- package/src/postgres/internal/sql-expression-renderer.ts +420 -91
- package/src/postgres/json.ts +57 -17
- package/src/postgres/query.ts +9 -2
- package/src/postgres/schema-management.ts +91 -4
- package/src/postgres/schema.ts +1 -1
- package/src/postgres/table.ts +189 -53
- package/src/sqlite/column.ts +128 -0
- package/src/sqlite/datatypes/index.ts +79 -0
- package/src/sqlite/datatypes/spec.ts +98 -0
- package/src/sqlite/errors/catalog.ts +103 -0
- package/src/sqlite/errors/fields.ts +19 -0
- package/src/sqlite/errors/index.ts +19 -0
- package/src/sqlite/errors/normalize.ts +229 -0
- package/src/sqlite/errors/requirements.ts +71 -0
- package/src/sqlite/errors/types.ts +29 -0
- package/src/sqlite/executor.ts +227 -0
- package/src/sqlite/function/aggregate.ts +2 -0
- package/src/sqlite/function/core.ts +2 -0
- package/src/sqlite/function/index.ts +19 -0
- package/src/sqlite/function/string.ts +2 -0
- package/src/sqlite/function/temporal.ts +100 -0
- package/src/sqlite/function/window.ts +2 -0
- package/src/sqlite/internal/dialect.ts +37 -0
- package/src/sqlite/internal/dsl.ts +6926 -0
- package/src/sqlite/internal/renderer.ts +47 -0
- package/src/sqlite/internal/sql-expression-renderer.ts +1821 -0
- package/src/sqlite/json.ts +2 -0
- package/src/sqlite/query.ts +196 -0
- package/src/sqlite/renderer.ts +24 -0
- package/src/sqlite/table.ts +183 -0
- package/src/sqlite.ts +22 -0
|
@@ -176,6 +176,27 @@ var bindColumn = (tableName, columnName, column, baseTableName, schemaName) => {
|
|
|
176
176
|
};
|
|
177
177
|
|
|
178
178
|
// src/internal/table-options.ts
|
|
179
|
+
var referentialActionError = "Foreign key action must be noAction, restrict, cascade, setNull, or setDefault";
|
|
180
|
+
var renderReferentialAction = (action) => {
|
|
181
|
+
switch (action) {
|
|
182
|
+
case "noAction":
|
|
183
|
+
return "no action";
|
|
184
|
+
case "restrict":
|
|
185
|
+
return "restrict";
|
|
186
|
+
case "cascade":
|
|
187
|
+
return "cascade";
|
|
188
|
+
case "setNull":
|
|
189
|
+
return "set null";
|
|
190
|
+
case "setDefault":
|
|
191
|
+
return "set default";
|
|
192
|
+
}
|
|
193
|
+
throw new Error(referentialActionError);
|
|
194
|
+
};
|
|
195
|
+
var validateReferentialAction = (action) => {
|
|
196
|
+
if (action !== undefined) {
|
|
197
|
+
renderReferentialAction(action);
|
|
198
|
+
}
|
|
199
|
+
};
|
|
179
200
|
var normalizeColumnList = (columns) => {
|
|
180
201
|
const normalized = Array.isArray(columns) ? [...columns] : [columns];
|
|
181
202
|
if (normalized.length === 0) {
|
|
@@ -203,6 +224,8 @@ var collectInlineOptions = (fields) => {
|
|
|
203
224
|
});
|
|
204
225
|
}
|
|
205
226
|
if (column.metadata.references) {
|
|
227
|
+
validateReferentialAction(column.metadata.references.onUpdate);
|
|
228
|
+
validateReferentialAction(column.metadata.references.onDelete);
|
|
206
229
|
const local = [columnName];
|
|
207
230
|
options.push({
|
|
208
231
|
kind: "foreignKey",
|
|
@@ -279,6 +302,8 @@ var validateOptions = (tableName, fields, options) => {
|
|
|
279
302
|
}
|
|
280
303
|
}
|
|
281
304
|
if (option.kind === "foreignKey") {
|
|
305
|
+
validateReferentialAction(option.onUpdate);
|
|
306
|
+
validateReferentialAction(option.onDelete);
|
|
282
307
|
const reference = option.references();
|
|
283
308
|
if (reference.columns.length !== columns.length) {
|
|
284
309
|
throw new Error(`Foreign key on table '${tableName}' must reference the same number of columns`);
|
|
@@ -303,7 +328,7 @@ var validateOptions = (tableName, fields, options) => {
|
|
|
303
328
|
throw new Error(`Unknown index key column '${key.column}' on table '${tableName}'`);
|
|
304
329
|
}
|
|
305
330
|
}
|
|
306
|
-
if (
|
|
331
|
+
if (columns.length === 0 && (option.keys === undefined || option.keys.length === 0)) {
|
|
307
332
|
throw new Error(`Index on table '${tableName}' requires at least one column or key`);
|
|
308
333
|
}
|
|
309
334
|
}
|
|
@@ -517,10 +542,13 @@ function make2(name, fields, schemaName) {
|
|
|
517
542
|
const resolvedSchemaName = arguments.length >= 3 ? schemaName : "public";
|
|
518
543
|
return makeTable(name, fields, [], name, "schema", resolvedSchemaName, arguments.length >= 3 ? "explicit" : "default");
|
|
519
544
|
}
|
|
520
|
-
var schema = (schemaName) =>
|
|
521
|
-
schemaName,
|
|
522
|
-
|
|
523
|
-
|
|
545
|
+
var schema = (schemaName) => {
|
|
546
|
+
const table = (name, fields, ...options2) => applyDeclaredOptions(makeTable(name, fields, [], name, "schema", schemaName, "explicit"), options2);
|
|
547
|
+
return {
|
|
548
|
+
schemaName,
|
|
549
|
+
table
|
|
550
|
+
};
|
|
551
|
+
};
|
|
524
552
|
var alias = (table, aliasName) => {
|
|
525
553
|
const state = table[TypeId4];
|
|
526
554
|
const columns = Object.fromEntries(Object.entries(state.fields).map(([key, column]) => [key, bindColumn(aliasName, key, column, state.baseName, state.schemaName)]));
|
|
@@ -696,6 +724,9 @@ var normalize = (expression) => (() => {
|
|
|
696
724
|
}
|
|
697
725
|
})();
|
|
698
726
|
|
|
727
|
+
// src/postgres/internal/sql-expression-renderer.ts
|
|
728
|
+
import * as Schema5 from "effect/Schema";
|
|
729
|
+
|
|
699
730
|
// src/internal/query.ts
|
|
700
731
|
import { pipeArguments as pipeArguments4 } from "effect/Pipeable";
|
|
701
732
|
|
|
@@ -732,7 +763,18 @@ var cloneContext = (context) => ({
|
|
|
732
763
|
unknown: context.unknown
|
|
733
764
|
});
|
|
734
765
|
var freezeContext = (context) => context;
|
|
735
|
-
var
|
|
766
|
+
var columnPredicateKey = (tableName, columnName) => JSON.stringify([tableName, columnName]);
|
|
767
|
+
var columnPredicateKeyParts = (key) => {
|
|
768
|
+
const jsonSeparator = key.indexOf("#json:");
|
|
769
|
+
const columnKey = jsonSeparator === -1 ? key : key.slice(0, jsonSeparator);
|
|
770
|
+
try {
|
|
771
|
+
const parsed = JSON.parse(columnKey);
|
|
772
|
+
return Array.isArray(parsed) && parsed.length === 2 && typeof parsed[0] === "string" && typeof parsed[1] === "string" ? [parsed[0], parsed[1]] : undefined;
|
|
773
|
+
} catch {
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
var sourceNameOfKey = (key) => columnPredicateKeyParts(key)?.[0] ?? key.split(".", 1)[0] ?? key;
|
|
736
778
|
var addSourceName = (context, key) => {
|
|
737
779
|
context.sourceNames.add(sourceNameOfKey(key));
|
|
738
780
|
};
|
|
@@ -982,9 +1024,10 @@ var analyzeFormula = (formula) => freezeContext(analyzeStack(emptyContext(), [{
|
|
|
982
1024
|
var astOf = (value) => value[TypeId3];
|
|
983
1025
|
var columnKeyOfExpression = (value) => {
|
|
984
1026
|
const ast = astOf(value);
|
|
985
|
-
return ast.kind === "column" ?
|
|
1027
|
+
return ast.kind === "column" ? columnPredicateKey(ast.tableName, ast.columnName) : undefined;
|
|
986
1028
|
};
|
|
987
1029
|
var sameDbType = (left, right) => left.dialect === right.dialect && left.kind === right.kind;
|
|
1030
|
+
var escapeJsonPathPredicateKeySegment = (value) => value.replaceAll("\\", "\\\\").replaceAll(".", "\\.");
|
|
988
1031
|
var jsonPathPredicateKeyOfExpression = (value) => {
|
|
989
1032
|
const ast = astOf(value);
|
|
990
1033
|
switch (ast.kind) {
|
|
@@ -1008,7 +1051,7 @@ var jsonPathPredicateKeyOfExpression = (value) => {
|
|
|
1008
1051
|
return;
|
|
1009
1052
|
}
|
|
1010
1053
|
const baseKey = columnKeyOfExpression(jsonAst.base);
|
|
1011
|
-
return baseKey === undefined ? undefined : `${baseKey}#json:${path.join(".")}`;
|
|
1054
|
+
return baseKey === undefined ? undefined : `${baseKey}#json:${path.map(escapeJsonPathPredicateKeySegment).join(".")}`;
|
|
1012
1055
|
}
|
|
1013
1056
|
default:
|
|
1014
1057
|
return;
|
|
@@ -1463,13 +1506,1300 @@ var path = (...segments) => ({
|
|
|
1463
1506
|
segments
|
|
1464
1507
|
});
|
|
1465
1508
|
|
|
1509
|
+
// src/internal/dsl-plan-runtime.ts
|
|
1510
|
+
var renderSelectLockMode = (mode) => {
|
|
1511
|
+
switch (mode) {
|
|
1512
|
+
case "update":
|
|
1513
|
+
return "for update";
|
|
1514
|
+
case "share":
|
|
1515
|
+
return "for share";
|
|
1516
|
+
}
|
|
1517
|
+
throw new Error("lock(...) mode must be update or share for select statements");
|
|
1518
|
+
};
|
|
1519
|
+
var renderMysqlMutationLockMode = (mode, statement) => {
|
|
1520
|
+
switch (mode) {
|
|
1521
|
+
case "lowPriority":
|
|
1522
|
+
return " low_priority";
|
|
1523
|
+
case "ignore":
|
|
1524
|
+
return " ignore";
|
|
1525
|
+
case "quick":
|
|
1526
|
+
if (statement === "delete") {
|
|
1527
|
+
return " quick";
|
|
1528
|
+
}
|
|
1529
|
+
break;
|
|
1530
|
+
}
|
|
1531
|
+
throw new Error(statement === "update" ? "lock(...) mode must be lowPriority or ignore for update statements" : "lock(...) mode must be lowPriority, quick, or ignore for delete statements");
|
|
1532
|
+
};
|
|
1533
|
+
var makeDslPlanRuntime = (ctx) => {
|
|
1534
|
+
const aliasedSourceKinds = new Set(["derived", "cte", "lateral", "values", "unnest", "tableFunction"]);
|
|
1535
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
1536
|
+
const isPlan = (value) => isRecord(value) && (TypeId in value);
|
|
1537
|
+
const hasColumnRecord = (value) => isRecord(value.columns);
|
|
1538
|
+
const sourceRequiredList = (source) => typeof source === "object" && source !== null && ("required" in source) ? ctx.currentRequiredList(source.required) : [];
|
|
1539
|
+
const isAliasedSource = (source) => {
|
|
1540
|
+
if (!isRecord(source)) {
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1543
|
+
if (TypeId4 in source) {
|
|
1544
|
+
return true;
|
|
1545
|
+
}
|
|
1546
|
+
if (!("kind" in source) || !("name" in source) || !("baseName" in source)) {
|
|
1547
|
+
return false;
|
|
1548
|
+
}
|
|
1549
|
+
if (typeof source.kind !== "string" || !aliasedSourceKinds.has(source.kind)) {
|
|
1550
|
+
return false;
|
|
1551
|
+
}
|
|
1552
|
+
if (typeof source.name !== "string" || typeof source.baseName !== "string") {
|
|
1553
|
+
return false;
|
|
1554
|
+
}
|
|
1555
|
+
switch (source.kind) {
|
|
1556
|
+
case "derived":
|
|
1557
|
+
case "cte":
|
|
1558
|
+
case "lateral":
|
|
1559
|
+
return isPlan(source.plan) && hasColumnRecord(source);
|
|
1560
|
+
case "values":
|
|
1561
|
+
return Array.isArray(source.rows) && hasColumnRecord(source);
|
|
1562
|
+
case "unnest":
|
|
1563
|
+
return isRecord(source.arrays) && hasColumnRecord(source);
|
|
1564
|
+
case "tableFunction":
|
|
1565
|
+
return typeof source.functionName === "string" && Array.isArray(source.args) && hasColumnRecord(source);
|
|
1566
|
+
}
|
|
1567
|
+
return false;
|
|
1568
|
+
};
|
|
1569
|
+
const assertAliasedSource = (source, message) => {
|
|
1570
|
+
if (!isAliasedSource(source)) {
|
|
1571
|
+
throw new Error(message);
|
|
1572
|
+
}
|
|
1573
|
+
};
|
|
1574
|
+
const assertPlanComplete = (plan) => {
|
|
1575
|
+
const required = ctx.currentRequiredList(plan[TypeId].required);
|
|
1576
|
+
if (required.length > 0) {
|
|
1577
|
+
throw new Error(`query references sources that are not yet in scope: ${required.join(", ")}`);
|
|
1578
|
+
}
|
|
1579
|
+
};
|
|
1580
|
+
const assertSourceNameAvailable = (available, sourceName) => {
|
|
1581
|
+
if (sourceName in available) {
|
|
1582
|
+
throw new Error(`query source name is already in scope: ${sourceName}`);
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1585
|
+
const assertSelectHasBaseSourceForJoin = (statement, available) => {
|
|
1586
|
+
if (statement === "select" && Object.keys(available).length === 0) {
|
|
1587
|
+
throw new Error("select joins require a from(...) source before joining");
|
|
1588
|
+
}
|
|
1589
|
+
};
|
|
1590
|
+
const supportsJoinSources = (statement) => statement === "select" || statement === "update" || statement === "delete";
|
|
1591
|
+
const assertSetOperandStatement = (plan) => {
|
|
1592
|
+
const statement = ctx.getQueryState(plan).statement;
|
|
1593
|
+
if (statement !== "select" && statement !== "set") {
|
|
1594
|
+
throw new Error("set operator operands only accept select-like query plans");
|
|
1595
|
+
}
|
|
1596
|
+
};
|
|
1597
|
+
const buildSetOperation = (kind, all, left, right) => {
|
|
1598
|
+
assertSetOperandStatement(left);
|
|
1599
|
+
assertSetOperandStatement(right);
|
|
1600
|
+
assertPlanComplete(left);
|
|
1601
|
+
assertPlanComplete(right);
|
|
1602
|
+
const leftState = left[TypeId];
|
|
1603
|
+
const leftAst = ctx.getAst(left);
|
|
1604
|
+
const basePlan = leftAst.kind === "set" ? leftAst.setBase ?? left : left;
|
|
1605
|
+
const leftOperations = leftAst.kind === "set" ? [...leftAst.setOperations ?? []] : [];
|
|
1606
|
+
return ctx.makePlan({
|
|
1607
|
+
selection: leftState.selection,
|
|
1608
|
+
required: undefined,
|
|
1609
|
+
available: {},
|
|
1610
|
+
dialect: leftState.dialect ?? right[TypeId].dialect
|
|
1611
|
+
}, {
|
|
1612
|
+
kind: "set",
|
|
1613
|
+
select: leftState.selection,
|
|
1614
|
+
where: [],
|
|
1615
|
+
having: [],
|
|
1616
|
+
joins: [],
|
|
1617
|
+
groupBy: [],
|
|
1618
|
+
orderBy: [],
|
|
1619
|
+
setBase: basePlan,
|
|
1620
|
+
setOperations: [
|
|
1621
|
+
...leftOperations,
|
|
1622
|
+
{
|
|
1623
|
+
kind,
|
|
1624
|
+
all,
|
|
1625
|
+
query: right
|
|
1626
|
+
}
|
|
1627
|
+
]
|
|
1628
|
+
}, undefined, undefined, "set");
|
|
1629
|
+
};
|
|
1630
|
+
const where = (predicate) => (plan) => {
|
|
1631
|
+
const current = plan[TypeId];
|
|
1632
|
+
const currentAst = ctx.getAst(plan);
|
|
1633
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
1634
|
+
const predicateExpression = ctx.toDialectExpression(predicate);
|
|
1635
|
+
const predicateRequired = ctx.extractRequiredFromDialectInputRuntime(predicate);
|
|
1636
|
+
return ctx.makePlan({
|
|
1637
|
+
selection: current.selection,
|
|
1638
|
+
required: [...ctx.currentRequiredList(current.required), ...predicateRequired].filter((name, index3, values) => !(name in current.available) && values.indexOf(name) === index3),
|
|
1639
|
+
available: current.available,
|
|
1640
|
+
dialect: current.dialect ?? predicateExpression[TypeId2].dialect
|
|
1641
|
+
}, {
|
|
1642
|
+
...currentAst,
|
|
1643
|
+
where: [...currentAst.where, {
|
|
1644
|
+
kind: "where",
|
|
1645
|
+
predicate: predicateExpression
|
|
1646
|
+
}]
|
|
1647
|
+
}, ctx.assumeFormulaTrue(currentQuery.assumptions, ctx.formulaOfExpressionRuntime(predicateExpression)), currentQuery.capabilities, currentQuery.statement);
|
|
1648
|
+
};
|
|
1649
|
+
const from = (source) => (plan) => {
|
|
1650
|
+
const current = plan[TypeId];
|
|
1651
|
+
const currentAst = ctx.getAst(plan);
|
|
1652
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
1653
|
+
if (currentQuery.statement === "insert") {
|
|
1654
|
+
return ctx.attachInsertSource(plan, source);
|
|
1655
|
+
}
|
|
1656
|
+
assertAliasedSource(source, "from(...) requires an aliased source in select/update statements");
|
|
1657
|
+
if (currentQuery.statement === "select" && currentAst.from !== undefined) {
|
|
1658
|
+
throw new Error("select statements accept only one from(...) source; use joins for additional sources");
|
|
1659
|
+
}
|
|
1660
|
+
const sourceLike = source;
|
|
1661
|
+
const { sourceName, sourceBaseName } = ctx.sourceDetails(sourceLike);
|
|
1662
|
+
const presenceWitnesses = ctx.presenceWitnessesOfSourceLike(sourceLike);
|
|
1663
|
+
const sourceRequired = sourceRequiredList(sourceLike);
|
|
1664
|
+
assertSourceNameAvailable(current.available, sourceName);
|
|
1665
|
+
if (currentQuery.statement === "select") {
|
|
1666
|
+
const nextAvailable = {
|
|
1667
|
+
[sourceName]: {
|
|
1668
|
+
name: sourceName,
|
|
1669
|
+
mode: "required",
|
|
1670
|
+
baseName: sourceBaseName,
|
|
1671
|
+
_presentFormula: ctx.trueFormula(),
|
|
1672
|
+
_presenceWitnesses: presenceWitnesses
|
|
1673
|
+
}
|
|
1674
|
+
};
|
|
1675
|
+
return ctx.makePlan({
|
|
1676
|
+
selection: current.selection,
|
|
1677
|
+
required: [...ctx.currentRequiredList(current.required), ...sourceRequired].filter((name, index3, values) => !(name in nextAvailable) && values.indexOf(name) === index3),
|
|
1678
|
+
available: nextAvailable,
|
|
1679
|
+
dialect: current.dialect
|
|
1680
|
+
}, {
|
|
1681
|
+
...currentAst,
|
|
1682
|
+
from: {
|
|
1683
|
+
kind: "from",
|
|
1684
|
+
tableName: sourceName,
|
|
1685
|
+
baseTableName: sourceBaseName,
|
|
1686
|
+
source: sourceLike
|
|
1687
|
+
}
|
|
1688
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
|
|
1689
|
+
}
|
|
1690
|
+
if (currentQuery.statement === "update") {
|
|
1691
|
+
const nextAvailable = {
|
|
1692
|
+
...current.available,
|
|
1693
|
+
[sourceName]: {
|
|
1694
|
+
name: sourceName,
|
|
1695
|
+
mode: "required",
|
|
1696
|
+
baseName: sourceBaseName,
|
|
1697
|
+
_presentFormula: ctx.trueFormula(),
|
|
1698
|
+
_presenceWitnesses: presenceWitnesses
|
|
1699
|
+
}
|
|
1700
|
+
};
|
|
1701
|
+
return ctx.makePlan({
|
|
1702
|
+
selection: current.selection,
|
|
1703
|
+
required: [...ctx.currentRequiredList(current.required), ...sourceRequired].filter((name, index3, values) => !(name in nextAvailable) && values.indexOf(name) === index3),
|
|
1704
|
+
available: nextAvailable,
|
|
1705
|
+
dialect: current.dialect
|
|
1706
|
+
}, {
|
|
1707
|
+
...currentAst,
|
|
1708
|
+
fromSources: [
|
|
1709
|
+
...currentAst.fromSources ?? [],
|
|
1710
|
+
{
|
|
1711
|
+
kind: "from",
|
|
1712
|
+
tableName: sourceName,
|
|
1713
|
+
baseTableName: sourceBaseName,
|
|
1714
|
+
source: sourceLike
|
|
1715
|
+
}
|
|
1716
|
+
]
|
|
1717
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
|
|
1718
|
+
}
|
|
1719
|
+
throw new Error(`from(...) is not supported for ${currentQuery.statement} statements`);
|
|
1720
|
+
};
|
|
1721
|
+
const having = (predicate) => (plan) => {
|
|
1722
|
+
const current = plan[TypeId];
|
|
1723
|
+
const currentAst = ctx.getAst(plan);
|
|
1724
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
1725
|
+
const predicateExpression = ctx.toDialectExpression(predicate);
|
|
1726
|
+
const predicateRequired = ctx.extractRequiredFromDialectInputRuntime(predicate);
|
|
1727
|
+
return ctx.makePlan({
|
|
1728
|
+
selection: current.selection,
|
|
1729
|
+
required: [...ctx.currentRequiredList(current.required), ...predicateRequired].filter((name, index3, values) => !(name in current.available) && values.indexOf(name) === index3),
|
|
1730
|
+
available: current.available,
|
|
1731
|
+
dialect: current.dialect ?? predicateExpression[TypeId2].dialect
|
|
1732
|
+
}, {
|
|
1733
|
+
...currentAst,
|
|
1734
|
+
having: [...currentAst.having, {
|
|
1735
|
+
kind: "having",
|
|
1736
|
+
predicate: predicateExpression
|
|
1737
|
+
}]
|
|
1738
|
+
}, ctx.assumeFormulaTrue(currentQuery.assumptions, ctx.formulaOfExpressionRuntime(predicateExpression)), currentQuery.capabilities, currentQuery.statement);
|
|
1739
|
+
};
|
|
1740
|
+
const crossJoin = (table) => (plan) => {
|
|
1741
|
+
const current = plan[TypeId];
|
|
1742
|
+
const currentAst = ctx.getAst(plan);
|
|
1743
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
1744
|
+
if (supportsJoinSources(currentQuery.statement)) {
|
|
1745
|
+
assertAliasedSource(table, "join(...) requires an aliased source in select/update/delete statements");
|
|
1746
|
+
assertSelectHasBaseSourceForJoin(currentQuery.statement, current.available);
|
|
1747
|
+
}
|
|
1748
|
+
const { sourceName, sourceBaseName } = ctx.sourceDetails(table);
|
|
1749
|
+
const presenceWitnesses = ctx.presenceWitnessesOfSourceLike(table);
|
|
1750
|
+
const sourceRequired = sourceRequiredList(table);
|
|
1751
|
+
if (supportsJoinSources(currentQuery.statement)) {
|
|
1752
|
+
assertSourceNameAvailable(current.available, sourceName);
|
|
1753
|
+
}
|
|
1754
|
+
const nextAvailable = {
|
|
1755
|
+
...current.available,
|
|
1756
|
+
[sourceName]: {
|
|
1757
|
+
name: sourceName,
|
|
1758
|
+
mode: "required",
|
|
1759
|
+
baseName: sourceBaseName,
|
|
1760
|
+
_presentFormula: ctx.trueFormula(),
|
|
1761
|
+
_presenceWitnesses: presenceWitnesses
|
|
1762
|
+
}
|
|
1763
|
+
};
|
|
1764
|
+
return ctx.makePlan({
|
|
1765
|
+
selection: current.selection,
|
|
1766
|
+
required: [...ctx.currentRequiredList(current.required), ...sourceRequired].filter((name, index3, values) => !(name in nextAvailable) && values.indexOf(name) === index3),
|
|
1767
|
+
available: nextAvailable,
|
|
1768
|
+
dialect: current.dialect ?? table[TypeId]?.dialect ?? table.dialect
|
|
1769
|
+
}, {
|
|
1770
|
+
...currentAst,
|
|
1771
|
+
joins: [...currentAst.joins, {
|
|
1772
|
+
kind: "cross",
|
|
1773
|
+
tableName: sourceName,
|
|
1774
|
+
baseTableName: sourceBaseName,
|
|
1775
|
+
source: table
|
|
1776
|
+
}]
|
|
1777
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
|
|
1778
|
+
};
|
|
1779
|
+
const join = (kind, table, on) => (plan) => {
|
|
1780
|
+
const current = plan[TypeId];
|
|
1781
|
+
const currentAst = ctx.getAst(plan);
|
|
1782
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
1783
|
+
const onExpression = ctx.toDialectExpression(on);
|
|
1784
|
+
const onFormula = ctx.formulaOfExpressionRuntime(onExpression);
|
|
1785
|
+
if (supportsJoinSources(currentQuery.statement)) {
|
|
1786
|
+
assertAliasedSource(table, "join(...) requires an aliased source in select/update/delete statements");
|
|
1787
|
+
assertSelectHasBaseSourceForJoin(currentQuery.statement, current.available);
|
|
1788
|
+
}
|
|
1789
|
+
const { sourceName, sourceBaseName } = ctx.sourceDetails(table);
|
|
1790
|
+
const presenceWitnesses = ctx.presenceWitnessesOfSourceLike(table);
|
|
1791
|
+
const sourceRequired = sourceRequiredList(table);
|
|
1792
|
+
if (supportsJoinSources(currentQuery.statement)) {
|
|
1793
|
+
assertSourceNameAvailable(current.available, sourceName);
|
|
1794
|
+
}
|
|
1795
|
+
const baseAvailable = kind === "right" || kind === "full" ? Object.fromEntries(Object.entries(current.available).map(([name, source]) => [name, {
|
|
1796
|
+
name: source.name,
|
|
1797
|
+
mode: "optional",
|
|
1798
|
+
baseName: source.baseName,
|
|
1799
|
+
_presentFormula: source._presentFormula,
|
|
1800
|
+
_presenceWitnesses: source._presenceWitnesses
|
|
1801
|
+
}])) : current.available;
|
|
1802
|
+
const nextAvailable = {
|
|
1803
|
+
...baseAvailable,
|
|
1804
|
+
[sourceName]: {
|
|
1805
|
+
name: sourceName,
|
|
1806
|
+
mode: kind === "left" || kind === "full" ? "optional" : "required",
|
|
1807
|
+
baseName: sourceBaseName,
|
|
1808
|
+
_presentFormula: kind === "inner" || kind === "left" ? onFormula : ctx.trueFormula(),
|
|
1809
|
+
_presenceWitnesses: presenceWitnesses
|
|
1810
|
+
}
|
|
1811
|
+
};
|
|
1812
|
+
return ctx.makePlan({
|
|
1813
|
+
selection: current.selection,
|
|
1814
|
+
required: [...ctx.currentRequiredList(current.required), ...sourceRequired, ...ctx.extractRequiredFromDialectInputRuntime(on)].filter((name, index3, values) => !(name in nextAvailable) && values.indexOf(name) === index3),
|
|
1815
|
+
available: nextAvailable,
|
|
1816
|
+
dialect: current.dialect ?? table.dialect ?? onExpression[TypeId2].dialect
|
|
1817
|
+
}, {
|
|
1818
|
+
...currentAst,
|
|
1819
|
+
joins: [...currentAst.joins, {
|
|
1820
|
+
kind,
|
|
1821
|
+
tableName: sourceName,
|
|
1822
|
+
baseTableName: sourceBaseName,
|
|
1823
|
+
source: table,
|
|
1824
|
+
on: onExpression
|
|
1825
|
+
}]
|
|
1826
|
+
}, kind === "inner" ? ctx.assumeFormulaTrue(currentQuery.assumptions, onFormula) : currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
|
|
1827
|
+
};
|
|
1828
|
+
const orderBy = (value, direction = "asc") => (plan) => {
|
|
1829
|
+
if (direction !== "asc" && direction !== "desc") {
|
|
1830
|
+
throw new Error("orderBy(...) direction must be asc or desc");
|
|
1831
|
+
}
|
|
1832
|
+
const current = plan[TypeId];
|
|
1833
|
+
const currentAst = ctx.getAst(plan);
|
|
1834
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
1835
|
+
const expression = ctx.toDialectExpression(value);
|
|
1836
|
+
const required = ctx.extractRequiredFromDialectInputRuntime(value);
|
|
1837
|
+
return ctx.makePlan({
|
|
1838
|
+
selection: current.selection,
|
|
1839
|
+
required: [...ctx.currentRequiredList(current.required), ...required].filter((name, index3, values) => !(name in current.available) && values.indexOf(name) === index3),
|
|
1840
|
+
available: current.available,
|
|
1841
|
+
dialect: current.dialect ?? expression[TypeId2].dialect
|
|
1842
|
+
}, {
|
|
1843
|
+
...currentAst,
|
|
1844
|
+
orderBy: [...currentAst.orderBy, {
|
|
1845
|
+
kind: "orderBy",
|
|
1846
|
+
value: expression,
|
|
1847
|
+
direction
|
|
1848
|
+
}]
|
|
1849
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
|
|
1850
|
+
};
|
|
1851
|
+
const lock = (mode, options2 = {}) => (plan) => {
|
|
1852
|
+
const current = plan[TypeId];
|
|
1853
|
+
const currentAst = ctx.getAst(plan);
|
|
1854
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
1855
|
+
if (currentQuery.statement === "select") {
|
|
1856
|
+
renderSelectLockMode(mode);
|
|
1857
|
+
}
|
|
1858
|
+
if (ctx.profile.dialect === "mysql" && currentQuery.statement === "update") {
|
|
1859
|
+
renderMysqlMutationLockMode(mode, "update");
|
|
1860
|
+
}
|
|
1861
|
+
if (ctx.profile.dialect === "mysql" && currentQuery.statement === "delete") {
|
|
1862
|
+
renderMysqlMutationLockMode(mode, "delete");
|
|
1863
|
+
}
|
|
1864
|
+
return ctx.makePlan({
|
|
1865
|
+
selection: current.selection,
|
|
1866
|
+
required: current.required,
|
|
1867
|
+
available: current.available,
|
|
1868
|
+
dialect: current.dialect
|
|
1869
|
+
}, {
|
|
1870
|
+
...currentAst,
|
|
1871
|
+
lock: {
|
|
1872
|
+
kind: "lock",
|
|
1873
|
+
mode,
|
|
1874
|
+
nowait: options2.nowait ?? false,
|
|
1875
|
+
skipLocked: options2.skipLocked ?? false
|
|
1876
|
+
}
|
|
1877
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
|
|
1878
|
+
};
|
|
1879
|
+
const distinct = () => (plan) => {
|
|
1880
|
+
const current = plan[TypeId];
|
|
1881
|
+
const currentAst = ctx.getAst(plan);
|
|
1882
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
1883
|
+
return ctx.makePlan({
|
|
1884
|
+
selection: current.selection,
|
|
1885
|
+
required: current.required,
|
|
1886
|
+
available: current.available,
|
|
1887
|
+
dialect: current.dialect
|
|
1888
|
+
}, {
|
|
1889
|
+
...currentAst,
|
|
1890
|
+
distinct: true
|
|
1891
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
|
|
1892
|
+
};
|
|
1893
|
+
const limit = (value) => (plan) => {
|
|
1894
|
+
const current = plan[TypeId];
|
|
1895
|
+
const currentAst = ctx.getAst(plan);
|
|
1896
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
1897
|
+
const expression = ctx.toDialectNumericExpression(value);
|
|
1898
|
+
const required = ctx.extractRequiredFromDialectNumericInputRuntime(value);
|
|
1899
|
+
return ctx.makePlan({
|
|
1900
|
+
selection: current.selection,
|
|
1901
|
+
required: [...ctx.currentRequiredList(current.required), ...required].filter((name, index3, values) => !(name in current.available) && values.indexOf(name) === index3),
|
|
1902
|
+
available: current.available,
|
|
1903
|
+
dialect: current.dialect ?? expression[TypeId2].dialect
|
|
1904
|
+
}, {
|
|
1905
|
+
...currentAst,
|
|
1906
|
+
limit: expression
|
|
1907
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
|
|
1908
|
+
};
|
|
1909
|
+
const offset = (value) => (plan) => {
|
|
1910
|
+
const current = plan[TypeId];
|
|
1911
|
+
const currentAst = ctx.getAst(plan);
|
|
1912
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
1913
|
+
const expression = ctx.toDialectNumericExpression(value);
|
|
1914
|
+
const required = ctx.extractRequiredFromDialectNumericInputRuntime(value);
|
|
1915
|
+
return ctx.makePlan({
|
|
1916
|
+
selection: current.selection,
|
|
1917
|
+
required: [...ctx.currentRequiredList(current.required), ...required].filter((name, index3, values) => !(name in current.available) && values.indexOf(name) === index3),
|
|
1918
|
+
available: current.available,
|
|
1919
|
+
dialect: current.dialect ?? expression[TypeId2].dialect
|
|
1920
|
+
}, {
|
|
1921
|
+
...currentAst,
|
|
1922
|
+
offset: expression
|
|
1923
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
|
|
1924
|
+
};
|
|
1925
|
+
return {
|
|
1926
|
+
buildSetOperation,
|
|
1927
|
+
where,
|
|
1928
|
+
from,
|
|
1929
|
+
having,
|
|
1930
|
+
crossJoin,
|
|
1931
|
+
join,
|
|
1932
|
+
orderBy,
|
|
1933
|
+
lock,
|
|
1934
|
+
distinct,
|
|
1935
|
+
limit,
|
|
1936
|
+
offset
|
|
1937
|
+
};
|
|
1938
|
+
};
|
|
1939
|
+
|
|
1940
|
+
// src/internal/dsl-mutation-runtime.ts
|
|
1941
|
+
var expectInsertSourceKind = (source) => {
|
|
1942
|
+
if (source !== undefined && source.kind !== "values" && source.kind !== "query" && source.kind !== "unnest") {
|
|
1943
|
+
throw new Error("Unsupported insert source kind");
|
|
1944
|
+
}
|
|
1945
|
+
return source;
|
|
1946
|
+
};
|
|
1947
|
+
var expectConflictClause = (conflict) => {
|
|
1948
|
+
if (conflict === undefined) {
|
|
1949
|
+
return conflict;
|
|
1950
|
+
}
|
|
1951
|
+
if (conflict.kind !== "conflict") {
|
|
1952
|
+
throw new Error("Unsupported conflict clause kind");
|
|
1953
|
+
}
|
|
1954
|
+
if (conflict.action !== "doNothing" && conflict.action !== "doUpdate") {
|
|
1955
|
+
throw new Error("Unsupported conflict action");
|
|
1956
|
+
}
|
|
1957
|
+
if (conflict.target !== undefined && conflict.target.kind !== "columns" && conflict.target.kind !== "constraint") {
|
|
1958
|
+
throw new Error("Unsupported conflict target kind");
|
|
1959
|
+
}
|
|
1960
|
+
return conflict;
|
|
1961
|
+
};
|
|
1962
|
+
var makeDslMutationRuntime = (ctx) => {
|
|
1963
|
+
const aliasedSourceKinds = new Set(["derived", "cte", "lateral", "values", "unnest", "tableFunction"]);
|
|
1964
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
1965
|
+
const isTableTarget = (target) => typeof target === "object" && target !== null && (TypeId4 in target) && (TypeId in target);
|
|
1966
|
+
const hasColumnRecord = (value) => isRecord(value.columns);
|
|
1967
|
+
const isAliasedSource = (source) => {
|
|
1968
|
+
if (!isRecord(source)) {
|
|
1969
|
+
return false;
|
|
1970
|
+
}
|
|
1971
|
+
if (isTableTarget(source)) {
|
|
1972
|
+
return true;
|
|
1973
|
+
}
|
|
1974
|
+
if (!("kind" in source) || !("name" in source) || !("baseName" in source)) {
|
|
1975
|
+
return false;
|
|
1976
|
+
}
|
|
1977
|
+
if (typeof source.kind !== "string" || !aliasedSourceKinds.has(source.kind)) {
|
|
1978
|
+
return false;
|
|
1979
|
+
}
|
|
1980
|
+
if (typeof source.name !== "string" || typeof source.baseName !== "string") {
|
|
1981
|
+
return false;
|
|
1982
|
+
}
|
|
1983
|
+
switch (source.kind) {
|
|
1984
|
+
case "derived":
|
|
1985
|
+
case "cte":
|
|
1986
|
+
case "lateral":
|
|
1987
|
+
return isRecord(source.plan) && TypeId in source.plan && hasColumnRecord(source);
|
|
1988
|
+
case "values":
|
|
1989
|
+
return Array.isArray(source.rows) && hasColumnRecord(source);
|
|
1990
|
+
case "unnest":
|
|
1991
|
+
return isRecord(source.arrays) && hasColumnRecord(source);
|
|
1992
|
+
case "tableFunction":
|
|
1993
|
+
return typeof source.functionName === "string" && Array.isArray(source.args) && hasColumnRecord(source);
|
|
1994
|
+
}
|
|
1995
|
+
return false;
|
|
1996
|
+
};
|
|
1997
|
+
const assertMutationTarget = (target, apiName) => {
|
|
1998
|
+
if (!isTableTarget(target)) {
|
|
1999
|
+
throw new Error(`${apiName}(...) requires table targets`);
|
|
2000
|
+
}
|
|
2001
|
+
};
|
|
2002
|
+
const assertAliasedSource = (source, apiName) => {
|
|
2003
|
+
if (!isAliasedSource(source)) {
|
|
2004
|
+
throw new Error(`${apiName}(...) requires an aliased source`);
|
|
2005
|
+
}
|
|
2006
|
+
};
|
|
2007
|
+
const assertMutationTargets = (target, apiName, options2 = {}) => {
|
|
2008
|
+
const targets = Array.isArray(target) ? target : [target];
|
|
2009
|
+
if (targets.length === 0) {
|
|
2010
|
+
throw new Error(`${apiName}(...) requires at least one table target`);
|
|
2011
|
+
}
|
|
2012
|
+
if (Array.isArray(target) && targets.length === 1) {
|
|
2013
|
+
throw new Error(`${apiName}(...) requires a table target, not a single-element target tuple`);
|
|
2014
|
+
}
|
|
2015
|
+
for (const entry of targets) {
|
|
2016
|
+
assertMutationTarget(entry, apiName);
|
|
2017
|
+
}
|
|
2018
|
+
if (targets.length > 1 && options2.allowMultiple !== true) {
|
|
2019
|
+
throw new Error(`${apiName}(...) requires a single table target`);
|
|
2020
|
+
}
|
|
2021
|
+
if (targets.length > 1 && ctx.profile.dialect !== "mysql" && ctx.profile.dialect !== "sqlite") {
|
|
2022
|
+
throw new Error(`${apiName}(...) only supports multiple mutation targets for mysql`);
|
|
2023
|
+
}
|
|
2024
|
+
};
|
|
2025
|
+
const assertUniqueTargetNames = (targets) => {
|
|
2026
|
+
const seen = new Set;
|
|
2027
|
+
for (const target of targets) {
|
|
2028
|
+
if (seen.has(target.tableName)) {
|
|
2029
|
+
throw new Error(`mutation target source names must be unique: ${target.tableName}`);
|
|
2030
|
+
}
|
|
2031
|
+
seen.add(target.tableName);
|
|
2032
|
+
}
|
|
2033
|
+
};
|
|
2034
|
+
const assertInsertSelectSource = (sourcePlan, selection) => {
|
|
2035
|
+
const statement = ctx.getQueryState(sourcePlan).statement;
|
|
2036
|
+
if (statement !== "select" && statement !== "set") {
|
|
2037
|
+
throw new Error("insert sources only accept select-like query plans");
|
|
2038
|
+
}
|
|
2039
|
+
for (const value of Object.values(selection)) {
|
|
2040
|
+
if (value === null || typeof value !== "object" || !(TypeId2 in value)) {
|
|
2041
|
+
throw new Error("insert sources require a flat selection object");
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
};
|
|
2045
|
+
const insert = (target, values) => {
|
|
2046
|
+
assertMutationTargets(target, "insert");
|
|
2047
|
+
const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
|
|
2048
|
+
const assignments = values === undefined ? [] : ctx.buildMutationAssignments(target, values);
|
|
2049
|
+
const required = assignments.flatMap((entry) => Object.keys(entry.value[TypeId2].dependencies));
|
|
2050
|
+
const insertState = values === undefined ? "missing" : "ready";
|
|
2051
|
+
return ctx.makePlan({
|
|
2052
|
+
selection: {},
|
|
2053
|
+
required: required.filter((name, index3, list) => name !== sourceName && list.indexOf(name) === index3),
|
|
2054
|
+
available: {
|
|
2055
|
+
[sourceName]: {
|
|
2056
|
+
name: sourceName,
|
|
2057
|
+
mode: "required",
|
|
2058
|
+
baseName: sourceBaseName
|
|
2059
|
+
}
|
|
2060
|
+
},
|
|
2061
|
+
dialect: target[TypeId].dialect
|
|
2062
|
+
}, {
|
|
2063
|
+
kind: "insert",
|
|
2064
|
+
select: {},
|
|
2065
|
+
into: {
|
|
2066
|
+
kind: "from",
|
|
2067
|
+
tableName: sourceName,
|
|
2068
|
+
baseTableName: sourceBaseName,
|
|
2069
|
+
source: target
|
|
2070
|
+
},
|
|
2071
|
+
values: assignments,
|
|
2072
|
+
conflict: undefined,
|
|
2073
|
+
where: [],
|
|
2074
|
+
having: [],
|
|
2075
|
+
joins: [],
|
|
2076
|
+
groupBy: [],
|
|
2077
|
+
orderBy: []
|
|
2078
|
+
}, undefined, "write", "insert", target, insertState);
|
|
2079
|
+
};
|
|
2080
|
+
const attachInsertSource = (plan, source) => {
|
|
2081
|
+
const current = plan[TypeId];
|
|
2082
|
+
const currentAst = ctx.getAst(plan);
|
|
2083
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
2084
|
+
const target = currentQuery.target;
|
|
2085
|
+
const sourceName = currentAst.into.tableName;
|
|
2086
|
+
if (typeof source === "object" && source !== null && "kind" in source && source.kind === "values") {
|
|
2087
|
+
const normalized = ctx.buildInsertValuesRows(target, source.rows);
|
|
2088
|
+
return ctx.makePlan({
|
|
2089
|
+
selection: current.selection,
|
|
2090
|
+
required: normalized.required.filter((name) => name !== sourceName),
|
|
2091
|
+
available: current.available,
|
|
2092
|
+
dialect: current.dialect
|
|
2093
|
+
}, {
|
|
2094
|
+
...currentAst,
|
|
2095
|
+
values: [],
|
|
2096
|
+
insertSource: {
|
|
2097
|
+
kind: "values",
|
|
2098
|
+
columns: normalized.columns,
|
|
2099
|
+
rows: normalized.rows
|
|
2100
|
+
}
|
|
2101
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement, currentQuery.target, "ready");
|
|
2102
|
+
}
|
|
2103
|
+
if (typeof source === "object" && source !== null && "kind" in source && source.kind === "unnest") {
|
|
2104
|
+
const normalized = ctx.normalizeInsertUnnestValues(target, source.values);
|
|
2105
|
+
return ctx.makePlan({
|
|
2106
|
+
selection: current.selection,
|
|
2107
|
+
required: [],
|
|
2108
|
+
available: current.available,
|
|
2109
|
+
dialect: current.dialect
|
|
2110
|
+
}, {
|
|
2111
|
+
...currentAst,
|
|
2112
|
+
values: [],
|
|
2113
|
+
insertSource: {
|
|
2114
|
+
kind: "unnest",
|
|
2115
|
+
columns: normalized.columns,
|
|
2116
|
+
values: normalized.values
|
|
2117
|
+
}
|
|
2118
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement, currentQuery.target, "ready");
|
|
2119
|
+
}
|
|
2120
|
+
const sourcePlan = source;
|
|
2121
|
+
const selection = sourcePlan[TypeId].selection;
|
|
2122
|
+
assertInsertSelectSource(sourcePlan, selection);
|
|
2123
|
+
const columns = ctx.normalizeInsertSelectColumns(selection);
|
|
2124
|
+
return ctx.makePlan({
|
|
2125
|
+
selection: current.selection,
|
|
2126
|
+
required: ctx.currentRequiredList(sourcePlan[TypeId].required),
|
|
2127
|
+
available: current.available,
|
|
2128
|
+
dialect: current.dialect
|
|
2129
|
+
}, {
|
|
2130
|
+
...currentAst,
|
|
2131
|
+
values: [],
|
|
2132
|
+
insertSource: {
|
|
2133
|
+
kind: "query",
|
|
2134
|
+
columns,
|
|
2135
|
+
query: sourcePlan
|
|
2136
|
+
}
|
|
2137
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement, currentQuery.target, "ready");
|
|
2138
|
+
};
|
|
2139
|
+
const onConflict = (target, options2 = {}) => (plan) => {
|
|
2140
|
+
const current = plan[TypeId];
|
|
2141
|
+
const currentAst = ctx.getAst(plan);
|
|
2142
|
+
const currentQuery = ctx.getQueryState(plan);
|
|
2143
|
+
if (currentQuery.statement !== "insert") {
|
|
2144
|
+
throw new Error(`onConflict(...) is not supported for ${currentQuery.statement} statements`);
|
|
2145
|
+
}
|
|
2146
|
+
const insertTarget = currentAst.into.source;
|
|
2147
|
+
const conflictTarget = ctx.buildConflictTarget(insertTarget, target);
|
|
2148
|
+
const updateAssignments = options2.update ? ctx.buildMutationAssignments(insertTarget, options2.update) : [];
|
|
2149
|
+
if (options2.update !== undefined && updateAssignments.length === 0) {
|
|
2150
|
+
throw new Error("conflict update assignments require at least one assignment");
|
|
2151
|
+
}
|
|
2152
|
+
const updateWhere = options2.where === undefined ? undefined : ctx.toDialectExpression(options2.where);
|
|
2153
|
+
const targetWhere = conflictTarget.kind === "columns" ? conflictTarget.where : undefined;
|
|
2154
|
+
const required = [
|
|
2155
|
+
...ctx.currentRequiredList(current.required),
|
|
2156
|
+
...updateAssignments.flatMap((entry) => Object.keys(entry.value[TypeId2].dependencies)),
|
|
2157
|
+
...updateWhere ? Object.keys(updateWhere[TypeId2].dependencies) : [],
|
|
2158
|
+
...targetWhere ? Object.keys(targetWhere[TypeId2].dependencies) : []
|
|
2159
|
+
].filter((name, index3, list) => !(name in current.available) && list.indexOf(name) === index3);
|
|
2160
|
+
return ctx.makePlan({
|
|
2161
|
+
selection: current.selection,
|
|
2162
|
+
required,
|
|
2163
|
+
available: current.available,
|
|
2164
|
+
dialect: current.dialect
|
|
2165
|
+
}, {
|
|
2166
|
+
...currentAst,
|
|
2167
|
+
conflict: {
|
|
2168
|
+
kind: "conflict",
|
|
2169
|
+
target: conflictTarget,
|
|
2170
|
+
action: updateAssignments.length === 0 ? "doNothing" : "doUpdate",
|
|
2171
|
+
values: updateAssignments.length === 0 ? undefined : updateAssignments,
|
|
2172
|
+
where: updateWhere
|
|
2173
|
+
}
|
|
2174
|
+
}, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement, currentQuery.target, currentQuery.insertSource);
|
|
2175
|
+
};
|
|
2176
|
+
const update = (target, values) => {
|
|
2177
|
+
assertMutationTargets(target, "update", { allowMultiple: true });
|
|
2178
|
+
const targets = ctx.mutationTargetClauses(target);
|
|
2179
|
+
assertUniqueTargetNames(targets);
|
|
2180
|
+
const primaryTarget = targets[0];
|
|
2181
|
+
const assignments = ctx.buildMutationAssignments(target, values);
|
|
2182
|
+
const targetNames = new Set(targets.map((entry) => entry.tableName));
|
|
2183
|
+
const required = assignments.flatMap((entry) => Object.keys(entry.value[TypeId2].dependencies)).filter((name, index3, list) => !targetNames.has(name) && list.indexOf(name) === index3);
|
|
2184
|
+
return ctx.makePlan({
|
|
2185
|
+
selection: {},
|
|
2186
|
+
required,
|
|
2187
|
+
available: ctx.mutationAvailableSources(target),
|
|
2188
|
+
dialect: primaryTarget.source[TypeId].dialect
|
|
2189
|
+
}, {
|
|
2190
|
+
kind: "update",
|
|
2191
|
+
select: {},
|
|
2192
|
+
target: primaryTarget,
|
|
2193
|
+
targets,
|
|
2194
|
+
set: assignments,
|
|
2195
|
+
where: [],
|
|
2196
|
+
having: [],
|
|
2197
|
+
joins: [],
|
|
2198
|
+
groupBy: [],
|
|
2199
|
+
orderBy: []
|
|
2200
|
+
}, undefined, "write", "update");
|
|
2201
|
+
};
|
|
2202
|
+
const upsert = (target, values, conflictColumns, updateValues) => {
|
|
2203
|
+
assertMutationTargets(target, "upsert");
|
|
2204
|
+
const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
|
|
2205
|
+
const assignments = ctx.buildMutationAssignments(target, values);
|
|
2206
|
+
const updateAssignments = updateValues ? ctx.buildMutationAssignments(target, updateValues) : [];
|
|
2207
|
+
if (updateValues !== undefined && updateAssignments.length === 0) {
|
|
2208
|
+
throw new Error("upsert update assignments require at least one assignment");
|
|
2209
|
+
}
|
|
2210
|
+
const required = [
|
|
2211
|
+
...assignments.flatMap((entry) => Object.keys(entry.value[TypeId2].dependencies)),
|
|
2212
|
+
...updateAssignments.flatMap((entry) => Object.keys(entry.value[TypeId2].dependencies))
|
|
2213
|
+
];
|
|
2214
|
+
return ctx.makePlan({
|
|
2215
|
+
selection: {},
|
|
2216
|
+
required: required.filter((name, index3, list) => name !== sourceName && list.indexOf(name) === index3),
|
|
2217
|
+
available: {
|
|
2218
|
+
[sourceName]: {
|
|
2219
|
+
name: sourceName,
|
|
2220
|
+
mode: "required",
|
|
2221
|
+
baseName: sourceBaseName
|
|
2222
|
+
}
|
|
2223
|
+
},
|
|
2224
|
+
dialect: target[TypeId].dialect
|
|
2225
|
+
}, {
|
|
2226
|
+
kind: "insert",
|
|
2227
|
+
select: {},
|
|
2228
|
+
into: {
|
|
2229
|
+
kind: "from",
|
|
2230
|
+
tableName: sourceName,
|
|
2231
|
+
baseTableName: sourceBaseName,
|
|
2232
|
+
source: target
|
|
2233
|
+
},
|
|
2234
|
+
values: assignments,
|
|
2235
|
+
conflict: {
|
|
2236
|
+
kind: "conflict",
|
|
2237
|
+
target: {
|
|
2238
|
+
kind: "columns",
|
|
2239
|
+
columns: ctx.normalizeConflictColumns(target, conflictColumns)
|
|
2240
|
+
},
|
|
2241
|
+
action: updateAssignments.length > 0 ? "doUpdate" : "doNothing",
|
|
2242
|
+
values: updateAssignments.length > 0 ? updateAssignments : undefined
|
|
2243
|
+
},
|
|
2244
|
+
where: [],
|
|
2245
|
+
having: [],
|
|
2246
|
+
joins: [],
|
|
2247
|
+
groupBy: [],
|
|
2248
|
+
orderBy: []
|
|
2249
|
+
}, undefined, "write", "insert", target, "ready");
|
|
2250
|
+
};
|
|
2251
|
+
const delete_ = (target) => {
|
|
2252
|
+
assertMutationTargets(target, "delete", { allowMultiple: true });
|
|
2253
|
+
const targets = ctx.mutationTargetClauses(target);
|
|
2254
|
+
assertUniqueTargetNames(targets);
|
|
2255
|
+
const primaryTarget = targets[0];
|
|
2256
|
+
return ctx.makePlan({
|
|
2257
|
+
selection: {},
|
|
2258
|
+
required: [],
|
|
2259
|
+
available: ctx.mutationAvailableSources(target),
|
|
2260
|
+
dialect: primaryTarget.source[TypeId].dialect
|
|
2261
|
+
}, {
|
|
2262
|
+
kind: "delete",
|
|
2263
|
+
select: {},
|
|
2264
|
+
target: primaryTarget,
|
|
2265
|
+
targets,
|
|
2266
|
+
where: [],
|
|
2267
|
+
having: [],
|
|
2268
|
+
joins: [],
|
|
2269
|
+
groupBy: [],
|
|
2270
|
+
orderBy: []
|
|
2271
|
+
}, undefined, "write", "delete");
|
|
2272
|
+
};
|
|
2273
|
+
const truncate = (target, options2 = {}) => {
|
|
2274
|
+
assertMutationTargets(target, "truncate");
|
|
2275
|
+
const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
|
|
2276
|
+
return ctx.makePlan({
|
|
2277
|
+
selection: {},
|
|
2278
|
+
required: [],
|
|
2279
|
+
available: {},
|
|
2280
|
+
dialect: target[TypeId].dialect
|
|
2281
|
+
}, {
|
|
2282
|
+
kind: "truncate",
|
|
2283
|
+
select: {},
|
|
2284
|
+
target: {
|
|
2285
|
+
kind: "from",
|
|
2286
|
+
tableName: sourceName,
|
|
2287
|
+
baseTableName: sourceBaseName,
|
|
2288
|
+
source: target
|
|
2289
|
+
},
|
|
2290
|
+
truncate: {
|
|
2291
|
+
kind: "truncate",
|
|
2292
|
+
restartIdentity: options2.restartIdentity ?? false,
|
|
2293
|
+
cascade: options2.cascade ?? false
|
|
2294
|
+
},
|
|
2295
|
+
where: [],
|
|
2296
|
+
having: [],
|
|
2297
|
+
joins: [],
|
|
2298
|
+
groupBy: [],
|
|
2299
|
+
orderBy: []
|
|
2300
|
+
}, undefined, "write", "truncate");
|
|
2301
|
+
};
|
|
2302
|
+
const merge = (target, source, on, options2 = {}) => {
|
|
2303
|
+
assertMutationTargets(target, "merge");
|
|
2304
|
+
assertAliasedSource(source, "merge");
|
|
2305
|
+
const { sourceName: targetName, sourceBaseName: targetBaseName } = ctx.targetSourceDetails(target);
|
|
2306
|
+
const { sourceName: usingName, sourceBaseName: usingBaseName } = ctx.sourceDetails(source);
|
|
2307
|
+
if (targetName === usingName) {
|
|
2308
|
+
throw new Error(`merge(...) source name must differ from target source name: ${targetName}`);
|
|
2309
|
+
}
|
|
2310
|
+
const onExpression = ctx.toDialectExpression(on);
|
|
2311
|
+
const matched = options2.whenMatched;
|
|
2312
|
+
const notMatched = options2.whenNotMatched;
|
|
2313
|
+
if (matched && "delete" in matched && "update" in matched) {
|
|
2314
|
+
throw new Error("merge whenMatched cannot specify both update and delete");
|
|
2315
|
+
}
|
|
2316
|
+
const matchedPredicate = matched?.predicate ? ctx.toDialectExpression(matched.predicate) : undefined;
|
|
2317
|
+
const matchedAssignments = matched && "update" in matched && matched.update ? ctx.buildMutationAssignments(target, matched.update) : [];
|
|
2318
|
+
const notMatchedPredicate = notMatched?.predicate ? ctx.toDialectExpression(notMatched.predicate) : undefined;
|
|
2319
|
+
const notMatchedAssignments = notMatched ? ctx.buildMutationAssignments(target, notMatched.values) : [];
|
|
2320
|
+
const required = [
|
|
2321
|
+
...Object.keys(onExpression[TypeId2].dependencies),
|
|
2322
|
+
...matchedAssignments.flatMap((entry) => Object.keys(entry.value[TypeId2].dependencies)),
|
|
2323
|
+
...notMatchedAssignments.flatMap((entry) => Object.keys(entry.value[TypeId2].dependencies)),
|
|
2324
|
+
...matchedPredicate ? Object.keys(matchedPredicate[TypeId2].dependencies) : [],
|
|
2325
|
+
...notMatchedPredicate ? Object.keys(notMatchedPredicate[TypeId2].dependencies) : []
|
|
2326
|
+
].filter((name, index3, values) => name !== targetName && name !== usingName && values.indexOf(name) === index3);
|
|
2327
|
+
return ctx.makePlan({
|
|
2328
|
+
selection: {},
|
|
2329
|
+
required,
|
|
2330
|
+
available: {
|
|
2331
|
+
[targetName]: {
|
|
2332
|
+
name: targetName,
|
|
2333
|
+
mode: "required",
|
|
2334
|
+
baseName: targetBaseName
|
|
2335
|
+
},
|
|
2336
|
+
[usingName]: {
|
|
2337
|
+
name: usingName,
|
|
2338
|
+
mode: "required",
|
|
2339
|
+
baseName: usingBaseName
|
|
2340
|
+
}
|
|
2341
|
+
},
|
|
2342
|
+
dialect: target[TypeId].dialect
|
|
2343
|
+
}, {
|
|
2344
|
+
kind: "merge",
|
|
2345
|
+
select: {},
|
|
2346
|
+
target: {
|
|
2347
|
+
kind: "from",
|
|
2348
|
+
tableName: targetName,
|
|
2349
|
+
baseTableName: targetBaseName,
|
|
2350
|
+
source: target
|
|
2351
|
+
},
|
|
2352
|
+
using: {
|
|
2353
|
+
kind: "from",
|
|
2354
|
+
tableName: usingName,
|
|
2355
|
+
baseTableName: usingBaseName,
|
|
2356
|
+
source
|
|
2357
|
+
},
|
|
2358
|
+
merge: {
|
|
2359
|
+
kind: "merge",
|
|
2360
|
+
on: onExpression,
|
|
2361
|
+
whenMatched: matched ? "delete" in matched && matched.delete ? {
|
|
2362
|
+
kind: "delete",
|
|
2363
|
+
predicate: matchedPredicate
|
|
2364
|
+
} : {
|
|
2365
|
+
kind: "update",
|
|
2366
|
+
values: matchedAssignments,
|
|
2367
|
+
predicate: matchedPredicate
|
|
2368
|
+
} : undefined,
|
|
2369
|
+
whenNotMatched: notMatched ? {
|
|
2370
|
+
kind: "insert",
|
|
2371
|
+
values: notMatchedAssignments,
|
|
2372
|
+
predicate: notMatchedPredicate
|
|
2373
|
+
} : undefined
|
|
2374
|
+
},
|
|
2375
|
+
where: [],
|
|
2376
|
+
having: [],
|
|
2377
|
+
joins: [],
|
|
2378
|
+
groupBy: [],
|
|
2379
|
+
orderBy: []
|
|
2380
|
+
}, undefined, "write", "merge");
|
|
2381
|
+
};
|
|
2382
|
+
return {
|
|
2383
|
+
insert,
|
|
2384
|
+
attachInsertSource,
|
|
2385
|
+
onConflict,
|
|
2386
|
+
update,
|
|
2387
|
+
upsert,
|
|
2388
|
+
delete_,
|
|
2389
|
+
truncate,
|
|
2390
|
+
merge
|
|
2391
|
+
};
|
|
2392
|
+
};
|
|
2393
|
+
|
|
2394
|
+
// src/internal/dsl-transaction-ddl-runtime.ts
|
|
2395
|
+
var allowedIsolationLevels = new Set(["read committed", "repeatable read", "serializable"]);
|
|
2396
|
+
var renderTransactionIsolationLevel = (isolationLevel) => {
|
|
2397
|
+
if (isolationLevel === undefined) {
|
|
2398
|
+
return "";
|
|
2399
|
+
}
|
|
2400
|
+
if (typeof isolationLevel !== "string" || !allowedIsolationLevels.has(isolationLevel)) {
|
|
2401
|
+
throw new Error("Unsupported transaction isolation level");
|
|
2402
|
+
}
|
|
2403
|
+
return `isolation level ${isolationLevel}`;
|
|
2404
|
+
};
|
|
2405
|
+
var expectDdlClauseKind = (ddl, kind) => {
|
|
2406
|
+
if (ddl === undefined || ddl.kind !== kind) {
|
|
2407
|
+
throw new Error("Unsupported DDL statement kind");
|
|
2408
|
+
}
|
|
2409
|
+
return ddl;
|
|
2410
|
+
};
|
|
2411
|
+
var expectTruncateClause = (truncate) => {
|
|
2412
|
+
if (truncate === undefined || truncate.kind !== "truncate") {
|
|
2413
|
+
throw new Error("Unsupported truncate statement kind");
|
|
2414
|
+
}
|
|
2415
|
+
return truncate;
|
|
2416
|
+
};
|
|
2417
|
+
var validateIsolationLevel = (isolationLevel) => {
|
|
2418
|
+
renderTransactionIsolationLevel(isolationLevel);
|
|
2419
|
+
};
|
|
2420
|
+
var makeDslTransactionDdlRuntime = (ctx) => {
|
|
2421
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
2422
|
+
const assertTableTarget = (target, apiName) => {
|
|
2423
|
+
if (!isRecord(target) || !(TypeId4 in target) || !(TypeId in target)) {
|
|
2424
|
+
throw new Error(`${apiName}(...) requires a table target`);
|
|
2425
|
+
}
|
|
2426
|
+
};
|
|
2427
|
+
const validateIndexColumns = (target, columns) => {
|
|
2428
|
+
const fields = target[TypeId4]?.fields;
|
|
2429
|
+
if (fields === undefined) {
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
for (const columnName of columns) {
|
|
2433
|
+
if (!(columnName in fields)) {
|
|
2434
|
+
throw new Error(`effect-qb: unknown index column '${columnName}'`);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
};
|
|
2438
|
+
const transaction = (options2 = {}) => {
|
|
2439
|
+
validateIsolationLevel(options2.isolationLevel);
|
|
2440
|
+
return ctx.makePlan({
|
|
2441
|
+
selection: {},
|
|
2442
|
+
required: [],
|
|
2443
|
+
available: {},
|
|
2444
|
+
dialect: ctx.profile.dialect
|
|
2445
|
+
}, {
|
|
2446
|
+
kind: "transaction",
|
|
2447
|
+
select: {},
|
|
2448
|
+
transaction: {
|
|
2449
|
+
kind: "transaction",
|
|
2450
|
+
isolationLevel: options2.isolationLevel,
|
|
2451
|
+
readOnly: options2.readOnly
|
|
2452
|
+
},
|
|
2453
|
+
where: [],
|
|
2454
|
+
having: [],
|
|
2455
|
+
joins: [],
|
|
2456
|
+
groupBy: [],
|
|
2457
|
+
orderBy: []
|
|
2458
|
+
}, undefined, "transaction", "transaction");
|
|
2459
|
+
};
|
|
2460
|
+
const commit = () => ctx.makePlan({
|
|
2461
|
+
selection: {},
|
|
2462
|
+
required: [],
|
|
2463
|
+
available: {},
|
|
2464
|
+
dialect: ctx.profile.dialect
|
|
2465
|
+
}, {
|
|
2466
|
+
kind: "commit",
|
|
2467
|
+
select: {},
|
|
2468
|
+
transaction: {
|
|
2469
|
+
kind: "commit"
|
|
2470
|
+
},
|
|
2471
|
+
where: [],
|
|
2472
|
+
having: [],
|
|
2473
|
+
joins: [],
|
|
2474
|
+
groupBy: [],
|
|
2475
|
+
orderBy: []
|
|
2476
|
+
}, undefined, "transaction", "commit");
|
|
2477
|
+
const rollback = () => ctx.makePlan({
|
|
2478
|
+
selection: {},
|
|
2479
|
+
required: [],
|
|
2480
|
+
available: {},
|
|
2481
|
+
dialect: ctx.profile.dialect
|
|
2482
|
+
}, {
|
|
2483
|
+
kind: "rollback",
|
|
2484
|
+
select: {},
|
|
2485
|
+
transaction: {
|
|
2486
|
+
kind: "rollback"
|
|
2487
|
+
},
|
|
2488
|
+
where: [],
|
|
2489
|
+
having: [],
|
|
2490
|
+
joins: [],
|
|
2491
|
+
groupBy: [],
|
|
2492
|
+
orderBy: []
|
|
2493
|
+
}, undefined, "transaction", "rollback");
|
|
2494
|
+
const savepoint = (name) => ctx.makePlan({
|
|
2495
|
+
selection: {},
|
|
2496
|
+
required: [],
|
|
2497
|
+
available: {},
|
|
2498
|
+
dialect: ctx.profile.dialect
|
|
2499
|
+
}, {
|
|
2500
|
+
kind: "savepoint",
|
|
2501
|
+
select: {},
|
|
2502
|
+
transaction: {
|
|
2503
|
+
kind: "savepoint",
|
|
2504
|
+
name
|
|
2505
|
+
},
|
|
2506
|
+
where: [],
|
|
2507
|
+
having: [],
|
|
2508
|
+
joins: [],
|
|
2509
|
+
groupBy: [],
|
|
2510
|
+
orderBy: []
|
|
2511
|
+
}, undefined, "transaction", "savepoint");
|
|
2512
|
+
const rollbackTo = (name) => ctx.makePlan({
|
|
2513
|
+
selection: {},
|
|
2514
|
+
required: [],
|
|
2515
|
+
available: {},
|
|
2516
|
+
dialect: ctx.profile.dialect
|
|
2517
|
+
}, {
|
|
2518
|
+
kind: "rollbackTo",
|
|
2519
|
+
select: {},
|
|
2520
|
+
transaction: {
|
|
2521
|
+
kind: "rollbackTo",
|
|
2522
|
+
name
|
|
2523
|
+
},
|
|
2524
|
+
where: [],
|
|
2525
|
+
having: [],
|
|
2526
|
+
joins: [],
|
|
2527
|
+
groupBy: [],
|
|
2528
|
+
orderBy: []
|
|
2529
|
+
}, undefined, "transaction", "rollbackTo");
|
|
2530
|
+
const releaseSavepoint = (name) => ctx.makePlan({
|
|
2531
|
+
selection: {},
|
|
2532
|
+
required: [],
|
|
2533
|
+
available: {},
|
|
2534
|
+
dialect: ctx.profile.dialect
|
|
2535
|
+
}, {
|
|
2536
|
+
kind: "releaseSavepoint",
|
|
2537
|
+
select: {},
|
|
2538
|
+
transaction: {
|
|
2539
|
+
kind: "releaseSavepoint",
|
|
2540
|
+
name
|
|
2541
|
+
},
|
|
2542
|
+
where: [],
|
|
2543
|
+
having: [],
|
|
2544
|
+
joins: [],
|
|
2545
|
+
groupBy: [],
|
|
2546
|
+
orderBy: []
|
|
2547
|
+
}, undefined, "transaction", "releaseSavepoint");
|
|
2548
|
+
const createTable = (target, options2 = {}) => {
|
|
2549
|
+
assertTableTarget(target, "createTable");
|
|
2550
|
+
const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
|
|
2551
|
+
return ctx.makePlan({
|
|
2552
|
+
selection: {},
|
|
2553
|
+
required: [],
|
|
2554
|
+
available: {},
|
|
2555
|
+
dialect: target[TypeId].dialect
|
|
2556
|
+
}, {
|
|
2557
|
+
kind: "createTable",
|
|
2558
|
+
select: {},
|
|
2559
|
+
target: {
|
|
2560
|
+
kind: "from",
|
|
2561
|
+
tableName: sourceName,
|
|
2562
|
+
baseTableName: sourceBaseName,
|
|
2563
|
+
source: target
|
|
2564
|
+
},
|
|
2565
|
+
ddl: {
|
|
2566
|
+
kind: "createTable",
|
|
2567
|
+
ifNotExists: options2.ifNotExists ?? false
|
|
2568
|
+
},
|
|
2569
|
+
where: [],
|
|
2570
|
+
having: [],
|
|
2571
|
+
joins: [],
|
|
2572
|
+
groupBy: [],
|
|
2573
|
+
orderBy: []
|
|
2574
|
+
}, undefined, "ddl", "createTable");
|
|
2575
|
+
};
|
|
2576
|
+
const dropTable = (target, options2 = {}) => {
|
|
2577
|
+
assertTableTarget(target, "dropTable");
|
|
2578
|
+
const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
|
|
2579
|
+
return ctx.makePlan({
|
|
2580
|
+
selection: {},
|
|
2581
|
+
required: [],
|
|
2582
|
+
available: {},
|
|
2583
|
+
dialect: target[TypeId].dialect
|
|
2584
|
+
}, {
|
|
2585
|
+
kind: "dropTable",
|
|
2586
|
+
select: {},
|
|
2587
|
+
target: {
|
|
2588
|
+
kind: "from",
|
|
2589
|
+
tableName: sourceName,
|
|
2590
|
+
baseTableName: sourceBaseName,
|
|
2591
|
+
source: target
|
|
2592
|
+
},
|
|
2593
|
+
ddl: {
|
|
2594
|
+
kind: "dropTable",
|
|
2595
|
+
ifExists: options2.ifExists ?? false
|
|
2596
|
+
},
|
|
2597
|
+
where: [],
|
|
2598
|
+
having: [],
|
|
2599
|
+
joins: [],
|
|
2600
|
+
groupBy: [],
|
|
2601
|
+
orderBy: []
|
|
2602
|
+
}, undefined, "ddl", "dropTable");
|
|
2603
|
+
};
|
|
2604
|
+
const createIndex = (target, columns, options2 = {}) => {
|
|
2605
|
+
assertTableTarget(target, "createIndex");
|
|
2606
|
+
const normalizedColumns = ctx.normalizeColumnList(columns);
|
|
2607
|
+
validateIndexColumns(target, normalizedColumns);
|
|
2608
|
+
const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
|
|
2609
|
+
return ctx.makePlan({
|
|
2610
|
+
selection: {},
|
|
2611
|
+
required: [],
|
|
2612
|
+
available: {},
|
|
2613
|
+
dialect: target[TypeId].dialect
|
|
2614
|
+
}, {
|
|
2615
|
+
kind: "createIndex",
|
|
2616
|
+
select: {},
|
|
2617
|
+
target: {
|
|
2618
|
+
kind: "from",
|
|
2619
|
+
tableName: sourceName,
|
|
2620
|
+
baseTableName: sourceBaseName,
|
|
2621
|
+
source: target
|
|
2622
|
+
},
|
|
2623
|
+
ddl: {
|
|
2624
|
+
kind: "createIndex",
|
|
2625
|
+
name: options2.name ?? ctx.defaultIndexName(sourceBaseName, normalizedColumns, options2.unique ?? false),
|
|
2626
|
+
columns: normalizedColumns,
|
|
2627
|
+
unique: options2.unique ?? false,
|
|
2628
|
+
ifNotExists: options2.ifNotExists ?? false
|
|
2629
|
+
},
|
|
2630
|
+
where: [],
|
|
2631
|
+
having: [],
|
|
2632
|
+
joins: [],
|
|
2633
|
+
groupBy: [],
|
|
2634
|
+
orderBy: []
|
|
2635
|
+
}, undefined, "ddl", "createIndex");
|
|
2636
|
+
};
|
|
2637
|
+
const dropIndex = (target, columns, options2 = {}) => {
|
|
2638
|
+
assertTableTarget(target, "dropIndex");
|
|
2639
|
+
const normalizedColumns = ctx.normalizeColumnList(columns);
|
|
2640
|
+
validateIndexColumns(target, normalizedColumns);
|
|
2641
|
+
const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
|
|
2642
|
+
return ctx.makePlan({
|
|
2643
|
+
selection: {},
|
|
2644
|
+
required: [],
|
|
2645
|
+
available: {},
|
|
2646
|
+
dialect: target[TypeId].dialect
|
|
2647
|
+
}, {
|
|
2648
|
+
kind: "dropIndex",
|
|
2649
|
+
select: {},
|
|
2650
|
+
target: {
|
|
2651
|
+
kind: "from",
|
|
2652
|
+
tableName: sourceName,
|
|
2653
|
+
baseTableName: sourceBaseName,
|
|
2654
|
+
source: target
|
|
2655
|
+
},
|
|
2656
|
+
ddl: {
|
|
2657
|
+
kind: "dropIndex",
|
|
2658
|
+
name: options2.name ?? ctx.defaultIndexName(sourceBaseName, normalizedColumns, false),
|
|
2659
|
+
ifExists: options2.ifExists ?? false
|
|
2660
|
+
},
|
|
2661
|
+
where: [],
|
|
2662
|
+
having: [],
|
|
2663
|
+
joins: [],
|
|
2664
|
+
groupBy: [],
|
|
2665
|
+
orderBy: []
|
|
2666
|
+
}, undefined, "ddl", "dropIndex");
|
|
2667
|
+
};
|
|
2668
|
+
return {
|
|
2669
|
+
transaction,
|
|
2670
|
+
commit,
|
|
2671
|
+
rollback,
|
|
2672
|
+
savepoint,
|
|
2673
|
+
rollbackTo,
|
|
2674
|
+
releaseSavepoint,
|
|
2675
|
+
createTable,
|
|
2676
|
+
dropTable,
|
|
2677
|
+
createIndex,
|
|
2678
|
+
dropIndex
|
|
2679
|
+
};
|
|
2680
|
+
};
|
|
2681
|
+
|
|
1466
2682
|
// src/internal/runtime/driver-value-mapping.ts
|
|
2683
|
+
import * as Schema4 from "effect/Schema";
|
|
2684
|
+
|
|
2685
|
+
// src/internal/runtime/value.ts
|
|
1467
2686
|
import * as Schema3 from "effect/Schema";
|
|
2687
|
+
var brandString = (pattern2, brand4) => Schema3.String.pipe(Schema3.pattern(pattern2), Schema3.brand(brand4));
|
|
2688
|
+
var localDatePattern = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
2689
|
+
var isValidLocalDateString = (value) => {
|
|
2690
|
+
const match = localDatePattern.exec(value);
|
|
2691
|
+
if (match === null) {
|
|
2692
|
+
return false;
|
|
2693
|
+
}
|
|
2694
|
+
const year = Number(match[1]);
|
|
2695
|
+
const month = Number(match[2]);
|
|
2696
|
+
const day = Number(match[3]);
|
|
2697
|
+
const parsed = new Date(Date.UTC(year, month - 1, day));
|
|
2698
|
+
parsed.setUTCFullYear(year);
|
|
2699
|
+
return parsed.getUTCFullYear() === year && parsed.getUTCMonth() === month - 1 && parsed.getUTCDate() === day;
|
|
2700
|
+
};
|
|
2701
|
+
var localTimePattern = /^(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?$/;
|
|
2702
|
+
var isValidLocalTimeString = (value) => {
|
|
2703
|
+
const match = localTimePattern.exec(value);
|
|
2704
|
+
if (match === null) {
|
|
2705
|
+
return false;
|
|
2706
|
+
}
|
|
2707
|
+
const hour = Number(match[1]);
|
|
2708
|
+
const minute = Number(match[2]);
|
|
2709
|
+
const second = Number(match[3]);
|
|
2710
|
+
return hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59 && second >= 0 && second <= 59;
|
|
2711
|
+
};
|
|
2712
|
+
var offsetPattern = /^(?:Z|[+-](\d{2}):(\d{2}))$/;
|
|
2713
|
+
var isValidOffset = (value) => {
|
|
2714
|
+
const match = offsetPattern.exec(value);
|
|
2715
|
+
if (match === null) {
|
|
2716
|
+
return false;
|
|
2717
|
+
}
|
|
2718
|
+
if (value === "Z") {
|
|
2719
|
+
return true;
|
|
2720
|
+
}
|
|
2721
|
+
const hour = Number(match[1]);
|
|
2722
|
+
const minute = Number(match[2]);
|
|
2723
|
+
return hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59;
|
|
2724
|
+
};
|
|
2725
|
+
var offsetTimePattern = /^(\d{2}:\d{2}:\d{2}(?:\.\d+)?)(Z|[+-]\d{2}:\d{2})$/;
|
|
2726
|
+
var isValidOffsetTimeString = (value) => {
|
|
2727
|
+
const match = offsetTimePattern.exec(value);
|
|
2728
|
+
return match !== null && isValidLocalTimeString(match[1]) && isValidOffset(match[2]);
|
|
2729
|
+
};
|
|
2730
|
+
var localDateTimePattern = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}(?:\.\d+)?)$/;
|
|
2731
|
+
var isValidLocalDateTimeString = (value) => {
|
|
2732
|
+
const match = localDateTimePattern.exec(value);
|
|
2733
|
+
return match !== null && isValidLocalDateString(match[1]) && isValidLocalTimeString(match[2]);
|
|
2734
|
+
};
|
|
2735
|
+
var instantPattern = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}(?:\.\d+)?)(Z|[+-]\d{2}:\d{2})$/;
|
|
2736
|
+
var isValidInstantString = (value) => {
|
|
2737
|
+
const match = instantPattern.exec(value);
|
|
2738
|
+
return match !== null && isValidLocalDateString(match[1]) && isValidLocalTimeString(match[2]) && isValidOffset(match[3]);
|
|
2739
|
+
};
|
|
2740
|
+
var LocalDateStringSchema = Schema3.String.pipe(Schema3.pattern(localDatePattern), Schema3.filter(isValidLocalDateString), Schema3.brand("LocalDateString"));
|
|
2741
|
+
var LocalTimeStringSchema = Schema3.String.pipe(Schema3.pattern(localTimePattern), Schema3.filter(isValidLocalTimeString), Schema3.brand("LocalTimeString"));
|
|
2742
|
+
var OffsetTimeStringSchema = Schema3.String.pipe(Schema3.pattern(offsetTimePattern), Schema3.filter(isValidOffsetTimeString), Schema3.brand("OffsetTimeString"));
|
|
2743
|
+
var LocalDateTimeStringSchema = Schema3.String.pipe(Schema3.pattern(localDateTimePattern), Schema3.filter(isValidLocalDateTimeString), Schema3.brand("LocalDateTimeString"));
|
|
2744
|
+
var InstantStringSchema = Schema3.String.pipe(Schema3.pattern(instantPattern), Schema3.filter(isValidInstantString), Schema3.brand("InstantString"));
|
|
2745
|
+
var YearStringSchema = brandString(/^\d{4}$/, "YearString");
|
|
2746
|
+
var canonicalizeBigIntString = (input) => {
|
|
2747
|
+
const trimmed = input.trim();
|
|
2748
|
+
if (!/^-?\d+$/.test(trimmed)) {
|
|
2749
|
+
throw new Error("Expected an integer-like bigint value");
|
|
2750
|
+
}
|
|
2751
|
+
return BigInt(trimmed).toString();
|
|
2752
|
+
};
|
|
2753
|
+
var isCanonicalBigIntString = (value) => {
|
|
2754
|
+
try {
|
|
2755
|
+
return canonicalizeBigIntString(value) === value;
|
|
2756
|
+
} catch {
|
|
2757
|
+
return false;
|
|
2758
|
+
}
|
|
2759
|
+
};
|
|
2760
|
+
var canonicalizeDecimalString = (input) => {
|
|
2761
|
+
const trimmed = input.trim();
|
|
2762
|
+
const match = /^([+-]?)(\d+)(?:\.(\d+))?$/.exec(trimmed);
|
|
2763
|
+
if (match === null) {
|
|
2764
|
+
throw new Error("Expected a decimal string");
|
|
2765
|
+
}
|
|
2766
|
+
const sign = match[1] === "-" ? "-" : "";
|
|
2767
|
+
const integer = match[2].replace(/^0+(?=\d)/, "") || "0";
|
|
2768
|
+
const fraction = (match[3] ?? "").replace(/0+$/, "");
|
|
2769
|
+
if (fraction.length === 0) {
|
|
2770
|
+
if (integer === "0") {
|
|
2771
|
+
return "0";
|
|
2772
|
+
}
|
|
2773
|
+
return `${sign}${integer}`;
|
|
2774
|
+
}
|
|
2775
|
+
return `${sign}${integer}.${fraction}`;
|
|
2776
|
+
};
|
|
2777
|
+
var isCanonicalDecimalString = (value) => {
|
|
2778
|
+
try {
|
|
2779
|
+
return canonicalizeDecimalString(value) === value;
|
|
2780
|
+
} catch {
|
|
2781
|
+
return false;
|
|
2782
|
+
}
|
|
2783
|
+
};
|
|
2784
|
+
var BigIntStringSchema = Schema3.String.pipe(Schema3.filter(isCanonicalBigIntString), Schema3.brand("BigIntString"));
|
|
2785
|
+
var DecimalStringSchema = Schema3.String.pipe(Schema3.filter(isCanonicalDecimalString), Schema3.brand("DecimalString"));
|
|
2786
|
+
var JsonValueSchema = Schema3.suspend(() => Schema3.Union(Schema3.String, Schema3.Number.pipe(Schema3.finite()), Schema3.Boolean, Schema3.Null, Schema3.Array(JsonValueSchema), Schema3.Record({
|
|
2787
|
+
key: Schema3.String,
|
|
2788
|
+
value: JsonValueSchema
|
|
2789
|
+
})));
|
|
2790
|
+
var JsonPrimitiveSchema = Schema3.Union(Schema3.String, Schema3.Number.pipe(Schema3.finite()), Schema3.Boolean, Schema3.Null);
|
|
1468
2791
|
|
|
1469
2792
|
// src/internal/runtime/normalize.ts
|
|
1470
2793
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2794
|
+
var isPlainRecord = (value) => {
|
|
2795
|
+
if (!isRecord(value)) {
|
|
2796
|
+
return false;
|
|
2797
|
+
}
|
|
2798
|
+
const prototype = Object.getPrototypeOf(value);
|
|
2799
|
+
return prototype === Object.prototype || prototype === null;
|
|
2800
|
+
};
|
|
1471
2801
|
var pad = (value, width = 2) => value.toString().padStart(width, "0");
|
|
1472
|
-
var formatLocalDate = (value) => `${value.getUTCFullYear()}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())}`;
|
|
2802
|
+
var formatLocalDate = (value) => `${pad(value.getUTCFullYear(), 4)}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())}`;
|
|
1473
2803
|
var formatLocalTime = (value) => {
|
|
1474
2804
|
const milliseconds = value.getUTCMilliseconds();
|
|
1475
2805
|
const base = `${pad(value.getUTCHours())}:${pad(value.getUTCMinutes())}:${pad(value.getUTCSeconds())}`;
|
|
@@ -1489,12 +2819,14 @@ var expectString = (value, label) => {
|
|
|
1489
2819
|
}
|
|
1490
2820
|
throw new Error(`Expected ${label} as string`);
|
|
1491
2821
|
};
|
|
2822
|
+
var finiteNumberStringPattern = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:[eE][+-]?\d+)?$/;
|
|
1492
2823
|
var normalizeNumber = (value) => {
|
|
1493
2824
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1494
2825
|
return value;
|
|
1495
2826
|
}
|
|
1496
|
-
if (typeof value === "string"
|
|
1497
|
-
const
|
|
2827
|
+
if (typeof value === "string") {
|
|
2828
|
+
const trimmed = value.trim();
|
|
2829
|
+
const parsed = finiteNumberStringPattern.test(trimmed) ? Number(trimmed) : Number.NaN;
|
|
1498
2830
|
if (Number.isFinite(parsed)) {
|
|
1499
2831
|
return parsed;
|
|
1500
2832
|
}
|
|
@@ -1534,25 +2866,11 @@ var normalizeBigIntString = (value) => {
|
|
|
1534
2866
|
if (typeof value === "number" && Number.isSafeInteger(value)) {
|
|
1535
2867
|
return BigInt(value).toString();
|
|
1536
2868
|
}
|
|
1537
|
-
if (typeof value === "string"
|
|
1538
|
-
return
|
|
2869
|
+
if (typeof value === "string") {
|
|
2870
|
+
return canonicalizeBigIntString(value);
|
|
1539
2871
|
}
|
|
1540
2872
|
throw new Error("Expected an integer-like bigint value");
|
|
1541
2873
|
};
|
|
1542
|
-
var canonicalizeDecimalString = (input) => {
|
|
1543
|
-
const trimmed = input.trim();
|
|
1544
|
-
const match = /^([+-]?)(\d+)(?:\.(\d+))?$/.exec(trimmed);
|
|
1545
|
-
if (match === null) {
|
|
1546
|
-
throw new Error("Expected a decimal string");
|
|
1547
|
-
}
|
|
1548
|
-
const sign = match[1] === "-" ? "-" : "";
|
|
1549
|
-
const integer = match[2].replace(/^0+(?=\d)/, "") || "0";
|
|
1550
|
-
const fraction = (match[3] ?? "").replace(/0+$/, "");
|
|
1551
|
-
if (fraction.length === 0) {
|
|
1552
|
-
return `${sign}${integer}`;
|
|
1553
|
-
}
|
|
1554
|
-
return `${sign}${integer}.${fraction}`;
|
|
1555
|
-
};
|
|
1556
2874
|
var normalizeDecimalString = (value) => {
|
|
1557
2875
|
if (typeof value === "string") {
|
|
1558
2876
|
return canonicalizeDecimalString(value);
|
|
@@ -1571,12 +2889,15 @@ var normalizeLocalDate = (value) => {
|
|
|
1571
2889
|
return formatLocalDate(value);
|
|
1572
2890
|
}
|
|
1573
2891
|
const raw = expectString(value, "local date").trim();
|
|
1574
|
-
if (
|
|
2892
|
+
if (isValidLocalDateString(raw)) {
|
|
1575
2893
|
return raw;
|
|
1576
2894
|
}
|
|
1577
|
-
const
|
|
1578
|
-
if (
|
|
1579
|
-
|
|
2895
|
+
const canonicalInstant = raw.replace(" ", "T").replace(/z$/, "Z");
|
|
2896
|
+
if (isValidInstantString(canonicalInstant)) {
|
|
2897
|
+
const parsed = new Date(canonicalInstant);
|
|
2898
|
+
if (!Number.isNaN(parsed.getTime())) {
|
|
2899
|
+
return formatLocalDate(parsed);
|
|
2900
|
+
}
|
|
1580
2901
|
}
|
|
1581
2902
|
throw new Error("Expected a local-date value");
|
|
1582
2903
|
};
|
|
@@ -1585,7 +2906,7 @@ var normalizeLocalTime = (value) => {
|
|
|
1585
2906
|
return formatLocalTime(value);
|
|
1586
2907
|
}
|
|
1587
2908
|
const raw = expectString(value, "local time").trim();
|
|
1588
|
-
if (
|
|
2909
|
+
if (isValidLocalTimeString(raw)) {
|
|
1589
2910
|
return raw;
|
|
1590
2911
|
}
|
|
1591
2912
|
throw new Error("Expected a local-time value");
|
|
@@ -1595,7 +2916,7 @@ var normalizeOffsetTime = (value) => {
|
|
|
1595
2916
|
return `${formatLocalTime(value)}Z`;
|
|
1596
2917
|
}
|
|
1597
2918
|
const raw = expectString(value, "offset time").trim();
|
|
1598
|
-
if (
|
|
2919
|
+
if (isValidOffsetTimeString(raw)) {
|
|
1599
2920
|
return raw;
|
|
1600
2921
|
}
|
|
1601
2922
|
throw new Error("Expected an offset-time value");
|
|
@@ -1605,11 +2926,13 @@ var normalizeLocalDateTime = (value) => {
|
|
|
1605
2926
|
return formatLocalDateTime(value);
|
|
1606
2927
|
}
|
|
1607
2928
|
const raw = expectString(value, "local datetime").trim();
|
|
1608
|
-
|
|
1609
|
-
|
|
2929
|
+
const canonicalLocalDateTime = raw.replace(" ", "T");
|
|
2930
|
+
if (isValidLocalDateTimeString(canonicalLocalDateTime)) {
|
|
2931
|
+
return canonicalLocalDateTime;
|
|
1610
2932
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
2933
|
+
const canonicalInstant = raw.replace(" ", "T").replace(/z$/, "Z");
|
|
2934
|
+
if (isValidInstantString(canonicalInstant)) {
|
|
2935
|
+
const parsed = new Date(canonicalInstant);
|
|
1613
2936
|
if (!Number.isNaN(parsed.getTime())) {
|
|
1614
2937
|
return formatLocalDateTime(parsed);
|
|
1615
2938
|
}
|
|
@@ -1624,7 +2947,11 @@ var normalizeInstant = (value) => {
|
|
|
1624
2947
|
if (!/[zZ]|[+-]\d{2}:\d{2}$/.test(raw)) {
|
|
1625
2948
|
throw new Error("Instant values require a timezone offset");
|
|
1626
2949
|
}
|
|
1627
|
-
const
|
|
2950
|
+
const canonicalInstant = raw.replace(" ", "T").replace(/z$/, "Z");
|
|
2951
|
+
if (!isValidInstantString(canonicalInstant)) {
|
|
2952
|
+
throw new Error("Expected an ISO instant value");
|
|
2953
|
+
}
|
|
2954
|
+
const parsed = new Date(canonicalInstant);
|
|
1628
2955
|
if (Number.isNaN(parsed.getTime())) {
|
|
1629
2956
|
throw new Error("Expected an ISO instant value");
|
|
1630
2957
|
}
|
|
@@ -1656,25 +2983,33 @@ var isJsonValue = (value) => {
|
|
|
1656
2983
|
}
|
|
1657
2984
|
switch (typeof value) {
|
|
1658
2985
|
case "string":
|
|
1659
|
-
case "number":
|
|
1660
2986
|
case "boolean":
|
|
1661
2987
|
return true;
|
|
2988
|
+
case "number":
|
|
2989
|
+
return Number.isFinite(value);
|
|
1662
2990
|
case "object":
|
|
1663
2991
|
if (Array.isArray(value)) {
|
|
1664
2992
|
return value.every(isJsonValue);
|
|
1665
2993
|
}
|
|
1666
|
-
return
|
|
2994
|
+
return isPlainRecord(value) && Object.values(value).every(isJsonValue);
|
|
1667
2995
|
default:
|
|
1668
2996
|
return false;
|
|
1669
2997
|
}
|
|
1670
2998
|
};
|
|
1671
2999
|
var normalizeJson = (value) => {
|
|
1672
3000
|
if (typeof value === "string") {
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
3001
|
+
try {
|
|
3002
|
+
const parsed = JSON.parse(value);
|
|
3003
|
+
if (isJsonValue(parsed)) {
|
|
3004
|
+
return parsed;
|
|
3005
|
+
}
|
|
3006
|
+
throw new Error("Parsed JSON value is not a valid JSON runtime");
|
|
3007
|
+
} catch (error) {
|
|
3008
|
+
if (error instanceof SyntaxError) {
|
|
3009
|
+
return value;
|
|
3010
|
+
}
|
|
3011
|
+
throw error;
|
|
1676
3012
|
}
|
|
1677
|
-
throw new Error("Parsed JSON value is not a valid JSON runtime");
|
|
1678
3013
|
}
|
|
1679
3014
|
if (isJsonValue(value)) {
|
|
1680
3015
|
return value;
|
|
@@ -1809,22 +3144,61 @@ var findMapping = (context, key2) => {
|
|
|
1809
3144
|
}
|
|
1810
3145
|
return;
|
|
1811
3146
|
};
|
|
3147
|
+
var isJsonDbType = (dbType) => {
|
|
3148
|
+
if (dbType === undefined) {
|
|
3149
|
+
return false;
|
|
3150
|
+
}
|
|
3151
|
+
if ("base" in dbType) {
|
|
3152
|
+
return isJsonDbType(dbType.base);
|
|
3153
|
+
}
|
|
3154
|
+
if (!("variant" in dbType)) {
|
|
3155
|
+
return false;
|
|
3156
|
+
}
|
|
3157
|
+
const variant = dbType.variant;
|
|
3158
|
+
return variant === "json" || variant === "jsonb";
|
|
3159
|
+
};
|
|
3160
|
+
var schemaAccepts = (schema2, value) => schema2 !== undefined && Schema4.is(schema2)(value);
|
|
1812
3161
|
var encodeWithSchema = (schema2, value) => {
|
|
1813
3162
|
if (schema2 === undefined) {
|
|
1814
3163
|
return { value, encoded: false };
|
|
1815
3164
|
}
|
|
1816
|
-
if (!
|
|
3165
|
+
if (!Schema4.is(schema2)(value)) {
|
|
1817
3166
|
return { value, encoded: false };
|
|
1818
3167
|
}
|
|
1819
3168
|
return {
|
|
1820
|
-
value:
|
|
3169
|
+
value: Schema4.encodeUnknownSync(schema2)(value),
|
|
1821
3170
|
encoded: true
|
|
1822
3171
|
};
|
|
1823
3172
|
};
|
|
3173
|
+
var normalizeJsonDriverString = (value, context) => {
|
|
3174
|
+
if (!isJsonDbType(context.dbType) || context.runtimeSchema === undefined) {
|
|
3175
|
+
return;
|
|
3176
|
+
}
|
|
3177
|
+
try {
|
|
3178
|
+
const parsed = JSON.parse(value);
|
|
3179
|
+
if (value.trimStart().startsWith('"') && schemaAccepts(context.runtimeSchema, parsed)) {
|
|
3180
|
+
return parsed;
|
|
3181
|
+
}
|
|
3182
|
+
if (schemaAccepts(context.runtimeSchema, value) && !schemaAccepts(context.runtimeSchema, parsed)) {
|
|
3183
|
+
return value;
|
|
3184
|
+
}
|
|
3185
|
+
} catch (error) {
|
|
3186
|
+
if (error instanceof SyntaxError && schemaAccepts(context.runtimeSchema, value)) {
|
|
3187
|
+
return value;
|
|
3188
|
+
}
|
|
3189
|
+
if (!(error instanceof SyntaxError)) {
|
|
3190
|
+
throw error;
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
return;
|
|
3194
|
+
};
|
|
1824
3195
|
var toDriverValue = (value, context) => {
|
|
1825
3196
|
if (value === null) {
|
|
1826
3197
|
return null;
|
|
1827
3198
|
}
|
|
3199
|
+
if (value instanceof Date && Number.isNaN(value.getTime())) {
|
|
3200
|
+
throw new Error("Expected a valid Date value");
|
|
3201
|
+
}
|
|
1828
3202
|
const dbType = context.dbType;
|
|
1829
3203
|
const encoded = encodeWithSchema(context.runtimeSchema, value);
|
|
1830
3204
|
let current = encoded.value;
|
|
@@ -1832,6 +3206,9 @@ var toDriverValue = (value, context) => {
|
|
|
1832
3206
|
if (custom !== undefined && dbType !== undefined) {
|
|
1833
3207
|
return custom(current, dbType);
|
|
1834
3208
|
}
|
|
3209
|
+
if (encoded.encoded && typeof current === "string" && isJsonDbType(dbType)) {
|
|
3210
|
+
return current;
|
|
3211
|
+
}
|
|
1835
3212
|
return dbType === undefined || !encoded.encoded ? current : normalizeDbValue(dbType, current);
|
|
1836
3213
|
};
|
|
1837
3214
|
var fromDriverValue = (value, context) => {
|
|
@@ -1843,6 +3220,12 @@ var fromDriverValue = (value, context) => {
|
|
|
1843
3220
|
if (custom !== undefined && dbType !== undefined) {
|
|
1844
3221
|
return custom(value, dbType);
|
|
1845
3222
|
}
|
|
3223
|
+
if (typeof value === "string") {
|
|
3224
|
+
const normalizedJsonString = normalizeJsonDriverString(value, context);
|
|
3225
|
+
if (normalizedJsonString !== undefined) {
|
|
3226
|
+
return normalizedJsonString;
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
1846
3229
|
return dbType === undefined ? value : normalizeDbValue(dbType, value);
|
|
1847
3230
|
};
|
|
1848
3231
|
var textCast = (sql) => `(${sql})::text`;
|
|
@@ -1930,6 +3313,20 @@ var validateProjections = (projections) => {
|
|
|
1930
3313
|
};
|
|
1931
3314
|
|
|
1932
3315
|
// src/internal/grouping-key.ts
|
|
3316
|
+
var subqueryPlanIds = new WeakMap;
|
|
3317
|
+
var nextSubqueryPlanId = 0;
|
|
3318
|
+
var subqueryPlanGroupingKey = (plan) => {
|
|
3319
|
+
if (plan === null || typeof plan !== "object") {
|
|
3320
|
+
return "unknown";
|
|
3321
|
+
}
|
|
3322
|
+
const existing = subqueryPlanIds.get(plan);
|
|
3323
|
+
if (existing !== undefined) {
|
|
3324
|
+
return existing;
|
|
3325
|
+
}
|
|
3326
|
+
const next = `${nextSubqueryPlanId++}`;
|
|
3327
|
+
subqueryPlanIds.set(plan, next);
|
|
3328
|
+
return next;
|
|
3329
|
+
};
|
|
1933
3330
|
var literalGroupingKey = (value) => {
|
|
1934
3331
|
if (value instanceof Date) {
|
|
1935
3332
|
return `date:${value.toISOString()}`;
|
|
@@ -1948,15 +3345,62 @@ var literalGroupingKey = (value) => {
|
|
|
1948
3345
|
return `literal:${JSON.stringify(value)}`;
|
|
1949
3346
|
}
|
|
1950
3347
|
};
|
|
3348
|
+
var isExpression2 = (value) => value !== null && typeof value === "object" && (TypeId2 in value);
|
|
3349
|
+
var expressionGroupingKey = (value) => isExpression2(value) ? groupingKeyOfExpression(value) : "missing";
|
|
3350
|
+
var escapeGroupingText = (value) => value.replace(/\\/g, "\\\\").replace(/,/g, "\\,").replace(/\|/g, "\\|").replace(/=/g, "\\=").replace(/>/g, "\\>");
|
|
3351
|
+
var jsonSegmentGroupingKey = (segment) => {
|
|
3352
|
+
if (segment !== null && typeof segment === "object" && "kind" in segment) {
|
|
3353
|
+
switch (segment.kind) {
|
|
3354
|
+
case "key":
|
|
3355
|
+
return `key:${escapeGroupingText(segment.key)}`;
|
|
3356
|
+
case "index":
|
|
3357
|
+
return `index:${segment.index}`;
|
|
3358
|
+
case "wildcard":
|
|
3359
|
+
return "wildcard";
|
|
3360
|
+
case "slice": {
|
|
3361
|
+
const slice2 = segment;
|
|
3362
|
+
return `slice:${slice2.start ?? ""}:${slice2.end ?? ""}`;
|
|
3363
|
+
}
|
|
3364
|
+
case "descend":
|
|
3365
|
+
return "descend";
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
if (typeof segment === "string") {
|
|
3369
|
+
return `key:${escapeGroupingText(segment)}`;
|
|
3370
|
+
}
|
|
3371
|
+
if (typeof segment === "number") {
|
|
3372
|
+
return `index:${segment}`;
|
|
3373
|
+
}
|
|
3374
|
+
return "unknown";
|
|
3375
|
+
};
|
|
3376
|
+
var jsonPathGroupingKey = (segments) => (segments ?? []).map(jsonSegmentGroupingKey).join(",");
|
|
3377
|
+
var isJsonPath = (value) => value !== null && typeof value === "object" && (TypeId7 in value);
|
|
3378
|
+
var jsonOpaquePathGroupingKey = (value) => {
|
|
3379
|
+
if (isJsonPath(value)) {
|
|
3380
|
+
return `jsonpath:${jsonPathGroupingKey(value.segments)}`;
|
|
3381
|
+
}
|
|
3382
|
+
if (typeof value === "string") {
|
|
3383
|
+
return `jsonpath:${escapeGroupingText(value)}`;
|
|
3384
|
+
}
|
|
3385
|
+
if (isExpression2(value)) {
|
|
3386
|
+
return `jsonpath:${groupingKeyOfExpression(value)}`;
|
|
3387
|
+
}
|
|
3388
|
+
return "jsonpath:unknown";
|
|
3389
|
+
};
|
|
3390
|
+
var jsonEntryGroupingKey = (entry) => `${escapeGroupingText(entry.key)}=>${groupingKeyOfExpression(entry.value)}`;
|
|
1951
3391
|
var groupingKeyOfExpression = (expression) => {
|
|
1952
3392
|
const ast = expression[TypeId3];
|
|
1953
3393
|
switch (ast.kind) {
|
|
1954
3394
|
case "column":
|
|
1955
|
-
return `column:${ast.tableName
|
|
3395
|
+
return `column:${columnPredicateKey(ast.tableName, ast.columnName)}`;
|
|
1956
3396
|
case "literal":
|
|
1957
3397
|
return `literal:${literalGroupingKey(ast.value)}`;
|
|
1958
3398
|
case "cast":
|
|
1959
3399
|
return `cast(${groupingKeyOfExpression(ast.value)} as ${ast.target.dialect}:${ast.target.kind})`;
|
|
3400
|
+
case "collate":
|
|
3401
|
+
return `collate(${groupingKeyOfExpression(ast.value)},${ast.collation.map(escapeGroupingText).join(",")})`;
|
|
3402
|
+
case "function":
|
|
3403
|
+
return `function(${escapeGroupingText(ast.name)},${ast.args.map(groupingKeyOfExpression).join(",")})`;
|
|
1960
3404
|
case "isNull":
|
|
1961
3405
|
case "isNotNull":
|
|
1962
3406
|
case "not":
|
|
@@ -1974,8 +3418,15 @@ var groupingKeyOfExpression = (expression) => {
|
|
|
1974
3418
|
case "gte":
|
|
1975
3419
|
case "like":
|
|
1976
3420
|
case "ilike":
|
|
3421
|
+
case "regexMatch":
|
|
3422
|
+
case "regexIMatch":
|
|
3423
|
+
case "regexNotMatch":
|
|
3424
|
+
case "regexNotIMatch":
|
|
1977
3425
|
case "isDistinctFrom":
|
|
1978
3426
|
case "isNotDistinctFrom":
|
|
3427
|
+
case "contains":
|
|
3428
|
+
case "containedBy":
|
|
3429
|
+
case "overlaps":
|
|
1979
3430
|
return `${ast.kind}(${groupingKeyOfExpression(ast.left)},${groupingKeyOfExpression(ast.right)})`;
|
|
1980
3431
|
case "and":
|
|
1981
3432
|
case "or":
|
|
@@ -1987,6 +3438,54 @@ var groupingKeyOfExpression = (expression) => {
|
|
|
1987
3438
|
return `${ast.kind}(${ast.values.map(groupingKeyOfExpression).join(",")})`;
|
|
1988
3439
|
case "case":
|
|
1989
3440
|
return `case(${ast.branches.map((branch) => `when:${groupingKeyOfExpression(branch.when)}=>${groupingKeyOfExpression(branch.then)}`).join("|")};else:${groupingKeyOfExpression(ast.else)})`;
|
|
3441
|
+
case "exists":
|
|
3442
|
+
return `exists(${subqueryPlanGroupingKey(ast.plan)})`;
|
|
3443
|
+
case "scalarSubquery":
|
|
3444
|
+
return `scalarSubquery(${subqueryPlanGroupingKey(ast.plan)})`;
|
|
3445
|
+
case "inSubquery":
|
|
3446
|
+
return `inSubquery(${groupingKeyOfExpression(ast.left)},${subqueryPlanGroupingKey(ast.plan)})`;
|
|
3447
|
+
case "comparisonAny":
|
|
3448
|
+
case "comparisonAll":
|
|
3449
|
+
return `${ast.kind}(${ast.operator},${groupingKeyOfExpression(ast.left)},${subqueryPlanGroupingKey(ast.plan)})`;
|
|
3450
|
+
case "jsonGet":
|
|
3451
|
+
case "jsonPath":
|
|
3452
|
+
case "jsonAccess":
|
|
3453
|
+
case "jsonTraverse":
|
|
3454
|
+
case "jsonGetText":
|
|
3455
|
+
case "jsonPathText":
|
|
3456
|
+
case "jsonAccessText":
|
|
3457
|
+
case "jsonTraverseText":
|
|
3458
|
+
return `json(${ast.kind},${expressionGroupingKey(ast.base)},${jsonPathGroupingKey(ast.segments)})`;
|
|
3459
|
+
case "jsonHasKey":
|
|
3460
|
+
case "jsonKeyExists":
|
|
3461
|
+
case "jsonHasAnyKeys":
|
|
3462
|
+
case "jsonHasAllKeys":
|
|
3463
|
+
return `json(${ast.kind},${expressionGroupingKey(ast.base)},${(ast.keys ?? []).map(escapeGroupingText).join(",")})`;
|
|
3464
|
+
case "jsonConcat":
|
|
3465
|
+
case "jsonMerge":
|
|
3466
|
+
return `json(${ast.kind},${expressionGroupingKey(ast.left)},${expressionGroupingKey(ast.right)},)`;
|
|
3467
|
+
case "jsonDelete":
|
|
3468
|
+
case "jsonDeletePath":
|
|
3469
|
+
case "jsonRemove":
|
|
3470
|
+
return `json(${ast.kind},${expressionGroupingKey(ast.base)},${expressionGroupingKey(undefined)},${jsonPathGroupingKey(ast.segments)})`;
|
|
3471
|
+
case "jsonSet":
|
|
3472
|
+
return `json(${ast.kind},${expressionGroupingKey(ast.base)},${expressionGroupingKey(ast.newValue)},${jsonPathGroupingKey(ast.segments)})`;
|
|
3473
|
+
case "jsonInsert":
|
|
3474
|
+
return `json(${ast.kind},${expressionGroupingKey(ast.base)},${expressionGroupingKey(ast.insert)},${jsonPathGroupingKey(ast.segments)})`;
|
|
3475
|
+
case "jsonPathExists":
|
|
3476
|
+
case "jsonPathMatch":
|
|
3477
|
+
return `json(${ast.kind},${expressionGroupingKey(ast.base)},${jsonOpaquePathGroupingKey(ast.query)})`;
|
|
3478
|
+
case "jsonBuildObject":
|
|
3479
|
+
return `json(${ast.kind},${(ast.entries ?? []).map(jsonEntryGroupingKey).join("|")})`;
|
|
3480
|
+
case "jsonBuildArray":
|
|
3481
|
+
return `json(${ast.kind},${(ast.values ?? []).map(groupingKeyOfExpression).join(",")})`;
|
|
3482
|
+
case "jsonToJson":
|
|
3483
|
+
case "jsonToJsonb":
|
|
3484
|
+
case "jsonTypeOf":
|
|
3485
|
+
case "jsonLength":
|
|
3486
|
+
case "jsonKeys":
|
|
3487
|
+
case "jsonStripNulls":
|
|
3488
|
+
return `json(${ast.kind},${expressionGroupingKey(ast.value)})`;
|
|
1990
3489
|
default:
|
|
1991
3490
|
throw new Error("Unsupported expression for grouping key generation");
|
|
1992
3491
|
}
|
|
@@ -2004,15 +3503,15 @@ var dedupeGroupedExpressions = (values) => {
|
|
|
2004
3503
|
};
|
|
2005
3504
|
|
|
2006
3505
|
// src/internal/aggregation-validation.ts
|
|
2007
|
-
var
|
|
3506
|
+
var isExpression3 = (value) => typeof value === "object" && value !== null && (TypeId2 in value);
|
|
2008
3507
|
var selectionHasAggregate = (selection) => {
|
|
2009
|
-
if (
|
|
3508
|
+
if (isExpression3(selection)) {
|
|
2010
3509
|
return selection[TypeId2].kind === "aggregate";
|
|
2011
3510
|
}
|
|
2012
3511
|
return Object.values(selection).some((value) => selectionHasAggregate(value));
|
|
2013
3512
|
};
|
|
2014
3513
|
var isGroupedSelectionValid = (selection, groupedExpressions) => {
|
|
2015
|
-
if (
|
|
3514
|
+
if (isExpression3(selection)) {
|
|
2016
3515
|
const aggregation = selection[TypeId2].kind;
|
|
2017
3516
|
if (aggregation === "aggregate") {
|
|
2018
3517
|
return true;
|
|
@@ -2065,7 +3564,46 @@ var renderCastType = (dialect, dbType) => {
|
|
|
2065
3564
|
return dbType.kind;
|
|
2066
3565
|
}
|
|
2067
3566
|
};
|
|
2068
|
-
var
|
|
3567
|
+
var renderPostgresDdlString = (value) => `'${value.replaceAll("'", "''")}'`;
|
|
3568
|
+
var renderPostgresDdlBytes = (value) => `decode('${Array.from(value, (byte) => byte.toString(16).padStart(2, "0")).join("")}', 'hex')`;
|
|
3569
|
+
var renderPostgresDdlLiteral = (value, state, context = {}) => {
|
|
3570
|
+
const driverValue = toDriverValue(value, {
|
|
3571
|
+
dialect: "postgres",
|
|
3572
|
+
valueMappings: state.valueMappings,
|
|
3573
|
+
...context
|
|
3574
|
+
});
|
|
3575
|
+
if (driverValue === null) {
|
|
3576
|
+
return "null";
|
|
3577
|
+
}
|
|
3578
|
+
switch (typeof driverValue) {
|
|
3579
|
+
case "boolean":
|
|
3580
|
+
return driverValue ? "true" : "false";
|
|
3581
|
+
case "number":
|
|
3582
|
+
if (!Number.isFinite(driverValue)) {
|
|
3583
|
+
throw new Error("Expected a finite numeric value");
|
|
3584
|
+
}
|
|
3585
|
+
return String(driverValue);
|
|
3586
|
+
case "bigint":
|
|
3587
|
+
return driverValue.toString();
|
|
3588
|
+
case "string":
|
|
3589
|
+
return renderPostgresDdlString(driverValue);
|
|
3590
|
+
case "object":
|
|
3591
|
+
if (driverValue instanceof Uint8Array) {
|
|
3592
|
+
return renderPostgresDdlBytes(driverValue);
|
|
3593
|
+
}
|
|
3594
|
+
break;
|
|
3595
|
+
}
|
|
3596
|
+
throw new Error("Unsupported postgres DDL literal value");
|
|
3597
|
+
};
|
|
3598
|
+
var renderDdlExpression = (expression, state, dialect) => {
|
|
3599
|
+
if (isSchemaExpression(expression)) {
|
|
3600
|
+
return render(expression);
|
|
3601
|
+
}
|
|
3602
|
+
return renderExpression(expression, state, {
|
|
3603
|
+
...dialect,
|
|
3604
|
+
renderLiteral: renderPostgresDdlLiteral
|
|
3605
|
+
});
|
|
3606
|
+
};
|
|
2069
3607
|
var renderColumnDefinition = (dialect, state, columnName, column) => {
|
|
2070
3608
|
const clauses = [
|
|
2071
3609
|
dialect.quoteIdentifier(columnName),
|
|
@@ -2097,14 +3635,16 @@ var renderCreateTableSql = (targetSource, state, dialect, ifNotExists) => {
|
|
|
2097
3635
|
break;
|
|
2098
3636
|
case "foreignKey": {
|
|
2099
3637
|
const reference = option2.references();
|
|
2100
|
-
definitions.push(`${option2.name ? `constraint ${dialect.quoteIdentifier(option2.name)} ` : ""}foreign key (${option2.columns.map((column) => dialect.quoteIdentifier(column)).join(", ")}) references ${dialect.renderTableReference(reference.tableName, reference.tableName, reference.schemaName)} (${reference.columns.map((column) => dialect.quoteIdentifier(column)).join(", ")})${option2.onDelete ? ` on delete ${option2.onDelete
|
|
3638
|
+
definitions.push(`${option2.name ? `constraint ${dialect.quoteIdentifier(option2.name)} ` : ""}foreign key (${option2.columns.map((column) => dialect.quoteIdentifier(column)).join(", ")}) references ${dialect.renderTableReference(reference.tableName, reference.tableName, reference.schemaName)} (${reference.columns.map((column) => dialect.quoteIdentifier(column)).join(", ")})${option2.onDelete !== undefined ? ` on delete ${renderReferentialAction(option2.onDelete)}` : ""}${option2.onUpdate !== undefined ? ` on update ${renderReferentialAction(option2.onUpdate)}` : ""}${option2.deferrable ? ` deferrable${option2.initiallyDeferred ? " initially deferred" : ""}` : ""}`);
|
|
2101
3639
|
break;
|
|
2102
3640
|
}
|
|
2103
3641
|
case "check":
|
|
2104
|
-
definitions.push(`constraint ${dialect.quoteIdentifier(option2.name)} check (${renderDdlExpression(option2.predicate, state, dialect)})${option2.noInherit ? " no inherit" : ""}`);
|
|
3642
|
+
definitions.push(`constraint ${dialect.quoteIdentifier(option2.name)} check (${renderDdlExpression(option2.predicate, { ...state, rowLocalColumns: true }, dialect)})${option2.noInherit ? " no inherit" : ""}`);
|
|
2105
3643
|
break;
|
|
2106
3644
|
case "index":
|
|
2107
3645
|
break;
|
|
3646
|
+
default:
|
|
3647
|
+
throw new Error("Unsupported table option kind");
|
|
2108
3648
|
}
|
|
2109
3649
|
}
|
|
2110
3650
|
return `create table${ifNotExists ? " if not exists" : ""} ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)} (${definitions.join(", ")})`;
|
|
@@ -2113,10 +3653,56 @@ var renderCreateIndexSql = (targetSource, ddl, state, dialect) => {
|
|
|
2113
3653
|
const maybeIfNotExists = dialect.name === "postgres" && ddl.ifNotExists ? " if not exists" : "";
|
|
2114
3654
|
return `create${ddl.unique ? " unique" : ""} index${maybeIfNotExists} ${dialect.quoteIdentifier(ddl.name)} on ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)} (${ddl.columns.map((column) => dialect.quoteIdentifier(column)).join(", ")})`;
|
|
2115
3655
|
};
|
|
2116
|
-
var renderDropIndexSql = (targetSource, ddl, state, dialect) =>
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
3656
|
+
var renderDropIndexSql = (targetSource, ddl, state, dialect) => {
|
|
3657
|
+
if (dialect.name === "postgres") {
|
|
3658
|
+
const schemaName = typeof targetSource.source === "object" && targetSource.source !== null && TypeId4 in targetSource.source ? targetSource.source[TypeId4].schemaName : undefined;
|
|
3659
|
+
const indexName = schemaName === undefined || schemaName === "public" ? dialect.quoteIdentifier(ddl.name) : `${dialect.quoteIdentifier(schemaName)}.${dialect.quoteIdentifier(ddl.name)}`;
|
|
3660
|
+
return `drop index${ddl.ifExists ? " if exists" : ""} ${indexName}`;
|
|
3661
|
+
}
|
|
3662
|
+
return `drop index ${dialect.quoteIdentifier(ddl.name)} on ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)}`;
|
|
3663
|
+
};
|
|
3664
|
+
var isExpression4 = (value) => value !== null && typeof value === "object" && (TypeId2 in value);
|
|
3665
|
+
var isJsonDbType2 = (dbType) => {
|
|
3666
|
+
if (dbType.kind === "jsonb" || dbType.kind === "json") {
|
|
3667
|
+
return true;
|
|
3668
|
+
}
|
|
3669
|
+
if (!("variant" in dbType)) {
|
|
3670
|
+
return false;
|
|
3671
|
+
}
|
|
3672
|
+
const variant = dbType.variant;
|
|
3673
|
+
return variant === "json" || variant === "jsonb";
|
|
3674
|
+
};
|
|
3675
|
+
var isJsonExpression = (value) => isExpression4(value) && isJsonDbType2(value[TypeId2].dbType);
|
|
3676
|
+
var postgresRangeSubtypeByKind = {
|
|
3677
|
+
int4range: "int4",
|
|
3678
|
+
int8range: "int8",
|
|
3679
|
+
numrange: "numeric",
|
|
3680
|
+
tsrange: "timestamp",
|
|
3681
|
+
tstzrange: "timestamptz",
|
|
3682
|
+
daterange: "date",
|
|
3683
|
+
int4multirange: "int4",
|
|
3684
|
+
int8multirange: "int8",
|
|
3685
|
+
nummultirange: "numeric",
|
|
3686
|
+
tsmultirange: "timestamp",
|
|
3687
|
+
tstzmultirange: "timestamptz",
|
|
3688
|
+
datemultirange: "date"
|
|
3689
|
+
};
|
|
3690
|
+
var postgresRangeSubtypeKey = (dbType) => {
|
|
3691
|
+
if ("base" in dbType) {
|
|
3692
|
+
return postgresRangeSubtypeKey(dbType.base);
|
|
3693
|
+
}
|
|
3694
|
+
if ("subtype" in dbType) {
|
|
3695
|
+
return postgresRangeSubtypeKey(dbType.subtype) ?? dbType.subtype.kind;
|
|
3696
|
+
}
|
|
3697
|
+
return postgresRangeSubtypeByKind[dbType.kind];
|
|
3698
|
+
};
|
|
3699
|
+
var assertCompatiblePostgresRangeOperands = (left, right) => {
|
|
3700
|
+
const leftKey = postgresRangeSubtypeKey(left[TypeId2].dbType);
|
|
3701
|
+
const rightKey = postgresRangeSubtypeKey(right[TypeId2].dbType);
|
|
3702
|
+
if (leftKey !== undefined && rightKey !== undefined && leftKey !== rightKey) {
|
|
3703
|
+
throw new Error("Incompatible postgres range operands");
|
|
3704
|
+
}
|
|
3705
|
+
};
|
|
2120
3706
|
var unsupportedJsonFeature = (dialect, feature) => {
|
|
2121
3707
|
const error = new Error(`Unsupported JSON feature for ${dialect.name}: ${feature}`);
|
|
2122
3708
|
Object.assign(error, {
|
|
@@ -2159,15 +3745,16 @@ var extractJsonPathSegments = (node) => {
|
|
|
2159
3745
|
};
|
|
2160
3746
|
var extractJsonValue = (node) => node.newValue ?? node.insert ?? node.right;
|
|
2161
3747
|
var renderJsonPathSegment = (segment) => {
|
|
3748
|
+
const renderKey = (value) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(value) ? `.${value}` : `.${JSON.stringify(value)}`;
|
|
2162
3749
|
if (typeof segment === "string") {
|
|
2163
|
-
return
|
|
3750
|
+
return renderKey(segment);
|
|
2164
3751
|
}
|
|
2165
3752
|
if (typeof segment === "number") {
|
|
2166
3753
|
return `[${segment}]`;
|
|
2167
3754
|
}
|
|
2168
3755
|
switch (segment.kind) {
|
|
2169
3756
|
case "key":
|
|
2170
|
-
return
|
|
3757
|
+
return renderKey(segment.key);
|
|
2171
3758
|
case "index":
|
|
2172
3759
|
return `[${segment.index}]`;
|
|
2173
3760
|
case "wildcard":
|
|
@@ -2210,13 +3797,13 @@ var renderPostgresJsonAccessStep = (segment, textMode, state, dialect) => {
|
|
|
2210
3797
|
case "key":
|
|
2211
3798
|
return `${textMode ? "->>" : "->"} ${dialect.renderLiteral(segment.key, state)}`;
|
|
2212
3799
|
case "index":
|
|
2213
|
-
return `${textMode ? "->>" : "->"} ${dialect.renderLiteral(
|
|
3800
|
+
return `${textMode ? "->>" : "->"} ${dialect.renderLiteral(segment.index, state)}`;
|
|
2214
3801
|
default:
|
|
2215
3802
|
throw new Error("Postgres exact JSON access requires key/index segments");
|
|
2216
3803
|
}
|
|
2217
3804
|
};
|
|
2218
3805
|
var renderPostgresJsonValue = (value, state, dialect) => {
|
|
2219
|
-
if (!
|
|
3806
|
+
if (!isExpression4(value)) {
|
|
2220
3807
|
throw new Error("Expected a JSON expression");
|
|
2221
3808
|
}
|
|
2222
3809
|
const rendered = renderExpression(value, state, dialect);
|
|
@@ -2234,13 +3821,21 @@ var expressionDriverContext = (expression, state, dialect) => ({
|
|
|
2234
3821
|
driverValueMapping: expression[TypeId2].driverValueMapping
|
|
2235
3822
|
});
|
|
2236
3823
|
var renderJsonInputExpression = (expression, state, dialect) => renderJsonSelectSql(renderExpression(expression, state, dialect), expressionDriverContext(expression, state, dialect));
|
|
2237
|
-
var encodeArrayValues = (values, column, state, dialect) => values.map((value) =>
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
3824
|
+
var encodeArrayValues = (values, column, state, dialect) => values.map((value) => {
|
|
3825
|
+
if (value === null && column.metadata.nullable) {
|
|
3826
|
+
return null;
|
|
3827
|
+
}
|
|
3828
|
+
const runtimeSchemaAccepts = column.schema !== undefined && Schema5.is(column.schema)(value);
|
|
3829
|
+
const normalizedValue = runtimeSchemaAccepts ? value : normalizeDbValue(column.metadata.dbType, value);
|
|
3830
|
+
const encodedValue = column.schema === undefined || runtimeSchemaAccepts ? normalizedValue : Schema5.decodeUnknownSync(column.schema)(normalizedValue);
|
|
3831
|
+
return toDriverValue(encodedValue, {
|
|
3832
|
+
dialect: dialect.name,
|
|
3833
|
+
valueMappings: state.valueMappings,
|
|
3834
|
+
dbType: column.metadata.dbType,
|
|
3835
|
+
runtimeSchema: column.schema,
|
|
3836
|
+
driverValueMapping: column.metadata.driverValueMapping
|
|
3837
|
+
});
|
|
3838
|
+
});
|
|
2244
3839
|
var renderPostgresJsonKind = (value) => value[TypeId2].dbType.kind === "jsonb" ? "jsonb" : "json";
|
|
2245
3840
|
var renderJsonOpaquePath = (value, state, dialect) => {
|
|
2246
3841
|
if (isJsonPathValue(value)) {
|
|
@@ -2249,7 +3844,7 @@ var renderJsonOpaquePath = (value, state, dialect) => {
|
|
|
2249
3844
|
if (typeof value === "string") {
|
|
2250
3845
|
return dialect.renderLiteral(value, state);
|
|
2251
3846
|
}
|
|
2252
|
-
if (
|
|
3847
|
+
if (isExpression4(value)) {
|
|
2253
3848
|
return renderExpression(value, state, dialect);
|
|
2254
3849
|
}
|
|
2255
3850
|
throw new Error("Unsupported SQL/JSON path input");
|
|
@@ -2267,7 +3862,7 @@ var renderFunctionCall = (name, args, state, dialect) => {
|
|
|
2267
3862
|
if (source === undefined) {
|
|
2268
3863
|
throw new Error("Unsupported SQL extract expression");
|
|
2269
3864
|
}
|
|
2270
|
-
const fieldRuntime =
|
|
3865
|
+
const fieldRuntime = isExpression4(field) && field[TypeId2].dbType.kind === "text" && typeof field[TypeId2].runtime === "string" ? field[TypeId2].runtime : undefined;
|
|
2271
3866
|
const renderedField = fieldRuntime ?? renderExpression(field, state, dialect);
|
|
2272
3867
|
return `extract(${renderedField} from ${renderExpression(source, state, dialect)})`;
|
|
2273
3868
|
}
|
|
@@ -2305,7 +3900,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2305
3900
|
case "jsonPathText":
|
|
2306
3901
|
case "jsonAccessText":
|
|
2307
3902
|
case "jsonTraverseText": {
|
|
2308
|
-
if (!
|
|
3903
|
+
if (!isExpression4(base) || segments.length === 0) {
|
|
2309
3904
|
return;
|
|
2310
3905
|
}
|
|
2311
3906
|
const baseSql = renderExpression(base, state, dialect);
|
|
@@ -2328,7 +3923,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2328
3923
|
case "jsonKeyExists":
|
|
2329
3924
|
case "jsonHasAnyKeys":
|
|
2330
3925
|
case "jsonHasAllKeys": {
|
|
2331
|
-
if (!
|
|
3926
|
+
if (!isExpression4(base)) {
|
|
2332
3927
|
return;
|
|
2333
3928
|
}
|
|
2334
3929
|
const baseSql = dialect.name === "postgres" ? renderPostgresJsonValue(base, state, dialect) : renderExpression(base, state, dialect);
|
|
@@ -2354,7 +3949,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2354
3949
|
}
|
|
2355
3950
|
case "jsonConcat":
|
|
2356
3951
|
case "jsonMerge": {
|
|
2357
|
-
if (!
|
|
3952
|
+
if (!isExpression4(ast.left) || !isExpression4(ast.right)) {
|
|
2358
3953
|
return;
|
|
2359
3954
|
}
|
|
2360
3955
|
if (dialect.name === "postgres") {
|
|
@@ -2391,7 +3986,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2391
3986
|
return;
|
|
2392
3987
|
}
|
|
2393
3988
|
case "jsonToJson":
|
|
2394
|
-
if (!
|
|
3989
|
+
if (!isExpression4(base)) {
|
|
2395
3990
|
return;
|
|
2396
3991
|
}
|
|
2397
3992
|
if (dialect.name === "postgres") {
|
|
@@ -2402,7 +3997,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2402
3997
|
}
|
|
2403
3998
|
return;
|
|
2404
3999
|
case "jsonToJsonb":
|
|
2405
|
-
if (!
|
|
4000
|
+
if (!isExpression4(base)) {
|
|
2406
4001
|
return;
|
|
2407
4002
|
}
|
|
2408
4003
|
if (dialect.name === "postgres") {
|
|
@@ -2413,7 +4008,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2413
4008
|
}
|
|
2414
4009
|
return;
|
|
2415
4010
|
case "jsonTypeOf":
|
|
2416
|
-
if (!
|
|
4011
|
+
if (!isExpression4(base)) {
|
|
2417
4012
|
return;
|
|
2418
4013
|
}
|
|
2419
4014
|
if (dialect.name === "postgres") {
|
|
@@ -2425,7 +4020,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2425
4020
|
}
|
|
2426
4021
|
return;
|
|
2427
4022
|
case "jsonLength":
|
|
2428
|
-
if (!
|
|
4023
|
+
if (!isExpression4(base)) {
|
|
2429
4024
|
return;
|
|
2430
4025
|
}
|
|
2431
4026
|
if (dialect.name === "postgres") {
|
|
@@ -2440,21 +4035,21 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2440
4035
|
}
|
|
2441
4036
|
return;
|
|
2442
4037
|
case "jsonKeys":
|
|
2443
|
-
if (!
|
|
4038
|
+
if (!isExpression4(base)) {
|
|
2444
4039
|
return;
|
|
2445
4040
|
}
|
|
2446
4041
|
if (dialect.name === "postgres") {
|
|
2447
4042
|
const baseSql = renderExpression(base, state, dialect);
|
|
2448
4043
|
const typeOf = `${postgresBaseKind === "jsonb" ? "jsonb" : "json"}_typeof`;
|
|
2449
4044
|
const objectKeys = `${postgresBaseKind === "jsonb" ? "jsonb" : "json"}_object_keys`;
|
|
2450
|
-
return `(case when ${typeOf}(${baseSql}) = 'object' then array(select ${objectKeys}(${baseSql})) else null end)`;
|
|
4045
|
+
return `(case when ${typeOf}(${baseSql}) = 'object' then to_json(array(select ${objectKeys}(${baseSql}))) else null end)`;
|
|
2451
4046
|
}
|
|
2452
4047
|
if (dialect.name === "mysql") {
|
|
2453
4048
|
return `json_keys(${renderExpression(base, state, dialect)})`;
|
|
2454
4049
|
}
|
|
2455
4050
|
return;
|
|
2456
4051
|
case "jsonStripNulls":
|
|
2457
|
-
if (!
|
|
4052
|
+
if (!isExpression4(base)) {
|
|
2458
4053
|
return;
|
|
2459
4054
|
}
|
|
2460
4055
|
if (dialect.name === "postgres") {
|
|
@@ -2465,14 +4060,14 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2465
4060
|
case "jsonDelete":
|
|
2466
4061
|
case "jsonDeletePath":
|
|
2467
4062
|
case "jsonRemove": {
|
|
2468
|
-
if (!
|
|
4063
|
+
if (!isExpression4(base) || segments.length === 0) {
|
|
2469
4064
|
return;
|
|
2470
4065
|
}
|
|
2471
4066
|
if (dialect.name === "postgres") {
|
|
2472
4067
|
const baseSql = renderPostgresJsonValue(base, state, dialect);
|
|
2473
4068
|
if (segments.length === 1 && (segments[0].kind === "key" || segments[0].kind === "index")) {
|
|
2474
4069
|
const segment = segments[0];
|
|
2475
|
-
return `(${baseSql} - ${segment.kind === "key" ? dialect.renderLiteral(segment.key, state) : dialect.renderLiteral(
|
|
4070
|
+
return `(${baseSql} - ${segment.kind === "key" ? dialect.renderLiteral(segment.key, state) : dialect.renderLiteral(segment.index, state)})`;
|
|
2476
4071
|
}
|
|
2477
4072
|
return `(${baseSql} #- ${renderPostgresJsonPathArray(segments, state, dialect)})`;
|
|
2478
4073
|
}
|
|
@@ -2483,11 +4078,11 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2483
4078
|
}
|
|
2484
4079
|
case "jsonSet":
|
|
2485
4080
|
case "jsonInsert": {
|
|
2486
|
-
if (!
|
|
4081
|
+
if (!isExpression4(base) || segments.length === 0) {
|
|
2487
4082
|
return;
|
|
2488
4083
|
}
|
|
2489
4084
|
const nextValue = extractJsonValue(ast);
|
|
2490
|
-
if (!
|
|
4085
|
+
if (!isExpression4(nextValue)) {
|
|
2491
4086
|
return;
|
|
2492
4087
|
}
|
|
2493
4088
|
const createMissing = ast.createMissing === true;
|
|
@@ -2504,7 +4099,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2504
4099
|
return;
|
|
2505
4100
|
}
|
|
2506
4101
|
case "jsonPathExists": {
|
|
2507
|
-
if (!
|
|
4102
|
+
if (!isExpression4(base)) {
|
|
2508
4103
|
return;
|
|
2509
4104
|
}
|
|
2510
4105
|
const path2 = ast.path ?? ast.query ?? ast.right;
|
|
@@ -2520,7 +4115,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
|
|
|
2520
4115
|
return;
|
|
2521
4116
|
}
|
|
2522
4117
|
case "jsonPathMatch": {
|
|
2523
|
-
if (!
|
|
4118
|
+
if (!isExpression4(base)) {
|
|
2524
4119
|
return;
|
|
2525
4120
|
}
|
|
2526
4121
|
const path2 = ast.path ?? ast.query ?? ast.right;
|
|
@@ -2547,6 +4142,11 @@ var renderJoinSourcesForMutation = (joins, state, dialect) => joins.map((join) =
|
|
|
2547
4142
|
var renderFromSources = (sources, state, dialect) => sources.map((source) => renderSourceReference(source.source, source.tableName, source.baseTableName, state, dialect)).join(", ");
|
|
2548
4143
|
var renderJoinPredicatesForMutation = (joins, state, dialect) => joins.flatMap((join) => join.kind === "cross" || !join.on ? [] : [renderExpression(join.on, state, dialect)]);
|
|
2549
4144
|
var renderDeleteTargets = (targets, dialect) => targets.map((target) => dialect.quoteIdentifier(target.tableName)).join(", ");
|
|
4145
|
+
var assertMergeActionKind = (kind, allowed) => {
|
|
4146
|
+
if (typeof kind !== "string" || !allowed.includes(kind)) {
|
|
4147
|
+
throw new Error("Unsupported merge action kind");
|
|
4148
|
+
}
|
|
4149
|
+
};
|
|
2550
4150
|
var renderMysqlMutationLock = (lock, statement) => {
|
|
2551
4151
|
if (!lock) {
|
|
2552
4152
|
return "";
|
|
@@ -2566,8 +4166,9 @@ var renderTransactionClause = (clause, dialect) => {
|
|
|
2566
4166
|
switch (clause.kind) {
|
|
2567
4167
|
case "transaction": {
|
|
2568
4168
|
const modes = [];
|
|
2569
|
-
|
|
2570
|
-
|
|
4169
|
+
const isolationLevel = renderTransactionIsolationLevel(clause.isolationLevel);
|
|
4170
|
+
if (isolationLevel) {
|
|
4171
|
+
modes.push(isolationLevel);
|
|
2571
4172
|
}
|
|
2572
4173
|
if (clause.readOnly === true) {
|
|
2573
4174
|
modes.push("read only");
|
|
@@ -2585,13 +4186,16 @@ var renderTransactionClause = (clause, dialect) => {
|
|
|
2585
4186
|
case "releaseSavepoint":
|
|
2586
4187
|
return `release savepoint ${dialect.quoteIdentifier(clause.name)}`;
|
|
2587
4188
|
}
|
|
2588
|
-
|
|
4189
|
+
throw new Error("Unsupported transaction statement kind");
|
|
2589
4190
|
};
|
|
2590
4191
|
var renderSelectionList = (selection, state, dialect, validateAggregation) => {
|
|
2591
4192
|
if (validateAggregation) {
|
|
2592
4193
|
validateAggregationSelection(selection, []);
|
|
2593
4194
|
}
|
|
2594
4195
|
const flattened = flattenSelection(selection);
|
|
4196
|
+
if (dialect.name === "mysql" && flattened.length === 0) {
|
|
4197
|
+
throw new Error("mysql select statements require at least one selected expression");
|
|
4198
|
+
}
|
|
2595
4199
|
const projections = selectionProjections(selection);
|
|
2596
4200
|
const sql = flattened.map(({ expression, alias: alias2 }) => `${renderSelectSql(renderExpression(expression, state, dialect), expressionDriverContext(expression, state, dialect))} as ${dialect.quoteIdentifier(alias2)}`).join(", ");
|
|
2597
4201
|
return {
|
|
@@ -2599,7 +4203,84 @@ var renderSelectionList = (selection, state, dialect, validateAggregation) => {
|
|
|
2599
4203
|
projections
|
|
2600
4204
|
};
|
|
2601
4205
|
};
|
|
2602
|
-
var
|
|
4206
|
+
var nestedRenderState = (state) => ({
|
|
4207
|
+
params: state.params,
|
|
4208
|
+
valueMappings: state.valueMappings,
|
|
4209
|
+
ctes: [],
|
|
4210
|
+
cteNames: new Set(state.cteNames),
|
|
4211
|
+
cteSources: new Map(state.cteSources)
|
|
4212
|
+
});
|
|
4213
|
+
var assertMatchingSetProjections = (left, right) => {
|
|
4214
|
+
const leftKeys = left.map((projection) => JSON.stringify(projection.path));
|
|
4215
|
+
const rightKeys = right.map((projection) => JSON.stringify(projection.path));
|
|
4216
|
+
if (leftKeys.length !== rightKeys.length || leftKeys.some((key2, index3) => key2 !== rightKeys[index3])) {
|
|
4217
|
+
throw new Error("set operator operands must have matching result rows");
|
|
4218
|
+
}
|
|
4219
|
+
};
|
|
4220
|
+
var assertNoGroupedMutationClauses = (ast, statement) => {
|
|
4221
|
+
if (ast.groupBy.length > 0) {
|
|
4222
|
+
throw new Error(`groupBy(...) is not supported for ${statement} statements`);
|
|
4223
|
+
}
|
|
4224
|
+
if (ast.having.length > 0) {
|
|
4225
|
+
throw new Error(`having(...) is not supported for ${statement} statements`);
|
|
4226
|
+
}
|
|
4227
|
+
};
|
|
4228
|
+
var assertNoInsertQueryClauses = (ast) => {
|
|
4229
|
+
if (ast.where.length > 0) {
|
|
4230
|
+
throw new Error("where(...) is not supported for insert statements");
|
|
4231
|
+
}
|
|
4232
|
+
if (ast.joins.length > 0) {
|
|
4233
|
+
throw new Error("join(...) is not supported for insert statements");
|
|
4234
|
+
}
|
|
4235
|
+
if (ast.orderBy.length > 0) {
|
|
4236
|
+
throw new Error("orderBy(...) is not supported for insert statements");
|
|
4237
|
+
}
|
|
4238
|
+
if (ast.limit) {
|
|
4239
|
+
throw new Error("limit(...) is not supported for insert statements");
|
|
4240
|
+
}
|
|
4241
|
+
if (ast.offset) {
|
|
4242
|
+
throw new Error("offset(...) is not supported for insert statements");
|
|
4243
|
+
}
|
|
4244
|
+
if (ast.lock) {
|
|
4245
|
+
throw new Error("lock(...) is not supported for insert statements");
|
|
4246
|
+
}
|
|
4247
|
+
};
|
|
4248
|
+
var assertNoStatementQueryClauses = (ast, statement, options2 = {}) => {
|
|
4249
|
+
if (ast.distinct) {
|
|
4250
|
+
throw new Error(`distinct(...) is not supported for ${statement} statements`);
|
|
4251
|
+
}
|
|
4252
|
+
if (ast.where.length > 0) {
|
|
4253
|
+
throw new Error(`where(...) is not supported for ${statement} statements`);
|
|
4254
|
+
}
|
|
4255
|
+
if ((ast.fromSources?.length ?? 0) > 0 || ast.from) {
|
|
4256
|
+
throw new Error(`from(...) is not supported for ${statement} statements`);
|
|
4257
|
+
}
|
|
4258
|
+
if (ast.joins.length > 0) {
|
|
4259
|
+
throw new Error(`join(...) is not supported for ${statement} statements`);
|
|
4260
|
+
}
|
|
4261
|
+
if (ast.groupBy.length > 0) {
|
|
4262
|
+
throw new Error(`groupBy(...) is not supported for ${statement} statements`);
|
|
4263
|
+
}
|
|
4264
|
+
if (ast.having.length > 0) {
|
|
4265
|
+
throw new Error(`having(...) is not supported for ${statement} statements`);
|
|
4266
|
+
}
|
|
4267
|
+
if (ast.orderBy.length > 0) {
|
|
4268
|
+
throw new Error(`orderBy(...) is not supported for ${statement} statements`);
|
|
4269
|
+
}
|
|
4270
|
+
if (ast.limit) {
|
|
4271
|
+
throw new Error(`limit(...) is not supported for ${statement} statements`);
|
|
4272
|
+
}
|
|
4273
|
+
if (ast.offset) {
|
|
4274
|
+
throw new Error(`offset(...) is not supported for ${statement} statements`);
|
|
4275
|
+
}
|
|
4276
|
+
if (ast.lock) {
|
|
4277
|
+
throw new Error(`lock(...) is not supported for ${statement} statements`);
|
|
4278
|
+
}
|
|
4279
|
+
if (options2.allowSelection !== true && Object.keys(ast.select).length > 0) {
|
|
4280
|
+
throw new Error(`returning(...) is not supported for ${statement} statements`);
|
|
4281
|
+
}
|
|
4282
|
+
};
|
|
4283
|
+
var renderQueryAst = (ast, state, dialect, options2 = {}) => {
|
|
2603
4284
|
let sql = "";
|
|
2604
4285
|
let projections = [];
|
|
2605
4286
|
switch (ast.kind) {
|
|
@@ -2607,8 +4288,9 @@ var renderQueryAst = (ast, state, dialect) => {
|
|
|
2607
4288
|
validateAggregationSelection(ast.select, ast.groupBy);
|
|
2608
4289
|
const rendered = renderSelectionList(ast.select, state, dialect, false);
|
|
2609
4290
|
projections = rendered.projections;
|
|
4291
|
+
const selectList = rendered.sql.length > 0 ? ` ${rendered.sql}` : "";
|
|
2610
4292
|
const clauses = [
|
|
2611
|
-
ast.distinctOn && ast.distinctOn.length > 0 ? `select distinct on (${ast.distinctOn.map((value) => renderExpression(value, state, dialect)).join(", ")})
|
|
4293
|
+
ast.distinctOn && ast.distinctOn.length > 0 ? `select distinct on (${ast.distinctOn.map((value) => renderExpression(value, state, dialect)).join(", ")})${selectList}` : `select${ast.distinct ? " distinct" : ""}${selectList}`
|
|
2612
4294
|
];
|
|
2613
4295
|
if (ast.from) {
|
|
2614
4296
|
clauses.push(`from ${renderSourceReference(ast.from.source, ast.from.tableName, ast.from.baseTableName, state, dialect)}`);
|
|
@@ -2636,19 +4318,25 @@ var renderQueryAst = (ast, state, dialect) => {
|
|
|
2636
4318
|
clauses.push(`offset ${renderExpression(ast.offset, state, dialect)}`);
|
|
2637
4319
|
}
|
|
2638
4320
|
if (ast.lock) {
|
|
2639
|
-
|
|
4321
|
+
if (ast.lock.nowait && ast.lock.skipLocked) {
|
|
4322
|
+
throw new Error("lock(...) cannot specify both nowait and skipLocked");
|
|
4323
|
+
}
|
|
4324
|
+
clauses.push(`${renderSelectLockMode(ast.lock.mode)}${ast.lock.nowait ? " nowait" : ""}${ast.lock.skipLocked ? " skip locked" : ""}`);
|
|
2640
4325
|
}
|
|
2641
4326
|
sql = clauses.join(" ");
|
|
2642
4327
|
break;
|
|
2643
4328
|
}
|
|
2644
4329
|
case "set": {
|
|
2645
4330
|
const setAst = ast;
|
|
4331
|
+
assertNoStatementQueryClauses(setAst, "set", { allowSelection: true });
|
|
2646
4332
|
const base = renderQueryAst(getAst(setAst.setBase), state, dialect);
|
|
2647
4333
|
projections = selectionProjections(setAst.select);
|
|
4334
|
+
assertMatchingSetProjections(projections, base.projections);
|
|
2648
4335
|
sql = [
|
|
2649
4336
|
`(${base.sql})`,
|
|
2650
4337
|
...(setAst.setOperations ?? []).map((entry) => {
|
|
2651
4338
|
const rendered = renderQueryAst(getAst(entry.query), state, dialect);
|
|
4339
|
+
assertMatchingSetProjections(projections, rendered.projections);
|
|
2652
4340
|
return `${entry.kind}${entry.all ? " all" : ""} (${rendered.sql})`;
|
|
2653
4341
|
})
|
|
2654
4342
|
].join(" ");
|
|
@@ -2656,28 +4344,34 @@ var renderQueryAst = (ast, state, dialect) => {
|
|
|
2656
4344
|
}
|
|
2657
4345
|
case "insert": {
|
|
2658
4346
|
const insertAst = ast;
|
|
4347
|
+
if (insertAst.distinct) {
|
|
4348
|
+
throw new Error("distinct(...) is not supported for insert statements");
|
|
4349
|
+
}
|
|
4350
|
+
assertNoGroupedMutationClauses(insertAst, "insert");
|
|
4351
|
+
assertNoInsertQueryClauses(insertAst);
|
|
2659
4352
|
const targetSource = insertAst.into;
|
|
2660
4353
|
const target = renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect);
|
|
4354
|
+
const insertSource = expectInsertSourceKind(insertAst.insertSource);
|
|
4355
|
+
const conflict = expectConflictClause(insertAst.conflict);
|
|
2661
4356
|
sql = `insert into ${target}`;
|
|
2662
|
-
if (
|
|
2663
|
-
const columns =
|
|
2664
|
-
const rows =
|
|
4357
|
+
if (insertSource?.kind === "values") {
|
|
4358
|
+
const columns = insertSource.columns.map((column) => dialect.quoteIdentifier(column)).join(", ");
|
|
4359
|
+
const rows = insertSource.rows.map((row) => `(${row.values.map((entry) => renderExpression(entry.value, state, dialect)).join(", ")})`).join(", ");
|
|
2665
4360
|
sql += ` (${columns}) values ${rows}`;
|
|
2666
|
-
} else if (
|
|
2667
|
-
const columns =
|
|
2668
|
-
const renderedQuery = renderQueryAst(getAst(
|
|
4361
|
+
} else if (insertSource?.kind === "query") {
|
|
4362
|
+
const columns = insertSource.columns.map((column) => dialect.quoteIdentifier(column)).join(", ");
|
|
4363
|
+
const renderedQuery = renderQueryAst(getAst(insertSource.query), state, dialect);
|
|
2669
4364
|
sql += ` (${columns}) ${renderedQuery.sql}`;
|
|
2670
|
-
} else if (
|
|
2671
|
-
const
|
|
2672
|
-
const columns = unnestSource.columns.map((column) => dialect.quoteIdentifier(column)).join(", ");
|
|
4365
|
+
} else if (insertSource?.kind === "unnest") {
|
|
4366
|
+
const columns = insertSource.columns.map((column) => dialect.quoteIdentifier(column)).join(", ");
|
|
2673
4367
|
if (dialect.name === "postgres") {
|
|
2674
4368
|
const table = targetSource.source;
|
|
2675
4369
|
const fields = table[TypeId4].fields;
|
|
2676
|
-
const rendered =
|
|
4370
|
+
const rendered = insertSource.values.map((entry) => `cast(${dialect.renderLiteral(encodeArrayValues(entry.values, fields[entry.columnName], state, dialect), state)} as ${renderCastType(dialect, fields[entry.columnName].metadata.dbType)}[])`).join(", ");
|
|
2677
4371
|
sql += ` (${columns}) select * from unnest(${rendered})`;
|
|
2678
4372
|
} else {
|
|
2679
|
-
const rowCount =
|
|
2680
|
-
const rows = Array.from({ length: rowCount }, (_, index3) => `(${
|
|
4373
|
+
const rowCount = insertSource.values[0]?.values.length ?? 0;
|
|
4374
|
+
const rows = Array.from({ length: rowCount }, (_, index3) => `(${insertSource.values.map((entry) => dialect.renderLiteral(entry.values[index3], state, targetSource.source[TypeId4].fields[entry.columnName][TypeId2])).join(", ")})`).join(", ");
|
|
2681
4375
|
sql += ` (${columns}) values ${rows}`;
|
|
2682
4376
|
}
|
|
2683
4377
|
} else {
|
|
@@ -2689,13 +4383,16 @@ var renderQueryAst = (ast, state, dialect) => {
|
|
|
2689
4383
|
sql += " default values";
|
|
2690
4384
|
}
|
|
2691
4385
|
}
|
|
2692
|
-
if (
|
|
2693
|
-
|
|
4386
|
+
if (conflict) {
|
|
4387
|
+
if (conflict.action === "doNothing" && conflict.where) {
|
|
4388
|
+
throw new Error("conflict action predicates require update assignments");
|
|
4389
|
+
}
|
|
4390
|
+
const updateValues = (conflict.values ?? []).map((entry) => `${dialect.quoteIdentifier(entry.columnName)} = ${renderExpression(entry.value, state, dialect)}`).join(", ");
|
|
2694
4391
|
if (dialect.name === "postgres") {
|
|
2695
|
-
const targetSql =
|
|
4392
|
+
const targetSql = conflict.target?.kind === "constraint" ? ` on conflict on constraint ${dialect.quoteIdentifier(conflict.target.name)}` : conflict.target?.kind === "columns" ? ` on conflict (${conflict.target.columns.map((column) => dialect.quoteIdentifier(column)).join(", ")})${conflict.target.where ? ` where ${renderExpression(conflict.target.where, state, dialect)}` : ""}` : " on conflict";
|
|
2696
4393
|
sql += targetSql;
|
|
2697
|
-
sql +=
|
|
2698
|
-
} else if (
|
|
4394
|
+
sql += conflict.action === "doNothing" ? " do nothing" : ` do update set ${updateValues}${conflict.where ? ` where ${renderExpression(conflict.where, state, dialect)}` : ""}`;
|
|
4395
|
+
} else if (conflict.action === "doNothing") {
|
|
2699
4396
|
sql = sql.replace(/^insert/, "insert ignore");
|
|
2700
4397
|
} else {
|
|
2701
4398
|
sql += ` on duplicate key update ${updateValues}`;
|
|
@@ -2710,10 +4407,29 @@ var renderQueryAst = (ast, state, dialect) => {
|
|
|
2710
4407
|
}
|
|
2711
4408
|
case "update": {
|
|
2712
4409
|
const updateAst = ast;
|
|
4410
|
+
if (updateAst.distinct) {
|
|
4411
|
+
throw new Error("distinct(...) is not supported for update statements");
|
|
4412
|
+
}
|
|
4413
|
+
assertNoGroupedMutationClauses(updateAst, "update");
|
|
4414
|
+
if (updateAst.orderBy.length > 0) {
|
|
4415
|
+
throw new Error("orderBy(...) is not supported for update statements");
|
|
4416
|
+
}
|
|
4417
|
+
if (updateAst.limit) {
|
|
4418
|
+
throw new Error("limit(...) is not supported for update statements");
|
|
4419
|
+
}
|
|
4420
|
+
if (updateAst.offset) {
|
|
4421
|
+
throw new Error("offset(...) is not supported for update statements");
|
|
4422
|
+
}
|
|
4423
|
+
if (updateAst.lock) {
|
|
4424
|
+
throw new Error("lock(...) is not supported for update statements");
|
|
4425
|
+
}
|
|
2713
4426
|
const targetSource = updateAst.target;
|
|
2714
4427
|
const target = renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect);
|
|
2715
4428
|
const targets = updateAst.targets ?? [targetSource];
|
|
2716
4429
|
const fromSources = updateAst.fromSources ?? [];
|
|
4430
|
+
if ((updateAst.set ?? []).length === 0) {
|
|
4431
|
+
throw new Error("update statements require at least one assignment");
|
|
4432
|
+
}
|
|
2717
4433
|
const assignments = updateAst.set.map((entry) => renderMutationAssignment(entry, state, dialect)).join(", ");
|
|
2718
4434
|
if (dialect.name === "mysql") {
|
|
2719
4435
|
const modifiers = renderMysqlMutationLock(updateAst.lock, "update");
|
|
@@ -2756,6 +4472,22 @@ var renderQueryAst = (ast, state, dialect) => {
|
|
|
2756
4472
|
}
|
|
2757
4473
|
case "delete": {
|
|
2758
4474
|
const deleteAst = ast;
|
|
4475
|
+
if (deleteAst.distinct) {
|
|
4476
|
+
throw new Error("distinct(...) is not supported for delete statements");
|
|
4477
|
+
}
|
|
4478
|
+
assertNoGroupedMutationClauses(deleteAst, "delete");
|
|
4479
|
+
if (deleteAst.orderBy.length > 0 && dialect.name === "postgres") {
|
|
4480
|
+
throw new Error("orderBy(...) is not supported for delete statements");
|
|
4481
|
+
}
|
|
4482
|
+
if (deleteAst.limit && dialect.name === "postgres") {
|
|
4483
|
+
throw new Error("limit(...) is not supported for delete statements");
|
|
4484
|
+
}
|
|
4485
|
+
if (deleteAst.offset) {
|
|
4486
|
+
throw new Error("offset(...) is not supported for delete statements");
|
|
4487
|
+
}
|
|
4488
|
+
if (deleteAst.lock) {
|
|
4489
|
+
throw new Error("lock(...) is not supported for delete statements");
|
|
4490
|
+
}
|
|
2759
4491
|
const targetSource = deleteAst.target;
|
|
2760
4492
|
const target = renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect);
|
|
2761
4493
|
const targets = deleteAst.targets ?? [targetSource];
|
|
@@ -2794,12 +4526,14 @@ var renderQueryAst = (ast, state, dialect) => {
|
|
|
2794
4526
|
}
|
|
2795
4527
|
case "truncate": {
|
|
2796
4528
|
const truncateAst = ast;
|
|
4529
|
+
assertNoStatementQueryClauses(truncateAst, "truncate");
|
|
4530
|
+
const truncate = expectTruncateClause(truncateAst.truncate);
|
|
2797
4531
|
const targetSource = truncateAst.target;
|
|
2798
4532
|
sql = `truncate table ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)}`;
|
|
2799
|
-
if (
|
|
4533
|
+
if (truncate.restartIdentity) {
|
|
2800
4534
|
sql += " restart identity";
|
|
2801
4535
|
}
|
|
2802
|
-
if (
|
|
4536
|
+
if (truncate.cascade) {
|
|
2803
4537
|
sql += " cascade";
|
|
2804
4538
|
}
|
|
2805
4539
|
break;
|
|
@@ -2812,8 +4546,18 @@ var renderQueryAst = (ast, state, dialect) => {
|
|
|
2812
4546
|
const targetSource = mergeAst.target;
|
|
2813
4547
|
const usingSource = mergeAst.using;
|
|
2814
4548
|
const merge = mergeAst.merge;
|
|
4549
|
+
if (merge.kind !== "merge") {
|
|
4550
|
+
throw new Error("Unsupported merge statement kind");
|
|
4551
|
+
}
|
|
4552
|
+
if (Object.keys(mergeAst.select).length > 0) {
|
|
4553
|
+
throw new Error("returning(...) is not supported for merge statements");
|
|
4554
|
+
}
|
|
4555
|
+
if (!merge.whenMatched && !merge.whenNotMatched) {
|
|
4556
|
+
throw new Error("merge statements require at least one action");
|
|
4557
|
+
}
|
|
2815
4558
|
sql = `merge into ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)} using ${renderSourceReference(usingSource.source, usingSource.tableName, usingSource.baseTableName, state, dialect)} on ${renderExpression(merge.on, state, dialect)}`;
|
|
2816
4559
|
if (merge.whenMatched) {
|
|
4560
|
+
assertMergeActionKind(merge.whenMatched.kind, ["update", "delete"]);
|
|
2817
4561
|
sql += " when matched";
|
|
2818
4562
|
if (merge.whenMatched.predicate) {
|
|
2819
4563
|
sql += ` and ${renderExpression(merge.whenMatched.predicate, state, dialect)}`;
|
|
@@ -2821,14 +4565,21 @@ var renderQueryAst = (ast, state, dialect) => {
|
|
|
2821
4565
|
if (merge.whenMatched.kind === "delete") {
|
|
2822
4566
|
sql += " then delete";
|
|
2823
4567
|
} else {
|
|
4568
|
+
if (merge.whenMatched.values.length === 0) {
|
|
4569
|
+
throw new Error("merge update actions require at least one assignment");
|
|
4570
|
+
}
|
|
2824
4571
|
sql += ` then update set ${merge.whenMatched.values.map((entry) => `${dialect.quoteIdentifier(entry.columnName)} = ${renderExpression(entry.value, state, dialect)}`).join(", ")}`;
|
|
2825
4572
|
}
|
|
2826
4573
|
}
|
|
2827
4574
|
if (merge.whenNotMatched) {
|
|
4575
|
+
assertMergeActionKind(merge.whenNotMatched.kind, ["insert"]);
|
|
2828
4576
|
sql += " when not matched";
|
|
2829
4577
|
if (merge.whenNotMatched.predicate) {
|
|
2830
4578
|
sql += ` and ${renderExpression(merge.whenNotMatched.predicate, state, dialect)}`;
|
|
2831
4579
|
}
|
|
4580
|
+
if (merge.whenNotMatched.values.length === 0) {
|
|
4581
|
+
throw new Error("merge insert actions require at least one value");
|
|
4582
|
+
}
|
|
2832
4583
|
sql += ` then insert (${merge.whenNotMatched.values.map((entry) => dialect.quoteIdentifier(entry.columnName)).join(", ")}) values (${merge.whenNotMatched.values.map((entry) => renderExpression(entry.value, state, dialect)).join(", ")})`;
|
|
2833
4584
|
}
|
|
2834
4585
|
break;
|
|
@@ -2839,32 +4590,40 @@ var renderQueryAst = (ast, state, dialect) => {
|
|
|
2839
4590
|
case "savepoint":
|
|
2840
4591
|
case "rollbackTo":
|
|
2841
4592
|
case "releaseSavepoint": {
|
|
4593
|
+
assertNoStatementQueryClauses(ast, ast.kind);
|
|
2842
4594
|
sql = renderTransactionClause(ast.transaction, dialect);
|
|
2843
4595
|
break;
|
|
2844
4596
|
}
|
|
2845
4597
|
case "createTable": {
|
|
2846
4598
|
const createTableAst = ast;
|
|
2847
|
-
|
|
4599
|
+
assertNoStatementQueryClauses(createTableAst, "createTable");
|
|
4600
|
+
const ddl = expectDdlClauseKind(createTableAst.ddl, "createTable");
|
|
4601
|
+
sql = renderCreateTableSql(createTableAst.target, state, dialect, ddl.ifNotExists);
|
|
2848
4602
|
break;
|
|
2849
4603
|
}
|
|
2850
4604
|
case "dropTable": {
|
|
2851
4605
|
const dropTableAst = ast;
|
|
2852
|
-
|
|
2853
|
-
|
|
4606
|
+
assertNoStatementQueryClauses(dropTableAst, "dropTable");
|
|
4607
|
+
const ddl = expectDdlClauseKind(dropTableAst.ddl, "dropTable");
|
|
4608
|
+
sql = `drop table${ddl.ifExists ? " if exists" : ""} ${renderSourceReference(dropTableAst.target.source, dropTableAst.target.tableName, dropTableAst.target.baseTableName, state, dialect)}`;
|
|
2854
4609
|
break;
|
|
2855
4610
|
}
|
|
2856
4611
|
case "createIndex": {
|
|
2857
4612
|
const createIndexAst = ast;
|
|
2858
|
-
|
|
4613
|
+
assertNoStatementQueryClauses(createIndexAst, "createIndex");
|
|
4614
|
+
sql = renderCreateIndexSql(createIndexAst.target, expectDdlClauseKind(createIndexAst.ddl, "createIndex"), state, dialect);
|
|
2859
4615
|
break;
|
|
2860
4616
|
}
|
|
2861
4617
|
case "dropIndex": {
|
|
2862
4618
|
const dropIndexAst = ast;
|
|
2863
|
-
|
|
4619
|
+
assertNoStatementQueryClauses(dropIndexAst, "dropIndex");
|
|
4620
|
+
sql = renderDropIndexSql(dropIndexAst.target, expectDdlClauseKind(dropIndexAst.ddl, "dropIndex"), state, dialect);
|
|
2864
4621
|
break;
|
|
2865
4622
|
}
|
|
4623
|
+
default:
|
|
4624
|
+
throw new Error("Unsupported query statement kind");
|
|
2866
4625
|
}
|
|
2867
|
-
if (state.ctes.length === 0) {
|
|
4626
|
+
if (state.ctes.length === 0 || options2.emitCtes === false) {
|
|
2868
4627
|
return {
|
|
2869
4628
|
sql,
|
|
2870
4629
|
projections
|
|
@@ -2887,9 +4646,14 @@ var renderSourceReference = (source, tableName, baseTableName, state, dialect) =
|
|
|
2887
4646
|
};
|
|
2888
4647
|
if (typeof source === "object" && source !== null && "kind" in source && source.kind === "cte") {
|
|
2889
4648
|
const cte = source;
|
|
4649
|
+
const registeredCteSource = state.cteSources.get(cte.name);
|
|
4650
|
+
if (registeredCteSource !== undefined && registeredCteSource !== cte.plan) {
|
|
4651
|
+
throw new Error(`common table expression name is already registered with a different plan: ${cte.name}`);
|
|
4652
|
+
}
|
|
2890
4653
|
if (!state.cteNames.has(cte.name)) {
|
|
2891
4654
|
state.cteNames.add(cte.name);
|
|
2892
|
-
|
|
4655
|
+
state.cteSources.set(cte.name, cte.plan);
|
|
4656
|
+
const rendered = renderQueryAst(getAst(cte.plan), state, dialect, { emitCtes: false });
|
|
2893
4657
|
state.ctes.push({
|
|
2894
4658
|
name: cte.name,
|
|
2895
4659
|
sql: rendered.sql,
|
|
@@ -2901,11 +4665,11 @@ var renderSourceReference = (source, tableName, baseTableName, state, dialect) =
|
|
|
2901
4665
|
if (typeof source === "object" && source !== null && "kind" in source && source.kind === "derived") {
|
|
2902
4666
|
const derived = source;
|
|
2903
4667
|
if (!state.cteNames.has(derived.name)) {}
|
|
2904
|
-
return `(${renderQueryAst(getAst(derived.plan), state, dialect).sql}) as ${dialect.quoteIdentifier(derived.name)}`;
|
|
4668
|
+
return `(${renderQueryAst(getAst(derived.plan), nestedRenderState(state), dialect).sql}) as ${dialect.quoteIdentifier(derived.name)}`;
|
|
2905
4669
|
}
|
|
2906
4670
|
if (typeof source === "object" && source !== null && "kind" in source && source.kind === "lateral") {
|
|
2907
4671
|
const lateral = source;
|
|
2908
|
-
return `lateral (${renderQueryAst(getAst(lateral.plan), state, dialect).sql}) as ${dialect.quoteIdentifier(lateral.name)}`;
|
|
4672
|
+
return `lateral (${renderQueryAst(getAst(lateral.plan), nestedRenderState(state), dialect).sql}) as ${dialect.quoteIdentifier(lateral.name)}`;
|
|
2909
4673
|
}
|
|
2910
4674
|
if (typeof source === "object" && source !== null && source.kind === "values") {
|
|
2911
4675
|
const values = source;
|
|
@@ -2926,6 +4690,13 @@ var renderSourceReference = (source, tableName, baseTableName, state, dialect) =
|
|
|
2926
4690
|
const schemaName = typeof source === "object" && source !== null && TypeId4 in source ? source[TypeId4].schemaName : undefined;
|
|
2927
4691
|
return dialect.renderTableReference(tableName, baseTableName, schemaName);
|
|
2928
4692
|
};
|
|
4693
|
+
var renderSubqueryExpressionPlan = (plan, state, dialect) => {
|
|
4694
|
+
const statement = getQueryState(plan).statement;
|
|
4695
|
+
if (statement !== "select" && statement !== "set") {
|
|
4696
|
+
throw new Error("subquery expressions only accept select-like query plans");
|
|
4697
|
+
}
|
|
4698
|
+
return renderQueryAst(getAst(plan), state, dialect).sql;
|
|
4699
|
+
};
|
|
2929
4700
|
var renderExpression = (expression, state, dialect) => {
|
|
2930
4701
|
const rawAst = expression[TypeId3];
|
|
2931
4702
|
const jsonSql = renderJsonExpression(expression, rawAst, state, dialect);
|
|
@@ -2936,8 +4707,11 @@ var renderExpression = (expression, state, dialect) => {
|
|
|
2936
4707
|
const renderComparisonOperator = (operator) => operator === "eq" ? "=" : operator === "neq" ? "<>" : operator === "lt" ? "<" : operator === "lte" ? "<=" : operator === "gt" ? ">" : ">=";
|
|
2937
4708
|
switch (ast.kind) {
|
|
2938
4709
|
case "column":
|
|
2939
|
-
return ast.tableName.length === 0 ? dialect.quoteIdentifier(ast.columnName) : `${dialect.quoteIdentifier(ast.tableName)}.${dialect.quoteIdentifier(ast.columnName)}`;
|
|
4710
|
+
return state.rowLocalColumns || ast.tableName.length === 0 ? dialect.quoteIdentifier(ast.columnName) : `${dialect.quoteIdentifier(ast.tableName)}.${dialect.quoteIdentifier(ast.columnName)}`;
|
|
2940
4711
|
case "literal":
|
|
4712
|
+
if (typeof ast.value === "number" && !Number.isFinite(ast.value)) {
|
|
4713
|
+
throw new Error("Expected a finite numeric value");
|
|
4714
|
+
}
|
|
2941
4715
|
return dialect.renderLiteral(ast.value, state, expression[TypeId2]);
|
|
2942
4716
|
case "excluded":
|
|
2943
4717
|
return dialect.name === "mysql" ? `values(${dialect.quoteIdentifier(ast.columnName)})` : `excluded.${dialect.quoteIdentifier(ast.columnName)}`;
|
|
@@ -2977,6 +4751,7 @@ var renderExpression = (expression, state, dialect) => {
|
|
|
2977
4751
|
return dialect.name === "mysql" ? `(${renderExpression(ast.left, state, dialect)} <=> ${renderExpression(ast.right, state, dialect)})` : `(${renderExpression(ast.left, state, dialect)} is not distinct from ${renderExpression(ast.right, state, dialect)})`;
|
|
2978
4752
|
case "contains":
|
|
2979
4753
|
if (dialect.name === "postgres") {
|
|
4754
|
+
assertCompatiblePostgresRangeOperands(ast.left, ast.right);
|
|
2980
4755
|
const left = isJsonExpression(ast.left) ? renderPostgresJsonValue(ast.left, state, dialect) : renderExpression(ast.left, state, dialect);
|
|
2981
4756
|
const right = isJsonExpression(ast.right) ? renderPostgresJsonValue(ast.right, state, dialect) : renderExpression(ast.right, state, dialect);
|
|
2982
4757
|
return `(${left} @> ${right})`;
|
|
@@ -2987,6 +4762,7 @@ var renderExpression = (expression, state, dialect) => {
|
|
|
2987
4762
|
throw new Error("Unsupported container operator for SQL rendering");
|
|
2988
4763
|
case "containedBy":
|
|
2989
4764
|
if (dialect.name === "postgres") {
|
|
4765
|
+
assertCompatiblePostgresRangeOperands(ast.left, ast.right);
|
|
2990
4766
|
const left = isJsonExpression(ast.left) ? renderPostgresJsonValue(ast.left, state, dialect) : renderExpression(ast.left, state, dialect);
|
|
2991
4767
|
const right = isJsonExpression(ast.right) ? renderPostgresJsonValue(ast.right, state, dialect) : renderExpression(ast.right, state, dialect);
|
|
2992
4768
|
return `(${left} <@ ${right})`;
|
|
@@ -2997,6 +4773,7 @@ var renderExpression = (expression, state, dialect) => {
|
|
|
2997
4773
|
throw new Error("Unsupported container operator for SQL rendering");
|
|
2998
4774
|
case "overlaps":
|
|
2999
4775
|
if (dialect.name === "postgres") {
|
|
4776
|
+
assertCompatiblePostgresRangeOperands(ast.left, ast.right);
|
|
3000
4777
|
const left = isJsonExpression(ast.left) ? renderPostgresJsonValue(ast.left, state, dialect) : renderExpression(ast.left, state, dialect);
|
|
3001
4778
|
const right = isJsonExpression(ast.right) ? renderPostgresJsonValue(ast.right, state, dialect) : renderExpression(ast.right, state, dialect);
|
|
3002
4779
|
return `(${left} && ${right})`;
|
|
@@ -3022,14 +4799,26 @@ var renderExpression = (expression, state, dialect) => {
|
|
|
3022
4799
|
case "min":
|
|
3023
4800
|
return `min(${renderExpression(ast.value, state, dialect)})`;
|
|
3024
4801
|
case "and":
|
|
4802
|
+
if (ast.values.length === 0) {
|
|
4803
|
+
throw new Error("and(...) requires at least one predicate");
|
|
4804
|
+
}
|
|
3025
4805
|
return `(${ast.values.map((value) => renderExpression(value, state, dialect)).join(" and ")})`;
|
|
3026
4806
|
case "or":
|
|
4807
|
+
if (ast.values.length === 0) {
|
|
4808
|
+
throw new Error("or(...) requires at least one predicate");
|
|
4809
|
+
}
|
|
3027
4810
|
return `(${ast.values.map((value) => renderExpression(value, state, dialect)).join(" or ")})`;
|
|
3028
4811
|
case "coalesce":
|
|
3029
4812
|
return `coalesce(${ast.values.map((value) => renderExpression(value, state, dialect)).join(", ")})`;
|
|
3030
4813
|
case "in":
|
|
4814
|
+
if (ast.values.length < 2) {
|
|
4815
|
+
throw new Error("in(...) requires at least one candidate value");
|
|
4816
|
+
}
|
|
3031
4817
|
return `(${renderExpression(ast.values[0], state, dialect)} in (${ast.values.slice(1).map((value) => renderExpression(value, state, dialect)).join(", ")}))`;
|
|
3032
4818
|
case "notIn":
|
|
4819
|
+
if (ast.values.length < 2) {
|
|
4820
|
+
throw new Error("notIn(...) requires at least one candidate value");
|
|
4821
|
+
}
|
|
3033
4822
|
return `(${renderExpression(ast.values[0], state, dialect)} not in (${ast.values.slice(1).map((value) => renderExpression(value, state, dialect)).join(", ")}))`;
|
|
3034
4823
|
case "between":
|
|
3035
4824
|
return `(${renderExpression(ast.values[0], state, dialect)} between ${renderExpression(ast.values[1], state, dialect)} and ${renderExpression(ast.values[2], state, dialect)})`;
|
|
@@ -3038,15 +4827,15 @@ var renderExpression = (expression, state, dialect) => {
|
|
|
3038
4827
|
case "case":
|
|
3039
4828
|
return `case ${ast.branches.map((branch) => `when ${renderExpression(branch.when, state, dialect)} then ${renderExpression(branch.then, state, dialect)}`).join(" ")} else ${renderExpression(ast.else, state, dialect)} end`;
|
|
3040
4829
|
case "exists":
|
|
3041
|
-
return `exists (${
|
|
4830
|
+
return `exists (${renderSubqueryExpressionPlan(ast.plan, state, dialect)})`;
|
|
3042
4831
|
case "scalarSubquery":
|
|
3043
|
-
return `(${
|
|
4832
|
+
return `(${renderSubqueryExpressionPlan(ast.plan, state, dialect)})`;
|
|
3044
4833
|
case "inSubquery":
|
|
3045
|
-
return `(${renderExpression(ast.left, state, dialect)} in (${
|
|
4834
|
+
return `(${renderExpression(ast.left, state, dialect)} in (${renderSubqueryExpressionPlan(ast.plan, state, dialect)}))`;
|
|
3046
4835
|
case "comparisonAny":
|
|
3047
|
-
return `(${renderExpression(ast.left, state, dialect)} ${renderComparisonOperator(ast.operator)} any (${
|
|
4836
|
+
return `(${renderExpression(ast.left, state, dialect)} ${renderComparisonOperator(ast.operator)} any (${renderSubqueryExpressionPlan(ast.plan, state, dialect)}))`;
|
|
3048
4837
|
case "comparisonAll":
|
|
3049
|
-
return `(${renderExpression(ast.left, state, dialect)} ${renderComparisonOperator(ast.operator)} all (${
|
|
4838
|
+
return `(${renderExpression(ast.left, state, dialect)} ${renderComparisonOperator(ast.operator)} all (${renderSubqueryExpressionPlan(ast.plan, state, dialect)}))`;
|
|
3050
4839
|
case "window": {
|
|
3051
4840
|
if (!Array.isArray(ast.partitionBy) || !Array.isArray(ast.orderBy) || typeof ast.function !== "string") {
|
|
3052
4841
|
break;
|
|
@@ -3131,7 +4920,8 @@ var inlineLiteralDialect = {
|
|
|
3131
4920
|
var renderDdlExpressionSql = (expression) => isSchemaExpression(expression) ? render(expression) : renderExpression(expression, {
|
|
3132
4921
|
params: [],
|
|
3133
4922
|
ctes: [],
|
|
3134
|
-
cteNames: new Set
|
|
4923
|
+
cteNames: new Set,
|
|
4924
|
+
cteSources: new Map
|
|
3135
4925
|
}, inlineLiteralDialect);
|
|
3136
4926
|
var stripRedundantOuterParens = (value) => {
|
|
3137
4927
|
let current = value.trim();
|
|
@@ -3182,10 +4972,14 @@ var normalizeDdlExpressionSql = (expression) => {
|
|
|
3182
4972
|
};
|
|
3183
4973
|
|
|
3184
4974
|
// src/postgres/schema-management.ts
|
|
3185
|
-
import * as
|
|
4975
|
+
import * as Schema6 from "effect/Schema";
|
|
3186
4976
|
import { pipeArguments as pipeArguments5 } from "effect/Pipeable";
|
|
3187
4977
|
var EnumTypeId = Symbol.for("effect-qb/SchemaManagement/Enum");
|
|
3188
4978
|
var SequenceTypeId = Symbol.for("effect-qb/SchemaManagement/Sequence");
|
|
4979
|
+
var safeUnquotedIdentifier = /^[a-z_][a-z0-9_$]*$/;
|
|
4980
|
+
var quoteIdentifier2 = (value) => `"${value.replaceAll('"', '""')}"`;
|
|
4981
|
+
var renderIdentifier = (value) => safeUnquotedIdentifier.test(value) ? value : quoteIdentifier2(value);
|
|
4982
|
+
var renderQualifiedTypeName = (name, schemaName) => schemaName === undefined || schemaName === "public" ? renderIdentifier(name) : `${renderIdentifier(schemaName)}.${renderIdentifier(name)}`;
|
|
3189
4983
|
var EnumProto = {
|
|
3190
4984
|
pipe() {
|
|
3191
4985
|
return pipeArguments5(this, arguments);
|
|
@@ -3196,13 +4990,13 @@ var EnumProto = {
|
|
|
3196
4990
|
type() {
|
|
3197
4991
|
return {
|
|
3198
4992
|
dialect: "postgres",
|
|
3199
|
-
kind: this.
|
|
4993
|
+
kind: renderQualifiedTypeName(this.name, this.schemaName),
|
|
3200
4994
|
variant: "enum"
|
|
3201
4995
|
};
|
|
3202
4996
|
},
|
|
3203
4997
|
column() {
|
|
3204
|
-
const values = this.values.map((value) =>
|
|
3205
|
-
return makeColumnDefinition(values.length === 1 ? values[0] :
|
|
4998
|
+
const values = this.values.map((value) => Schema6.Literal(value));
|
|
4999
|
+
return makeColumnDefinition(values.length === 1 ? values[0] : Schema6.Union(...values), {
|
|
3206
5000
|
dbType: this.type(),
|
|
3207
5001
|
nullable: false,
|
|
3208
5002
|
hasDefault: false,
|
|
@@ -3210,7 +5004,7 @@ var EnumProto = {
|
|
|
3210
5004
|
primaryKey: false,
|
|
3211
5005
|
unique: false,
|
|
3212
5006
|
references: undefined,
|
|
3213
|
-
ddlType: this.
|
|
5007
|
+
ddlType: renderQualifiedTypeName(this.name, this.schemaName),
|
|
3214
5008
|
identity: undefined,
|
|
3215
5009
|
enum: {
|
|
3216
5010
|
name: this.name,
|
|
@@ -3311,17 +5105,17 @@ var fromDiscoveredValues = (values) => {
|
|
|
3311
5105
|
const enums = new Map;
|
|
3312
5106
|
for (const value of values) {
|
|
3313
5107
|
if (isEnumDefinition(value)) {
|
|
3314
|
-
enums.set(
|
|
5108
|
+
enums.set(modelIdentityKey(value.schemaName, value.name), toEnumModel(value));
|
|
3315
5109
|
} else if (isTableDefinition(value)) {
|
|
3316
5110
|
for (const enumModel of enumModelsOfTable(value)) {
|
|
3317
|
-
const key2 =
|
|
5111
|
+
const key2 = modelIdentityKey(enumModel.schemaName, enumModel.name);
|
|
3318
5112
|
const existing = enums.get(key2);
|
|
3319
5113
|
if (existing === undefined) {
|
|
3320
5114
|
enums.set(key2, enumModel);
|
|
3321
5115
|
continue;
|
|
3322
5116
|
}
|
|
3323
5117
|
if (JSON.stringify(existing.values) !== JSON.stringify(enumModel.values)) {
|
|
3324
|
-
throw new Error(`Conflicting enum definitions discovered for '${
|
|
5118
|
+
throw new Error(`Conflicting enum definitions discovered for '${enumKey(enumModel.schemaName, enumModel.name)}'`);
|
|
3325
5119
|
}
|
|
3326
5120
|
}
|
|
3327
5121
|
}
|
|
@@ -3334,6 +5128,7 @@ var fromDiscoveredValues = (values) => {
|
|
|
3334
5128
|
};
|
|
3335
5129
|
var tableKey = (schemaName, name) => `${schemaName ?? "public"}.${name}`;
|
|
3336
5130
|
var enumKey = (schemaName, name) => `${schemaName ?? "public"}.${name}`;
|
|
5131
|
+
var modelIdentityKey = (schemaName, name) => JSON.stringify([schemaName ?? "public", name]);
|
|
3337
5132
|
export {
|
|
3338
5133
|
toTableModel,
|
|
3339
5134
|
toEnumModel,
|