@aventara/prisma7-adapter 0.1.0-pilot.1 → 0.1.0-pilot.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.
Files changed (79) hide show
  1. package/README.md +33 -20
  2. package/dist/discovery/artifact.loader.d.ts +6 -2
  3. package/dist/discovery/artifact.loader.js +12 -57
  4. package/dist/discovery/capability-surface.interface.d.ts +29 -40
  5. package/dist/discovery/capability-surface.interface.js +0 -12
  6. package/dist/discovery/capability.deriver.d.ts +10 -40
  7. package/dist/discovery/capability.deriver.js +0 -179
  8. package/dist/discovery/client-shape.verifier.d.ts +13 -0
  9. package/dist/discovery/client-shape.verifier.js +93 -0
  10. package/dist/discovery/discovery-artifact.interface.d.ts +55 -30
  11. package/dist/discovery/enum.mapper.d.ts +6 -14
  12. package/dist/discovery/enum.mapper.js +1 -2
  13. package/dist/discovery/field.mapper.d.ts +49 -63
  14. package/dist/discovery/field.mapper.js +0 -161
  15. package/dist/discovery/identifier.mapper.d.ts +38 -77
  16. package/dist/discovery/identifier.mapper.js +0 -64
  17. package/dist/discovery/model.discoverer.d.ts +18 -35
  18. package/dist/discovery/model.discoverer.js +66 -141
  19. package/dist/discovery/operations.deriver.d.ts +10 -38
  20. package/dist/discovery/operations.deriver.js +0 -40
  21. package/dist/discovery/scalar.mapper.d.ts +12 -35
  22. package/dist/discovery/scalar.mapper.js +0 -8
  23. package/dist/discovery/schema-facts.interface.d.ts +26 -25
  24. package/dist/discovery/schema-facts.interface.js +0 -10
  25. package/dist/discovery/schema.reader.d.ts +53 -64
  26. package/dist/discovery/schema.reader.js +0 -174
  27. package/dist/discovery/types.reader.d.ts +0 -4
  28. package/dist/discovery/types.reader.js +2 -177
  29. package/dist/discovery/vocabulary.dictionary.d.ts +36 -75
  30. package/dist/discovery/vocabulary.dictionary.js +2 -152
  31. package/dist/errors/error.normalizer.d.ts +85 -135
  32. package/dist/errors/error.normalizer.js +1 -70
  33. package/dist/errors/prisma-error.reader.d.ts +53 -68
  34. package/dist/errors/prisma-error.reader.js +0 -91
  35. package/dist/execution/first-variant.emulator.d.ts +11 -22
  36. package/dist/execution/first-variant.emulator.js +0 -142
  37. package/dist/execution/operation.executor.d.ts +12 -19
  38. package/dist/execution/operation.executor.js +0 -92
  39. package/dist/execution/result.shaper.d.ts +22 -31
  40. package/dist/execution/result.shaper.js +0 -24
  41. package/dist/execution/transaction.executor.d.ts +36 -73
  42. package/dist/generate/artifact.emitter.d.ts +27 -27
  43. package/dist/generate/artifact.emitter.js +30 -13
  44. package/dist/generate/declared-support.reader.d.ts +11 -11
  45. package/dist/generate/declared-support.reader.js +0 -12
  46. package/dist/generate/discovery.bin.js +0 -10
  47. package/dist/generate/discovery.cli.js +0 -55
  48. package/dist/generate/existence.gate.d.ts +26 -32
  49. package/dist/generate/existence.gate.js +0 -6
  50. package/dist/generate/index.d.ts +10 -12
  51. package/dist/generate/index.js +0 -42
  52. package/dist/generate/node-version.guard.js +0 -12
  53. package/dist/generate/prisma-cli.resolver.d.ts +9 -11
  54. package/dist/generate/prisma-cli.resolver.js +0 -13
  55. package/dist/generate/prisma.generate.d.ts +49 -65
  56. package/dist/generate/prisma.generate.js +13 -123
  57. package/dist/generate/reader-crosscheck.d.ts +36 -60
  58. package/dist/generate/reader-crosscheck.js +5 -41
  59. package/dist/prisma-client.interface.d.ts +14 -19
  60. package/dist/prisma-client.interface.js +0 -6
  61. package/dist/prisma.adapter.d.ts +9 -17
  62. package/dist/prisma.adapter.js +11 -53
  63. package/dist/provider/provider-profile.d.ts +6 -23
  64. package/dist/provider/provider-profile.js +0 -64
  65. package/dist/translation/identifier.addressing.d.ts +15 -22
  66. package/dist/translation/identifier.addressing.js +0 -10
  67. package/dist/translation/mutation.translator.d.ts +19 -43
  68. package/dist/translation/mutation.translator.js +1 -209
  69. package/dist/translation/operation.translator.d.ts +36 -63
  70. package/dist/translation/operation.translator.js +1 -51
  71. package/dist/translation/order-pagination.translator.d.ts +24 -31
  72. package/dist/translation/order-pagination.translator.js +0 -43
  73. package/dist/translation/projection.translator.d.ts +25 -58
  74. package/dist/translation/projection.translator.js +0 -27
  75. package/dist/translation/scalar.conversion.d.ts +15 -26
  76. package/dist/translation/scalar.conversion.js +1 -129
  77. package/dist/translation/where.translator.d.ts +17 -28
  78. package/dist/translation/where.translator.js +0 -83
  79. package/package.json +3 -3
