@prisma/client-engine-runtime 7.10.0-dev.20 → 7.10.0-dev.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +123 -91
- package/dist/index.d.ts +123 -91
- package/dist/index.js +268 -23
- package/dist/index.mjs +268 -23
- package/dist/interpreter/query-interpreter.d.ts +20 -1
- package/dist/interpreter/query-interpreter.test.d.ts +1 -0
- package/dist/query-plan.d.ts +61 -31
- package/dist/utils.d.ts +5 -0
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -145,6 +145,16 @@ function safeJsonStringify(obj) {
|
|
|
145
145
|
return val;
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
|
+
var MAX_PUSH_SPREAD_ARGS = 8192;
|
|
149
|
+
function appendToArray(target, source) {
|
|
150
|
+
if (source.length <= MAX_PUSH_SPREAD_ARGS) {
|
|
151
|
+
target.push(...source);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
for (let i = 0; i < source.length; i += MAX_PUSH_SPREAD_ARGS) {
|
|
155
|
+
target.push(...source.slice(i, i + MAX_PUSH_SPREAD_ARGS));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
148
158
|
|
|
149
159
|
// src/json-protocol.ts
|
|
150
160
|
function normalizeJsonProtocolValues(result) {
|
|
@@ -1148,8 +1158,9 @@ function renderTemplateSql(fragments, placeholderFormat, params, argTypes) {
|
|
|
1148
1158
|
if (fragment.type === "stringChunk") {
|
|
1149
1159
|
continue;
|
|
1150
1160
|
}
|
|
1151
|
-
const
|
|
1152
|
-
const added =
|
|
1161
|
+
const fragmentParams = Array.from(flattenedFragmentParams(fragment));
|
|
1162
|
+
const added = fragmentParams.length;
|
|
1163
|
+
appendToArray(flattenedParams, fragmentParams);
|
|
1153
1164
|
if (fragment.argType.arity === "tuple") {
|
|
1154
1165
|
if (added % fragment.argType.elements.length !== 0) {
|
|
1155
1166
|
throw new Error(
|
|
@@ -1612,17 +1623,27 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1612
1623
|
});
|
|
1613
1624
|
}
|
|
1614
1625
|
async run(queryPlan, options) {
|
|
1615
|
-
const
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1626
|
+
const generators = this.#generators.snapshot();
|
|
1627
|
+
const context = { ...options, generators };
|
|
1628
|
+
const purified = purifyQueryPlan(queryPlan, (node) => this.interpretNode(node, context))?.catch(
|
|
1629
|
+
(e) => rethrowAsUserFacing(e)
|
|
1630
|
+
);
|
|
1631
|
+
if (purified) {
|
|
1632
|
+
try {
|
|
1633
|
+
return this.#interpretPureNode(await purified, context.scope, generators).value;
|
|
1634
|
+
} catch (e) {
|
|
1635
|
+
rethrowAsUserFacing(e);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
const { value } = await this.interpretNode(queryPlan, context).catch((e) => rethrowAsUserFacing(e));
|
|
1619
1639
|
return value;
|
|
1620
1640
|
}
|
|
1621
1641
|
async interpretNode(node, context) {
|
|
1622
1642
|
switch (node.type) {
|
|
1623
1643
|
case "value": {
|
|
1624
1644
|
return {
|
|
1625
|
-
value: evaluateArg(node.args, context.scope, context.generators)
|
|
1645
|
+
value: evaluateArg(node.args, context.scope, context.generators),
|
|
1646
|
+
lastInsertId: node.lastInsertId
|
|
1626
1647
|
};
|
|
1627
1648
|
}
|
|
1628
1649
|
case "seq": {
|
|
@@ -1632,9 +1653,6 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1632
1653
|
}
|
|
1633
1654
|
return result ?? { value: void 0 };
|
|
1634
1655
|
}
|
|
1635
|
-
case "get": {
|
|
1636
|
-
return { value: context.scope[node.args.name] };
|
|
1637
|
-
}
|
|
1638
1656
|
case "let": {
|
|
1639
1657
|
const nestedScope = Object.create(context.scope);
|
|
1640
1658
|
for (const binding of node.args.bindings) {
|
|
@@ -1643,15 +1661,6 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1643
1661
|
}
|
|
1644
1662
|
return this.interpretNode(node.args.expr, { ...context, scope: nestedScope });
|
|
1645
1663
|
}
|
|
1646
|
-
case "getFirstNonEmpty": {
|
|
1647
|
-
for (const name of node.args.names) {
|
|
1648
|
-
const value = context.scope[name];
|
|
1649
|
-
if (!isEmpty(value)) {
|
|
1650
|
-
return { value };
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
return { value: [] };
|
|
1654
|
-
}
|
|
1655
1664
|
case "concat": {
|
|
1656
1665
|
const parts = await Promise.all(
|
|
1657
1666
|
node.args.map((arg) => this.interpretNode(arg, context).then((res) => res.value))
|
|
@@ -1698,7 +1707,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1698
1707
|
if (results === void 0) {
|
|
1699
1708
|
results = result;
|
|
1700
1709
|
} else {
|
|
1701
|
-
results.rows
|
|
1710
|
+
appendToArray(results.rows, result.rows);
|
|
1702
1711
|
results.lastInsertId = result.lastInsertId;
|
|
1703
1712
|
}
|
|
1704
1713
|
}
|
|
@@ -1778,9 +1787,6 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1778
1787
|
return await this.interpretNode(node.args.else, context);
|
|
1779
1788
|
}
|
|
1780
1789
|
}
|
|
1781
|
-
case "unit": {
|
|
1782
|
-
return { value: void 0 };
|
|
1783
|
-
}
|
|
1784
1790
|
case "diff": {
|
|
1785
1791
|
const { value: from } = await this.interpretNode(node.args.from, context);
|
|
1786
1792
|
const { value: to } = await this.interpretNode(node.args.to, context);
|
|
@@ -1810,6 +1816,139 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1810
1816
|
}
|
|
1811
1817
|
return { value: record, lastInsertId };
|
|
1812
1818
|
}
|
|
1819
|
+
default:
|
|
1820
|
+
return this.#interpretPureNode(node, context.scope, context.generators);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
#interpretPureNode(node, scope, generators) {
|
|
1824
|
+
switch (node.type) {
|
|
1825
|
+
case "value": {
|
|
1826
|
+
return { value: evaluateArg(node.args, scope, generators), lastInsertId: node.lastInsertId };
|
|
1827
|
+
}
|
|
1828
|
+
case "seq": {
|
|
1829
|
+
let result;
|
|
1830
|
+
for (const arg of node.args) {
|
|
1831
|
+
result = this.#interpretPureNode(arg, scope, generators);
|
|
1832
|
+
}
|
|
1833
|
+
return result ?? { value: void 0 };
|
|
1834
|
+
}
|
|
1835
|
+
case "get": {
|
|
1836
|
+
return { value: scope[node.args.name] };
|
|
1837
|
+
}
|
|
1838
|
+
case "let": {
|
|
1839
|
+
const nestedScope = Object.create(scope);
|
|
1840
|
+
for (const binding of node.args.bindings) {
|
|
1841
|
+
const { value } = this.#interpretPureNode(binding.expr, nestedScope, generators);
|
|
1842
|
+
nestedScope[binding.name] = value;
|
|
1843
|
+
}
|
|
1844
|
+
return this.#interpretPureNode(node.args.expr, nestedScope, generators);
|
|
1845
|
+
}
|
|
1846
|
+
case "getFirstNonEmpty": {
|
|
1847
|
+
for (const name of node.args.names) {
|
|
1848
|
+
const value = scope[name];
|
|
1849
|
+
if (!isEmpty(value)) {
|
|
1850
|
+
return { value };
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
return { value: [] };
|
|
1854
|
+
}
|
|
1855
|
+
case "concat": {
|
|
1856
|
+
const parts = node.args.map((arg) => this.#interpretPureNode(arg, scope, generators).value);
|
|
1857
|
+
return {
|
|
1858
|
+
value: parts.length > 0 ? parts.reduce((acc, part) => acc.concat(asList(part)), []) : []
|
|
1859
|
+
};
|
|
1860
|
+
}
|
|
1861
|
+
case "sum": {
|
|
1862
|
+
const parts = node.args.map((arg) => this.#interpretPureNode(arg, scope, generators).value);
|
|
1863
|
+
return {
|
|
1864
|
+
value: parts.length > 0 ? parts.reduce((acc, part) => asNumber2(acc) + asNumber2(part)) : 0
|
|
1865
|
+
};
|
|
1866
|
+
}
|
|
1867
|
+
case "reverse": {
|
|
1868
|
+
const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
|
|
1869
|
+
return { value: Array.isArray(value) ? value.reverse() : value, lastInsertId };
|
|
1870
|
+
}
|
|
1871
|
+
case "unique": {
|
|
1872
|
+
const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
|
|
1873
|
+
if (!Array.isArray(value)) {
|
|
1874
|
+
return { value, lastInsertId };
|
|
1875
|
+
}
|
|
1876
|
+
if (value.length > 1) {
|
|
1877
|
+
throw new Error(`Expected zero or one element, got ${value.length}`);
|
|
1878
|
+
}
|
|
1879
|
+
return { value: value[0] ?? null, lastInsertId };
|
|
1880
|
+
}
|
|
1881
|
+
case "required": {
|
|
1882
|
+
const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
|
|
1883
|
+
if (isEmpty(value)) {
|
|
1884
|
+
throw new Error("Required value is empty");
|
|
1885
|
+
}
|
|
1886
|
+
return { value, lastInsertId };
|
|
1887
|
+
}
|
|
1888
|
+
case "mapField": {
|
|
1889
|
+
const { value, lastInsertId } = this.#interpretPureNode(node.args.records, scope, generators);
|
|
1890
|
+
return { value: mapField2(value, node.args.field), lastInsertId };
|
|
1891
|
+
}
|
|
1892
|
+
case "join": {
|
|
1893
|
+
const { value: parent, lastInsertId } = this.#interpretPureNode(node.args.parent, scope, generators);
|
|
1894
|
+
if (parent === null) {
|
|
1895
|
+
return { value: null, lastInsertId };
|
|
1896
|
+
}
|
|
1897
|
+
const children = node.args.children.map((joinExpr) => ({
|
|
1898
|
+
joinExpr,
|
|
1899
|
+
childRecords: this.#interpretPureNode(joinExpr.child, scope, generators).value
|
|
1900
|
+
}));
|
|
1901
|
+
return { value: attachChildrenToParents(parent, children, node.args.canAssumeStrictEquality), lastInsertId };
|
|
1902
|
+
}
|
|
1903
|
+
case "dataMap": {
|
|
1904
|
+
const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
|
|
1905
|
+
return { value: applyDataMap(value, node.args.structure, node.args.enums), lastInsertId };
|
|
1906
|
+
}
|
|
1907
|
+
case "validate": {
|
|
1908
|
+
const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
|
|
1909
|
+
performValidation(value, node.args.rules, node.args);
|
|
1910
|
+
return { value, lastInsertId };
|
|
1911
|
+
}
|
|
1912
|
+
case "if": {
|
|
1913
|
+
const { value } = this.#interpretPureNode(node.args.value, scope, generators);
|
|
1914
|
+
if (doesSatisfyRule(value, node.args.rule)) {
|
|
1915
|
+
return this.#interpretPureNode(node.args.then, scope, generators);
|
|
1916
|
+
} else {
|
|
1917
|
+
return this.#interpretPureNode(node.args.else, scope, generators);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
case "unit": {
|
|
1921
|
+
return { value: void 0 };
|
|
1922
|
+
}
|
|
1923
|
+
case "diff": {
|
|
1924
|
+
const { value: from } = this.#interpretPureNode(node.args.from, scope, generators);
|
|
1925
|
+
const { value: to } = this.#interpretPureNode(node.args.to, scope, generators);
|
|
1926
|
+
const keyGetter = (item) => item !== null ? getRecordKey(asRecord(item), node.args.fields) : null;
|
|
1927
|
+
const toSet = new Set(asList(to).map(keyGetter));
|
|
1928
|
+
return { value: asList(from).filter((item) => !toSet.has(keyGetter(item))) };
|
|
1929
|
+
}
|
|
1930
|
+
case "process": {
|
|
1931
|
+
const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
|
|
1932
|
+
const ops = cloneObject(node.args.operations);
|
|
1933
|
+
evaluateProcessingParameters(ops, scope, generators);
|
|
1934
|
+
return { value: processRecords(value, ops), lastInsertId };
|
|
1935
|
+
}
|
|
1936
|
+
case "initializeRecord": {
|
|
1937
|
+
const { lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
|
|
1938
|
+
const record = {};
|
|
1939
|
+
for (const [key, initializer] of Object.entries(node.args.fields)) {
|
|
1940
|
+
record[key] = evalFieldInitializer(initializer, lastInsertId, scope, generators);
|
|
1941
|
+
}
|
|
1942
|
+
return { value: record, lastInsertId };
|
|
1943
|
+
}
|
|
1944
|
+
case "mapRecord": {
|
|
1945
|
+
const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
|
|
1946
|
+
const record = value === null ? {} : asRecord(value);
|
|
1947
|
+
for (const [key, entry] of Object.entries(node.args.fields)) {
|
|
1948
|
+
record[key] = evalFieldOperation(entry, record[key], scope, generators);
|
|
1949
|
+
}
|
|
1950
|
+
return { value: record, lastInsertId };
|
|
1951
|
+
}
|
|
1813
1952
|
default:
|
|
1814
1953
|
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
1815
1954
|
}
|
|
@@ -1987,6 +2126,112 @@ function evalFieldOperation(op, value, scope, generators) {
|
|
|
1987
2126
|
assertNever(op, `Unexpected field operation type: ${op["type"]}`);
|
|
1988
2127
|
}
|
|
1989
2128
|
}
|
|
2129
|
+
function purifyQueryPlan(node, evalNode) {
|
|
2130
|
+
const impureNode = findUniqueUnconditionalImpureNode(node);
|
|
2131
|
+
if (!impureNode) {
|
|
2132
|
+
return void 0;
|
|
2133
|
+
}
|
|
2134
|
+
return evalNode(impureNode).then((result) => {
|
|
2135
|
+
const evaluated = {
|
|
2136
|
+
type: "value",
|
|
2137
|
+
args: result.value,
|
|
2138
|
+
lastInsertId: result.lastInsertId
|
|
2139
|
+
};
|
|
2140
|
+
const purified = replaceImpureNode(node, impureNode, evaluated);
|
|
2141
|
+
if (!purified) {
|
|
2142
|
+
throw new Error("Could not substitute the evaluated impure node into the query plan");
|
|
2143
|
+
}
|
|
2144
|
+
return purified;
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
function replaceImpureNode(node, target, replacement) {
|
|
2148
|
+
if (node === target) {
|
|
2149
|
+
return replacement;
|
|
2150
|
+
}
|
|
2151
|
+
switch (node.type) {
|
|
2152
|
+
case "seq":
|
|
2153
|
+
case "sum":
|
|
2154
|
+
case "concat": {
|
|
2155
|
+
for (let i = 0; i < node.args.length; i++) {
|
|
2156
|
+
const child = replaceImpureNode(node.args[i], target, replacement);
|
|
2157
|
+
if (child) {
|
|
2158
|
+
return { ...node, args: node.args.map((arg, j) => j === i ? child : arg) };
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
return void 0;
|
|
2162
|
+
}
|
|
2163
|
+
case "dataMap":
|
|
2164
|
+
case "validate":
|
|
2165
|
+
case "initializeRecord":
|
|
2166
|
+
case "mapRecord":
|
|
2167
|
+
case "process": {
|
|
2168
|
+
const expr = replaceImpureNode(node.args.expr, target, replacement);
|
|
2169
|
+
return expr && { ...node, args: { ...node.args, expr } };
|
|
2170
|
+
}
|
|
2171
|
+
case "mapField": {
|
|
2172
|
+
const records = replaceImpureNode(node.args.records, target, replacement);
|
|
2173
|
+
return records && { ...node, args: { ...node.args, records } };
|
|
2174
|
+
}
|
|
2175
|
+
case "reverse":
|
|
2176
|
+
case "unique":
|
|
2177
|
+
case "required": {
|
|
2178
|
+
const args = replaceImpureNode(node.args, target, replacement);
|
|
2179
|
+
return args && { ...node, args };
|
|
2180
|
+
}
|
|
2181
|
+
default:
|
|
2182
|
+
return void 0;
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
function findUniqueUnconditionalImpureNode(node) {
|
|
2186
|
+
switch (node.type) {
|
|
2187
|
+
case "query":
|
|
2188
|
+
case "execute":
|
|
2189
|
+
return node;
|
|
2190
|
+
case "seq":
|
|
2191
|
+
case "sum":
|
|
2192
|
+
case "concat": {
|
|
2193
|
+
let found = void 0;
|
|
2194
|
+
for (const child of node.args) {
|
|
2195
|
+
const childFound = findUniqueUnconditionalImpureNode(child);
|
|
2196
|
+
if (childFound === null) {
|
|
2197
|
+
return null;
|
|
2198
|
+
}
|
|
2199
|
+
if (childFound) {
|
|
2200
|
+
if (found) {
|
|
2201
|
+
return null;
|
|
2202
|
+
}
|
|
2203
|
+
found = childFound;
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
return found;
|
|
2207
|
+
}
|
|
2208
|
+
case "dataMap":
|
|
2209
|
+
case "validate":
|
|
2210
|
+
case "initializeRecord":
|
|
2211
|
+
case "mapRecord":
|
|
2212
|
+
case "process":
|
|
2213
|
+
return findUniqueUnconditionalImpureNode(node.args.expr);
|
|
2214
|
+
case "mapField":
|
|
2215
|
+
return findUniqueUnconditionalImpureNode(node.args.records);
|
|
2216
|
+
case "reverse":
|
|
2217
|
+
case "unique":
|
|
2218
|
+
case "required":
|
|
2219
|
+
return findUniqueUnconditionalImpureNode(node.args);
|
|
2220
|
+
case "let":
|
|
2221
|
+
case "join":
|
|
2222
|
+
case "diff":
|
|
2223
|
+
case "if":
|
|
2224
|
+
case "transaction":
|
|
2225
|
+
return null;
|
|
2226
|
+
case "value":
|
|
2227
|
+
case "get":
|
|
2228
|
+
case "getFirstNonEmpty":
|
|
2229
|
+
case "unit":
|
|
2230
|
+
return void 0;
|
|
2231
|
+
default:
|
|
2232
|
+
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
1990
2235
|
function applyComments(query, sqlCommenter) {
|
|
1991
2236
|
if (!sqlCommenter || sqlCommenter.plugins.length === 0) {
|
|
1992
2237
|
return query;
|