@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.js CHANGED
@@ -30,10 +30,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ DataMapperError: () => DataMapperError,
33
34
  QueryInterpreter: () => QueryInterpreter,
34
35
  TransactionManager: () => TransactionManager,
35
36
  TransactionManagerError: () => TransactionManagerError,
36
37
  UserFacingError: () => UserFacingError,
38
+ doKeysMatch: () => doKeysMatch,
39
+ isDeepStrictEqual: () => isDeepStrictEqual,
40
+ isPrismaValueBigInt: () => isPrismaValueBigInt,
37
41
  isPrismaValueBytes: () => isPrismaValueBytes,
38
42
  isPrismaValueGenerator: () => isPrismaValueGenerator,
39
43
  isPrismaValuePlaceholder: () => isPrismaValuePlaceholder,
@@ -41,13 +45,147 @@ __export(index_exports, {
41
45
  });
42
46
  module.exports = __toCommonJS(index_exports);
43
47
 
44
- // src/interpreter/QueryInterpreter.ts
45
- var import_api = require("@opentelemetry/api");
48
+ // src/interpreter/DataMapper.ts
49
+ var import_decimal2 = __toESM(require("decimal.js"));
46
50
 
47
51
  // src/utils.ts
52
+ var import_decimal = __toESM(require("decimal.js"));
48
53
  function assertNever(_, message) {
49
54
  throw new Error(message);
50
55
  }
56
+ function isDeepStrictEqual(a, b) {
57
+ 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]));
58
+ }
59
+ function doKeysMatch(lhs, rhs) {
60
+ const lhsKeys = Object.keys(lhs);
61
+ const rhsKeys = Object.keys(rhs);
62
+ const smallerKeyList = lhsKeys.length < rhsKeys.length ? lhsKeys : rhsKeys;
63
+ return smallerKeyList.every((key) => {
64
+ if (typeof lhs[key] !== typeof rhs[key]) {
65
+ if (typeof lhs[key] === "number" || typeof rhs[key] === "number") {
66
+ return `${lhs[key]}` === `${rhs[key]}`;
67
+ } else if (typeof lhs[key] === "bigint" || typeof rhs[key] === "bigint") {
68
+ return BigInt(`${lhs[key]}`.replace(/n$/, "")) === BigInt(`${rhs[key]}`.replace(/n$/, ""));
69
+ } else if (lhs[key] instanceof Date || rhs[key] instanceof Date) {
70
+ return (/* @__PURE__ */ new Date(`${lhs[key]}`)).getTime() === (/* @__PURE__ */ new Date(`${rhs[key]}`)).getTime();
71
+ } else if (import_decimal.default.isDecimal(lhs[key]) || import_decimal.default.isDecimal(rhs[key])) {
72
+ return new import_decimal.default(`${lhs[key]}`).equals(new import_decimal.default(`${rhs[key]}`));
73
+ }
74
+ }
75
+ return isDeepStrictEqual(lhs[key], rhs[key]);
76
+ });
77
+ }
78
+
79
+ // src/interpreter/DataMapper.ts
80
+ var DataMapperError = class extends Error {
81
+ name = "DataMapperError";
82
+ };
83
+ function applyDataMap(data, structure) {
84
+ switch (structure.type) {
85
+ case "Object":
86
+ return mapArrayOrObject(data, structure.fields);
87
+ case "Value":
88
+ return mapValue(data, structure.resultType);
89
+ default:
90
+ assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
91
+ }
92
+ }
93
+ function mapArrayOrObject(data, fields) {
94
+ if (data === null) return null;
95
+ if (Array.isArray(data)) {
96
+ const rows = data;
97
+ return rows.map((row) => mapObject(row, fields));
98
+ }
99
+ if (typeof data === "object") {
100
+ const row = data;
101
+ return mapObject(row, fields);
102
+ }
103
+ if (typeof data === "string") {
104
+ let decodedData;
105
+ try {
106
+ decodedData = JSON.parse(data);
107
+ } catch (error) {
108
+ throw new DataMapperError(`Expected an array or object, got a string that is not valid JSON`, {
109
+ cause: error
110
+ });
111
+ }
112
+ return mapArrayOrObject(decodedData, fields);
113
+ }
114
+ throw new DataMapperError(`Expected an array or an object, got: ${typeof data}`);
115
+ }
116
+ function mapObject(data, fields) {
117
+ if (typeof data !== "object") {
118
+ throw new DataMapperError(`Expected an object, but got '${typeof data}'`);
119
+ }
120
+ const result = {};
121
+ for (const [name, node] of Object.entries(fields)) {
122
+ switch (node.type) {
123
+ case "Object": {
124
+ if (!node.flattened && !Object.hasOwn(data, name)) {
125
+ throw new DataMapperError(
126
+ `Missing data field (Object): '${name}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
127
+ );
128
+ }
129
+ const target = node.flattened ? data : data[name];
130
+ result[name] = mapArrayOrObject(target, node.fields);
131
+ break;
132
+ }
133
+ case "Value":
134
+ {
135
+ const dbName = node.dbName;
136
+ if (Object.hasOwn(data, dbName)) {
137
+ result[name] = mapValue(data[dbName], node.resultType);
138
+ } else {
139
+ throw new DataMapperError(
140
+ `Missing data field (Value): '${dbName}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
141
+ );
142
+ }
143
+ }
144
+ break;
145
+ default:
146
+ assertNever(node, `DataMapper: Invalid data mapping node type: '${node.type}'`);
147
+ }
148
+ }
149
+ return result;
150
+ }
151
+ function mapValue(value, resultType) {
152
+ if (value === null) return null;
153
+ switch (resultType.type) {
154
+ case "Any":
155
+ return value;
156
+ case "String":
157
+ return typeof value === "string" ? value : `${value}`;
158
+ case "Int":
159
+ return typeof value === "number" ? value : parseInt(`${value}`, 10);
160
+ case "BigInt":
161
+ return typeof value === "bigint" ? value : BigInt(`${value}`);
162
+ case "Float":
163
+ return typeof value === "number" ? value : parseFloat(`${value}`);
164
+ case "Boolean":
165
+ return typeof value === "boolean" ? value : value !== "0";
166
+ case "Decimal":
167
+ return typeof value === "number" ? new import_decimal2.default(value) : new import_decimal2.default(`${value}`);
168
+ case "Date":
169
+ return value instanceof Date ? value : /* @__PURE__ */ new Date(`${value}`);
170
+ case "Array": {
171
+ const values = value;
172
+ return values.map((v) => mapValue(v, resultType.inner));
173
+ }
174
+ case "Object":
175
+ return typeof value === "string" ? value : JSON.stringify(value);
176
+ case "Bytes": {
177
+ if (!Array.isArray(value)) {
178
+ throw new DataMapperError(`Bytes data is invalid, got: ${typeof value}`);
179
+ }
180
+ return new Uint8Array(value);
181
+ }
182
+ default:
183
+ assertNever(resultType, `DataMapper: Unknown result type: ${resultType.type}`);
184
+ }
185
+ }
186
+
187
+ // src/interpreter/QueryInterpreter.ts
188
+ var import_api = require("@opentelemetry/api");
51
189
 
