@prisma/query-plan-executor 7.10.0-dev.21 → 7.10.0-dev.23

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +102 -82
  2. package/dist/index.js +265 -23
  3. package/package.json +6 -6
package/dist/index.d.ts CHANGED
@@ -1645,6 +1645,21 @@ declare interface HTTPResponseError extends Error {
1645
1645
 
1646
1646
  declare type IfAnyThenEmptyObject<T> = 0 extends 1 & T ? {} : T;
1647
1647
 
1648
+ /**
1649
+ * Query plan nodes that perform database I/O: individual queries and statements,
1650
+ * and subtrees executed within a transaction.
1651
+ */
1652
+ declare type ImpureQueryPlanNode = {
1653
+ type: 'query';
1654
+ args: QueryPlanDbQuery;
1655
+ } | {
1656
+ type: 'execute';
1657
+ args: QueryPlanDbQuery;
1658
+ } | {
1659
+ type: 'transaction';
1660
+ args: QueryPlanNode;
1661
+ };
1662
+
1648
1663
  /**
1649
1664
  * Logs an informational message using the active logger.
1650
1665
  *
@@ -1690,13 +1705,6 @@ declare type IsInvalid<T> = T extends InvalidJSONValue ? true : false;
1690
1705
 
1691
1706
  declare type IsolationLevel = 'READ UNCOMMITTED' | 'READ COMMITTED' | 'REPEATABLE READ' | 'SNAPSHOT' | 'SERIALIZABLE';
1692
1707
 
1693
- declare type JoinExpression = {
1694
- child: QueryPlanNode;
1695
- on: [left: string, right: string][];
1696
- parentField: string;
1697
- isRelationUnique: boolean;
1698
- };
1699
-
1700
1708
  declare type JSONArray = (JSONPrimitive | JSONObject | JSONArray)[];
1701
1709
 
1702
1710
  declare type JSONObject = {
@@ -2403,57 +2411,23 @@ declare type PropsForRenderer = [...Required<Parameters<Renderer>>] extends [unk
2403
2411
  declare type Provider = 'mysql' | 'postgres' | 'sqlite' | 'sqlserver';
2404
2412
 
2405
2413
  /**
2406
- * Logs a database query event using the active logger.
2407
- *
2408
- * @param message The message to log
2409
- * @param attributes Optional key-value pairs to include with the log event
2410
- * @throws {Error} if no active logger is found
2414
+ * Query plan nodes that are free of side effects and can be interpreted synchronously
2415
+ * without touching the database. The `Rest` parameter controls what other nodes may
2416
+ * appear in child positions: with the default `never` the tree is fully pure, while
2417
+ * `PureQueryPlanNode<ImpureQueryPlanNode>` describes a tree of pure nodes that may
2418
+ * contain impure nodes anywhere inside.
2411
2419
  */
2412
- declare function query(message: string, attributes?: ExtendedAttributes): void;
2413
-
2414
- declare interface Queryable<Query, Result> extends AdapterInfo {
2415
- /**
2416
- * Execute a query and return its result.
2417
- */
2418
- queryRaw(params: Query): Promise<Result>;
2419
- /**
2420
- * Execute a query and return the number of affected rows.
2421
- */
2422
- executeRaw(params: Query): Promise<number>;
2423
- }
2424
-
2425
- declare type QueryEvent = {
2426
- timestamp: Date;
2427
- query: string;
2428
- params: readonly unknown[];
2429
- duration: number;
2430
- };
2431
-
2432
- declare type QueryPlanBinding = {
2433
- name: string;
2434
- expr: QueryPlanNode;
2435
- };
2436
-
2437
- declare type QueryPlanDbQuery = {
2438
- type: 'rawSql';
2439
- sql: string;
2440
- args: PrismaValue[];
2441
- argTypes: ArgType[];
2442
- } | {
2443
- type: 'templateSql';
2444
- fragments: Fragment[];
2445
- placeholderFormat: PlaceholderFormat;
2446
- args: PrismaValue[];
2447
- argTypes: DynamicArgType[];
2448
- chunkable: boolean;
2449
- };
2450
-
2451
- declare type QueryPlanNode = {
2420
+ declare type PureQueryPlanNode<Rest = never> = {
2452
2421
  type: 'value';
2453
2422
  args: PrismaValue;
2423
+ /**
2424
+ * Present when this node is the result of evaluating an impure node during
2425
+ * query plan purification. Never produced by the query compiler.
2426
+ */
2427
+ lastInsertId?: string;
2454
2428
  } | {
2455
2429
  type: 'seq';
2456
- args: QueryPlanNode[];
2430
+ args: (PureQueryPlanNode<Rest> | Rest)[];
2457
2431
  } | {
2458
2432
  type: 'get';
2459
2433
  args: {
@@ -2462,101 +2436,147 @@ declare type QueryPlanNode = {
2462
2436
  } | {
2463
2437
  type: 'let';
2464
2438
  args: {
2465
- bindings: QueryPlanBinding[];
2466
- expr: QueryPlanNode;
2439
+ bindings: {
2440
+ name: string;
2441
+ expr: PureQueryPlanNode<Rest> | Rest;
2442
+ }[];
2443
+ expr: PureQueryPlanNode<Rest> | Rest;
2467
2444
  };
2468
2445
  } | {
2469
2446
  type: 'getFirstNonEmpty';
2470
2447
  args: {
2471
2448
  names: string[];
2472
2449
  };
2473
- } | {
2474
- type: 'query';
2475
- args: QueryPlanDbQuery;
2476
- } | {
2477
- type: 'execute';
2478
- args: QueryPlanDbQuery;
2479
2450
  } | {
2480
2451
  type: 'reverse';
2481
- args: QueryPlanNode;
2452
+ args: PureQueryPlanNode<Rest> | Rest;
2482
2453
  } | {
2483
2454
  type: 'sum';
2484
- args: QueryPlanNode[];
2455
+ args: (PureQueryPlanNode<Rest> | Rest)[];
2485
2456
  } | {
2486
2457
  type: 'concat';
2487
- args: QueryPlanNode[];
2458
+ args: (PureQueryPlanNode<Rest> | Rest)[];
2488
2459
  } | {
2489
2460
  type: 'unique';
2490
- args: QueryPlanNode;
2461
+ args: PureQueryPlanNode<Rest> | Rest;
2491
2462
  } | {
2492
2463
  type: 'required';
2493
- args: QueryPlanNode;
2464
+ args: PureQueryPlanNode<Rest> | Rest;
2494
2465
  } | {
2495
2466
  type: 'join';
2496
2467
  args: {
2497
- parent: QueryPlanNode;
2498
- children: JoinExpression[];
2468
+ parent: PureQueryPlanNode<Rest> | Rest;
2469
+ children: {
2470
+ child: PureQueryPlanNode<Rest> | Rest;
2471
+ on: [left: string, right: string][];
2472
+ parentField: string;
2473
+ isRelationUnique: boolean;
2474
+ }[];
2499
2475
  canAssumeStrictEquality: boolean;
2500
2476
  };
2501
2477
  } | {
2502
2478
  type: 'mapField';
2503
2479
  args: {
2504
2480
  field: string;
2505
- records: QueryPlanNode;
2481
+ records: PureQueryPlanNode<Rest> | Rest;
2506
2482
  };
2507
- } | {
2508
- type: 'transaction';
2509
- args: QueryPlanNode;
2510
2483
  } | {
2511
2484
  type: 'dataMap';
2512
2485
  args: {
2513
- expr: QueryPlanNode;
2486
+ expr: PureQueryPlanNode<Rest> | Rest;
2514
2487
  structure: ResultNode;
2515
2488
  enums: Record<string, Record<string, string>>;
2516
2489
  };
2517
2490
  } | {
2518
2491
  type: 'validate';
2519
2492
  args: {
2520
- expr: QueryPlanNode;
2493
+ expr: PureQueryPlanNode<Rest> | Rest;
2521
2494
  rules: DataRule[];
2522
2495
  } & ValidationError;
2523
2496
  } | {
2524
2497
  type: 'if';
2525
2498
  args: {
2526
- value: QueryPlanNode;
2499
+ value: PureQueryPlanNode<Rest> | Rest;
2527
2500
  rule: DataRule;
2528
- then: QueryPlanNode;
2529
- else: QueryPlanNode;
2501
+ then: PureQueryPlanNode<Rest> | Rest;
2502
+ else: PureQueryPlanNode<Rest> | Rest;
2530
2503
  };
2531
2504
  } | {
2532
2505
  type: 'unit';
2533
2506
  } | {
2534
2507
  type: 'diff';
2535
2508
  args: {
2536
- from: QueryPlanNode;
2537
- to: QueryPlanNode;
2509
+ from: PureQueryPlanNode<Rest> | Rest;
2510
+ to: PureQueryPlanNode<Rest> | Rest;
2538
2511
  fields: string[];
2539
2512
  };
2540
2513
  } | {
2541
2514
  type: 'initializeRecord';
2542
2515
  args: {
2543
- expr: QueryPlanNode;
2516
+ expr: PureQueryPlanNode<Rest> | Rest;
2544
2517
  fields: Record<string, FieldInitializer>;
2545
2518
  };
2546
2519
  } | {
2547
2520
  type: 'mapRecord';
2548
2521
  args: {
2549
- expr: QueryPlanNode;
2522
+ expr: PureQueryPlanNode<Rest> | Rest;
2550
2523
  fields: Record<string, FieldOperation>;
2551
2524
  };
2552
2525
  } | {
2553
2526
  type: 'process';
2554
2527
  args: {
2555
- expr: QueryPlanNode;
2528
+ expr: PureQueryPlanNode<Rest> | Rest;
2556
2529
  operations: InMemoryOps;
2557
2530
  };
2558
2531
  };
2559
2532
 
2533
+ /**
2534
+ * Logs a database query event using the active logger.
2535
+ *
2536
+ * @param message The message to log
2537
+ * @param attributes Optional key-value pairs to include with the log event
2538
+ * @throws {Error} if no active logger is found
2539
+ */
2540
+ declare function query(message: string, attributes?: ExtendedAttributes): void;
2541
+
2542
+ declare interface Queryable<Query, Result> extends AdapterInfo {
2543
+ /**
2544
+ * Execute a query and return its result.
2545
+ */
2546
+ queryRaw(params: Query): Promise<Result>;
2547
+ /**
2548
+ * Execute a query and return the number of affected rows.
2549
+ */
2550
+ executeRaw(params: Query): Promise<number>;
2551
+ }
2552
+
2553
+ declare type QueryEvent = {
2554
+ timestamp: Date;
2555
+ query: string;
2556
+ params: readonly unknown[];
2557
+ duration: number;
2558
+ };
2559
+
2560
+ declare type QueryPlanDbQuery = {
2561
+ type: 'rawSql';
2562
+ sql: string;
2563
+ args: PrismaValue[];
2564
+ argTypes: ArgType[];
2565
+ } | {
2566
+ type: 'templateSql';
2567
+ fragments: Fragment[];
2568
+ placeholderFormat: PlaceholderFormat;
2569
+ args: PrismaValue[];
2570
+ argTypes: DynamicArgType[];
2571
+ chunkable: boolean;
2572
+ };
2573
+
2574
+ /**
2575
+ * A query plan as emitted by the query compiler: a tree of pure nodes that may
2576
+ * contain impure nodes anywhere inside.
2577
+ */
2578
+ declare type QueryPlanNode = ImpureQueryPlanNode | PureQueryPlanNode<ImpureQueryPlanNode>;
2579
+
2560
2580
  declare type RedirectStatusCode = 300 | 301 | 302 | 303 | 304 | DeprecatedStatusCode | 307 | 308;
2561
2581
 
2562
2582
  declare type RemoveBlankRecord<T> = T extends Record<infer K, unknown> ? (K extends string ? T : never) : never;
package/dist/index.js CHANGED
@@ -93473,7 +93473,7 @@ __export(index_exports, {
93473
93473
  module.exports = __toCommonJS(index_exports);
93474
93474
 
93475
93475
  // package.json
93476
- var version = "7.10.0-dev.21";
93476
+ var version = "7.10.0-dev.23";
93477
93477
 
93478
93478
  // ../../node_modules/.pnpm/temporal-polyfill@0.3.0/node_modules/temporal-polyfill/chunks/internal.js
93479
93479
  function clampProp(e2, n2, t2, o2, r2) {
@@ -103126,17 +103126,27 @@ var QueryInterpreter = class _QueryInterpreter {
103126
103126
  });
103127
103127
  }
103128
103128
  async run(queryPlan, options) {
103129
- const { value } = await this.interpretNode(queryPlan, {
103130
- ...options,
103131
- generators: this.#generators.snapshot()
103132
- }).catch((e2) => rethrowAsUserFacing(e2));
103129
+ const generators = this.#generators.snapshot();
103130
+ const context4 = { ...options, generators };
103131
+ const purified = purifyQueryPlan(queryPlan, (node) => this.interpretNode(node, context4))?.catch(
103132
+ (e2) => rethrowAsUserFacing(e2)
103133
+ );
103134
+ if (purified) {
103135
+ try {
103136
+ return this.#interpretPureNode(await purified, context4.scope, generators).value;
103137
+ } catch (e2) {
103138
+ rethrowAsUserFacing(e2);
103139
+ }
103140
+ }
103141
+ const { value } = await this.interpretNode(queryPlan, context4).catch((e2) => rethrowAsUserFacing(e2));
103133
103142
  return value;
103134
103143
  }
103135
103144
  async interpretNode(node, context4) {
103136
103145
  switch (node.type) {
103137
103146
  case "value": {
103138
103147
  return {
103139
- value: evaluateArg(node.args, context4.scope, context4.generators)
103148
+ value: evaluateArg(node.args, context4.scope, context4.generators),
103149
+ lastInsertId: node.lastInsertId
103140
103150
  };
103141
103151
  }
103142
103152
  case "seq": {
@@ -103146,9 +103156,6 @@ var QueryInterpreter = class _QueryInterpreter {
103146
103156
  }
103147
103157
  return result ?? { value: void 0 };
103148
103158
  }
103149
- case "get": {
103150
- return { value: context4.scope[node.args.name] };
103151
- }
103152
103159
  case "let": {
103153
103160
  const nestedScope = Object.create(context4.scope);
103154
103161
  for (const binding of node.args.bindings) {
@@ -103157,15 +103164,6 @@ var QueryInterpreter = class _QueryInterpreter {
103157
103164
  }
103158
103165
  return this.interpretNode(node.args.expr, { ...context4, scope: nestedScope });
103159
103166
  }
103160
- case "getFirstNonEmpty": {
103161
- for (const name6 of node.args.names) {
103162
- const value = context4.scope[name6];
103163
- if (!isEmpty(value)) {
103164
- return { value };
103165
- }
103166
- }
103167
- return { value: [] };
103168
- }
103169
103167
  case "concat": {
103170
103168
  const parts = await Promise.all(
103171
103169
  node.args.map((arg) => this.interpretNode(arg, context4).then((res) => res.value))
@@ -103292,9 +103290,6 @@ var QueryInterpreter = class _QueryInterpreter {
103292
103290
  return await this.interpretNode(node.args.else, context4);
103293
103291
  }
103294
103292
  }
103295
- case "unit": {
103296
- return { value: void 0 };
103297
- }
103298
103293
  case "diff": {
103299
103294
  const { value: from } = await this.interpretNode(node.args.from, context4);
103300
103295
  const { value: to2 } = await this.interpretNode(node.args.to, context4);
@@ -103324,6 +103319,139 @@ var QueryInterpreter = class _QueryInterpreter {
103324
103319
  }
103325
103320
  return { value: record2, lastInsertId };
103326
103321
  }
103322
+ default:
103323
+ return this.#interpretPureNode(node, context4.scope, context4.generators);
103324
+ }
103325
+ }
103326
+ #interpretPureNode(node, scope, generators) {
103327
+ switch (node.type) {
103328
+ case "value": {
103329
+ return { value: evaluateArg(node.args, scope, generators), lastInsertId: node.lastInsertId };
103330
+ }
103331
+ case "seq": {
103332
+ let result;
103333
+ for (const arg of node.args) {
103334
+ result = this.#interpretPureNode(arg, scope, generators);
103335
+ }
103336
+ return result ?? { value: void 0 };
103337
+ }
103338
+ case "get": {
103339
+ return { value: scope[node.args.name] };
103340
+ }
103341
+ case "let": {
103342
+ const nestedScope = Object.create(scope);
103343
+ for (const binding of node.args.bindings) {
103344
+ const { value } = this.#interpretPureNode(binding.expr, nestedScope, generators);
103345
+ nestedScope[binding.name] = value;
103346
+ }
103347
+ return this.#interpretPureNode(node.args.expr, nestedScope, generators);
103348
+ }
103349
+ case "getFirstNonEmpty": {
103350
+ for (const name6 of node.args.names) {
103351
+ const value = scope[name6];
103352
+ if (!isEmpty(value)) {
103353
+ return { value };
103354
+ }
103355
+ }
103356
+ return { value: [] };
103357
+ }
103358
+ case "concat": {
103359
+ const parts = node.args.map((arg) => this.#interpretPureNode(arg, scope, generators).value);
103360
+ return {
103361
+ value: parts.length > 0 ? parts.reduce((acc, part) => acc.concat(asList(part)), []) : []
103362
+ };
103363
+ }
103364
+ case "sum": {
103365
+ const parts = node.args.map((arg) => this.#interpretPureNode(arg, scope, generators).value);
103366
+ return {
103367
+ value: parts.length > 0 ? parts.reduce((acc, part) => asNumber2(acc) + asNumber2(part)) : 0
103368
+ };
103369
+ }
103370
+ case "reverse": {
103371
+ const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
103372
+ return { value: Array.isArray(value) ? value.reverse() : value, lastInsertId };
103373
+ }
103374
+ case "unique": {
103375
+ const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
103376
+ if (!Array.isArray(value)) {
103377
+ return { value, lastInsertId };
103378
+ }
103379
+ if (value.length > 1) {
103380
+ throw new Error(`Expected zero or one element, got ${value.length}`);
103381
+ }
103382
+ return { value: value[0] ?? null, lastInsertId };
103383
+ }
103384
+ case "required": {
103385
+ const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
103386
+ if (isEmpty(value)) {
103387
+ throw new Error("Required value is empty");
103388
+ }
103389
+ return { value, lastInsertId };
103390
+ }
103391
+ case "mapField": {
103392
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.records, scope, generators);
103393
+ return { value: mapField2(value, node.args.field), lastInsertId };
103394
+ }
103395
+ case "join": {
103396
+ const { value: parent, lastInsertId } = this.#interpretPureNode(node.args.parent, scope, generators);
103397
+ if (parent === null) {
103398
+ return { value: null, lastInsertId };
103399
+ }
103400
+ const children = node.args.children.map((joinExpr) => ({
103401
+ joinExpr,
103402
+ childRecords: this.#interpretPureNode(joinExpr.child, scope, generators).value
103403
+ }));
103404
+ return { value: attachChildrenToParents(parent, children, node.args.canAssumeStrictEquality), lastInsertId };
103405
+ }
103406
+ case "dataMap": {
103407
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
103408
+ return { value: applyDataMap(value, node.args.structure, node.args.enums), lastInsertId };
103409
+ }
103410
+ case "validate": {
103411
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
103412
+ performValidation(value, node.args.rules, node.args);
103413
+ return { value, lastInsertId };
103414
+ }
103415
+ case "if": {
103416
+ const { value } = this.#interpretPureNode(node.args.value, scope, generators);
103417
+ if (doesSatisfyRule(value, node.args.rule)) {
103418
+ return this.#interpretPureNode(node.args.then, scope, generators);
103419
+ } else {
103420
+ return this.#interpretPureNode(node.args.else, scope, generators);
103421
+ }
103422
+ }
103423
+ case "unit": {
103424
+ return { value: void 0 };
103425
+ }
103426
+ case "diff": {
103427
+ const { value: from } = this.#interpretPureNode(node.args.from, scope, generators);
103428
+ const { value: to2 } = this.#interpretPureNode(node.args.to, scope, generators);
103429
+ const keyGetter = (item) => item !== null ? getRecordKey(asRecord(item), node.args.fields) : null;
103430
+ const toSet = new Set(asList(to2).map(keyGetter));
103431
+ return { value: asList(from).filter((item) => !toSet.has(keyGetter(item))) };
103432
+ }
103433
+ case "process": {
103434
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
103435
+ const ops = cloneObject(node.args.operations);
103436
+ evaluateProcessingParameters(ops, scope, generators);
103437
+ return { value: processRecords(value, ops), lastInsertId };
103438
+ }
103439
+ case "initializeRecord": {
103440
+ const { lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
103441
+ const record2 = {};
103442
+ for (const [key, initializer3] of Object.entries(node.args.fields)) {
103443
+ record2[key] = evalFieldInitializer(initializer3, lastInsertId, scope, generators);
103444
+ }
103445
+ return { value: record2, lastInsertId };
103446
+ }
103447
+ case "mapRecord": {
103448
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
103449
+ const record2 = value === null ? {} : asRecord(value);
103450
+ for (const [key, entry] of Object.entries(node.args.fields)) {
103451
+ record2[key] = evalFieldOperation(entry, record2[key], scope, generators);
103452
+ }
103453
+ return { value: record2, lastInsertId };
103454
+ }
103327
103455
  default:
103328
103456
  assertNever(node, `Unexpected node type: ${node.type}`);
103329
103457
  }
@@ -103501,6 +103629,112 @@ function evalFieldOperation(op, value, scope, generators) {
103501
103629
  assertNever(op, `Unexpected field operation type: ${op["type"]}`);
103502
103630
  }
103503
103631
  }
103632
+ function purifyQueryPlan(node, evalNode) {
103633
+ const impureNode = findUniqueUnconditionalImpureNode(node);
103634
+ if (!impureNode) {
103635
+ return void 0;
103636
+ }
103637
+ return evalNode(impureNode).then((result) => {
103638
+ const evaluated = {
103639
+ type: "value",
103640
+ args: result.value,
103641
+ lastInsertId: result.lastInsertId
103642
+ };
103643
+ const purified = replaceImpureNode(node, impureNode, evaluated);
103644
+ if (!purified) {
103645
+ throw new Error("Could not substitute the evaluated impure node into the query plan");
103646
+ }
103647
+ return purified;
103648
+ });
103649
+ }
103650
+ function replaceImpureNode(node, target, replacement) {
103651
+ if (node === target) {
103652
+ return replacement;
103653
+ }
103654
+ switch (node.type) {
103655
+ case "seq":
103656
+ case "sum":
103657
+ case "concat": {
103658
+ for (let i2 = 0; i2 < node.args.length; i2++) {
103659
+ const child = replaceImpureNode(node.args[i2], target, replacement);
103660
+ if (child) {
103661
+ return { ...node, args: node.args.map((arg, j2) => j2 === i2 ? child : arg) };
103662
+ }
103663
+ }
103664
+ return void 0;
103665
+ }
103666
+ case "dataMap":
103667
+ case "validate":
103668
+ case "initializeRecord":
103669
+ case "mapRecord":
103670
+ case "process": {
103671
+ const expr = replaceImpureNode(node.args.expr, target, replacement);
103672
+ return expr && { ...node, args: { ...node.args, expr } };
103673
+ }
103674
+ case "mapField": {
103675
+ const records = replaceImpureNode(node.args.records, target, replacement);
103676
+ return records && { ...node, args: { ...node.args, records } };
103677
+ }
103678
+ case "reverse":
103679
+ case "unique":
103680
+ case "required": {
103681
+ const args = replaceImpureNode(node.args, target, replacement);
103682
+ return args && { ...node, args };
103683
+ }
103684
+ default:
103685
+ return void 0;
103686
+ }
103687
+ }
103688
+ function findUniqueUnconditionalImpureNode(node) {
103689
+ switch (node.type) {
103690
+ case "query":
103691
+ case "execute":
103692
+ return node;
103693
+ case "seq":
103694
+ case "sum":
103695
+ case "concat": {
103696
+ let found = void 0;
103697
+ for (const child of node.args) {
103698
+ const childFound = findUniqueUnconditionalImpureNode(child);
103699
+ if (childFound === null) {
103700
+ return null;
103701
+ }
103702
+ if (childFound) {
103703
+ if (found) {
103704
+ return null;
103705
+ }
103706
+ found = childFound;
103707
+ }
103708
+ }
103709
+ return found;
103710
+ }
103711
+ case "dataMap":
103712
+ case "validate":
103713
+ case "initializeRecord":
103714
+ case "mapRecord":
103715
+ case "process":
103716
+ return findUniqueUnconditionalImpureNode(node.args.expr);
103717
+ case "mapField":
103718
+ return findUniqueUnconditionalImpureNode(node.args.records);
103719
+ case "reverse":
103720
+ case "unique":
103721
+ case "required":
103722
+ return findUniqueUnconditionalImpureNode(node.args);
103723
+ case "let":
103724
+ case "join":
103725
+ case "diff":
103726
+ case "if":
103727
+ case "transaction":
103728
+ return null;
103729
+ case "value":
103730
+ case "get":
103731
+ case "getFirstNonEmpty":
103732
+ case "unit":
103733
+ return void 0;
103734
+ default:
103735
+ assertNever(node, `Unexpected node type: ${node.type}`);
103736
+ }
103737
+ }
103504
103738
  function applyComments(query2, sqlCommenter) {
103505
103739
  if (!sqlCommenter || sqlCommenter.plugins.length === 0) {
103506
103740
  return query2;
@@ -108164,10 +108398,18 @@ function mapDriverError3(error44) {
108164
108398
  message: error44.message
108165
108399
  };
108166
108400
  case "23505": {
108167
- const fields = error44.detail?.match(/Key \(([^)]+)\)/)?.at(1)?.split(", ");
108401
+ let constraint;
108402
+ if (error44.constraint) {
108403
+ constraint = { index: error44.constraint };
108404
+ } else {
108405
+ const fields = error44.detail?.match(/Key \(([^)]+)\)/)?.at(1)?.split(", ");
108406
+ if (fields !== void 0) {
108407
+ constraint = { fields };
108408
+ }
108409
+ }
108168
108410
  return {
108169
108411
  kind: "UniqueConstraintViolation",
108170
- constraint: fields !== void 0 ? { fields } : void 0
108412
+ constraint
108171
108413
  };
108172
108414
  }
108173
108415
  case "23502": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/query-plan-executor",
3
- "version": "7.10.0-dev.21",
3
+ "version": "7.10.0-dev.23",
4
4
  "description": "This package is intended for Prisma's internal use",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,11 +19,11 @@
19
19
  "hono": "^4.12.23",
20
20
  "temporal-polyfill": "0.3.0",
21
21
  "zod": "4.1.3",
22
- "@prisma/adapter-pg": "7.10.0-dev.21",
23
- "@prisma/adapter-mssql": "7.10.0-dev.21",
24
- "@prisma/adapter-mariadb": "7.10.0-dev.21",
25
- "@prisma/client-engine-runtime": "7.10.0-dev.21",
26
- "@prisma/driver-adapter-utils": "7.10.0-dev.21"
22
+ "@prisma/adapter-pg": "7.10.0-dev.23",
23
+ "@prisma/adapter-mssql": "7.10.0-dev.23",
24
+ "@prisma/adapter-mariadb": "7.10.0-dev.23",
25
+ "@prisma/client-engine-runtime": "7.10.0-dev.23",
26
+ "@prisma/driver-adapter-utils": "7.10.0-dev.23"
27
27
  },
28
28
  "files": [
29
29
  "dist"