@prisma/client-engine-runtime 6.9.0-dev.2 → 6.9.0-dev.20

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.mjs CHANGED
@@ -1,10 +1,144 @@
1
- // src/interpreter/QueryInterpreter.ts
2
- import { SpanKind } from "@opentelemetry/api";
1
+ // src/interpreter/DataMapper.ts
2
+ import Decimal2 from "decimal.js";
3
3
 
4
4
  // src/utils.ts
5
+ import Decimal from "decimal.js";
5
6
  function assertNever(_, message) {
6
7
  throw new Error(message);
7
8
  }
9
+ function isDeepStrictEqual(a, b) {
10
+ return a === b || a !== null && b !== null && typeof a === "object" && typeof b === "object" && Object.keys(a).length === Object.keys(b).length && Object.keys(a).every((key) => isDeepStrictEqual(a[key], b[key]));
11
+ }
12
+ function doKeysMatch(lhs, rhs) {
13
+ const lhsKeys = Object.keys(lhs);
14
+ const rhsKeys = Object.keys(rhs);
15
+ const smallerKeyList = lhsKeys.length < rhsKeys.length ? lhsKeys : rhsKeys;
16
+ return smallerKeyList.every((key) => {
17
+ if (typeof lhs[key] !== typeof rhs[key]) {
18
+ if (typeof lhs[key] === "number" || typeof rhs[key] === "number") {
19
+ return `${lhs[key]}` === `${rhs[key]}`;
20
+ } else if (typeof lhs[key] === "bigint" || typeof rhs[key] === "bigint") {
21
+ return BigInt(`${lhs[key]}`.replace(/n$/, "")) === BigInt(`${rhs[key]}`.replace(/n$/, ""));
22
+ } else if (lhs[key] instanceof Date || rhs[key] instanceof Date) {
23
+ return (/* @__PURE__ */ new Date(`${lhs[key]}`)).getTime() === (/* @__PURE__ */ new Date(`${rhs[key]}`)).getTime();
24
+ } else if (Decimal.isDecimal(lhs[key]) || Decimal.isDecimal(rhs[key])) {
25
+ return new Decimal(`${lhs[key]}`).equals(new Decimal(`${rhs[key]}`));
26
+ }
27
+ }
28
+ return isDeepStrictEqual(lhs[key], rhs[key]);
29
+ });
30
+ }
31
+
32
+ // src/interpreter/DataMapper.ts
33
+ var DataMapperError = class extends Error {
34
+ name = "DataMapperError";
35
+ };
36
+ function applyDataMap(data, structure) {
37
+ switch (structure.type) {
38
+ case "Object":
39
+ return mapArrayOrObject(data, structure.fields);
40
+ case "Value":
41
+ return mapValue(data, structure.resultType);
42
+ default:
43
+ assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
44
+ }
45
+ }
46
+ function mapArrayOrObject(data, fields) {
47
+ if (data === null) return null;
48
+ if (Array.isArray(data)) {
49
+ const rows = data;
50
+ return rows.map((row) => mapObject(row, fields));
51
+ }
52
+ if (typeof data === "object") {
53
+ const row = data;
54
+ return mapObject(row, fields);
55
+ }
56
+ if (typeof data === "string") {
57
+ let decodedData;
58
+ try {
59
+ decodedData = JSON.parse(data);
60
+ } catch (error) {
61
+ throw new DataMapperError(`Expected an array or object, got a string that is not valid JSON`, {
62
+ cause: error
63
+ });
64
+ }
65
+ return mapArrayOrObject(decodedData, fields);
66
+ }
67
+ throw new DataMapperError(`Expected an array or an object, got: ${typeof data}`);
68
+ }
69
+ function mapObject(data, fields) {
70
+ if (typeof data !== "object") {
71
+ throw new DataMapperError(`Expected an object, but got '${typeof data}'`);
72
+ }
73
+ const result = {};
74
+ for (const [name, node] of Object.entries(fields)) {
75
+ switch (node.type) {
76
+ case "Object": {
77
+ if (!node.flattened && !Object.hasOwn(data, name)) {
78
+ throw new DataMapperError(
79
+ `Missing data field (Object): '${name}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
80
+ );
81
+ }
82
+ const target = node.flattened ? data : data[name];
83
+ result[name] = mapArrayOrObject(target, node.fields);
84
+ break;
85
+ }
86
+ case "Value":
87
+ {
88
+ const dbName = node.dbName;
89
+ if (Object.hasOwn(data, dbName)) {
90
+ result[name] = mapValue(data[dbName], node.resultType);
91
+ } else {
92
+ throw new DataMapperError(
93
+ `Missing data field (Value): '${dbName}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
94
+ );
95
+ }
96
+ }
97
+ break;
98
+ default:
99
+ assertNever(node, `DataMapper: Invalid data mapping node type: '${node.type}'`);
100
+ }
101
+ }
102
+ return result;
103
+ }
104
+ function mapValue(value, resultType) {
105
+ if (value === null) return null;
106
+ switch (resultType.type) {
107
+ case "Any":
108
+ return value;
109
+ case "String":
110
+ return typeof value === "string" ? value : `${value}`;
111
+ case "Int":
112
+ return typeof value === "number" ? value : parseInt(`${value}`, 10);
113
+ case "BigInt":
114
+ return typeof value === "bigint" ? value : BigInt(`${value}`);
115
+ case "Float":
116
+ return typeof value === "number" ? value : parseFloat(`${value}`);
117
+ case "Boolean":
118
+ return typeof value === "boolean" ? value : value !== "0";
119
+ case "Decimal":
120
+ return typeof value === "number" ? new Decimal2(value) : new Decimal2(`${value}`);
121
+ case "Date":
122
+ return value instanceof Date ? value : /* @__PURE__ */ new Date(`${value}`);
123
+ case "Array": {
124
+ const values = value;
125
+ return values.map((v) => mapValue(v, resultType.inner));
126
+ }
127
+ case "Object":
128
+ return typeof value === "string" ? value : JSON.stringify(value);
129
+ case "Bytes": {
130
+ if (!Array.isArray(value)) {
131
+ throw new DataMapperError(`Bytes data is invalid, got: ${typeof value}`);
132
+ }
133
+ return new Uint8Array(value);
134
+ }
135
+ default:
136
+ assertNever(resultType, `DataMapper: Unknown result type: ${resultType.type}`);
137
+ }
138
+ }
139
+
140
+ // src/interpreter/QueryInterpreter.ts
141
+ import { SpanKind } from "@opentelemetry/api";
8
142
 