52
190
  // src/tracing.ts
53
191
  var noopTracingHelper = {
@@ -77,7 +215,7 @@ var UserFacingError = class extends Error {
77
215
  constructor(message, code, meta) {
78
216
  super(message);
79
217
  this.code = code;
80
- this.meta = meta;
218
+ this.meta = meta ?? {};
81
219
  }
82
220
  toQueryResponseErrorObject() {
83
221
  return {
@@ -100,7 +238,7 @@ function rethrowAsUserFacing(error) {
100
238
  if (!code || !message) {
101
239
  throw error;
102
240
  }
103
- throw new UserFacingError(message, code, error);
241
+ throw new UserFacingError(message, code, { driverAdapterError: error });
104
242
  }
105
243
  function getErrorCode(err) {
106
244
  switch (err.cause.kind) {
@@ -211,100 +349,6 @@ function renderConstraint(constraint) {
211
349
  return "(not available)";
212
350
  }
213
351
 
214
- // src/interpreter/DataMapper.ts
215
- var import_decimal = __toESM(require("decimal.js"));
216
- function applyDataMap(data, structure) {
217
- switch (structure.type) {
218
- case "Object":
219
- return mapArrayOrObject(data, structure.fields);
220
- case "Value":
221
- return mapValue(data, structure.resultType);
222
- default:
223
- assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
224
- }
225
- }
226
- function mapArrayOrObject(data, fields) {
227
- if (data === null) return null;
228
- if (Array.isArray(data)) {
229
- const rows = data;
230
- return rows.map((row) => mapObject(row, fields));
231
- }
232
- if (typeof data === "object") {
233
- const row = data;
234
- return mapObject(row, fields);
235
- }
236
- throw new Error(`DataMapper: Expected an array or an object, got: ${typeof data}`);
237
- }
238
- function mapObject(data, fields) {
239
- if (typeof data !== "object") {
240
- throw new Error(`DataMapper: Expected an object, but got '${typeof data}'`);
241
- }
242
- const result = {};
243
- for (const [name, node] of Object.entries(fields)) {
244
- switch (node.type) {
245
- case "Object":
246
- if (Object.hasOwn(data, name)) {
247
- result[name] = mapArrayOrObject(data[name], node.fields);
248
- } else {
249
- throw new Error(
250
- `DataMapper: Missing data field (Object): '${name}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
251
- );
252
- }
253
- break;
254
- case "Value":
255
- {
256
- const dbName = node.dbName;
257
- if (Object.hasOwn(data, dbName)) {
258
- result[name] = mapValue(data[dbName], node.resultType);
259
- } else {
260
- throw new Error(
261
- `DataMapper: Missing data field (Value): '${dbName}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
262
- );
263
- }
264
- }
265
- break;
266
- default:
267
- assertNever(node, `DataMapper: Invalid data mapping node type: '${node.type}'`);
268
- }
269
- }
270
- return result;
271
- }
272
- function mapValue(value, resultType) {
273
- if (value === null) return null;
274
- switch (resultType.type) {
275
- case "Any":
276
- return value;
277
- case "String":
278
- return typeof value === "string" ? value : `${value}`;
279
- case "Int":
280
- return typeof value === "number" ? value : parseInt(`${value}`, 10);
281
- case "BigInt":
282
- return typeof value === "bigint" ? value : BigInt(`${value}`);
283
- case "Float":
284
- return typeof value === "number" ? value : parseFloat(`${value}`);
285
- case "Boolean":
286
- return typeof value === "boolean" ? value : value !== "0";
287
- case "Decimal":
288
- return typeof value === "number" ? new import_decimal.default(value) : new import_decimal.default(`${value}`);
289
- case "Date":
290
- return value instanceof Date ? value : /* @__PURE__ */ new Date(`${value}`);
291
- case "Array": {
292
- const values = value;
293
- return values.map((v) => mapValue(v, resultType.inner));
294
- }
295
- case "Object":
296
- return typeof value === "string" ? value : JSON.stringify(value);
297
- case "Bytes": {
298
- if (!Array.isArray(value)) {
299
- throw new Error(`DataMapper: Bytes data is invalid, got: ${typeof value}`);
300
- }
301
- return new Uint8Array(value);
302
- }
303
- default:
304
- assertNever(resultType, `DataMapper: Unknown result type: ${resultType.type}`);
305
- }
306
- }
307
-
308
352
  // src/interpreter/generators.ts
309
353
  var import_cuid = __toESM(require("@bugsnag/cuid"));
310
354
  var import_cuid2 = require("@paralleldrive/cuid2");
@@ -409,6 +453,9 @@ function isPrismaValueGenerator(value) {
409
453
  function isPrismaValueBytes(value) {
410
454
  return typeof value === "object" && value !== null && value["prisma__type"] === "bytes";
411
455
  }
456
+ function isPrismaValueBigInt(value) {
457
+ return typeof value === "object" && value !== null && value["prisma__type"] === "bigint";
458
+ }
412
459
 
413
460
  // src/interpreter/renderQuery.ts
414
461
  function renderQuery(dbQuery, scope, generators) {
@@ -451,9 +498,10 @@ function evaluateParam(param, scope, generators) {
451
498
  }
452
499
  if (Array.isArray(value)) {
453
500
  value = value.map((el) => evaluateParam(el, scope, generators));
454
- }
455
- if (isPrismaValueBytes(value)) {
501
+ } else if (isPrismaValueBytes(value)) {
456
502
  value = Buffer.from(value.prisma__value, "base64");
503
+ } else if (isPrismaValueBigInt(value)) {
504
+ value = BigInt(value.prisma__value);
457
505
  }
458
506
  return value;
459
507
  }
@@ -594,6 +642,8 @@ function doesSatisfyRule(data, rule) {
594
642
  return rule.args !== 0;
595
643
  }
596
644
  return rule.args !== 1;
645
+ case "affectedRowCountEq":
646
+ return data === rule.args;
597
647
  case "never":
598
648
  return false;
599
649
  default:
@@ -611,7 +661,9 @@ function renderMessage(data, error) {
611
661
  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}'.`;
612
662
  }
613
663
  case "INCOMPLETE_CONNECT_INPUT":
614
- 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}.`;
664
+ 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}.`;
665
+ case "INCOMPLETE_CONNECT_OUTPUT":
666
+ 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}.`;
615
667
  case "RECORDS_NOT_CONNECTED":
616
668
  return `The records for relation \`${error.context.relation}\` between the \`${error.context.parent}\` and \`${error.context.child}\` models are not connected.`;
617
669
  default:
@@ -624,6 +676,8 @@ function getErrorCode2(error) {
624
676
  return "P2014";
625
677
  case "RECORDS_NOT_CONNECTED":
626
678
  return "P2017";
679
+ case "INCOMPLETE_CONNECT_OUTPUT":
680
+ return "P2018";
627
681
  case "MISSING_RECORD":
628
682
  case "MISSING_RELATED_RECORD":
629
683
  case "INCOMPLETE_CONNECT_INPUT":
@@ -665,8 +719,11 @@ var QueryInterpreter = class _QueryInterpreter {
665
719
  async interpretNode(node, queryable, scope, generators) {
666
720
  switch (node.type) {
667
721
  case "seq": {
668
- const results = await Promise.all(node.args.map((arg) => this.interpretNode(arg, queryable, scope, generators)));
669
- return results[results.length - 1];
722
+ let result;
723
+ for (const arg of node.args) {
724
+ result = await this.interpretNode(arg, queryable, scope, generators);
725
+ }
726
+ return result;
670
727
  }
671
728
  case "get": {
672
729
  return scope[node.args.name];
@@ -689,11 +746,11 @@ var QueryInterpreter = class _QueryInterpreter {
689
746
  }
690
747
  case "concat": {
691
748
  const parts = await Promise.all(node.args.map((arg) => this.interpretNode(arg, queryable, scope, generators)));
692
- return parts.reduce((acc, part) => acc.concat(asList(part)), []);
749
+ return parts.length > 0 ? parts.reduce((acc, part) => acc.concat(asList(part)), []) : [];
693
750
  }
694
751
  case "sum": {
695
752
  const parts = await Promise.all(node.args.map((arg) => this.interpretNode(arg, queryable, scope, generators)));
696
- return parts.reduce((acc, part) => asNumber(acc) + asNumber(part));
753
+ return parts.length > 0 ? parts.reduce((acc, part) => asNumber(acc) + asNumber(part)) : 0;
697
754
  }
698
755
  case "execute": {
699
756
  const query = renderQuery(node.args, scope, generators);
@@ -734,6 +791,9 @@ var QueryInterpreter = class _QueryInterpreter {
734
791
  }
735
792
  case "join": {
736
793
  const parent = await this.interpretNode(node.args.parent, queryable, scope, generators);
794
+ if (parent === null) {
795
+ return null;
796
+ }
737
797
  const children = await Promise.all(
738
798
  node.args.children.map(async (joinExpr) => ({
739
799
  joinExpr,
@@ -790,6 +850,38 @@ var QueryInterpreter = class _QueryInterpreter {
790
850
  const toSet = new Set(asList(to));
791
851
  return asList(from).filter((item) => !toSet.has(item));
792
852
  }
853
+ case "distinctBy": {
854
+ const value = await this.interpretNode(node.args.expr, queryable, scope, generators);
855
+ const seen = /* @__PURE__ */ new Set();
856
+ const result = [];
857
+ for (const item of asList(value)) {
858
+ const key = getRecordKey(item, node.args.fields);
859
+ if (!seen.has(key)) {
860
+ seen.add(key);
861
+ result.push(item);
862
+ }
863
+ }
864
+ return result;
865
+ }
866
+ case "paginate": {
867
+ const value = await this.interpretNode(node.args.expr, queryable, scope, generators);
868
+ const list = asList(value);
869
+ const linkingFields = node.args.pagination.linkingFields;
870
+ if (linkingFields !== null) {
871
+ const groupedByParent = /* @__PURE__ */ new Map();
872
+ for (const item of list) {
873
+ const parentKey = getRecordKey(item, linkingFields);
874
+ if (!groupedByParent.has(parentKey)) {
875
+ groupedByParent.set(parentKey, []);
876
+ }
877
+ groupedByParent.get(parentKey).push(item);
878
+ }
879
+ const groupList = Array.from(groupedByParent.entries());
880
+ groupList.sort(([aId], [bId]) => aId < bId ? -1 : aId > bId ? 1 : 0);
881
+ return groupList.flatMap(([, elems]) => paginate(elems, node.args.pagination));
882
+ }
883
+ return paginate(list, node.args.pagination);
884
+ }
793
885
  default:
794
886
  assertNever(node, `Unexpected node type: ${node.type}`);
795
887
  }
@@ -861,7 +953,12 @@ function attachChildrenToParent(parentRecord, children) {
861
953
  }
862
954
  function filterChildRecords(records, parentRecord, joinExpr) {
863
955
  if (Array.isArray(records)) {
864
- return records.filter((record) => childRecordMatchesParent(asRecord(record), parentRecord, joinExpr));
956
+ const filtered = records.filter((record) => childRecordMatchesParent(asRecord(record), parentRecord, joinExpr));
957
+ if (joinExpr.isRelationUnique) {
958
+ return filtered.length > 0 ? filtered[0] : null;
959
+ } else {
960
+ return filtered;
961
+ }
865
962
  } else if (records === null) {
866
963
  return null;
867
964
  } else {
@@ -877,6 +974,18 @@ function childRecordMatchesParent(childRecord, parentRecord, joinExpr) {
877
974
  }
878
975
  return true;
879
976
  }
977
+ function paginate(list, { cursor, skip, take }) {
978
+ const cursorIndex = cursor !== null ? list.findIndex((item) => doKeysMatch(item, cursor)) : 0;
979
+ if (cursorIndex === -1) {
980
+ return [];
981
+ }
982
+ const start = cursorIndex + (skip ?? 0);
983
+ const end = take !== null ? start + take : list.length;
984
+ return list.slice(start, end);
985
+ }
986
+ function getRecordKey(record, fields) {
987
+ return JSON.stringify(fields.map((field) => record[field]));
988
+ }
880
989
 
881
990
  // src/transactionManager/TransactionManager.ts
882
991
  var import_debug = require("@prisma/debug");
@@ -891,12 +1000,11 @@ async function randomUUID() {
891
1000
  }
892
1001
 
893
1002
  // src/transactionManager/TransactionManagerErrors.ts
894
- var TransactionManagerError = class extends Error {
1003
+ var TransactionManagerError = class extends UserFacingError {
1004
+ name = "TransactionManagerError";
895
1005
  constructor(message, meta) {
896
- super("Transaction API error: " + message);
897
- this.meta = meta;
1006
+ super("Transaction API error: " + message, "P2028", meta);
898
1007
  }
899
- code = "P2028";
900
1008
  };
901
1009
  var TransactionNotFoundError = class extends TransactionManagerError {
902
1010
  constructor() {
@@ -907,12 +1015,12 @@ var TransactionNotFoundError = class extends TransactionManagerError {
907
1015
  };
908
1016
  var TransactionClosedError = class extends TransactionManagerError {
909
1017
  constructor(operation) {
910
- super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction`);
1018
+ super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction.`);
911
1019
  }
912
1020
  };
913
1021
  var TransactionRolledBackError = class extends TransactionManagerError {
914
1022
  constructor(operation) {
915
- super(`Transaction already closed: A ${operation} cannot be executed on a transaction that was rolled back`);
1023
+ super(`Transaction already closed: A ${operation} cannot be executed on a transaction that was rolled back.`);
916
1024
  }
917
1025
  };
918
1026
  var TransactionStartTimeoutError = class extends TransactionManagerError {
@@ -1095,10 +1203,14 @@ var TransactionManager = class {
1095
1203
  };
1096
1204
  // Annotate the CommonJS export names for ESM import in node:
1097
1205
  0 && (module.exports = {
1206
+ DataMapperError,
1098
1207
  QueryInterpreter,
1099
1208
  TransactionManager,
1100
1209
  TransactionManagerError,
1101
1210
  UserFacingError,
1211
+ doKeysMatch,
1212
+ isDeepStrictEqual,
1213
+ isPrismaValueBigInt,
1102
1214
  isPrismaValueBytes,
1103
1215
  isPrismaValueGenerator,
1104
1216
  isPrismaValuePlaceholder,