@@ -1,88 +1,9 @@
1
1
  import { advertisedDirectives, } from "@aventara/core";
2
2
  import { addressIdentifier } from "./identifier.addressing.js";
3
3
  import { emitScalarValue } from "./scalar.conversion.js";
4
- /**
5
- * T-7's mutation half — one validated Aventara `data` in, one Prisma write
6
- * argument out.
7
- *
8
- * # Pure, and the tables are the module
9
- *
10
- * No client, no database, no provider name. Three tables carry everything this
11
- * module knows, each one TOTAL over a core union by `satisfies`, so a member
12
- * added to core with no row here is a compile error rather than a silently
13
- * dropped argument (C-855's emission half, C-837's translator table — the one
14
- * `vocabulary.dictionary.ts` explicitly left to this task):
15
- *
16
- * - {@link SCALAR_DIRECTIVE_TOKENS} over `ScalarMutationDirective`;
17
- * - {@link RELATION_DIRECTIVE_EMISSIONS} over `RelationMutationDirective`;
18
- * - {@link MUTATION_DATA_SITES} over every standard operation key, which is
19
- * C-818's enforcement point.
20
- *
21
- * C-834's own table is NOT one of them any more: the scalar value conversion was
22
- * born here, and `where.translator.ts` and `execution/result.shaper.ts` need the
23
- * same answers, so it moved to `scalar.conversion.ts` and all three read it
24
- * (Task 10's `identifier.addressing.ts` is the precedent). This module's
25
- * emission site is {@link emitValue}, which is now a call rather than a copy.
26
- *
27
- * Phase 7's `RELATION_MUTATION_RECORD_SITES` is the pattern
28
- * (`packages/core/src/runtime/mutation-planner.ts`): `as const satisfies
29
- * Readonly<Record<Union, …>>` keeps every cell a literal while making the union
30
- * coverage a compile-time obligation. Two of core's passes are already keyed
31
- * that way; this is the third, and the only one that names Prisma.
32
- *
33
- * # Refusing is part of honouring (the `where.translator.ts` stance)
34
- *
35
- * The adapter assumes validated input (C-845). It still refuses to EMIT a
36
- * directive the discovered model does not advertise for that field and stage,
37
- * and refuses one for which Prisma's nested input at that stage and cardinality
38
- * has no key at all. Both refusals are C-855 seen from the emission side: an
39
- * argument is honoured or it is not sent. A directive quietly dropped here would
40
- * surface as a write that silently did less than it was asked to.
41
- *
42
- * # C-818 cannot reach the Contract, so it is enforced here
43
- *
44
- * `RelationFieldCapabilities` is one record per field with a single `create`
45
- * member **[CORE, adapters/adapter-field.ts]**, so "relation create directives
46
- * for `create.one` and none for `create.many`" is unrepresentable in the model;
47
- * `model.discoverer.ts` composes the permissive `create.one` answer and says so.
48
- * The restriction therefore lives in {@link MUTATION_DATA_SITES}, which is keyed
49
- * by the operation the data belongs to. Measured at 7.10.0 on both engines
50
- * (2026-10-02), a nested relation key in a bulk write is a hard failure, not a
51
- * no-op:
52
- *
53
- * - `post.createMany({ data: [{ title, author: { connect: … } }] })` →
54
- * *"Argument `authorId` is missing."*
55
- * - `post.updateMany({ where, data: { category: { connect: … } } })` →
56
- * *"Unknown argument `category`. Available options are marked with ?."*
57
- *
58
- * # Nothing in the caller's arguments is touched
59
- *
60
- * Every object and array returned is new. The input is read, never written: a
61
- * translator that mutated its argument would corrupt the second attempt of a
62
- * retried operation, which is the one place the bug would not show up in a
63
- * single-shot test.
64
- */
65
- /** A mutation the model, the stage or the active operation does not license. */
66
4
  export class PrismaMutationTranslationError extends Error {
67
5
  name = "PrismaMutationTranslationError";
68
6
  }
