@aventara/prisma7-adapter 0.1.0-pilot.0 → 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.
- package/README.md +39 -28
- package/dist/discovery/artifact.loader.d.ts +6 -2
- package/dist/discovery/artifact.loader.js +12 -57
- package/dist/discovery/capability-surface.interface.d.ts +29 -40
- package/dist/discovery/capability-surface.interface.js +0 -12
- package/dist/discovery/capability.deriver.d.ts +10 -40
- package/dist/discovery/capability.deriver.js +0 -179
- package/dist/discovery/client-shape.verifier.d.ts +13 -0
- package/dist/discovery/client-shape.verifier.js +93 -0
- package/dist/discovery/discovery-artifact.interface.d.ts +55 -30
- package/dist/discovery/enum.mapper.d.ts +6 -14
- package/dist/discovery/enum.mapper.js +1 -2
- package/dist/discovery/field.mapper.d.ts +49 -63
- package/dist/discovery/field.mapper.js +0 -161
- package/dist/discovery/identifier.mapper.d.ts +38 -77
- package/dist/discovery/identifier.mapper.js +0 -64
- package/dist/discovery/model.discoverer.d.ts +18 -35
- package/dist/discovery/model.discoverer.js +66 -141
- package/dist/discovery/operations.deriver.d.ts +10 -38
- package/dist/discovery/operations.deriver.js +0 -40
- package/dist/discovery/scalar.mapper.d.ts +12 -35
- package/dist/discovery/scalar.mapper.js +0 -8
- package/dist/discovery/schema-facts.interface.d.ts +26 -25
- package/dist/discovery/schema-facts.interface.js +0 -10
- package/dist/discovery/schema.reader.d.ts +53 -64
- package/dist/discovery/schema.reader.js +0 -174
- package/dist/discovery/types.reader.d.ts +0 -4
- package/dist/discovery/types.reader.js +2 -177
- package/dist/discovery/vocabulary.dictionary.d.ts +36 -75
- package/dist/discovery/vocabulary.dictionary.js +2 -152
- package/dist/errors/error.normalizer.d.ts +85 -135
- package/dist/errors/error.normalizer.js +1 -70
- package/dist/errors/prisma-error.reader.d.ts +53 -68
- package/dist/errors/prisma-error.reader.js +0 -91
- package/dist/execution/first-variant.emulator.d.ts +11 -22
- package/dist/execution/first-variant.emulator.js +0 -142
- package/dist/execution/operation.executor.d.ts +12 -19
- package/dist/execution/operation.executor.js +0 -92
- package/dist/execution/result.shaper.d.ts +22 -31
- package/dist/execution/result.shaper.js +0 -24
- package/dist/execution/transaction.executor.d.ts +36 -73
- package/dist/generate/artifact.emitter.d.ts +27 -27
- package/dist/generate/artifact.emitter.js +30 -13
- package/dist/generate/declared-support.reader.d.ts +11 -11
- package/dist/generate/declared-support.reader.js +0 -12
- package/dist/generate/discovery.bin.js +0 -10
- package/dist/generate/discovery.cli.js +0 -55
- package/dist/generate/existence.gate.d.ts +26 -32
- package/dist/generate/existence.gate.js +0 -6
- package/dist/generate/index.d.ts +10 -12
- package/dist/generate/index.js +0 -42
- package/dist/generate/node-version.guard.js +0 -12
- package/dist/generate/prisma-cli.resolver.d.ts +9 -11
- package/dist/generate/prisma-cli.resolver.js +0 -13
- package/dist/generate/prisma.generate.d.ts +49 -65
- package/dist/generate/prisma.generate.js +13 -123
- package/dist/generate/reader-crosscheck.d.ts +36 -60
- package/dist/generate/reader-crosscheck.js +5 -41
- package/dist/prisma-client.interface.d.ts +14 -19
- package/dist/prisma-client.interface.js +0 -6
- package/dist/prisma.adapter.d.ts +9 -17
- package/dist/prisma.adapter.js +11 -53
- package/dist/provider/provider-profile.d.ts +6 -23
- package/dist/provider/provider-profile.js +0 -64
- package/dist/translation/identifier.addressing.d.ts +15 -22
- package/dist/translation/identifier.addressing.js +0 -10
- package/dist/translation/mutation.translator.d.ts +19 -43
- package/dist/translation/mutation.translator.js +1 -209
- package/dist/translation/operation.translator.d.ts +36 -63
- package/dist/translation/operation.translator.js +1 -51
- package/dist/translation/order-pagination.translator.d.ts +24 -31
- package/dist/translation/order-pagination.translator.js +0 -43
- package/dist/translation/projection.translator.d.ts +25 -58
- package/dist/translation/projection.translator.js +0 -27
- package/dist/translation/scalar.conversion.d.ts +15 -26
- package/dist/translation/scalar.conversion.js +1 -129
- package/dist/translation/where.translator.d.ts +17 -28
- package/dist/translation/where.translator.js +0 -83
- package/package.json +3 -3
package/dist/prisma.adapter.js
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
import { loadDiscoveryArtifact } from "./discovery/artifact.loader.js";
|
|
2
|
+
import { assertClientMatchesArtifact } from "./discovery/client-shape.verifier.js";
|
|
2
3
|
import { createPrismaOperationExecutor } from "./execution/operation.executor.js";
|
|
3
4
|
import { createPrismaTransactionExecutor } from "./execution/transaction.executor.js";
|
|
4
5
|
import { resolveProviderProfile, } from "./provider/provider-profile.js";
|
|
5
|
-
/**
|
|
6
|
-
* Each Prisma referential action as core's word for it (F-806). Keyed by the
|
|
7
|
-
* closed {@link PrismaReferentialAction} union with `satisfies`, so a sixth
|
|
8
|
-
* Prisma action is a compile error here rather than an edge core never follows,
|
|
9
|
-
* and valued by core's own union, so a word core does not have is one too. The
|
|
10
|
-
* mapping is one to one (the architect's five words, 2026-10-04): `no-action`
|
|
11
|
-
* stays `noAction` although, measured on both engines (Phase 9 S0, U4), it is not
|
|
12
|
-
* `DEFERRABLE` and answers one delete exactly as `restrict` does; `set-default`
|
|
13
|
-
* stays `setDefault` although, like `setNull`, it keeps the rows.
|
|
14
|
-
*/
|
|
15
6
|
const DELETE_EFFECTS = {
|
|
16
7
|
cascade: "cascade",
|
|
17
8
|
restrict: "restrict",
|
|
@@ -19,14 +10,6 @@ const DELETE_EFFECTS = {
|
|
|
19
10
|
"set-null": "setNull",
|
|
20
11
|
"set-default": "setDefault",
|
|
21
12
|
};
|
|
22
|
-
/**
|
|
23
|
-
* The artifact's referential actions, translated into core's vocabulary.
|
|
24
|
-
*
|
|
25
|
-
* The direction is carried over unchanged, because it is the same sentence on
|
|
26
|
-
* both sides of the seam: an edge listed under Resource `R` says **deleting a
|
|
27
|
-
* `target` row does `onDelete` to rows of `R`**. Only owning edges exist in the
|
|
28
|
-
* artifact, and `onUpdate` is not carried: core plans the delete closure only.
|
|
29
|
-
*/
|
|
30
13
|
function translateReferentialActions(table) {
|
|
31
14
|
return Object.fromEntries(Object.entries(table).map(([resource, { owningEdges }]) => [
|
|
32
15
|
resource,
|
|
@@ -37,44 +20,19 @@ function translateReferentialActions(table) {
|
|
|
37
20
|
})),
|
|
38
21
|
]));
|
|
39
22
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Construction is `async` because core's `Adapter.model` is a settled fact read
|
|
42
|
-
* synchronously at framework construction, while *verifying* the artifact is
|
|
43
|
-
* asynchronous: `computeModelHash` digests through `globalThis.crypto.subtle`,
|
|
44
|
-
* which is a promise-returning API. The artifact itself is already a value in
|
|
45
|
-
* hand (`options.discovery`); only its verification has to
|
|
46
|
-
* await, so it happens here, once, before an adapter exists — every fence is
|
|
47
|
-
* the same fence, moved from the first `discover()` call to construction.
|
|
48
|
-
*/
|
|
49
23
|
export async function createPrismaAdapter(options) {
|
|
50
24
|
const profile = resolveProviderProfile({
|
|
51
25
|
provider: options.provider,
|
|
52
26
|
driver: options.driver,
|
|
53
27
|
});
|
|
54
|
-
// The loader is a *verifier*, and its return is deliberately discarded. It
|
|
55
|
-
// takes `unknown` because it guards the runtime boundary, so its answer is
|
|
56
|
-
// the general `PrismaAdapterModel`; the literal `M` is already in hand on
|
|
57
|
-
// `options.discovery.model`, which is the very object the loader would have
|
|
58
|
-
// handed back. Reading it from the argument keeps the literal without a
|
|
59
|
-
// cast, and keeps the loader honest about validating untrusted input.
|
|
60
28
|
await loadDiscoveryArtifact({
|
|
61
29
|
artifact: options.discovery,
|
|
62
30
|
installedPrismaVersion: options.installedPrismaVersion ?? options.discovery.prismaVersion,
|
|
63
31
|
});
|
|
32
|
+
assertClientMatchesArtifact(options.discovery.client, options.client);
|
|
64
33
|
const model = options.discovery.model;
|
|
65
|
-
// Read once, like the model: a settled fact of the constructed adapter.
|
|
66
34
|
const referentialActions = translateReferentialActions(options.discovery.referentialActions);
|
|
67
|
-
|
|
68
|
-
// closes over the client, the discovered model and the generate-time
|
|
69
|
-
// translation table — the three facts every call needs and none of which can
|
|
70
|
-
// change afterwards.
|
|
71
|
-
//
|
|
72
|
-
// `translation` is widened by one deliberate cast. `PrismaTranslationTable<M>`
|
|
73
|
-
// is a mapped type over `M`'s own resource keys, which is exactly what makes a
|
|
74
|
-
// missing Resource a compile error at the generate step; a mapped type over a
|
|
75
|
-
// literal union carries no index signature, so the executor — which looks a
|
|
76
|
-
// Resource up by a name core validated — takes the widened view. The narrow
|
|
77
|
-
// type has already done its work by the time this line runs.
|
|
35
|
+
const createRequirements = options.discovery.createRequirements;
|
|
78
36
|
const { execute } = createPrismaOperationExecutor({
|
|
79
37
|
client: options.client,
|
|
80
38
|
model: options.discovery.model,
|
|
@@ -84,14 +42,8 @@ export async function createPrismaAdapter(options) {
|
|
|
84
42
|
? {}
|
|
85
43
|
: { transactionOptions: options.transactionOptions }),
|
|
86
44
|
});
|
|
87
|
-
// DA-12: `transaction` is mounted exactly when the declared driver supports
|
|
88
|
-
// an interactive one. For `@prisma/adapter-d1` the profile says `"none"`
|
|
89
|
-
// [PKG], so core never calls it and the `_transactions` route is never
|
|
90
|
-
// mounted. The declaration is Task 10's (D-805) and the body is Task 11's:
|
|
91
|
-
// one interactive transaction per plan, with the transaction-scoped executor
|
|
92
|
-
// as the only thing the callback hands core (C-803, C-804).
|
|
93
45
|
if (profile.transactions === "none") {
|
|
94
|
-
return { model, referentialActions, execute };
|
|
46
|
+
return { model, referentialActions, createRequirements, execute };
|
|
95
47
|
}
|
|
96
48
|
const transaction = createPrismaTransactionExecutor({
|
|
97
49
|
client: options.client,
|
|
@@ -101,5 +53,11 @@ export async function createPrismaAdapter(options) {
|
|
|
101
53
|
? {}
|
|
102
54
|
: { transactionOptions: options.transactionOptions }),
|
|
103
55
|
});
|
|
104
|
-
return {
|
|
56
|
+
return {
|
|
57
|
+
model,
|
|
58
|
+
referentialActions,
|
|
59
|
+
createRequirements,
|
|
60
|
+
execute,
|
|
61
|
+
transaction,
|
|
62
|
+
};
|
|
105
63
|
}
|
|
@@ -1,38 +1,21 @@
|
|
|
1
1
|
import type { TransactionCapability } from "@aventara/core";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* A stored copy of either class would be a second source of truth, which is
|
|
4
|
+
* dictionary invariant 6.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* *discovered* from the generated client's own types at generate time and
|
|
9
|
-
* recorded in `PrismaDiscoveryArtifact` (T-3, T-3.2); `supportsEmulatedFirst
|
|
10
|
-
* Variants` is *derived* — it is exactly `transactions !== "none"` — and is
|
|
11
|
-
* computed where the §8.3 gate lives. A stored copy of either class would be a
|
|
12
|
-
* second source of truth, which is dictionary invariant 6.
|
|
13
|
-
*
|
|
14
|
-
* Nothing here is inferred at runtime, because nothing here is derived at
|
|
15
|
-
* runtime at all.
|
|
16
|
-
*/
|
|
17
|
-
/**
|
|
18
|
-
* The two engines Phase 8 runs — a value, so the bin's `--provider` check and
|
|
19
|
-
* the manifest's declaration drift guard (`declaration-drift.gate.spec.ts`)
|
|
20
|
-
* read the same list the type is derived from.
|
|
6
|
+
* Nothing here is inferred at runtime, because nothing here is derived at runtime
|
|
7
|
+
* at all.
|
|
21
8
|
*/
|
|
22
9
|
export declare const PRISMA_PROVIDERS: readonly ["sqlite", "postgresql"];
|
|
23
10
|
export type PrismaProvider = (typeof PRISMA_PROVIDERS)[number];
|
|
24
11
|
/**
|
|
25
|
-
* The closed driver set.
|
|
26
|
-
* `false`: their interactive-transaction support is genuinely UNVERIFIED for
|
|
27
|
-
* Prisma 7 (C-825 — no adapter package is installed, neither driver is in
|
|
28
|
-
* Phase 8's engine split, and all three v7 driver-adapter documentation pages
|
|
29
|
-
* returned HTTP 404), and an entry with no evidence is a guess.
|
|
12
|
+
* The closed driver set.
|
|
30
13
|
*/
|
|
31
14
|
export declare const PRISMA_DRIVERS: readonly ["@prisma/adapter-better-sqlite3", "@prisma/adapter-pg", "@prisma/adapter-d1"];
|
|
32
15
|
export type PrismaDriver = (typeof PRISMA_DRIVERS)[number];
|
|
33
16
|
/** The five levels `Prisma.IsolationLevel` admits **[PKG, `runtime/client.d.ts`]**. */
|
|
34
17
|
export type PrismaIsolationLevel = "ReadUncommitted" | "ReadCommitted" | "RepeatableRead" | "Snapshot" | "Serializable";
|
|
35
|
-
/** The caller's explicit declaration; never sniffed from client internals
|
|
18
|
+
/** The caller's explicit declaration; never sniffed from client internals. */
|
|
36
19
|
export type PrismaProviderDeclaration = {
|
|
37
20
|
readonly provider: PrismaProvider;
|
|
38
21
|
readonly driver: PrismaDriver;
|
|
@@ -1,74 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* T-2 / D-824 — the one closed table of provider and driver facts, carrying
|
|
3
|
-
* **only** the facts no reader can supply.
|
|
4
|
-
*
|
|
5
|
-
* What is deliberately absent: `supportsScalarLists`, `supportsOrderNulls`,
|
|
6
|
-
* `supportsCreateManyAndReturn` and `supportsUpdateManyAndReturn` are
|
|
7
|
-
* *discovered* from the generated client's own types at generate time and
|
|
8
|
-
* recorded in `PrismaDiscoveryArtifact` (T-3, T-3.2); `supportsEmulatedFirst
|
|
9
|
-
* Variants` is *derived* — it is exactly `transactions !== "none"` — and is
|
|
10
|
-
* computed where the §8.3 gate lives. A stored copy of either class would be a
|
|
11
|
-
* second source of truth, which is dictionary invariant 6.
|
|
12
|
-
*
|
|
13
|
-
* Nothing here is inferred at runtime, because nothing here is derived at
|
|
14
|
-
* runtime at all.
|
|
15
|
-
*/
|
|
16
|
-
/**
|
|
17
|
-
* The two engines Phase 8 runs — a value, so the bin's `--provider` check and
|
|
18
|
-
* the manifest's declaration drift guard (`declaration-drift.gate.spec.ts`)
|
|
19
|
-
* read the same list the type is derived from.
|
|
20
|
-
*/
|
|
21
1
|
export const PRISMA_PROVIDERS = ["sqlite", "postgresql"];
|
|
22
|
-
/**
|
|
23
|
-
* The closed driver set. Neon-HTTP and PlanetScale-HTTP are **absent**, not
|
|
24
|
-
* `false`: their interactive-transaction support is genuinely UNVERIFIED for
|
|
25
|
-
* Prisma 7 (C-825 — no adapter package is installed, neither driver is in
|
|
26
|
-
* Phase 8's engine split, and all three v7 driver-adapter documentation pages
|
|
27
|
-
* returned HTTP 404), and an entry with no evidence is a guess.
|
|
28
|
-
*/
|
|
29
2
|
export const PRISMA_DRIVERS = [
|
|
30
3
|
"@prisma/adapter-better-sqlite3",
|
|
31
4
|
"@prisma/adapter-pg",
|
|
32
5
|
"@prisma/adapter-d1",
|
|
33
6
|
];
|
|
34
|
-
/**
|
|
35
|
-
* `transactions` is a **DRIVER** fact, and each row carries its evidence.
|
|
36
|
-
*
|
|
37
|
-
* - `@prisma/adapter-d1` → `"none"` **[PKG]**: `runtime/client.js` of
|
|
38
|
-
* `@prisma/client` 7.10.0 branches on
|
|
39
|
-
* `this._engineConfig.adapter?.adapterName === "@prisma/adapter-d1"` and
|
|
40
|
-
* throws `"Cloudflare D1 does not support interactive transactions. …"`.
|
|
41
|
-
* Read from the installed package on 2026-09-23 (C-824, F-703).
|
|
42
|
-
* - `@prisma/adapter-better-sqlite3` and `@prisma/adapter-pg` →
|
|
43
|
-
* `"interactive"` **[RUN8]**: observed, not assumed. D-805 conditions this
|
|
44
|
-
* value on an interactive transaction having been *proved to run* on each
|
|
45
|
-
* driver, and `src/provider/interactive-transaction.spec.ts` runs one — a
|
|
46
|
-
* write and a read issued through the callback's `tx`, with the write
|
|
47
|
-
* visible afterwards — on both. Produced by
|
|
48
|
-
* `AVENTARA_TEST_POSTGRES_URL=postgresql://aventara:aventara_dev@127.0.0.1:5432/aventara
|
|
49
|
-
* npx vitest run --config ../../vitest.config.mts --root .
|
|
50
|
-
* src/provider/interactive-transaction.spec.ts --reporter=verbose`
|
|
51
|
-
* from `packages/prisma7-adapter`, which is what the relative `--config` path
|
|
52
|
-
* and `--root .` are relative to. Run on 2026-09-23 against `@prisma/client`
|
|
53
|
-
* 7.10.0, Node v24.20.0, SQLite through better-sqlite3 12.11.1 and
|
|
54
|
-
* PostgreSQL 18.6: 4 passed, and 2 of those 4 skip when the URL is absent, so
|
|
55
|
-
* the PostgreSQL half is not a silent pass. Re-run as written on 2026-10-02
|
|
56
|
-
* after the config's `.mts` rename (`aba66a2`): 4 passed, and 2 passed with
|
|
57
|
-
* 2 skipped without the URL.
|
|
58
|
-
*/
|
|
59
7
|
const DRIVER_TRANSACTIONS = {
|
|
60
8
|
"@prisma/adapter-better-sqlite3": "interactive",
|
|
61
9
|
"@prisma/adapter-pg": "interactive",
|
|
62
10
|
"@prisma/adapter-d1": "none",
|
|
63
11
|
};
|
|
64
|
-
/**
|
|
65
|
-
* `isolationLevels` is a **PROVIDER** fact **[DOC7]**, fetched 2026-09-23 from
|
|
66
|
-
* the version-pinned `prisma.io/docs/orm/v7/…/queries/transactions` page:
|
|
67
|
-
* PostgreSQL supports ReadUncommitted, ReadCommitted, RepeatableRead and
|
|
68
|
-
* Serializable; SQLite supports Serializable only. `Snapshot` is a SQL Server
|
|
69
|
-
* level and belongs to neither Phase 8 engine, so it appears in the level
|
|
70
|
-
* union (it is one of the five Prisma admits) and in no row.
|
|
71
|
-
*/
|
|
72
12
|
const PROVIDER_ISOLATION_LEVELS = {
|
|
73
13
|
sqlite: ["Serializable"],
|
|
74
14
|
postgresql: [
|
|
@@ -78,10 +18,6 @@ const PROVIDER_ISOLATION_LEVELS = {
|
|
|
78
18
|
"Serializable",
|
|
79
19
|
],
|
|
80
20
|
};
|
|
81
|
-
/**
|
|
82
|
-
* Resolves the profile for a declaration. Pure, total over the closed sets,
|
|
83
|
-
* and the only place provider truth is read.
|
|
84
|
-
*/
|
|
85
21
|
export function resolveProviderProfile(declaration) {
|
|
86
22
|
return {
|
|
87
23
|
provider: declaration.provider,
|
|
@@ -7,17 +7,13 @@ import type { PrismaIdentifierAddress } from "../discovery/discovery-artifact.in
|
|
|
7
7
|
*
|
|
8
8
|
* The rule is three facts, every one of them measured at 7.10.0 and recorded in
|
|
9
9
|
* {@link PrismaIdentifierAddress}: the generate-time `key` is matched and never
|
|
10
|
-
* re-derived (`members.join("_")` is wrong for every `name:`-renamed criterion),
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* re-derived (`members.join("_")` is wrong for every `name:`-renamed criterion), a
|
|
11
|
+
* key wraps its members iff `members.length > 1`, and the identifier chosen is the
|
|
12
|
+
* first recorded criterion the caller's values complete.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* top-level where-unique of `find.unique`, `update.unique`, `delete.unique` and
|
|
18
|
-
* `upsert.unique`. Three copies of a measured rule is three places a later
|
|
19
|
-
* maintainer can fix two of, so the rule moved here and the three call sites
|
|
20
|
-
* became three *configurations* of it.
|
|
14
|
+
* Three copies of a measured rule is three places a later maintainer can fix two
|
|
15
|
+
* of, so the rule moved here and the three call sites became three
|
|
16
|
+
* *configurations* of it.
|
|
21
17
|
*
|
|
22
18
|
* # What the call sites still own, and why that is not a leak
|
|
23
19
|
*
|
|
@@ -26,23 +22,20 @@ import type { PrismaIdentifierAddress } from "../discovery/discovery-artifact.in
|
|
|
26
22
|
* - **How complete the values must be.** A unique selector is `"exact"`: core's
|
|
27
23
|
* selector carries one identifier and nothing else, so a selector with a spare
|
|
28
24
|
* key is not that identifier. A cursor is `"subset"`: `validateCursor` requires
|
|
29
|
-
* the cursor's keys to equal the *active ordered scalar fields*, which include
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* -
|
|
33
|
-
* member through C-834's outbound scalar conversion (a core `Decimal` must
|
|
34
|
-
* leave as a base-10 string); a cursor's values are already Prisma-shaped.
|
|
35
|
-
* Passing the conversion in as `emit` keeps the scalar table in the module that
|
|
25
|
+
* the cursor's keys to equal the *active ordered scalar fields*, which include a
|
|
26
|
+
* complete identifier **plus** every other ordered key, so the identifier is a
|
|
27
|
+
* proper subset of what arrives.
|
|
28
|
+
* - Passing the conversion in as `emit` keeps the scalar table in the module that
|
|
36
29
|
* owns it rather than importing it here.
|
|
37
30
|
*
|
|
38
31
|
* # No spec file of its own, deliberately
|
|
39
32
|
*
|
|
40
33
|
* Every branch is exercised through its three callers' specs —
|
|
41
|
-
* `order-pagination.translator.spec.ts` (subset, compound wrapping, the
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
34
|
+
* `order-pagination.translator.spec.ts` (subset, compound wrapping, the "addresses
|
|
35
|
+
* no row" refusal), `mutation.translator.spec.ts` (exact, renamed keys, Decimal
|
|
36
|
+
* members) and `operation.translator.spec.ts` (exact, at the top level). A fourth
|
|
37
|
+
* spec restating them would test this module's three lines twice and the measured
|
|
38
|
+
* facts not at all.
|
|
46
39
|
*/
|
|
47
40
|
/**
|
|
48
41
|
* How completely the supplied values must cover a criterion.
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Addresses one row by the first recorded criterion the values complete.
|
|
3
|
-
*
|
|
4
|
-
* @returns the addressing, or `undefined` when no criterion is complete — which
|
|
5
|
-
* is a caller-specific refusal (each call site raises its own error type with
|
|
6
|
-
* its own path), never a silently unaddressed write.
|
|
7
|
-
*/
|
|
8
1
|
export function addressIdentifier(input) {
|
|
9
2
|
const keyCount = Object.keys(input.values).length;
|
|
10
3
|
for (const address of input.addresses) {
|
|
@@ -16,9 +9,6 @@ export function addressIdentifier(input) {
|
|
|
16
9
|
}
|
|
17
10
|
const members = address.members.map((member) => [member, input.emit(member, input.values[member])]);
|
|
18
11
|
const [single] = members;
|
|
19
|
-
// A single-column criterion does NOT wrap, and a compound one does. The
|
|
20
|
-
// difference is `members.length`, read off the recorded criterion rather
|
|
21
|
-
// than guessed from the shape of the value.
|
|
22
12
|
return {
|
|
23
13
|
address,
|
|
24
14
|
where: members.length === 1 && single !== undefined
|
|
@@ -1,58 +1,40 @@
|
|
|
1
1
|
import { type AdapterModel, type OperationIdentity } from "@aventara/core";
|
|
2
2
|
import type { PrismaIdentifierAddress } from "../discovery/discovery-artifact.interface.js";
|
|
3
3
|
/**
|
|
4
|
-
* T-7's mutation half — one validated Aventara `data` in, one Prisma write
|
|
5
|
-
* argument out.
|
|
6
|
-
*
|
|
7
4
|
* # Pure, and the tables are the module
|
|
8
5
|
*
|
|
9
|
-
* No client, no database, no provider name.
|
|
10
|
-
* module knows, each one TOTAL over a core union by `satisfies`, so a member
|
|
11
|
-
* added to core with no row here is a compile error rather than a silently
|
|
12
|
-
* dropped argument (C-855's emission half, C-837's translator table — the one
|
|
13
|
-
* `vocabulary.dictionary.ts` explicitly left to this task):
|
|
6
|
+
* No client, no database, no provider name.
|
|
14
7
|
*
|
|
15
8
|
* - {@link SCALAR_DIRECTIVE_TOKENS} over `ScalarMutationDirective`;
|
|
16
9
|
* - {@link RELATION_DIRECTIVE_EMISSIONS} over `RelationMutationDirective`;
|
|
17
|
-
* - {@link MUTATION_DATA_SITES} over every standard operation key, which is
|
|
18
|
-
* C-818's enforcement point.
|
|
19
10
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* same answers, so it moved to `scalar.conversion.ts` and all three read it
|
|
23
|
-
* (Task 10's `identifier.addressing.ts` is the precedent). This module's
|
|
24
|
-
* emission site is {@link emitValue}, which is now a call rather than a copy.
|
|
11
|
+
* This module's emission site is {@link emitValue}, which is now a call rather
|
|
12
|
+
* than a copy.
|
|
25
13
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* Readonly<Record<Union, …>>` keeps every cell a literal while making the union
|
|
29
|
-
* coverage a compile-time obligation. Two of core's passes are already keyed
|
|
30
|
-
* that way; this is the third, and the only one that names Prisma.
|
|
14
|
+
* Two of core's passes are already keyed that way; this is the third, and the only
|
|
15
|
+
* one that names Prisma.
|
|
31
16
|
*
|
|
32
17
|
* # Refusing is part of honouring (the `where.translator.ts` stance)
|
|
33
18
|
*
|
|
34
|
-
* The adapter assumes validated input
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* surface as a write that silently did less than it was asked to.
|
|
40
|
-
*
|
|
41
|
-
* # C-818 cannot reach the Contract, so it is enforced here
|
|
19
|
+
* The adapter assumes validated input. It still refuses to EMIT a directive the
|
|
20
|
+
* discovered model does not advertise for that field and stage, and refuses one
|
|
21
|
+
* for which Prisma's nested input at that stage and cardinality has no key at all.
|
|
22
|
+
* A directive quietly dropped here would surface as a write that silently did less
|
|
23
|
+
* than it was asked to.
|
|
42
24
|
*
|
|
43
25
|
* `RelationFieldCapabilities` is one record per field with a single `create`
|
|
44
|
-
* member **[CORE, adapters/adapter-field.ts]**, so "relation create directives
|
|
45
|
-
*
|
|
26
|
+
* member **[CORE, adapters/adapter-field.ts]**, so "relation create directives for
|
|
27
|
+
* `create.one` and none for `create.many`" is unrepresentable in the model;
|
|
46
28
|
* `model.discoverer.ts` composes the permissive `create.one` answer and says so.
|
|
47
29
|
* The restriction therefore lives in {@link MUTATION_DATA_SITES}, which is keyed
|
|
48
30
|
* by the operation the data belongs to. Measured at 7.10.0 on both engines
|
|
49
31
|
* (2026-10-02), a nested relation key in a bulk write is a hard failure, not a
|
|
50
32
|
* no-op:
|
|
51
33
|
*
|
|
52
|
-
* - `post.createMany({ data: [{ title, author: { connect: … } }] })` →
|
|
53
|
-
*
|
|
54
|
-
* - `post.updateMany({ where, data: { category: { connect: … } } })` →
|
|
55
|
-
*
|
|
34
|
+
* - `post.createMany({ data: [{ title, author: { connect: … } }] })` → *"Argument
|
|
35
|
+
* `authorId` is missing."*
|
|
36
|
+
* - `post.updateMany({ where, data: { category: { connect: … } } })` → *"Unknown
|
|
37
|
+
* argument `category`. Available options are marked with ?."*
|
|
56
38
|
*
|
|
57
39
|
* # Nothing in the caller's arguments is touched
|
|
58
40
|
*
|
|
@@ -73,11 +55,6 @@ export declare class PrismaMutationTranslationError extends Error {
|
|
|
73
55
|
export type PrismaMutationData = Readonly<Record<string, unknown>>;
|
|
74
56
|
/** The two write stages core distinguishes. */
|
|
75
57
|
export type PrismaWriteStage = "create" | "update";
|
|
76
|
-
/**
|
|
77
|
-
* Task 7's `where` translator, injected rather than imported so this module
|
|
78
|
-
* stays a pure function of its inputs and the filter grammar keeps one owner
|
|
79
|
-
* (the same shape `projection.translator.ts` uses for the same reason).
|
|
80
|
-
*/
|
|
81
58
|
export type PrismaNestedWhereTranslator = (resource: string, where: unknown, path: string) => Readonly<Record<string, unknown>>;
|
|
82
59
|
export type PrismaMutationDependencies = {
|
|
83
60
|
readonly translateWhere: PrismaNestedWhereTranslator;
|
|
@@ -97,7 +74,6 @@ export type MutationTranslation = {
|
|
|
97
74
|
readonly model: AdapterModel;
|
|
98
75
|
/** The Aventara Resource key the data is written against. */
|
|
99
76
|
readonly resource: string;
|
|
100
|
-
/** The operation whose argument this data becomes; it decides C-818 admission. */
|
|
101
77
|
readonly operation: OperationIdentity;
|
|
102
78
|
/** Which of that operation's write stages this data is (`upsert.unique` has two). */
|
|
103
79
|
readonly stage: PrismaWriteStage;
|
|
@@ -105,11 +81,11 @@ export type MutationTranslation = {
|
|
|
105
81
|
readonly data: unknown;
|
|
106
82
|
};
|
|
107
83
|
/**
|
|
108
|
-
* Translates one validated Aventara mutation `data` into the Prisma write
|
|
109
|
-
*
|
|
84
|
+
* Translates one validated Aventara mutation `data` into the Prisma write argument
|
|
85
|
+
* for the named operation and stage.
|
|
110
86
|
*
|
|
111
87
|
* @throws {PrismaMutationTranslationError} rather than emitting a directive the
|
|
112
88
|
* model does not advertise, one Prisma has no key for at this stage and
|
|
113
|
-
* cardinality, or a nested relation write inside a bulk argument
|
|
89
|
+
* cardinality, or a nested relation write inside a bulk argument.
|
|
114
90
|
*/
|
|
115
91
|
export declare function translateMutationData(input: MutationTranslation, dependencies: PrismaMutationDependencies): PrismaMutationData;
|