@prisma/client-engine-runtime 7.4.1 → 7.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/events.d.ts +1 -1
- package/dist/index.d.mts +16 -8
- package/dist/index.d.ts +16 -8
- package/dist/index.js +62 -13
- package/dist/index.mjs +62 -13
- package/dist/interpreter/in-memory-processing.d.ts +1 -1
- package/dist/interpreter/query-interpreter.d.ts +2 -1
- package/dist/interpreter/render-query.d.ts +2 -1
- package/dist/interpreter/validation.d.ts +2 -1
- package/dist/query-plan.d.ts +10 -6
- package/dist/tracing.d.ts +2 -1
- package/dist/utils.d.ts +6 -0
- package/package.json +5 -5
package/dist/events.d.ts
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -80,6 +80,10 @@ export declare type DecimalTaggedValue = {
|
|
|
80
80
|
value: string;
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
+
declare type DeepReadonly<T> = T extends undefined | null | boolean | string | number | symbol | Function | Date ? T : T extends Array<infer U> ? ReadonlyArray<DeepReadonly<U>> : unknown extends T ? unknown : {
|
|
84
|
+
readonly [K in keyof T]: DeepReadonly<T[K]>;
|
|
85
|
+
};
|
|
86
|
+
|
|
83
87
|
export declare function deserializeJsonObject(result: unknown): unknown;
|
|
84
88
|
|
|
85
89
|
/**
|
|
@@ -155,6 +159,9 @@ export declare type Fragment = {
|
|
|
155
159
|
type: 'parameter';
|
|
156
160
|
} | {
|
|
157
161
|
type: 'parameterTuple';
|
|
162
|
+
itemPrefix: string;
|
|
163
|
+
itemSeparator: string;
|
|
164
|
+
itemSuffix: string;
|
|
158
165
|
} | {
|
|
159
166
|
type: 'parameterTupleList';
|
|
160
167
|
itemPrefix: string;
|
|
@@ -243,7 +250,7 @@ export declare type PrismaValuePlaceholder = {
|
|
|
243
250
|
export declare type QueryEvent = {
|
|
244
251
|
timestamp: Date;
|
|
245
252
|
query: string;
|
|
246
|
-
params: unknown[];
|
|
253
|
+
params: readonly unknown[];
|
|
247
254
|
duration: number;
|
|
248
255
|
};
|
|
249
256
|
|
|
@@ -256,7 +263,7 @@ export declare class QueryInterpreter {
|
|
|
256
263
|
provider?: SchemaProvider;
|
|
257
264
|
connectionInfo?: ConnectionInfo;
|
|
258
265
|
}): QueryInterpreter;
|
|
259
|
-
run(queryPlan: QueryPlanNode
|
|
266
|
+
run(queryPlan: DeepReadonly<QueryPlanNode>, options: QueryRuntimeOptions): Promise<unknown>;
|
|
260
267
|
private interpretNode;
|
|
261
268
|
}
|
|
262
269
|
|
|
@@ -348,6 +355,7 @@ export declare type QueryPlanNode = {
|
|
|
348
355
|
args: {
|
|
349
356
|
parent: QueryPlanNode;
|
|
350
357
|
children: JoinExpression[];
|
|
358
|
+
canAssumeStrictEquality: boolean;
|
|
351
359
|
};
|
|
352
360
|
} | {
|
|
353
361
|
type: 'mapField';
|
|
@@ -516,14 +524,14 @@ export declare class UserFacingError extends Error {
|
|
|
516
524
|
}
|
|
517
525
|
|
|
518
526
|
export declare type ValidationError = {
|
|
519
|
-
|
|
527
|
+
errorIdentifier: 'RELATION_VIOLATION';
|
|
520
528
|
context: {
|
|
521
529
|
relation: string;
|
|
522
530
|
modelA: string;
|
|
523
531
|
modelB: string;
|
|
524
532
|
};
|
|
525
533
|
} | {
|
|
526
|
-
|
|
534
|
+
errorIdentifier: 'MISSING_RELATED_RECORD';
|
|
527
535
|
context: {
|
|
528
536
|
model: string;
|
|
529
537
|
relation: string;
|
|
@@ -532,24 +540,24 @@ export declare type ValidationError = {
|
|
|
532
540
|
neededFor?: string;
|
|
533
541
|
};
|
|
534
542
|
} | {
|
|
535
|
-
|
|
543
|
+
errorIdentifier: 'MISSING_RECORD';
|
|
536
544
|
context: {
|
|
537
545
|
operation: string;
|
|
538
546
|
};
|
|
539
547
|
} | {
|
|
540
|
-
|
|
548
|
+
errorIdentifier: 'INCOMPLETE_CONNECT_INPUT';
|
|
541
549
|
context: {
|
|
542
550
|
expectedRows: number;
|
|
543
551
|
};
|
|
544
552
|
} | {
|
|
545
|
-
|
|
553
|
+
errorIdentifier: 'INCOMPLETE_CONNECT_OUTPUT';
|
|
546
554
|
context: {
|
|
547
555
|
expectedRows: number;
|
|
548
556
|
relation: string;
|
|
549
557
|
relationType: string;
|
|
550
558
|
};
|
|
551
559
|
} | {
|
|
552
|
-
|
|
560
|
+
errorIdentifier: 'RECORDS_NOT_CONNECTED';
|
|
553
561
|
context: {
|
|
554
562
|
relation: string;
|
|
555
563
|
parent: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -80,6 +80,10 @@ export declare type DecimalTaggedValue = {
|
|
|
80
80
|
value: string;
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
+
declare type DeepReadonly<T> = T extends undefined | null | boolean | string | number | symbol | Function | Date ? T : T extends Array<infer U> ? ReadonlyArray<DeepReadonly<U>> : unknown extends T ? unknown : {
|
|
84
|
+
readonly [K in keyof T]: DeepReadonly<T[K]>;
|
|
85
|
+
};
|
|
86
|
+
|
|
83
87
|
export declare function deserializeJsonObject(result: unknown): unknown;
|
|
84
88
|
|
|
85
89
|
/**
|
|
@@ -155,6 +159,9 @@ export declare type Fragment = {
|
|
|
155
159
|
type: 'parameter';
|
|
156
160
|
} | {
|
|
157
161
|
type: 'parameterTuple';
|
|
162
|
+
itemPrefix: string;
|
|
163
|
+
itemSeparator: string;
|
|
164
|
+
itemSuffix: string;
|
|
158
165
|
} | {
|
|
159
166
|
type: 'parameterTupleList';
|
|
160
167
|
itemPrefix: string;
|
|
@@ -243,7 +250,7 @@ export declare type PrismaValuePlaceholder = {
|
|
|
243
250
|
export declare type QueryEvent = {
|
|
244
251
|
timestamp: Date;
|
|
245
252
|
query: string;
|
|
246
|
-
params: unknown[];
|
|
253
|
+
params: readonly unknown[];
|
|
247
254
|
duration: number;
|
|
248
255
|
};
|
|
249
256
|
|
|
@@ -256,7 +263,7 @@ export declare class QueryInterpreter {
|
|
|
256
263
|
provider?: SchemaProvider;
|
|
257
264
|
connectionInfo?: ConnectionInfo;
|
|
258
265
|
}): QueryInterpreter;
|
|
259
|
-
run(queryPlan: QueryPlanNode
|
|
266
|
+
run(queryPlan: DeepReadonly<QueryPlanNode>, options: QueryRuntimeOptions): Promise<unknown>;
|
|
260
267
|
private interpretNode;
|
|
261
268
|
}
|
|
262
269
|
|
|
@@ -348,6 +355,7 @@ export declare type QueryPlanNode = {
|
|
|
348
355
|
args: {
|
|
349
356
|
parent: QueryPlanNode;
|
|
350
357
|
children: JoinExpression[];
|
|
358
|
+
canAssumeStrictEquality: boolean;
|
|
351
359
|
};
|
|
352
360
|
} | {
|
|
353
361
|
type: 'mapField';
|
|
@@ -516,14 +524,14 @@ export declare class UserFacingError extends Error {
|
|
|
516
524
|
}
|
|
517
525
|
|
|
518
526
|
export declare type ValidationError = {
|
|
519
|
-
|
|
527
|
+
errorIdentifier: 'RELATION_VIOLATION';
|
|
520
528
|
context: {
|
|
521
529
|
relation: string;
|
|
522
530
|
modelA: string;
|
|
523
531
|
modelB: string;
|
|
524
532
|
};
|
|
525
533
|
} | {
|
|
526
|
-
|
|
534
|
+
errorIdentifier: 'MISSING_RELATED_RECORD';
|
|
527
535
|
context: {
|
|
528
536
|
model: string;
|
|
529
537
|
relation: string;
|
|
@@ -532,24 +540,24 @@ export declare type ValidationError = {
|
|
|
532
540
|
neededFor?: string;
|
|
533
541
|
};
|
|
534
542
|
} | {
|
|
535
|
-
|
|
543
|
+
errorIdentifier: 'MISSING_RECORD';
|
|
536
544
|
context: {
|
|
537
545
|
operation: string;
|
|
538
546
|
};
|
|
539
547
|
} | {
|
|
540
|
-
|
|
548
|
+
errorIdentifier: 'INCOMPLETE_CONNECT_INPUT';
|
|
541
549
|
context: {
|
|
542
550
|
expectedRows: number;
|
|
543
551
|
};
|
|
544
552
|
} | {
|
|
545
|
-
|
|
553
|
+
errorIdentifier: 'INCOMPLETE_CONNECT_OUTPUT';
|
|
546
554
|
context: {
|
|
547
555
|
expectedRows: number;
|
|
548
556
|
relation: string;
|
|
549
557
|
relationType: string;
|
|
550
558
|
};
|
|
551
559
|
} | {
|
|
552
|
-
|
|
560
|
+
errorIdentifier: 'RECORDS_NOT_CONNECTED';
|
|
553
561
|
context: {
|
|
554
562
|
relation: string;
|
|
555
563
|
parent: string;
|
package/dist/index.js
CHANGED
|
@@ -757,6 +757,9 @@ function normalizeDateTime(dt) {
|
|
|
757
757
|
return dtWithTz;
|
|
758
758
|
}
|
|
759
759
|
|
|
760
|
+
// src/interpreter/query-interpreter.ts
|
|
761
|
+
var import_klona2 = require("klona");
|
|
762
|
+
|
|
760
763
|
// src/sql-commenter.ts
|
|
761
764
|
var import_klona = require("klona");
|
|
762
765
|
function formatSqlComment(tags) {
|
|
@@ -1040,8 +1043,11 @@ function paginateSingleList(list, { cursor, skip, take }) {
|
|
|
1040
1043
|
const end = take !== null ? start + take : list.length;
|
|
1041
1044
|
return list.slice(start, end);
|
|
1042
1045
|
}
|
|
1043
|
-
function getRecordKey(record, fields) {
|
|
1044
|
-
|
|
1046
|
+
function getRecordKey(record, fields, mappers) {
|
|
1047
|
+
const array = fields.map(
|
|
1048
|
+
(field, index) => mappers?.[index] ? record[field] !== null ? mappers[index](record[field]) : null : record[field]
|
|
1049
|
+
);
|
|
1050
|
+
return JSON.stringify(array);
|
|
1045
1051
|
}
|
|
1046
1052
|
|
|
1047
1053
|
// src/query-plan.ts
|
|
@@ -1136,7 +1142,10 @@ function renderFragment(fragment, placeholderFormat, ctx) {
|
|
|
1136
1142
|
case "stringChunk":
|
|
1137
1143
|
return fragment.chunk;
|
|
1138
1144
|
case "parameterTuple": {
|
|
1139
|
-
const placeholders = fragment.value.length == 0 ? "NULL" : fragment.value.map(() =>
|
|
1145
|
+
const placeholders = fragment.value.length == 0 ? "NULL" : fragment.value.map(() => {
|
|
1146
|
+
const item = formatPlaceholder(placeholderFormat, ctx.placeholderNumber++);
|
|
1147
|
+
return `${fragment.itemPrefix}${item}${fragment.itemSuffix}`;
|
|
1148
|
+
}).join(fragment.itemSeparator);
|
|
1140
1149
|
return `(${placeholders})`;
|
|
1141
1150
|
}
|
|
1142
1151
|
case "parameterTupleList": {
|
|
@@ -1495,7 +1504,7 @@ function doesSatisfyRule(data, rule) {
|
|
|
1495
1504
|
}
|
|
1496
1505
|
}
|
|
1497
1506
|
function renderMessage(data, error) {
|
|
1498
|
-
switch (error.
|
|
1507
|
+
switch (error.errorIdentifier) {
|
|
1499
1508
|
case "RELATION_VIOLATION":
|
|
1500
1509
|
return `The change you are trying to make would violate the required relation '${error.context.relation}' between the \`${error.context.modelA}\` and \`${error.context.modelB}\` models.`;
|
|
1501
1510
|
case "MISSING_RECORD":
|
|
@@ -1515,7 +1524,7 @@ function renderMessage(data, error) {
|
|
|
1515
1524
|
}
|
|
1516
1525
|
}
|
|
1517
1526
|
function getErrorCode2(error) {
|
|
1518
|
-
switch (error.
|
|
1527
|
+
switch (error.errorIdentifier) {
|
|
1519
1528
|
case "RELATION_VIOLATION":
|
|
1520
1529
|
return "P2014";
|
|
1521
1530
|
case "RECORDS_NOT_CONNECTED":
|
|
@@ -1630,7 +1639,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1630
1639
|
sum += await this.#withQuerySpanAndEvent(
|
|
1631
1640
|
commentedQuery,
|
|
1632
1641
|
context.queryable,
|
|
1633
|
-
() => context.queryable.executeRaw(commentedQuery).catch(
|
|
1642
|
+
() => context.queryable.executeRaw(cloneObject(commentedQuery)).catch(
|
|
1634
1643
|
(err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
|
|
1635
1644
|
)
|
|
1636
1645
|
);
|
|
@@ -1645,7 +1654,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1645
1654
|
const result = await this.#withQuerySpanAndEvent(
|
|
1646
1655
|
commentedQuery,
|
|
1647
1656
|
context.queryable,
|
|
1648
|
-
() => context.queryable.queryRaw(commentedQuery).catch(
|
|
1657
|
+
() => context.queryable.queryRaw(cloneObject(commentedQuery)).catch(
|
|
1649
1658
|
(err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
|
|
1650
1659
|
)
|
|
1651
1660
|
);
|
|
@@ -1697,7 +1706,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1697
1706
|
childRecords: (await this.interpretNode(joinExpr.child, context)).value
|
|
1698
1707
|
}))
|
|
1699
1708
|
);
|
|
1700
|
-
return { value: attachChildrenToParents(parent, children), lastInsertId };
|
|
1709
|
+
return { value: attachChildrenToParents(parent, children, node.args.canAssumeStrictEquality), lastInsertId };
|
|
1701
1710
|
}
|
|
1702
1711
|
case "transaction": {
|
|
1703
1712
|
if (!context.transactionManager.enabled) {
|
|
@@ -1744,8 +1753,9 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1744
1753
|
}
|
|
1745
1754
|
case "process": {
|
|
1746
1755
|
const { value, lastInsertId } = await this.interpretNode(node.args.expr, context);
|
|
1747
|
-
|
|
1748
|
-
|
|
1756
|
+
const ops = cloneObject(node.args.operations);
|
|
1757
|
+
evaluateProcessingParameters(ops, context.scope, context.generators);
|
|
1758
|
+
return { value: processRecords(value, ops), lastInsertId };
|
|
1749
1759
|
}
|
|
1750
1760
|
case "initializeRecord": {
|
|
1751
1761
|
const { lastInsertId } = await this.interpretNode(node.args.expr, context);
|
|
@@ -1838,12 +1848,13 @@ function mapField2(value, field) {
|
|
|
1838
1848
|
}
|
|
1839
1849
|
return value;
|
|
1840
1850
|
}
|
|
1841
|
-
function attachChildrenToParents(parentRecords, children) {
|
|
1851
|
+
function attachChildrenToParents(parentRecords, children, canAssumeStrictEquality) {
|
|
1842
1852
|
for (const { joinExpr, childRecords } of children) {
|
|
1843
1853
|
const parentKeys = joinExpr.on.map(([k]) => k);
|
|
1844
1854
|
const childKeys = joinExpr.on.map(([, k]) => k);
|
|
1845
1855
|
const parentMap = {};
|
|
1846
|
-
|
|
1856
|
+
const parentArray = Array.isArray(parentRecords) ? parentRecords : [parentRecords];
|
|
1857
|
+
for (const parent of parentArray) {
|
|
1847
1858
|
const parentRecord = asRecord(parent);
|
|
1848
1859
|
const key = getRecordKey(parentRecord, parentKeys);
|
|
1849
1860
|
if (!parentMap[key]) {
|
|
@@ -1856,11 +1867,12 @@ function attachChildrenToParents(parentRecords, children) {
|
|
|
1856
1867
|
parentRecord[joinExpr.parentField] = [];
|
|
1857
1868
|
}
|
|
1858
1869
|
}
|
|
1870
|
+
const mappers = canAssumeStrictEquality ? void 0 : inferKeyCasts(parentArray, parentKeys);
|
|
1859
1871
|
for (const childRecord of Array.isArray(childRecords) ? childRecords : [childRecords]) {
|
|
1860
1872
|
if (childRecord === null) {
|
|
1861
1873
|
continue;
|
|
1862
1874
|
}
|
|
1863
|
-
const key = getRecordKey(asRecord(childRecord), childKeys);
|
|
1875
|
+
const key = getRecordKey(asRecord(childRecord), childKeys, mappers);
|
|
1864
1876
|
for (const parentRecord of parentMap[key] ?? []) {
|
|
1865
1877
|
if (joinExpr.isRelationUnique) {
|
|
1866
1878
|
parentRecord[joinExpr.parentField] = childRecord;
|
|
@@ -1872,6 +1884,40 @@ function attachChildrenToParents(parentRecords, children) {
|
|
|
1872
1884
|
}
|
|
1873
1885
|
return parentRecords;
|
|
1874
1886
|
}
|
|
1887
|
+
function inferKeyCasts(rows, keys) {
|
|
1888
|
+
function getKeyCast(type) {
|
|
1889
|
+
switch (type) {
|
|
1890
|
+
case "number":
|
|
1891
|
+
return Number;
|
|
1892
|
+
case "string":
|
|
1893
|
+
return String;
|
|
1894
|
+
case "boolean":
|
|
1895
|
+
return Boolean;
|
|
1896
|
+
case "bigint":
|
|
1897
|
+
return BigInt;
|
|
1898
|
+
default:
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
const keyCasts = Array.from({ length: keys.length });
|
|
1903
|
+
let keysFound = 0;
|
|
1904
|
+
for (const parent of rows) {
|
|
1905
|
+
const parentRecord = asRecord(parent);
|
|
1906
|
+
for (const [i, key] of keys.entries()) {
|
|
1907
|
+
if (parentRecord[key] !== null && keyCasts[i] === void 0) {
|
|
1908
|
+
const keyCast = getKeyCast(typeof parentRecord[key]);
|
|
1909
|
+
if (keyCast !== void 0) {
|
|
1910
|
+
keyCasts[i] = keyCast;
|
|
1911
|
+
}
|
|
1912
|
+
keysFound++;
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
if (keysFound === keys.length) {
|
|
1916
|
+
break;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
return keyCasts;
|
|
1920
|
+
}
|
|
1875
1921
|
function evalFieldInitializer(initializer, lastInsertId, scope, generators) {
|
|
1876
1922
|
switch (initializer.type) {
|
|
1877
1923
|
case "value":
|
|
@@ -1931,6 +1977,9 @@ function evaluateProcessingParameters(ops, scope, generators) {
|
|
|
1931
1977
|
evaluateProcessingParameters(nested, scope, generators);
|
|
1932
1978
|
}
|
|
1933
1979
|
}
|
|
1980
|
+
function cloneObject(value) {
|
|
1981
|
+
return (0, import_klona2.klona)(value);
|
|
1982
|
+
}
|
|
1934
1983
|
|
|
1935
1984
|
// src/raw-json-protocol.ts
|
|
1936
1985
|
var import_client_runtime_utils4 = require("@prisma/client-runtime-utils");
|
package/dist/index.mjs
CHANGED
|
@@ -706,6 +706,9 @@ function normalizeDateTime(dt) {
|
|
|
706
706
|
return dtWithTz;
|
|
707
707
|
}
|
|
708
708
|
|
|
709
|
+
// src/interpreter/query-interpreter.ts
|
|
710
|
+
import { klona as klona2 } from "klona";
|
|
711
|
+
|
|
709
712
|
// src/sql-commenter.ts
|
|
710
713
|
import { klona } from "klona";
|
|
711
714
|
function formatSqlComment(tags) {
|
|
@@ -989,8 +992,11 @@ function paginateSingleList(list, { cursor, skip, take }) {
|
|
|
989
992
|
const end = take !== null ? start + take : list.length;
|
|
990
993
|
return list.slice(start, end);
|
|
991
994
|
}
|
|
992
|
-
function getRecordKey(record, fields) {
|
|
993
|
-
|
|
995
|
+
function getRecordKey(record, fields, mappers) {
|
|
996
|
+
const array = fields.map(
|
|
997
|
+
(field, index) => mappers?.[index] ? record[field] !== null ? mappers[index](record[field]) : null : record[field]
|
|
998
|
+
);
|
|
999
|
+
return JSON.stringify(array);
|
|
994
1000
|
}
|
|
995
1001
|
|
|
996
1002
|
// src/query-plan.ts
|
|
@@ -1085,7 +1091,10 @@ function renderFragment(fragment, placeholderFormat, ctx) {
|
|
|
1085
1091
|
case "stringChunk":
|
|
1086
1092
|
return fragment.chunk;
|
|
1087
1093
|
case "parameterTuple": {
|
|
1088
|
-
const placeholders = fragment.value.length == 0 ? "NULL" : fragment.value.map(() =>
|
|
1094
|
+
const placeholders = fragment.value.length == 0 ? "NULL" : fragment.value.map(() => {
|
|
1095
|
+
const item = formatPlaceholder(placeholderFormat, ctx.placeholderNumber++);
|
|
1096
|
+
return `${fragment.itemPrefix}${item}${fragment.itemSuffix}`;
|
|
1097
|
+
}).join(fragment.itemSeparator);
|
|
1089
1098
|
return `(${placeholders})`;
|
|
1090
1099
|
}
|
|
1091
1100
|
case "parameterTupleList": {
|
|
@@ -1444,7 +1453,7 @@ function doesSatisfyRule(data, rule) {
|
|
|
1444
1453
|
}
|
|
1445
1454
|
}
|
|
1446
1455
|
function renderMessage(data, error) {
|
|
1447
|
-
switch (error.
|
|
1456
|
+
switch (error.errorIdentifier) {
|
|
1448
1457
|
case "RELATION_VIOLATION":
|
|
1449
1458
|
return `The change you are trying to make would violate the required relation '${error.context.relation}' between the \`${error.context.modelA}\` and \`${error.context.modelB}\` models.`;
|
|
1450
1459
|
case "MISSING_RECORD":
|
|
@@ -1464,7 +1473,7 @@ function renderMessage(data, error) {
|
|
|
1464
1473
|
}
|
|
1465
1474
|
}
|
|
1466
1475
|
function getErrorCode2(error) {
|
|
1467
|
-
switch (error.
|
|
1476
|
+
switch (error.errorIdentifier) {
|
|
1468
1477
|
case "RELATION_VIOLATION":
|
|
1469
1478
|
return "P2014";
|
|
1470
1479
|
case "RECORDS_NOT_CONNECTED":
|
|
@@ -1579,7 +1588,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1579
1588
|
sum += await this.#withQuerySpanAndEvent(
|
|
1580
1589
|
commentedQuery,
|
|
1581
1590
|
context.queryable,
|
|
1582
|
-
() => context.queryable.executeRaw(commentedQuery).catch(
|
|
1591
|
+
() => context.queryable.executeRaw(cloneObject(commentedQuery)).catch(
|
|
1583
1592
|
(err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
|
|
1584
1593
|
)
|
|
1585
1594
|
);
|
|
@@ -1594,7 +1603,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1594
1603
|
const result = await this.#withQuerySpanAndEvent(
|
|
1595
1604
|
commentedQuery,
|
|
1596
1605
|
context.queryable,
|
|
1597
|
-
() => context.queryable.queryRaw(commentedQuery).catch(
|
|
1606
|
+
() => context.queryable.queryRaw(cloneObject(commentedQuery)).catch(
|
|
1598
1607
|
(err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
|
|
1599
1608
|
)
|
|
1600
1609
|
);
|
|
@@ -1646,7 +1655,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1646
1655
|
childRecords: (await this.interpretNode(joinExpr.child, context)).value
|
|
1647
1656
|
}))
|
|
1648
1657
|
);
|
|
1649
|
-
return { value: attachChildrenToParents(parent, children), lastInsertId };
|
|
1658
|
+
return { value: attachChildrenToParents(parent, children, node.args.canAssumeStrictEquality), lastInsertId };
|
|
1650
1659
|
}
|
|
1651
1660
|
case "transaction": {
|
|
1652
1661
|
if (!context.transactionManager.enabled) {
|
|
@@ -1693,8 +1702,9 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1693
1702
|
}
|
|
1694
1703
|
case "process": {
|
|
1695
1704
|
const { value, lastInsertId } = await this.interpretNode(node.args.expr, context);
|
|
1696
|
-
|
|
1697
|
-
|
|
1705
|
+
const ops = cloneObject(node.args.operations);
|
|
1706
|
+
evaluateProcessingParameters(ops, context.scope, context.generators);
|
|
1707
|
+
return { value: processRecords(value, ops), lastInsertId };
|
|
1698
1708
|
}
|
|
1699
1709
|
case "initializeRecord": {
|
|
1700
1710
|
const { lastInsertId } = await this.interpretNode(node.args.expr, context);
|
|
@@ -1787,12 +1797,13 @@ function mapField2(value, field) {
|
|
|
1787
1797
|
}
|
|
1788
1798
|
return value;
|
|
1789
1799
|
}
|
|
1790
|
-
function attachChildrenToParents(parentRecords, children) {
|
|
1800
|
+
function attachChildrenToParents(parentRecords, children, canAssumeStrictEquality) {
|
|
1791
1801
|
for (const { joinExpr, childRecords } of children) {
|
|
1792
1802
|
const parentKeys = joinExpr.on.map(([k]) => k);
|
|
1793
1803
|
const childKeys = joinExpr.on.map(([, k]) => k);
|
|
1794
1804
|
const parentMap = {};
|
|
1795
|
-
|
|
1805
|
+
const parentArray = Array.isArray(parentRecords) ? parentRecords : [parentRecords];
|
|
1806
|
+
for (const parent of parentArray) {
|
|
1796
1807
|
const parentRecord = asRecord(parent);
|
|
1797
1808
|
const key = getRecordKey(parentRecord, parentKeys);
|
|
1798
1809
|
if (!parentMap[key]) {
|
|
@@ -1805,11 +1816,12 @@ function attachChildrenToParents(parentRecords, children) {
|
|
|
1805
1816
|
parentRecord[joinExpr.parentField] = [];
|
|
1806
1817
|
}
|
|
1807
1818
|
}
|
|
1819
|
+
const mappers = canAssumeStrictEquality ? void 0 : inferKeyCasts(parentArray, parentKeys);
|
|
1808
1820
|
for (const childRecord of Array.isArray(childRecords) ? childRecords : [childRecords]) {
|
|
1809
1821
|
if (childRecord === null) {
|
|
1810
1822
|
continue;
|
|
1811
1823
|
}
|
|
1812
|
-
const key = getRecordKey(asRecord(childRecord), childKeys);
|
|
1824
|
+
const key = getRecordKey(asRecord(childRecord), childKeys, mappers);
|
|
1813
1825
|
for (const parentRecord of parentMap[key] ?? []) {
|
|
1814
1826
|
if (joinExpr.isRelationUnique) {
|
|
1815
1827
|
parentRecord[joinExpr.parentField] = childRecord;
|
|
@@ -1821,6 +1833,40 @@ function attachChildrenToParents(parentRecords, children) {
|
|
|
1821
1833
|
}
|
|
1822
1834
|
return parentRecords;
|
|
1823
1835
|
}
|
|
1836
|
+
function inferKeyCasts(rows, keys) {
|
|
1837
|
+
function getKeyCast(type) {
|
|
1838
|
+
switch (type) {
|
|
1839
|
+
case "number":
|
|
1840
|
+
return Number;
|
|
1841
|
+
case "string":
|
|
1842
|
+
return String;
|
|
1843
|
+
case "boolean":
|
|
1844
|
+
return Boolean;
|
|
1845
|
+
case "bigint":
|
|
1846
|
+
return BigInt;
|
|
1847
|
+
default:
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
const keyCasts = Array.from({ length: keys.length });
|
|
1852
|
+
let keysFound = 0;
|
|
1853
|
+
for (const parent of rows) {
|
|
1854
|
+
const parentRecord = asRecord(parent);
|
|
1855
|
+
for (const [i, key] of keys.entries()) {
|
|
1856
|
+
if (parentRecord[key] !== null && keyCasts[i] === void 0) {
|
|
1857
|
+
const keyCast = getKeyCast(typeof parentRecord[key]);
|
|
1858
|
+
if (keyCast !== void 0) {
|
|
1859
|
+
keyCasts[i] = keyCast;
|
|
1860
|
+
}
|
|
1861
|
+
keysFound++;
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
if (keysFound === keys.length) {
|
|
1865
|
+
break;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
return keyCasts;
|
|
1869
|
+
}
|
|
1824
1870
|
function evalFieldInitializer(initializer, lastInsertId, scope, generators) {
|
|
1825
1871
|
switch (initializer.type) {
|
|
1826
1872
|
case "value":
|
|
@@ -1880,6 +1926,9 @@ function evaluateProcessingParameters(ops, scope, generators) {
|
|
|
1880
1926
|
evaluateProcessingParameters(nested, scope, generators);
|
|
1881
1927
|
}
|
|
1882
1928
|
}
|
|
1929
|
+
function cloneObject(value) {
|
|
1930
|
+
return klona2(value);
|
|
1931
|
+
}
|
|
1883
1932
|
|
|
1884
1933
|
// src/raw-json-protocol.ts
|
|
1885
1934
|
import { Decimal as Decimal4 } from "@prisma/client-runtime-utils";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { InMemoryOps } from '../query-plan';
|
|
2
2
|
export declare function processRecords(value: unknown, ops: InMemoryOps): unknown;
|
|
3
|
-
export declare function getRecordKey(record: {}, fields: string[]): string;
|
|
3
|
+
export declare function getRecordKey(record: {}, fields: readonly string[], mappers?: ((value: unknown) => unknown)[]): string;
|
|
@@ -5,6 +5,7 @@ import { QueryPlanNode } from '../query-plan';
|
|
|
5
5
|
import { type SchemaProvider } from '../schema';
|
|
6
6
|
import { type TracingHelper } from '../tracing';
|
|
7
7
|
import { type TransactionManager } from '../transaction-manager/transaction-manager';
|
|
8
|
+
import { DeepReadonly } from '../utils';
|
|
8
9
|
import { Value } from './scope';
|
|
9
10
|
export type QueryInterpreterTransactionManager = {
|
|
10
11
|
enabled: true;
|
|
@@ -39,6 +40,6 @@ export declare class QueryInterpreter {
|
|
|
39
40
|
provider?: SchemaProvider;
|
|
40
41
|
connectionInfo?: ConnectionInfo;
|
|
41
42
|
}): QueryInterpreter;
|
|
42
|
-
run(queryPlan: QueryPlanNode
|
|
43
|
+
run(queryPlan: DeepReadonly<QueryPlanNode>, options: QueryRuntimeOptions): Promise<unknown>;
|
|
43
44
|
private interpretNode;
|
|
44
45
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SqlQuery } from '@prisma/driver-adapter-utils';
|
|
2
2
|
import { type QueryPlanDbQuery } from '../query-plan';
|
|
3
|
+
import { DeepReadonly } from '../utils';
|
|
3
4
|
import { GeneratorRegistrySnapshot } from './generators';
|
|
4
5
|
import { ScopeBindings } from './scope';
|
|
5
|
-
export declare function renderQuery(dbQuery: QueryPlanDbQuery
|
|
6
|
+
export declare function renderQuery(dbQuery: DeepReadonly<QueryPlanDbQuery>, scope: ScopeBindings, generators: GeneratorRegistrySnapshot, maxChunkSize?: number): DeepReadonly<SqlQuery>[];
|
|
6
7
|
export declare function evaluateArg(arg: unknown, scope: ScopeBindings, generators: GeneratorRegistrySnapshot): unknown;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { DataRule, ValidationError } from '../query-plan';
|
|
2
|
-
|
|
2
|
+
import { DeepReadonly } from '../utils';
|
|
3
|
+
export declare function performValidation(data: unknown, rules: DeepReadonly<DataRule[]>, error: ValidationError): void;
|
|
3
4
|
export declare function doesSatisfyRule(data: unknown, rule: DataRule): boolean;
|
package/dist/query-plan.d.ts
CHANGED
|
@@ -56,6 +56,9 @@ export type Fragment = {
|
|
|
56
56
|
type: 'parameter';
|
|
57
57
|
} | {
|
|
58
58
|
type: 'parameterTuple';
|
|
59
|
+
itemPrefix: string;
|
|
60
|
+
itemSeparator: string;
|
|
61
|
+
itemSuffix: string;
|
|
59
62
|
} | {
|
|
60
63
|
type: 'parameterTupleList';
|
|
61
64
|
itemPrefix: string;
|
|
@@ -121,6 +124,7 @@ export type QueryPlanNode = {
|
|
|
121
124
|
args: {
|
|
122
125
|
parent: QueryPlanNode;
|
|
123
126
|
children: JoinExpression[];
|
|
127
|
+
canAssumeStrictEquality: boolean;
|
|
124
128
|
};
|
|
125
129
|
} | {
|
|
126
130
|
type: 'mapField';
|
|
@@ -227,14 +231,14 @@ export type DataRule = {
|
|
|
227
231
|
type: 'never';
|
|
228
232
|
};
|
|
229
233
|
export type ValidationError = {
|
|
230
|
-
|
|
234
|
+
errorIdentifier: 'RELATION_VIOLATION';
|
|
231
235
|
context: {
|
|
232
236
|
relation: string;
|
|
233
237
|
modelA: string;
|
|
234
238
|
modelB: string;
|
|
235
239
|
};
|
|
236
240
|
} | {
|
|
237
|
-
|
|
241
|
+
errorIdentifier: 'MISSING_RELATED_RECORD';
|
|
238
242
|
context: {
|
|
239
243
|
model: string;
|
|
240
244
|
relation: string;
|
|
@@ -243,24 +247,24 @@ export type ValidationError = {
|
|
|
243
247
|
neededFor?: string;
|
|
244
248
|
};
|
|
245
249
|
} | {
|
|
246
|
-
|
|
250
|
+
errorIdentifier: 'MISSING_RECORD';
|
|
247
251
|
context: {
|
|
248
252
|
operation: string;
|
|
249
253
|
};
|
|
250
254
|
} | {
|
|
251
|
-
|
|
255
|
+
errorIdentifier: 'INCOMPLETE_CONNECT_INPUT';
|
|
252
256
|
context: {
|
|
253
257
|
expectedRows: number;
|
|
254
258
|
};
|
|
255
259
|
} | {
|
|
256
|
-
|
|
260
|
+
errorIdentifier: 'INCOMPLETE_CONNECT_OUTPUT';
|
|
257
261
|
context: {
|
|
258
262
|
expectedRows: number;
|
|
259
263
|
relation: string;
|
|
260
264
|
relationType: string;
|
|
261
265
|
};
|
|
262
266
|
} | {
|
|
263
|
-
|
|
267
|
+
errorIdentifier: 'RECORDS_NOT_CONNECTED';
|
|
264
268
|
context: {
|
|
265
269
|
relation: string;
|
|
266
270
|
parent: string;
|
package/dist/tracing.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type Context, type Span, type SpanOptions } from '@opentelemetry/api';
|
|
|
2
2
|
import type { SqlQuery } from '@prisma/driver-adapter-utils';
|
|
3
3
|
import { QueryEvent } from './events';
|
|
4
4
|
import type { SchemaProvider } from './schema';
|
|
5
|
+
import { DeepReadonly } from './utils';
|
|
5
6
|
export type SpanCallback<R> = (span?: Span, context?: Context) => R;
|
|
6
7
|
export type ExtendedSpanOptions = SpanOptions & {
|
|
7
8
|
name: string;
|
|
@@ -13,7 +14,7 @@ export interface TracingHelper {
|
|
|
13
14
|
export declare const noopTracingHelper: TracingHelper;
|
|
14
15
|
export declare function providerToOtelSystem(provider: SchemaProvider): string;
|
|
15
16
|
export declare function withQuerySpanAndEvent<T>({ query, tracingHelper, provider, onQuery, execute, }: {
|
|
16
|
-
query: SqlQuery
|
|
17
|
+
query: DeepReadonly<SqlQuery>;
|
|
17
18
|
tracingHelper: TracingHelper;
|
|
18
19
|
provider: SchemaProvider;
|
|
19
20
|
onQuery?: (event: QueryEvent) => void;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
export type DeepReadonly<T> = T extends undefined | null | boolean | string | number | symbol | Function | Date ? T : T extends Array<infer U> ? ReadonlyArray<DeepReadonly<U>> : unknown extends T ? unknown : {
|
|
2
|
+
readonly [K in keyof T]: DeepReadonly<T[K]>;
|
|
3
|
+
};
|
|
4
|
+
export type DeepUnreadonly<T> = T extends undefined | null | boolean | string | number | symbol | Function | Date ? T : T extends ReadonlyArray<infer U> ? Array<DeepUnreadonly<U>> : unknown extends T ? unknown : {
|
|
5
|
+
-readonly [K in keyof T]: DeepUnreadonly<T[K]>;
|
|
6
|
+
};
|
|
1
7
|
export declare function assertNever(_: never, message: string): never;
|
|
2
8
|
/**
|
|
3
9
|
* Checks if two objects are deeply equal, recursively checking all properties for strict equality.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/client-engine-runtime",
|
|
3
|
-
"version": "7.4.
|
|
3
|
+
"version": "7.4.2",
|
|
4
4
|
"description": "This package is intended for Prisma's internal use",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"nanoid": "5.1.5",
|
|
32
32
|
"ulid": "3.0.0",
|
|
33
33
|
"uuid": "11.1.0",
|
|
34
|
-
"@prisma/
|
|
35
|
-
"@prisma/
|
|
36
|
-
"@prisma/
|
|
37
|
-
"@prisma/
|
|
34
|
+
"@prisma/client-runtime-utils": "7.4.2",
|
|
35
|
+
"@prisma/driver-adapter-utils": "7.4.2",
|
|
36
|
+
"@prisma/debug": "7.4.2",
|
|
37
|
+
"@prisma/sqlcommenter": "7.4.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@codspeed/benchmark.js-plugin": "4.0.0",
|