69
- /* ------------------------------------------------------------------ *
70
- * C-837 — the scalar directive table *
71
- * ------------------------------------------------------------------ */
72
- /**
73
- * The Prisma operand key for each of core's scalar mutation directives.
74
- *
75
- * The inverse of discovery's `PRISMA_SCALAR_DIRECTIVES` rename table, written
76
- * here rather than imported from it for the reason `where.translator.ts` gives:
77
- * that table is generate-time and `vocabulary.dictionary.ts` is excluded from
78
- * the published build, while this module is runtime. `mutation.translator.spec.ts`
79
- * round-trips every emitted token back through the dictionary, so the two cannot
80
- * drift.
81
- *
82
- * Prisma's `set` has no row because it is not a directive: plain assignment is
83
- * how core spells it, and the bare value is what this module emits — wrapping it
84
- * in `{ set: … }` would add a token the request never carried.
85
- */
86
7
  const SCALAR_DIRECTIVE_TOKENS = {
87
8
  $increment: "increment",
88
9
  $decrement: "decrement",
@@ -91,53 +12,6 @@ const SCALAR_DIRECTIVE_TOKENS = {
91
12
  $push: "push",
92
13
  $unset: "unset",
93
14
  };
94
- /**
95
- * §18.5's normalization table, forward: one Aventara directive → one Prisma
96
- * nested-write key and operand, per stage and cardinality.
97
- *
98
- * Total over `RelationMutationDirective`, so a ninth directive fails to compile
99
- * — the same obligation core's two tables carry. Every cell below was read off
100
- * the generated types and then RUN on both engines (2026-10-02); the three that
101
- * matter are not key-for-key renames and would each have been wrong the obvious
102
- * way.
103
- *
104
- * **To-many `$update` emits `updateMany`, not `update`.** Core validates a
105
- * to-many `$update` entry's `where` with `validateWhere` — a GENERAL filter, not
106
- * a unique selector **[CORE, operations/operation-validator-core.ts]** — and
107
- * §18.5 says so in as many words: *"Prisma nested update/updateMany normalize to
108
- * $update (general where → update every relation match)"*. Prisma's nested
109
- * `update` takes `<T>UpdateWithWhereUnique…Input`, which refuses a general
110
- * filter: *"Argument `where` of type PostWhereUniqueInput needs at least one of
111
- * `id` arguments."* `updateMany` takes `{ where: <T>ScalarWhereInput, data }`,
112
- * which is the shape core actually hands over.
113
- *
114
- * **To-many `$delete` emits `deleteMany`, for the same reason**, and its operand
115
- * is the where UNWRAPPED: `deleteMany?: PostScalarWhereInput`. The singular
116
- * `delete` is a `<T>WhereUniqueInput[]` and refuses the entry: *"Argument
117
- * `delete`: Invalid value provided. Expected PostWhereUniqueInput[], provided
118
- * Object."*
119
- *
120
- * **A `<T>ScalarWhereInput` carries scalars only**, so the two bulk forms refuse
121
- * a relation predicate rather than emit one Prisma will reject: *"Unknown
122
- * argument `category`. Did you mean `categoryId`?"* — and `updateMany`'s `data`
123
- * is an `UpdateMany` input, so it admits no nested relation write either:
124
- * *"Unknown argument `category`."*
125
- *
126
- * **The create stage admits four directives, not eight.**
127
- * `<T>Create…NestedInput` carries `create`, `connectOrCreate`, `createMany` and
128
- * `connect` and nothing else, on both cardinalities — *"Unknown argument
129
- * `disconnect`. Did you mean `connect`?"*, *"Unknown argument `set`."* A to-one
130
- * edge has no `set` at EITHER stage: *"Unknown argument `set`. Did you mean
131
- * `upsert`?"* The `create: null` cells are therefore measured facts.
132
- *
133
- * They were also where discovery over-advertised: `PrismaRelationSurface` carried
134
- * ONE mutation list, read off the UPDATE-stage nested input and reused for both
135
- * stages, so the model offered `$set`/`$disconnect`/`$update`/`$delete`/`$upsert`
136
- * at the create stage, which Prisma has no key for. This table refused them
137
- * loudly — which is C-855's whole point — and the deriver now reads each stage
138
- * from its own nested input (`createMutations` / `updateMutations`), so the
139
- * Contract no longer advertises what these cells refuse.
140
- */
141
15
  const RELATION_DIRECTIVE_EMISSIONS = {
142
16
  $create: {
143
17
  create: {
@@ -202,22 +76,6 @@ const RELATION_DIRECTIVE_EMISSIONS = {
202
76
  },
203
77
  },
204
78
  };
205
- /**
206
- * Every standard operation, and the mutation data it carries — `null` for the
207
- * ten that carry none.
208
- *
209
- * Total over the whole operation set rather than over the mutating subset, so a
210
- * variant added to `ResourceOperations` fails to compile here instead of
211
- * reaching the `forbidden`/`nested` question by default. The read and delete
212
- * families are `null` for the same reason the dictionary spells a missing
213
- * Aventara word `null`: *"no data"* is an answer, and an absent row is not.
214
- *
215
- * `create.many`, `create.count`, `update.many` and `update.count` are the
216
- * `forbidden` four: they become `createMany`/`updateMany`, whose inputs carry
217
- * scalars and foreign keys only. `update.first` is `nested` because the variant
218
- * is emulated as a read followed by a singular `update` (T-7.1), and that write
219
- * step is an `<M>UpdateInput`.
220
- */
221
79
  const MUTATION_DATA_SITES = {
222
80
  "find.first": null,
223
81
  "find.unique": null,
@@ -236,14 +94,6 @@ const MUTATION_DATA_SITES = {
236
94
  "delete.count": null,
237
95
  "upsert.unique": { stages: ["create", "update"], relations: "nested" },
238
96
  };
239
- /**
240
- * Translates one validated Aventara mutation `data` into the Prisma write
241
- * argument for the named operation and stage.
242
- *
243
- * @throws {PrismaMutationTranslationError} rather than emitting a directive the
244
- * model does not advertise, one Prisma has no key for at this stage and
245
- * cardinality, or a nested relation write inside a bulk argument (C-818).
246
- */
247
97
  export function translateMutationData(input, dependencies) {
248
98
  const key = `${input.operation.family}.${input.operation.variant}`;
249
99
  if (!isOperationKey(key)) {
@@ -281,9 +131,7 @@ function translateRecord(pass, resourceKey, data, stage, path) {
281
131
  continue;
282
132
  }
283
133
  if (pass.relations === "forbidden") {
284
- // C-818, and the only place it can be enforced: the Contract cannot say
285
- // which variant this data belongs to.
286
- throw new PrismaMutationTranslationError(`${path}.${key}: a bulk write carries no nested relation directive; Prisma's createMany/updateMany inputs admit scalars and foreign keys only (C-818)`);
134
+ throw new PrismaMutationTranslationError(`${path}.${key}: a bulk write carries no nested relation directive; Prisma's createMany/updateMany inputs admit scalars and foreign keys only`);
287
135
  }
288
136
  emitted[key] = translateRelationWrite(pass, field, value, stage, `${path}.${key}`);
289
137
  }
@@ -296,9 +144,6 @@ function translateScalarWrite(pass, field, value, stage, path) {
296
144
  }
297
145
  const directives = directiveKeysOf(value, path);
298
146
  if (directives === undefined) {
299
- // Core's own rule: a value that is not a directive object IS plain
300
- // assignment, and Prisma spells that the same way. Wrapping it in
301
- // `{ set: … }` would emit a token the request never carried.
302
147
  return emitValue(pass, field, value, path);
303
148
  }
304
149
  const operand = {};
@@ -313,16 +158,6 @@ function translateScalarWrite(pass, field, value, stage, path) {
313
158
  }
314
159
  return operand;
315
160
  }
316
- /**
317
- * The directive keys of a scalar write, or `undefined` when the value is a
318
- * value.
319
- *
320
- * The discriminant is the `$` prefix, which is core's own
321
- * (`validateScalarMutation` rejects a mixed object with `V1001` *"Scalar
322
- * mutation action objects may contain only $-prefixed directive keys"*). It is
323
- * mirrored rather than improved on: a `json` column's value is a plain object
324
- * too, and any second discriminant would disagree with core's on some input.
325
- */
326
161
  function directiveKeysOf(value, path) {
327
162
  if (!isRecord(value)) {
328
163
  return undefined;
@@ -337,13 +172,6 @@ function directiveKeysOf(value, path) {
337
172
  }
338
173
  return directives;
339
174
  }
340
- /**
341
- * C-834's emission site: one Aventara runtime value, one Prisma operand.
342
- *
343
- * The conversion itself belongs to `scalar.conversion.ts`, which owns both
344
- * directions for every scalar; this module owns only *where* a value sits in a
345
- * write argument.
346
- */
347
175
  function emitValue(pass, field, value, path) {
348
176
  return emitScalarValue(pass.model, field, value, path);
349
177
  }
@@ -374,11 +202,6 @@ function translateRelationWrite(pass, field, value, stage, path) {
374
202
  }
375
203
  return emitted;
376
204
  }
377
- /**
378
- * One directive's operand, with its ARITY preserved: core admits a single entry
379
- * or an array on a to-many edge, Prisma admits both, and collapsing or
380
- * expanding one would change the shape the request carried.
381
- */
382
205
  function emitRelationOperand(pass, target, cardinality, form, operand, path) {
383
206
  if (cardinality === "many" && Array.isArray(operand)) {
384
207
  return operand.map((entry, index) => emitRelationEntry(pass, target, form, entry, `${path}[${index}]`));
@@ -418,8 +241,6 @@ function emitRelationEntry(pass, target, form, entry, path) {
418
241
  throw new PrismaMutationTranslationError(`${path}: a to-one $delete is true or an optional where object`);
419
242
  }
420
243
  if (!Object.hasOwn(entry, "where")) {
421
- // `{}` is "delete the related row", which Prisma spells `true`. The
422
- // empty object is not a Prisma where: `delete: {}` would match nothing.
423
244
  return true;
424
245
  }
425
246
  return pass.dependencies.translateWhere(target, entry.where, `${path}.where`);
@@ -436,14 +257,11 @@ function emitRelationEntry(pass, target, form, entry, path) {
436
257
  const { where, data } = requireMembers(entry, ["where", "data"], path);
437
258
  return {
438
259
  where: scalarWhere(pass, target, where, `${path}.where`),
439
- // `<T>UpdateManyWithWhere…Input.data` is an UpdateMany input: scalars
440
- // and foreign keys only, exactly as a top-level `updateMany`.
441
260
  data: translateRecord(bulk(pass), target, data, "update", `${path}.data`),
442
261
  };
443
262
  }
444
263
  case "to-many-delete-many": {
445
264
  const { where } = requireMembers(entry, ["where"], path);
446
- // `deleteMany` takes the scalar where itself, not `{ where }`.
447
265
  return scalarWhere(pass, target, where, `${path}.where`);
448
266
  }
449
267
  case "to-many-upsert": {
@@ -464,27 +282,14 @@ function bulk(pass) {
464
282
  ? pass
465
283
  : { ...pass, relations: "forbidden" };
466
284
  }
467
- /** A to-one `$update`/`$upsert` `where` is optional, and absent is not `undefined`. */
468
285
  function optionalWhere(pass, target, entry, path) {
469
286
  if (!isRecord(entry) || !Object.hasOwn(entry, "where")) {
470
287
  return {};
471
288
  }
472
- // Prisma's to-one `update`/`upsert` `where` is a general `<T>WhereInput`, so
473
- // core's flat unique selector needs no addressing here — it is already a valid
474
- // filter. Measured on both engines (2026-10-02).
475
289
  return {
476
290
  where: pass.dependencies.translateWhere(target, entry.where, `${path}.where`),
477
291
  };
478
292
  }
479
- /**
480
- * A `<T>ScalarWhereInput`: the nested bulk forms' filter, which carries scalar
481
- * columns only.
482
- *
483
- * Core's `validateWhere` admits a relation predicate here, so this is a real
484
- * narrowing and it refuses rather than emits: Prisma answers *"Unknown argument
485
- * `category`. Did you mean `categoryId`?"* on both engines. Reported as a
486
- * C-855 gap in the advertised surface rather than silently dropped.
487
- */
488
293
  function scalarWhere(pass, target, where, path) {
489
294
  requireScalarPredicate(pass, target, where, path);
490
295
  return pass.dependencies.translateWhere(target, where, path);
@@ -513,15 +318,6 @@ function requireScalarPredicate(pass, target, where, path) {
513
318
  }
514
319
  }
515
320
  }
516
- /**
517
- * Core's FLAT unique selector → Prisma's `<T>WhereUniqueInput`, for a NESTED
518
- * `connect`/`disconnect`/`set`/`update`/`upsert` target.
519
- *
520
- * The addressing rule itself lives in `identifier.addressing.ts`, which Task 10
521
- * extracted when the top-level where-unique made it the third copy. What stays
522
- * here is this site's two decisions: the match is **exact**, and each member's
523
- * value goes out through C-834's scalar emission (`scalar.conversion.ts`).
524
- */
525
321
  function addressUnique(pass, target, selector, path) {
526
322
  if (!isRecord(selector)) {
527
323
  throw new PrismaMutationTranslationError(`${path} must be a unique identifier object`);
@@ -534,10 +330,6 @@ function addressUnique(pass, target, selector, path) {
534
330
  if (addresses === undefined) {
535
331
  throw new PrismaMutationTranslationError(`${path}: Resource "${target}" has no Prisma addressing in the translation table`);
536
332
  }
537
- // `"exact"`: core's unique selector carries one identifier and nothing else,
538
- // so a spare key means it is not that identifier. Each member goes out through
539
- // C-834's scalar emission, which is why the conversion is passed in rather
540
- // than the table imported by the addressing module.
541
333
  const addressed = addressIdentifier({
542
334
  addresses,
543
335
  values: selector,
@@ -2,14 +2,10 @@ import type { AdapterModel, AdapterOperation } from "@aventara/core";
2
2
  import type { PrismaResourceTranslation } from "../discovery/discovery-artifact.interface.js";
3
3
  import { type PrismaProjectionPlan } from "./projection.translator.js";
4
4
  /**
5
- * T-7 — **one validated Aventara operation → one provider call description**,
6
- * and the module that makes the whole sixteen-variant grammar assertable as pure
7
- * data with no database in sight.
8
- *
9
5
  * Splitting translation from execution is the plan's single largest testability
10
- * decision (T-7): everything below is a pure function of the discovered model,
11
- * the generate-time translation table and the arguments core validated. The
12
- * database is needed only for the *other* half, `execution/operation.executor.ts`.
6
+ * decision: everything below is a pure function of the discovered model, the
7
+ * generate-time translation table and the arguments core validated. The database
8
+ * is needed only for the *other* half, `execution/operation.executor.ts`.
13
9
  *
14
10
  * # The dispatch table is the module
15
11
  *
@@ -21,43 +17,32 @@ import { type PrismaProjectionPlan } from "./projection.translator.js";
21
17
  *
22
18
  * # The negative half of the table is the load-bearing half
23
19
  *
24
- * {@link PrismaAction} deliberately **excludes** `findUniqueOrThrow` and
25
- * `findFirstOrThrow` (RC-2: core's outcome mapper owns the absence decision, and
26
- * an `OrThrow` call would move it into the adapter), `groupBy` and `aggregate`
27
- * (spec §18.5), and **every raw action** — the `findRaw`/`aggregateRaw` model
28
- * actions and the client's own raw methods — which C-853 forbids outright and
29
- * permanently. Aventara is not an ORM and reaches the database only through the
30
- * adapter's ORM; a raw statement would forfeit the ORM's own injection
31
- * protection and oblige Aventara to build its own. Because the exclusion lives in
32
- * the *type*, a raw call is not representable in a {@link PrismaExecutionPlan} at
33
- * all: the rule is enforced by the compiler, not by a reviewer's memory.
20
+ * Aventara is not an ORM and reaches the database only through the adapter's ORM;
21
+ * a raw statement would forfeit the ORM's own injection protection and oblige
22
+ * Aventara to build its own. Because the exclusion lives in the *type*, a raw call
23
+ * is not representable in a {@link PrismaExecutionPlan} at all: the rule is
24
+ * enforced by the compiler, not by a reviewer's memory.
34
25
  * `operation.translator.spec.ts` asserts the same thing from the value side, as
35
26
  * the belt to that type's braces.
36
27
  *
37
28
  * # `delete.many` is a hole in the table, and the hole is the decision
38
29
  *
39
- * 7.10.0 has no `deleteManyAndReturn` **[PKG]**, and the architect ruled the
40
- * variant **omitted rather than emulated** (C-829, D-826). `operations.deriver.ts`
41
- * therefore never advertises it, so core rejects the request with `A2002
42
- * UNKNOWN_OPERATION` before any adapter call. The table still carries the key —
43
- * it is total over core's grammar — with an `"unavailable"` entry, so the
44
- * omission is a fact a reader can find rather than an absence they have to infer.
30
+ * `operations.deriver.ts` therefore never advertises it, so core rejects the
31
+ * request with `A2002 UNKNOWN_OPERATION` before any adapter call. The table still
32
+ * carries the key — it is total over core's grammar — with an `"unavailable"`
33
+ * entry, so the omission is a fact a reader can find rather than an absence they
34
+ * have to infer.
45
35
  *
46
36
  * # First-style variants, and the write route
47
37
  *
48
- * `update.first` and `delete.first` are **framework-manufactured** (D-828): a
49
- * cross-ORM survey found the four-part shape — general filter, ordering decides
50
- * "first", effect limited to one row, the affected row is returned, all in one
51
- * call — essentially absent across ORM design, and Prisma 7.10.0 has no
38
+ * `update.first` and `delete.first` are **framework-manufactured**: a cross-ORM
39
+ * survey found the four-part shape — general filter, ordering decides "first",
40
+ * effect limited to one row, the affected row is returned, all in one call —
41
+ * essentially absent across ORM design, and Prisma 7.10.0 has no
52
42
  * `updateFirst`/`deleteFirst` **[PKG]**. So the plan is an ordinary read then
53
43
  * write, and its two steps are {@link PrismaExecutionPlan}'s `"emulated"` arm.
54
44
  *
55
- * **The write route is Route A — select-first + unique mutation — and Task 10
56
- * measured it rather than inheriting it.** T-7.1.1 recorded two routes and §14e
57
- * reserved the choice; §1.0 forbids an implementation task from blocking on an
58
- * owner decision, so Task 10 ran both against the real 7.10.0 client on **both**
59
- * engines. Every row came out for Route A, and two of them came out *against*
60
- * Route B:
45
+ * Every row came out for Route A, and two of them came out *against* Route B:
61
46
  *
62
47
  * ```text
63
48
  * measured 2026-10-02, @prisma/client 7.10.0, SQLite + PostgreSQL 18, identical
@@ -76,13 +61,8 @@ import { type PrismaProjectionPlan } from "./projection.translator.js";
76
61
  * B deleteMany({ where: { id, AND: […] } }) -> { count: 1 } — carries no row at all
77
62
  * ```
78
63
  *
79
- * So Route A is the mechanism spec §8.3's own worked example names, it satisfies
80
- * §8.2's return contract for **every** projection core can plan, and it needs no
81
- * pre-write projection read and no identifier strip. Route B cannot serve a
82
- * caller projection that reaches a to-many relation or `$count` at all, and its
83
- * `delete.first` must read before it writes. The route is **one entry** in the
84
- * table below — {@link FIRST_VARIANT_WRITE_ROUTE} — which is the seam D-801/§9
85
- * put here precisely so §14e's ratification (or reversal) is one edit.
64
+ * Route B cannot serve a caller projection that reaches a to-many relation or
65
+ * `$count` at all, and its `delete.first` must read before it writes.
86
66
  *
87
67
  * # The write step of an emulated plan is a template, and says so
88
68
  *
@@ -90,17 +70,15 @@ import { type PrismaProjectionPlan } from "./projection.translator.js";
90
70
  * step is **not**, by construction: its `where` carries the caller's re-asserted
91
71
  * predicate under `AND` and the identifier is added by
92
72
  * `execution/first-variant.emulator.ts` from the row the read returned. That is
93
- * what "emulated" means — the second statement is not knowable until the first
94
- * has run — and it is why the emulator, not this module, issues it.
95
- *
96
- * # Nothing is emitted that the framework did not send (C-855, D-830)
73
+ * what "emulated" means — the second statement is not knowable until the first has
74
+ * run — and it is why the emulator, not this module, issues it.
97
75
  *
98
76
  * Every key below is added only when the corresponding Aventara argument is
99
77
  * **present**. An absent argument and an `undefined` one are different arguments
100
78
  * to a provider, so `"take" in args` is never made true by accident. An argument
101
79
  * this module does not recognise raises rather than being dropped: an argument
102
- * that typechecks and is silently ignored is worse than an absent one, because
103
- * the absent one fails loudly at the caller (D-830's MikroORM evidence).
80
+ * that typechecks and is silently ignored is worse than an absent one, because the
81
+ * absent one fails loudly at the caller.
104
82
  */
105
83
  /** The `ModelAction` subset this adapter uses. See the header for the exclusions. */
106
84
  export type PrismaAction = "findUnique" | "findFirst" | "findMany" | "count" | "create" | "createMany" | "createManyAndReturn" | "update" | "updateMany" | "updateManyAndReturn" | "delete" | "deleteMany" | "upsert";
@@ -115,7 +93,7 @@ export type PrismaCall = {
115
93
  readonly action: PrismaAction;
116
94
  readonly args: Readonly<Record<string, unknown>>;
117
95
  };
118
- /** A variant is either one call, or an emulated sequence (§8.3, D-807). */
96
+ /** A variant is either one call, or an emulated sequence. */
119
97
  export type PrismaExecutionPlan = {
120
98
  readonly kind: "single";
121
99
  readonly call: PrismaCall;
@@ -125,11 +103,11 @@ export type PrismaExecutionPlan = {
125
103
  readonly atomicity: "outer-tx" | "own-tx";
126
104
  };
127
105
  /**
128
- * What the variant owes its caller, and therefore which shaper runs (T-8).
106
+ * What the variant owes its caller, and therefore which shaper runs.
129
107
  *
130
- * It is a property of the *variant*, not of the provider answer, so it belongs
131
- * in the dispatch table beside the action rather than in a second table the
132
- * executor would have to keep in step.
108
+ * It is a property of the *variant*, not of the provider answer, so it belongs in
109
+ * the dispatch table beside the action rather than in a second table the executor
110
+ * would have to keep in step.
133
111
  */
134
112
  export type PrismaResultKind = "row" | "rows" | "count";
135
113
  export type PrismaVariantDispatch = {
@@ -145,7 +123,7 @@ export type PrismaVariantDispatch = {
145
123
  readonly kind: "unavailable";
146
124
  readonly reason: string;
147
125
  };
148
- /** The sixteen-variant dispatch table (T-7, §18.4), total over core's grammar. */
126
+ /** The sixteen-variant dispatch table, total over core's grammar. */
149
127
  export declare const PRISMA_VARIANT_DISPATCH: {
150
128
  readonly "find.first": {
151
129
  readonly kind: "single";
@@ -216,7 +194,7 @@ export declare const PRISMA_VARIANT_DISPATCH: {
216
194
  };
217
195
  readonly "delete.many": {
218
196
  readonly kind: "unavailable";
219
- readonly reason: "@prisma/client 7.10.0 has no deleteManyAndReturn, so delete.many is omitted rather than emulated (C-829, D-826); delete.count deletes a filtered set";
197
+ readonly reason: "@prisma/client 7.10.0 has no deleteManyAndReturn, so delete.many is omitted rather than emulated; delete.count deletes a filtered set";
220
198
  };
221
199
  readonly "delete.count": {
222
200
  readonly kind: "single";
@@ -237,13 +215,8 @@ export declare class PrismaOperationTranslationError extends Error {
237
215
  * The translation of one operation: the plan, plus the projection plan the result
238
216
  * shaper needs.
239
217
  *
240
- * T-7 names only `PrismaExecutionPlan`, and that is not enough on its own:
241
- * `AdapterOperation` carries no read plan **[CORE]**, so Task 8's
242
- * {@link PrismaProjectionPlan} — the reconstruction of where every `$count`
243
- * envelope sits — is produced *here*, while translating the projection, and
244
- * cannot be recovered from the emitted Prisma arguments afterwards (Prisma's
245
- * `_count` is a sibling key, not a position). Returning it beside the plan is
246
- * what keeps `result.shaper.ts` free of a second, drifting reconstruction.
218
+ * Returning it beside the plan is what keeps `result.shaper.ts` free of a second,
219
+ * drifting reconstruction.
247
220
  */
248
221
  export type PrismaOperationTranslation = {
249
222
  readonly plan: PrismaExecutionPlan;
@@ -251,9 +224,9 @@ export type PrismaOperationTranslation = {
251
224
  /**
252
225
  * The caller's `where`, translated, or `undefined` when they sent none.
253
226
  *
254
- * Recorded for the emulator, which re-asserts it on the write (C-856, D-829).
255
- * It is the same value the read step carries, by identity, so the two halves
256
- * of the manufacture cannot assert different predicates.
227
+ * Recorded for the emulator, which re-asserts it on the write. It is the same
228
+ * value the read step carries, by identity, so the two halves of the manufacture
229
+ * cannot assert different predicates.
257
230
  */
258
231
  readonly predicate: Readonly<Record<string, unknown>> | undefined;
259
232
  };
@@ -3,32 +3,16 @@ import { translateMutationData } from "./mutation.translator.js";
3
3
  import { translateOrderBy, translatePagination, } from "./order-pagination.translator.js";
4
4
  import { translateProjection, } from "./projection.translator.js";
5
5
  import { translateWhere } from "./where.translator.js";
6
- /**
7
- * The chosen first-variant write route, in one place (§14e, T-7.1.1).
8
- *
9
- * Route A: the read selects the identifier, and the write is Prisma's own
10
- * `update`/`delete` narrowed to that identifier with the caller's predicate
11
- * re-asserted. Both are projection-carrying — their result maps through
12
- * `GetFindResult`, the same helper `findFirst` uses **[PKG,
13
- * `runtime/client.d.ts:1352`, `:1356`, `:1144`]** — and Task 10 measured both on
14
- * both engines (see the header). Switching to Route B is an edit to these two
15
- * cells and to `first-variant.emulator.ts`'s lost-row detection, and nothing else.
16
- */
17
6
  const FIRST_VARIANT_WRITE_ROUTE = {
18
7
  update: "update",
19
8
  delete: "delete",
20
9
  };
21
- /** The sixteen-variant dispatch table (T-7, §18.4), total over core's grammar. */
22
10
  export const PRISMA_VARIANT_DISPATCH = {
23
11
  "find.first": { kind: "single", action: "findFirst", result: "row" },
24
- // RC-2: `findUnique` and a returned `null`, never `findUniqueOrThrow` — core's
25
- // `OUTCOME_TABLE` owns the absence decision and maps the `null` to `A2003`.
26
12
  "find.unique": { kind: "single", action: "findUnique", result: "row" },
27
13
  "find.many": { kind: "single", action: "findMany", result: "rows" },
28
14
  "find.count": { kind: "single", action: "count", result: "count" },
29
15
  "create.one": { kind: "single", action: "create", result: "row" },
30
- // C-817: the row-returning bulk write is what `create.many` owes its caller;
31
- // `createMany` answers `{ count }` and is `create.count`'s call instead.
32
16
  "create.many": {
33
17
  kind: "single",
34
18
  action: "createManyAndReturn",
@@ -57,22 +41,14 @@ export const PRISMA_VARIANT_DISPATCH = {
57
41
  "delete.unique": { kind: "single", action: "delete", result: "row" },
58
42
  "delete.many": {
59
43
  kind: "unavailable",
60
- reason: "@prisma/client 7.10.0 has no deleteManyAndReturn, so delete.many is omitted rather than emulated (C-829, D-826); delete.count deletes a filtered set",
44
+ reason: "@prisma/client 7.10.0 has no deleteManyAndReturn, so delete.many is omitted rather than emulated; delete.count deletes a filtered set",
61
45
  },
62
46
  "delete.count": { kind: "single", action: "deleteMany", result: "count" },
63
47
  "upsert.unique": { kind: "single", action: "upsert", result: "row" },
64
48
  };
65
- /** An operation the adapter will not translate. */
66
49
  export class PrismaOperationTranslationError extends Error {
67
50
  name = "PrismaOperationTranslationError";
68
51
  }
69
- /**
70
- * Translates one validated Aventara operation.
71
- *
72
- * @throws {PrismaOperationTranslationError} for a variant the adapter advertises
73
- * no call for, an argument it does not recognise, or a unique selector that
74
- * addresses no row — never a silently narrowed or widened call.
75
- */
76
52
  export function translateOperation(input) {
77
53
  const key = `${input.operation.family}.${input.operation.variant}`;
78
54
  const dispatch = Object.hasOwn(PRISMA_VARIANT_DISPATCH, key)
@@ -125,9 +101,6 @@ export function translateOperation(input) {
125
101
  args: {
126
102
  ...(predicate === undefined ? {} : { where: predicate }),
127
103
  ...orderByArgument(context),
128
- // The read selects the identifier and nothing else: under Route A
129
- // the WRITE carries the caller's projection, so reading it twice
130
- // would be a statement the contract does not need.
131
104
  select: identifierSelect(context),
132
105
  },
133
106
  },
@@ -135,8 +108,6 @@ export function translateOperation(input) {
135
108
  model: context.resource,
136
109
  action: dispatch.write,
137
110
  args: {
138
- // A template: the identifier is added by the emulator from the row
139
- // the read returned. `AND` carries the re-assertion (C-856, D-829).
140
111
  ...(predicate === undefined ? {} : { where: { AND: predicate } }),
141
112
  ...(context.operation.family === "update"
142
113
  ? { data: mutationData(context, "update", "data") }
@@ -151,12 +122,6 @@ export function translateOperation(input) {
151
122
  predicate,
152
123
  };
153
124
  }
154
- /**
155
- * The four variants whose `where` is core's FLAT unique selector rather than a
156
- * general predicate, read from core's own rule: `hasGeneralRootWhere` is false
157
- * for exactly `find.unique`, `update.unique`, `delete.unique` and `upsert.unique`
158
- * **[CORE, operations/operation-validator.ts]**.
159
- */
160
125
  function isUniqueSelectorVariant(key) {
161
126
  return (key === "find.unique" ||
162
127
  key === "update.unique" ||
@@ -224,7 +189,6 @@ function singleCallArguments(context, key, predicate, projectionArgs) {
224
189
  throw new PrismaOperationTranslationError(`"${key}" has a dispatch entry and no argument shape, which is a translator defect`);
225
190
  }
226
191
  }
227
- /** Core's flat unique selector → `<M>WhereUniqueInput`, at the top level. */
228
192
  function uniqueWhere(context) {
229
193
  const selector = context.args.where;
230
194
  if (!isRecord(selector)) {
@@ -234,10 +198,6 @@ function uniqueWhere(context) {
234
198
  addresses: identifiersOf(context, context.resource),
235
199
  values: selector,
236
200
  match: "exact",
237
- // A unique selector's values are scalars core has already normalized. The
238
- // one conversion C-834 names — a core `Decimal`, which Prisma refuses — is
239
- // NOT applied here, and that is a recorded gap rather than an omission: see
240
- // `operation.executor.ts`'s header.
241
201
  emit: (_member, value) => value,
242
202
  });
243
203
  if (addressed === undefined) {
@@ -245,7 +205,6 @@ function uniqueWhere(context) {
245
205
  }
246
206
  return addressed.where;
247
207
  }
248
- /** The identifier the first-style read selects: the first recorded criterion. */
249
208
  function identifierSelect(context) {
250
209
  const [address] = identifiersOf(context, context.resource);
251
210
  if (address === undefined) {
@@ -293,7 +252,6 @@ function mutationData(context, stage, argument) {
293
252
  data: context.args[argument],
294
253
  }, mutationDependencies(context));
295
254
  }
296
- /** `create.many`/`create.count` carry an ARRAY of records **[CORE]**. */
297
255
  function bulkMutationData(context, key, stage) {
298
256
  const data = context.args.data;
299
257
  if (!Array.isArray(data)) {
@@ -317,14 +275,6 @@ function mutationDependencies(context) {
317
275
  ])),
318
276
  };
319
277
  }
320
- /**
321
- * Task 7's vocabulary, as the projection translator's one dependency.
322
- *
323
- * The nested arguments are translated against the **target** Resource, which the
324
- * projection path names: `projection.translator.ts` owns where a relation sits
325
- * and this closure owns what its arguments mean, which is the seam that keeps the
326
- * `_count` filter the *same* translated `where` the relation read uses.
327
- */
328
278
  function relationArgumentTranslator(context) {
329
279
  return (args, { path }) => {
330
280
  const target = resolveRelationTarget(context, path);