9
143
  // src/tracing.ts
10
144
  var noopTracingHelper = {
@@ -34,7 +168,7 @@ var UserFacingError = class extends Error {
34
168
  constructor(message, code, meta) {
35
169
  super(message);
36
170
  this.code = code;
37
- this.meta = meta;
171
+ this.meta = meta ?? {};
38
172
  }
39
173
  toQueryResponseErrorObject() {
40
174
  return {
@@ -57,7 +191,7 @@ function rethrowAsUserFacing(error) {
57
191
  if (!code || !message) {
58
192
  throw error;
59
193
  }
60
- throw new UserFacingError(message, code, error);
194
+ throw new UserFacingError(message, code, { driverAdapterError: error });
61
195
  }
62
196
  function getErrorCode(err) {
63
197
  switch (err.cause.kind) {
@@ -168,100 +302,6 @@ function renderConstraint(constraint) {
168
302
  return "(not available)";
169
303
  }
170
304
 
171
- // src/interpreter/DataMapper.ts
172
- import Decimal from "decimal.js";
173
- function applyDataMap(data, structure) {
174
- switch (structure.type) {
175
- case "Object":
176
- return mapArrayOrObject(data, structure.fields);
177
- case "Value":
178
- return mapValue(data, structure.resultType);
179
- default:
180
- assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
181
- }
182
- }
183
- function mapArrayOrObject(data, fields) {
184
- if (data === null) return null;
185
- if (Array.isArray(data)) {
186
- const rows = data;
187
- return rows.map((row) => mapObject(row, fields));
188
- }
189
- if (typeof data === "object") {
190
- const row = data;
191
- return mapObject(row, fields);
192
- }
193
- throw new Error(`DataMapper: Expected an array or an object, got: ${typeof data}`);
194
- }
195
- function mapObject(data, fields) {
196
- if (typeof data !== "object") {
197
- throw new Error(`DataMapper: Expected an object, but got '${typeof data}'`);
198
- }
199
- const result = {};
200
- for (const [name, node] of Object.entries(fields)) {
201
- switch (node.type) {
202
- case "Object":
203
- if (Object.hasOwn(data, name)) {
204
- result[name] = mapArrayOrObject(data[name], node.fields);
205
- } else {
206
- throw new Error(
207
- `DataMapper: Missing data field (Object): '${name}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
208
- );
209
- }
210
- break;
211
- case "Value":
212
- {
213
- const dbName = node.dbName;
214
- if (Object.hasOwn(data, dbName)) {
215
- result[name] = mapValue(data[dbName], node.resultType);
216
- } else {
217
- throw new Error(
218
- `DataMapper: Missing data field (Value): '${dbName}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
219
- );
220
- }
221
- }
222
- break;
223
- default:
224
- assertNever(node, `DataMapper: Invalid data mapping node type: '${node.type}'`);
225
- }
226
- }
227
- return result;
228
- }
229
- function mapValue(value, resultType) {
230
- if (value === null) return null;
231
- switch (resultType.type) {
232
- case "Any":
233
- return value;
234
- case "String":
235
- return typeof value === "string" ? value : `${value}`;
236
- case "Int":
237
- return typeof value === "number" ? value : parseInt(`${value}`, 10);
238
- case "BigInt":
239
- return typeof value === "bigint" ? value : BigInt(`${value}`);
240
- case "Float":
241
- return typeof value === "number" ? value : parseFloat(`${value}`);
242
- case "Boolean":
243
- return typeof value === "boolean" ? value : value !== "0";
244
- case "Decimal":
245
- return typeof value === "number" ? new Decimal(value) : new Decimal(`${value}`);
246
- case "Date":
247
- return value instanceof Date ? value : /* @__PURE__ */ new Date(`${value}`);
248
- case "Array": {
249
- const values = value;
250
- return values.map((v) => mapValue(v, resultType.inner));
251
- }
252
- case "Object":
253
- return typeof value === "string" ? value : JSON.stringify(value);
254
- case "Bytes": {
255
- if (!Array.isArray(value)) {
256
- throw new Error(`DataMapper: Bytes data is invalid, got: ${typeof value}`);
257
- }
258
- return new Uint8Array(value);
259
- }
260
- default:
261
- assertNever(resultType, `DataMapper: Unknown result type: ${resultType.type}`);
262
- }
263
- }
264
-
265
305
  // src/interpreter/generators.ts
266
306
  import cuid1 from "@bugsnag/cuid";
267
307
  import { createId as cuid2 } from "@paralleldrive/cuid2";
@@ -366,6 +406,9 @@ function isPrismaValueGenerator(value) {
366
406
  function isPrismaValueBytes(value) {
367
407
  return typeof value === "object" && value !== null && value["prisma__type"] === "bytes";
368
408
  }
409
+ function isPrismaValueBigInt(value) {
410
+ return typeof value === "object" && value !== null && value["prisma__type"] === "bigint";
411
+ }
369
412
 
370
413
  // src/interpreter/renderQuery.ts
371
414
  function renderQuery(dbQuery, scope, generators) {
@@ -408,9 +451,10 @@ function evaluateParam(param, scope, generators) {
408
451
  }
409
452
  if (Array.isArray(value)) {
410
453
  value = value.map((el) => evaluateParam(el, scope, generators));
411
- }
412
- if (isPrismaValueBytes(value)) {
454
+ } else if (isPrismaValueBytes(value)) {
413
455
  value = Buffer.from(value.prisma__value, "base64");
456
+ } else if (isPrismaValueBigInt(value)) {
457
+ value = BigInt(value.prisma__value);
414
458
  }
415
459
  return value;
416
460
  }
@@ -551,6 +595,8 @@ function doesSatisfyRule(data, rule) {
551
595
  return rule.args !== 0;
552
596
  }
553
597
  return rule.args !== 1;
598
+ case "affectedRowCountEq":
599
+ return data === rule.args;
554
600
  case "never":
555
601
  return false;
556
602
  default:
@@ -568,7 +614,9 @@ function renderMessage(data, error) {
568
614
  return `An operation failed because it depends on one or more records that were required but not found. No '${error.context.model}' record${hint} was found for ${error.context.operation} on ${error.context.relationType} relation '${error.context.relation}'.`;
569
615
  }
570
616
  case "INCOMPLETE_CONNECT_INPUT":
571
- return `An operation failed because it depends on one or more records that were required but not found. Expected ${error.context.expectedRows} records to be connected, found only ${Array.isArray(data) ? data.length : 0}.`;
617
+ return `An operation failed because it depends on one or more records that were required but not found. Expected ${error.context.expectedRows} records to be connected, found only ${Array.isArray(data) ? data.length : data}.`;
618
+ case "INCOMPLETE_CONNECT_OUTPUT":
619
+ return `The required connected records were not found. Expected ${error.context.expectedRows} records to be connected after connect operation on ${error.context.relationType} relation '${error.context.relation}', found ${Array.isArray(data) ? data.length : data}.`;
572
620
  case "RECORDS_NOT_CONNECTED":
573
621
  return `The records for relation \`${error.context.relation}\` between the \`${error.context.parent}\` and \`${error.context.child}\` models are not connected.`;
574
622
  default:
@@ -581,6 +629,8 @@ function getErrorCode2(error) {
581
629
  return "P2014";
582
630
  case "RECORDS_NOT_CONNECTED":
583
631
  return "P2017";
632
+ case "INCOMPLETE_CONNECT_OUTPUT":
633
+ return "P2018";
584
634
  case "MISSING_RECORD":
585
635
  case "MISSING_RELATED_RECORD":
586
636
  case "INCOMPLETE_CONNECT_INPUT":
@@ -622,8 +672,11 @@ var QueryInterpreter = class _QueryInterpreter {
622
672
  async interpretNode(node, queryable, scope, generators) {
623
673
  switch (node.type) {
624
674
  case "seq": {
625
- const results = await Promise.all(node.args.map((arg) => this.interpretNode(arg, queryable, scope, generators)));
626
- return results[results.length - 1];
675
+ let result;
676
+ for (const arg of node.args) {
677
+ result = await this.interpretNode(arg, queryable, scope, generators);
678
+ }
679
+ return result;
627
680
  }
628
681
  case "get": {
629
682
  return scope[node.args.name];
@@ -646,11 +699,11 @@ var QueryInterpreter = class _QueryInterpreter {
646
699
  }
647
700
  case "concat": {
648
701
  const parts = await Promise.all(node.args.map((arg) => this.interpretNode(arg, queryable, scope, generators)));
649
- return parts.reduce((acc, part) => acc.concat(asList(part)), []);
702
+ return parts.length > 0 ? parts.reduce((acc, part) => acc.concat(asList(part)), []) : [];
650
703
  }
651
704
  case "sum": {
652
705
  const parts = await Promise.all(node.args.map((arg) => this.interpretNode(arg, queryable, scope, generators)));
653
- return parts.reduce((acc, part) => asNumber(acc) + asNumber(part));
706
+ return parts.length > 0 ? parts.reduce((acc, part) => asNumber(acc) + asNumber(part)) : 0;
654
707
  }
655
708
  case "execute": {
656
709
  const query = renderQuery(node.args, scope, generators);
@@ -691,6 +744,9 @@ var QueryInterpreter = class _QueryInterpreter {
691
744
  }
692
745
  case "join": {
693
746
  const parent = await this.interpretNode(node.args.parent, queryable, scope, generators);
747
+ if (parent === null) {
748
+ return null;
749
+ }
694
750
  const children = await Promise.all(
695
751
  node.args.children.map(async (joinExpr) => ({
696
752
  joinExpr,
@@ -747,6 +803,38 @@ var QueryInterpreter = class _QueryInterpreter {
747
803
  const toSet = new Set(asList(to));
748
804
  return asList(from).filter((item) => !toSet.has(item));
749
805
  }
806
+ case "distinctBy": {
807
+ const value = await this.interpretNode(node.args.expr, queryable, scope, generators);
808
+ const seen = /* @__PURE__ */ new Set();
809
+ const result = [];
810
+ for (const item of asList(value)) {
811
+ const key = getRecordKey(item, node.args.fields);
812
+ if (!seen.has(key)) {
813
+ seen.add(key);
814
+ result.push(item);
815
+ }
816
+ }
817
+ return result;
818
+ }
819
+ case "paginate": {
820
+ const value = await this.interpretNode(node.args.expr, queryable, scope, generators);
821
+ const list = asList(value);
822
+ const linkingFields = node.args.pagination.linkingFields;
823
+ if (linkingFields !== null) {
824
+ const groupedByParent = /* @__PURE__ */ new Map();
825
+ for (const item of list) {
826
+ const parentKey = getRecordKey(item, linkingFields);
827
+ if (!groupedByParent.has(parentKey)) {
828
+ groupedByParent.set(parentKey, []);
829
+ }
830
+ groupedByParent.get(parentKey).push(item);
831
+ }
832
+ const groupList = Array.from(groupedByParent.entries());
833
+ groupList.sort(([aId], [bId]) => aId < bId ? -1 : aId > bId ? 1 : 0);
834
+ return groupList.flatMap(([, elems]) => paginate(elems, node.args.pagination));
835
+ }
836
+ return paginate(list, node.args.pagination);
837
+ }
750
838
  default:
751
839
  assertNever(node, `Unexpected node type: ${node.type}`);
752
840
  }
@@ -818,7 +906,12 @@ function attachChildrenToParent(parentRecord, children) {
818
906
  }
819
907
  function filterChildRecords(records, parentRecord, joinExpr) {
820
908
  if (Array.isArray(records)) {
821
- return records.filter((record) => childRecordMatchesParent(asRecord(record), parentRecord, joinExpr));
909
+ const filtered = records.filter((record) => childRecordMatchesParent(asRecord(record), parentRecord, joinExpr));
910
+ if (joinExpr.isRelationUnique) {
911
+ return filtered.length > 0 ? filtered[0] : null;
912
+ } else {
913
+ return filtered;
914
+ }
822
915
  } else if (records === null) {
823
916
  return null;
824
917
  } else {
@@ -834,6 +927,18 @@ function childRecordMatchesParent(childRecord, parentRecord, joinExpr) {
834
927
  }
835
928
  return true;
836
929
  }
930
+ function paginate(list, { cursor, skip, take }) {
931
+ const cursorIndex = cursor !== null ? list.findIndex((item) => doKeysMatch(item, cursor)) : 0;
932
+ if (cursorIndex === -1) {
933
+ return [];
934
+ }
935
+ const start = cursorIndex + (skip ?? 0);
936
+ const end = take !== null ? start + take : list.length;
937
+ return list.slice(start, end);
938
+ }
939
+ function getRecordKey(record, fields) {
940
+ return JSON.stringify(fields.map((field) => record[field]));
941
+ }
837
942
 
838
943
  // src/transactionManager/TransactionManager.ts
839
944
  import { Debug } from "@prisma/debug";
@@ -848,12 +953,11 @@ async function randomUUID() {
848
953
  }
849
954
 
850
955
  // src/transactionManager/TransactionManagerErrors.ts
851
- var TransactionManagerError = class extends Error {
956
+ var TransactionManagerError = class extends UserFacingError {
957
+ name = "TransactionManagerError";
852
958
  constructor(message, meta) {
853
- super("Transaction API error: " + message);
854
- this.meta = meta;
959
+ super("Transaction API error: " + message, "P2028", meta);
855
960
  }
856
- code = "P2028";
857
961
  };
858
962
  var TransactionNotFoundError = class extends TransactionManagerError {
859
963
  constructor() {
@@ -864,12 +968,12 @@ var TransactionNotFoundError = class extends TransactionManagerError {
864
968
  };
865
969
  var TransactionClosedError = class extends TransactionManagerError {
866
970
  constructor(operation) {
867
- super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction`);
971
+ super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction.`);
868
972
  }
869
973
  };
870
974
  var TransactionRolledBackError = class extends TransactionManagerError {
871
975
  constructor(operation) {
872
- super(`Transaction already closed: A ${operation} cannot be executed on a transaction that was rolled back`);
976
+ super(`Transaction already closed: A ${operation} cannot be executed on a transaction that was rolled back.`);
873
977
  }
874
978
  };
875
979
  var TransactionStartTimeoutError = class extends TransactionManagerError {
@@ -1051,10 +1155,14 @@ var TransactionManager = class {
1051
1155
  }
1052
1156
  };
1053
1157
  export {
1158
+ DataMapperError,
1054
1159
  QueryInterpreter,
1055
1160
  TransactionManager,
1056
1161
  TransactionManagerError,
1057
1162
  UserFacingError,
1163
+ doKeysMatch,
1164
+ isDeepStrictEqual,
1165
+ isPrismaValueBigInt,
1058
1166
  isPrismaValueBytes,
1059
1167
  isPrismaValueGenerator,
1060
1168
  isPrismaValuePlaceholder,
@@ -1,3 +1,6 @@
1
1
  import { ResultNode } from '../QueryPlan';
2
2
  import { Value } from './scope';
3
+ export declare class DataMapperError extends Error {
4
+ name: string;
5
+ }
3
6
  export declare function applyDataMap(data: Value, structure: ResultNode): Value;
@@ -1,7 +1,7 @@
1
- export declare class TransactionManagerError extends Error {
2
- meta?: Record<string, unknown> | undefined;
3
- code: string;
4
- constructor(message: string, meta?: Record<string, unknown> | undefined);
1
+ import { UserFacingError } from '../UserFacingError';
2
+ export declare class TransactionManagerError extends UserFacingError {
3
+ name: string;
4
+ constructor(message: string, meta?: Record<string, unknown>);
5
5
  }
6
6
  export declare class TransactionNotFoundError extends TransactionManagerError {
7
7
  constructor();
package/dist/utils.d.ts CHANGED
@@ -1 +1,11 @@
1
1
  export declare function assertNever(_: never, message: string): never;
2
+ /**
3
+ * Checks if two objects are deeply equal, recursively checking all properties for strict equality.
4
+ */
5
+ export declare function isDeepStrictEqual(a: unknown, b: unknown): boolean;
6
+ /**
7
+ * Checks if two objects representing the names and values of key columns match. A match is
8
+ * defined by one of the sets of keys being a subset of the other. This function also
9
+ * converts arguments to the types used by driver adapters if necessary.
10
+ */
11
+ export declare function doKeysMatch(lhs: {}, rhs: {}): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/client-engine-runtime",
3
- "version": "6.9.0-dev.2",
3
+ "version": "6.9.0-dev.20",
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,8 +31,8 @@
31
31
  "nanoid": "5.1.5",
32
32
  "ulid": "3.0.0",
33
33
  "uuid": "11.1.0",
34
- "@prisma/debug": "6.9.0-dev.2",
35
- "@prisma/driver-adapter-utils": "6.9.0-dev.2"
34
+ "@prisma/debug": "6.9.0-dev.20",
35
+ "@prisma/driver-adapter-utils": "6.9.0-dev.20"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/jest": "29.5.14",