@aventara/prisma7-adapter 0.1.0-pilot.2 → 0.1.0-pilot.4
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 +22 -22
- package/dist/discovery/artifact.loader.d.ts +2 -7
- package/dist/discovery/artifact.loader.js +4 -0
- package/dist/discovery/capability-surface.interface.d.ts +2 -66
- package/dist/discovery/capability.deriver.d.ts +2 -47
- package/dist/discovery/discovery-artifact.interface.d.ts +34 -155
- package/dist/discovery/discovery-artifact.interface.js +1 -1
- package/dist/discovery/enum.mapper.d.ts +0 -24
- package/dist/discovery/field.mapper.d.ts +3 -114
- package/dist/discovery/field.mapper.js +6 -6
- package/dist/discovery/identifier.mapper.d.ts +4 -84
- package/dist/discovery/model.discoverer.d.ts +2 -69
- package/dist/discovery/operations.deriver.d.ts +0 -36
- package/dist/discovery/scalar.mapper.d.ts +1 -32
- package/dist/discovery/scalar.mapper.js +2 -2
- package/dist/discovery/schema-facts.interface.d.ts +3 -83
- package/dist/discovery/schema.reader.d.ts +0 -133
- package/dist/discovery/types.reader.d.ts +1 -9
- package/dist/discovery/types.reader.js +7 -7
- package/dist/discovery/vocabulary.dictionary.d.ts +6 -133
- package/dist/discovery/vocabulary.dictionary.js +2 -2
- package/dist/errors/error.normalizer.d.ts +5 -168
- package/dist/errors/prisma-error.reader.d.ts +1 -93
- package/dist/execution/first-variant.emulator.d.ts +5 -28
- package/dist/execution/operation.executor.d.ts +1 -62
- package/dist/execution/result.shaper.d.ts +0 -56
- package/dist/execution/transaction.executor.d.ts +0 -98
- package/dist/generate/artifact.emitter.d.ts +1 -35
- package/dist/generate/artifact.emitter.js +26 -43
- package/dist/generate/declared-support.reader.d.ts +0 -20
- package/dist/generate/discovery.cli.d.ts +0 -4
- package/dist/generate/existence.gate.d.ts +3 -37
- package/dist/generate/index.d.ts +4 -57
- package/dist/generate/prisma-cli.resolver.d.ts +0 -22
- package/dist/generate/prisma.generate.d.ts +14 -83
- package/dist/generate/reader-crosscheck.d.ts +3 -88
- package/dist/generate/reader-crosscheck.js +4 -4
- package/dist/prisma-client.interface.d.ts +5 -25
- package/dist/prisma.adapter.d.ts +21 -22
- package/dist/provider/provider-profile.d.ts +6 -14
- package/dist/translation/identifier.addressing.d.ts +0 -38
- package/dist/translation/mutation.translator.d.ts +5 -51
- package/dist/translation/operation.translator.d.ts +1 -102
- package/dist/translation/order-pagination.translator.d.ts +1 -47
- package/dist/translation/projection.translator.d.ts +1 -46
- package/dist/translation/scalar.conversion.d.ts +0 -64
- package/dist/translation/where.translator.d.ts +0 -52
- package/package.json +3 -2
|
@@ -1,85 +1,6 @@
|
|
|
1
1
|
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
|
-
/**
|
|
5
|
-
* Splitting translation from execution is the plan's single largest testability
|
|
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`.
|
|
9
|
-
*
|
|
10
|
-
* # The dispatch table is the module
|
|
11
|
-
*
|
|
12
|
-
* {@link PRISMA_VARIANT_DISPATCH} is total over core's own sixteen
|
|
13
|
-
* `family.variant` keys by `satisfies`, so a seventeenth standard operation added
|
|
14
|
-
* to core is a compile error here rather than a variant that quietly reaches no
|
|
15
|
-
* provider call. Reading it answers, in one place, every question of the form
|
|
16
|
-
* "what does Aventara's X actually issue".
|
|
17
|
-
*
|
|
18
|
-
* # The negative half of the table is the load-bearing half
|
|
19
|
-
*
|
|
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.
|
|
25
|
-
* `operation.translator.spec.ts` asserts the same thing from the value side, as
|
|
26
|
-
* the belt to that type's braces.
|
|
27
|
-
*
|
|
28
|
-
* # `delete.many` is a hole in the table, and the hole is the decision
|
|
29
|
-
*
|
|
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.
|
|
35
|
-
*
|
|
36
|
-
* # First-style variants, and the write route
|
|
37
|
-
*
|
|
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
|
|
42
|
-
* `updateFirst`/`deleteFirst` **[PKG]**. So the plan is an ordinary read then
|
|
43
|
-
* write, and its two steps are {@link PrismaExecutionPlan}'s `"emulated"` arm.
|
|
44
|
-
*
|
|
45
|
-
* Every row came out for Route A, and two of them came out *against* Route B:
|
|
46
|
-
*
|
|
47
|
-
* ```text
|
|
48
|
-
* measured 2026-10-02, @prisma/client 7.10.0, SQLite + PostgreSQL 18, identical
|
|
49
|
-
*
|
|
50
|
-
* A update({ where: { id, AND: […] }, data, select }) -> returned the row
|
|
51
|
-
* A …with a non-matching AND -> threw P2025, row untouched
|
|
52
|
-
* A …select reaching a to-many relation AND _count -> returned both
|
|
53
|
-
* A delete({ where: { id, AND: […] }, select }) -> returned the deleted row
|
|
54
|
-
* A …with a non-matching AND -> threw P2025, row still present
|
|
55
|
-
* A findFirst + update inside $transaction, non-matching AND -> threw P2025 at the emulator's own call site
|
|
56
|
-
* B updateManyAndReturn({ where: { id, AND: […] }, … }) -> returned [row]
|
|
57
|
-
* B …with a non-matching AND -> resolved []
|
|
58
|
-
* B …select: { posts: { … } } -> REJECTED: "Unknown field `posts` for select
|
|
59
|
-
* statement on model `UpdateManyAuthorAndReturnOutputType`"
|
|
60
|
-
* B …select: { _count: { … } } -> REJECTED: same, for `_count`
|
|
61
|
-
* B deleteMany({ where: { id, AND: […] } }) -> { count: 1 } — carries no row at all
|
|
62
|
-
* ```
|
|
63
|
-
*
|
|
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.
|
|
66
|
-
*
|
|
67
|
-
* # The write step of an emulated plan is a template, and says so
|
|
68
|
-
*
|
|
69
|
-
* A `"single"` plan's call is issuable as written. An `"emulated"` plan's write
|
|
70
|
-
* step is **not**, by construction: its `where` carries the caller's re-asserted
|
|
71
|
-
* predicate under `AND` and the identifier is added by
|
|
72
|
-
* `execution/first-variant.emulator.ts` from the row the read returned. That is
|
|
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.
|
|
75
|
-
*
|
|
76
|
-
* Every key below is added only when the corresponding Aventara argument is
|
|
77
|
-
* **present**. An absent argument and an `undefined` one are different arguments
|
|
78
|
-
* to a provider, so `"take" in args` is never made true by accident. An argument
|
|
79
|
-
* this module does not recognise raises rather than being dropped: an argument
|
|
80
|
-
* that typechecks and is silently ignored is worse than an absent one, because the
|
|
81
|
-
* absent one fails loudly at the caller.
|
|
82
|
-
*/
|
|
83
4
|
/** The `ModelAction` subset this adapter uses. See the header for the exclusions. */
|
|
84
5
|
export type PrismaAction = "findUnique" | "findFirst" | "findMany" | "count" | "create" | "createMany" | "createManyAndReturn" | "update" | "updateMany" | "updateManyAndReturn" | "delete" | "deleteMany" | "upsert";
|
|
85
6
|
/** One provider call description, as plain data. */
|
|
@@ -93,7 +14,6 @@ export type PrismaCall = {
|
|
|
93
14
|
readonly action: PrismaAction;
|
|
94
15
|
readonly args: Readonly<Record<string, unknown>>;
|
|
95
16
|
};
|
|
96
|
-
/** A variant is either one call, or an emulated sequence. */
|
|
97
17
|
export type PrismaExecutionPlan = {
|
|
98
18
|
readonly kind: "single";
|
|
99
19
|
readonly call: PrismaCall;
|
|
@@ -102,13 +22,6 @@ export type PrismaExecutionPlan = {
|
|
|
102
22
|
readonly steps: readonly PrismaCall[];
|
|
103
23
|
readonly atomicity: "outer-tx" | "own-tx";
|
|
104
24
|
};
|
|
105
|
-
/**
|
|
106
|
-
* What the variant owes its caller, and therefore which shaper runs.
|
|
107
|
-
*
|
|
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.
|
|
111
|
-
*/
|
|
112
25
|
export type PrismaResultKind = "row" | "rows" | "count";
|
|
113
26
|
export type PrismaVariantDispatch = {
|
|
114
27
|
readonly kind: "single";
|
|
@@ -123,7 +36,6 @@ export type PrismaVariantDispatch = {
|
|
|
123
36
|
readonly kind: "unavailable";
|
|
124
37
|
readonly reason: string;
|
|
125
38
|
};
|
|
126
|
-
/** The sixteen-variant dispatch table, total over core's grammar. */
|
|
127
39
|
export declare const PRISMA_VARIANT_DISPATCH: {
|
|
128
40
|
readonly "find.first": {
|
|
129
41
|
readonly kind: "single";
|
|
@@ -211,23 +123,10 @@ export declare const PRISMA_VARIANT_DISPATCH: {
|
|
|
211
123
|
export declare class PrismaOperationTranslationError extends Error {
|
|
212
124
|
readonly name = "PrismaOperationTranslationError";
|
|
213
125
|
}
|
|
214
|
-
/**
|
|
215
|
-
* The translation of one operation: the plan, plus the projection plan the result
|
|
216
|
-
* shaper needs.
|
|
217
|
-
*
|
|
218
|
-
* Returning it beside the plan is what keeps `result.shaper.ts` free of a second,
|
|
219
|
-
* drifting reconstruction.
|
|
220
|
-
*/
|
|
221
126
|
export type PrismaOperationTranslation = {
|
|
222
127
|
readonly plan: PrismaExecutionPlan;
|
|
223
128
|
readonly projection: PrismaProjectionPlan;
|
|
224
|
-
/**
|
|
225
|
-
* The caller's `where`, translated, or `undefined` when they sent none.
|
|
226
|
-
*
|
|
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.
|
|
230
|
-
*/
|
|
129
|
+
/** The caller's `where`, translated, or `undefined` when they sent none. */
|
|
231
130
|
readonly predicate: Readonly<Record<string, unknown>> | undefined;
|
|
232
131
|
};
|
|
233
132
|
export type PrismaOperationTranslationInput = {
|
|
@@ -1,21 +1,5 @@
|
|
|
1
1
|
import { type AdapterModel } from "@aventara/core";
|
|
2
2
|
import type { PrismaIdentifierAddress } from "../discovery/discovery-artifact.interface.js";
|
|
3
|
-
/**
|
|
4
|
-
* Pure functions over plain data: no client, no database, no provider name.
|
|
5
|
-
*
|
|
6
|
-
* The public names are `limit`, `offset` and `cursor`. `take` and `skip` are
|
|
7
|
-
* Prisma's and appear nowhere in this adapter's public types — they are produced
|
|
8
|
-
* here and nowhere else. The tables below are TOTAL over core's own unions, so a
|
|
9
|
-
* pagination capability or a reducer added to core with no emission site is a
|
|
10
|
-
* compile error.
|
|
11
|
-
*
|
|
12
|
-
* # An absent argument and an `undefined` one are different arguments
|
|
13
|
-
*
|
|
14
|
-
* `take: undefined` is a present key with no value, and `"take" in args` is what a
|
|
15
|
-
* provider sees. Every key below is added only when its Aventara argument is
|
|
16
|
-
* present, which is also why `0` is carried through rather than tested for
|
|
17
|
-
* truthiness.
|
|
18
|
-
*/
|
|
19
3
|
/** An order or cursor the discovered model does not license. */
|
|
20
4
|
export declare class PrismaOrderTranslationError extends Error {
|
|
21
5
|
readonly name = "PrismaOrderTranslationError";
|
|
@@ -27,37 +11,7 @@ export type PrismaPaginationArguments = Readonly<Record<string, unknown>>;
|
|
|
27
11
|
export type PaginationTranslation = {
|
|
28
12
|
readonly limit?: number;
|
|
29
13
|
readonly offset?: number;
|
|
30
|
-
/**
|
|
31
|
-
* The Aventara cursor: the active ordered scalar fields and their values.
|
|
32
|
-
*
|
|
33
|
-
* **Only the identifier subset is emitted, and that is faithful translation rather
|
|
34
|
-
* than a silent drop.** Settled 2026-10-02; do not re-open without reading
|
|
35
|
-
* `validateCursor` first.
|
|
36
|
-
*
|
|
37
|
-
* Core's `CursorInput` type is `Partial<Record<ScalarFieldKey, unknown>>`, which
|
|
38
|
-
* reads as permissive, but `operation-validator-core.ts`'s `validateCursor` pins
|
|
39
|
-
* it exactly: the cursor's keys must **equal** the active ordered scalar fields,
|
|
40
|
-
* and `orderBy` must include a complete Resource identifier as a tie-breaker. So
|
|
41
|
-
* the non-identifier keys are not optional context a caller happened to send —
|
|
42
|
-
* core requires every one of them, and has already verified they match `orderBy`.
|
|
43
|
-
*
|
|
44
|
-
* Prisma's `cursor` is a `<M>WhereUniqueInput`: it locates a *row*, and the
|
|
45
|
-
* ordering comes from `orderBy`, which this module translates alongside. The
|
|
46
|
-
* identifier therefore determines the position completely, and the remaining
|
|
47
|
-
* ordered keys are already expressed in the emitted `orderBy`.
|
|
48
|
-
*
|
|
49
|
-
* Two things follow, both load-bearing. Passing the extra keys through would make
|
|
50
|
-
* them equality members of a where-unique, *narrowing* the lookup: a key whose
|
|
51
|
-
* value no longer matches the stored row would resolve the cursor to nothing and
|
|
52
|
-
* return an empty page instead of a correct one. And narrowing core's
|
|
53
|
-
* `CursorInput` to the identifier — considered and rejected — would break the
|
|
54
|
-
* determinism contract `validateCursor` enforces, since core needs the full
|
|
55
|
-
* ordered set to know the position is unambiguous.
|
|
56
|
-
*
|
|
57
|
-
* The type is loose because the Contract is passive data; the precision lives in
|
|
58
|
-
* the validator. That is the pattern throughout `operation-arguments.ts`, and
|
|
59
|
-
* reading the type without its validator is how this was briefly mis-analysed.
|
|
60
|
-
*/
|
|
14
|
+
/** The Aventara cursor: the active ordered scalar fields and their values. */
|
|
61
15
|
readonly cursor?: Readonly<Record<string, unknown>>;
|
|
62
16
|
/**
|
|
63
17
|
* The Resource's Prisma addressing, from the generate-time translation table.
|
|
@@ -1,51 +1,11 @@
|
|
|
1
1
|
import type { RelationReducer } from "@aventara/core";
|
|
2
|
-
/**
|
|
3
|
-
* **What arrives here is core's plan, not a caller's request.** By the time an
|
|
4
|
-
* `AdapterOperation` reaches the adapter, `planReadOperation` has resolved
|
|
5
|
-
* `include` into `select`, expanded every relation it could resolve into object
|
|
6
|
-
* form, and dropped VIRTUAL scalars from the adapter's half while keeping them in
|
|
7
|
-
* the projection plan it validates against **[CORE,
|
|
8
|
-
* runtime/computed-read-runtime.ts]**. So this module reads one shape: `select` as
|
|
9
|
-
* an array whose entries are field-name strings, the reducer string `"$count"`, or
|
|
10
|
-
* single-key objects carrying a relation's own arguments beside a nested `select`.
|
|
11
|
-
*
|
|
12
|
-
* **Three translations are worth stating because they are not obvious:**
|
|
13
|
-
*
|
|
14
|
-
* 1. A reconstructed list would have to be derived from the model and would drift
|
|
15
|
-
* from it; this cannot.
|
|
16
|
-
* 2. Since the two emissions coincide, the translator needs no model lookup to
|
|
17
|
-
* tell a scalar from a relation — and therefore cannot get that lookup wrong.
|
|
18
|
-
* 3. *`$count` is lifted to the level that owns the edge.* Aventara writes the
|
|
19
|
-
* reducer inside the relation's own `select`; Prisma writes it in the PARENT's
|
|
20
|
-
* `select`, under `_count`. The `where` placed in `_count` is the relation's
|
|
21
|
-
* *translated* `where` and carries no pagination, which is what makes `count`
|
|
22
|
-
* the total matching the nested `where` before limit/offset/cursor.
|
|
23
|
-
*
|
|
24
|
-
* Measured against real databases on both engines — `@prisma/client` 7.10.0,
|
|
25
|
-
* `_count: { select: { posts: { where } } }` beside `posts: { where, take, skip }`
|
|
26
|
-
* — the count was `3` in every case while the row set was `3`, `1`, `2`, `1` and
|
|
27
|
-
* `1` for no pagination, `take: 1`, `skip: 1`, `take: 1 + skip: 1` and `take: 2 +
|
|
28
|
-
* skip: 2`, and `3` again with `cursor + take: 1`. SQLite and PostgreSQL agreed
|
|
29
|
-
* exactly. The filtered-count claim ("since 4.3.0") was re-measured in the same
|
|
30
|
-
* run: `_count` of the same edge answered `5` unfiltered and `3` with the `where`.
|
|
31
|
-
*
|
|
32
|
-
* Injecting the seam also makes the `_count` filter the *same* translated `where`
|
|
33
|
-
* the relation read uses, rather than a second translation of the same predicate
|
|
34
|
-
* that could drift from it.
|
|
35
|
-
*/
|
|
36
|
-
/** Core's own word for the reducer set, so the adapter cannot invent a second one. */
|
|
37
2
|
export type PrismaRelationProjection = {
|
|
38
3
|
readonly field: string;
|
|
39
4
|
/** Non-empty exactly when the edge requested a reducer. */
|
|
40
5
|
readonly reducers: readonly RelationReducer[];
|
|
41
|
-
/** Whether any row field was requested beside the reducer. */
|
|
42
6
|
readonly rows: boolean;
|
|
43
7
|
readonly projection: PrismaProjectionPlan;
|
|
44
8
|
};
|
|
45
|
-
/**
|
|
46
|
-
* It records only the edges that need reshaping — an edge with no reducer anywhere
|
|
47
|
-
* beneath it is absent, which is what lets the shaper return such a row untouched.
|
|
48
|
-
*/
|
|
49
9
|
export type PrismaProjectionPlan = {
|
|
50
10
|
readonly relations: readonly PrismaRelationProjection[];
|
|
51
11
|
};
|
|
@@ -66,16 +26,11 @@ export type PrismaProjectionTranslation = {
|
|
|
66
26
|
readonly args: Readonly<Record<string, unknown>>;
|
|
67
27
|
readonly plan: PrismaProjectionPlan;
|
|
68
28
|
};
|
|
69
|
-
/**
|
|
70
|
-
* A projection the adapter will not translate.
|
|
71
|
-
*/
|
|
29
|
+
/** A projection the adapter will not translate. */
|
|
72
30
|
export declare class PrismaProjectionTranslationError extends Error {
|
|
73
31
|
constructor(reason: string, path: readonly string[]);
|
|
74
32
|
}
|
|
75
33
|
/**
|
|
76
|
-
* Translates core's planned projection into the Prisma projection arguments and
|
|
77
|
-
* the plan the result shaper needs to place every `$count` envelope.
|
|
78
|
-
*
|
|
79
34
|
* @throws {PrismaProjectionTranslationError} for a projection the adapter will
|
|
80
35
|
* not translate rather than silently reinterpret.
|
|
81
36
|
*/
|
|
@@ -1,68 +1,4 @@
|
|
|
1
1
|
import { type AdapterField, type AdapterModel } from "@aventara/core";
|
|
2
|
-
/**
|
|
3
|
-
* # Why this is a module and not three private helpers
|
|
4
|
-
*
|
|
5
|
-
* Three consumers cross the same boundary with the same values: a write's `data`
|
|
6
|
-
* (`mutation.translator.ts`), a filter operand (`where.translator.ts`) and a row
|
|
7
|
-
* coming back (`execution/result.shaper.ts`). The emission table was born inside
|
|
8
|
-
* the mutation translator, which is where the first of the three needed it; a copy
|
|
9
|
-
* in each consumer would be three places to answer "what does a `decimal` look
|
|
10
|
-
* like on the wire", and the second copy to drift would be the one nobody reads.
|
|
11
|
-
*
|
|
12
|
-
* The table is TOTAL over core's `BuiltInScalar` by a mapped type, so a tenth
|
|
13
|
-
* scalar added to the protocol is a compile error here rather than a value that
|
|
14
|
-
* silently crosses unconverted in one direction only.
|
|
15
|
-
*
|
|
16
|
-
* # `decimal` is the one real conversion, and that is measured
|
|
17
|
-
*
|
|
18
|
-
* Eight of the nine scalars pass through in both directions, re-measured on both
|
|
19
|
-
* driver adapters at `@prisma/client` 7.10.0 (2026-10-02): a `bigint` primitive, a
|
|
20
|
-
* `Date` and a `Uint8Array` are what the generated input types accept and what a
|
|
21
|
-
* read returns (`Buffer.isBuffer(v) === false`, `v instanceof Uint8Array ===
|
|
22
|
-
* true`), `Json` is written and returned as a plain object (its prototype IS
|
|
23
|
-
* `Object.prototype`, which is what core's own `isPlainRecord` output check
|
|
24
|
-
* requires **[CORE, runtime/scalar-runtime.ts]**), and an enum member is its own
|
|
25
|
-
* name on both sides. Those are the same forms core's runtime scope requires
|
|
26
|
-
* (`normalizeScalarAtom`'s `"application"` branch), so a pass-through is a
|
|
27
|
-
* decision, not an omission.
|
|
28
|
-
*
|
|
29
|
-
* Neither accepts the other, so the crossing is a real conversion both ways: out,
|
|
30
|
-
* the base-10 string; in, core's own `Decimal`.
|
|
31
|
-
*
|
|
32
|
-
* # Outbound: three different failures, none of them a type error
|
|
33
|
-
*
|
|
34
|
-
* Passing core's `Decimal` through unconverted fails *differently* depending on
|
|
35
|
-
* where it lands, and none of the three is a plain rejection (measured on both
|
|
36
|
-
* engines, 2026-10-02):
|
|
37
|
-
*
|
|
38
|
-
* - as a **write value**: refused at the wire — *"Invalid value for argument
|
|
39
|
-
* `toString`: We could not serialize [object Function] value."*;
|
|
40
|
-
* - as a **comparison operand** (`gt`, `equals`, …): read as a **FieldRef**, not
|
|
41
|
-
* as a value — *"PrismaClientValidationError: Argument `_ref` is missing."*;
|
|
42
|
-
* - as a **bare equality operand**: *accepted*, and silently wrong. Core's
|
|
43
|
-
* `Decimal` keeps its digits in a private field, so `Object.keys` is empty and
|
|
44
|
-
* Prisma reads the object as an **empty `DecimalFilter`** — `findMany` returned
|
|
45
|
-
* **2 of 2** rows, byte-identical to passing no predicate at all, where the
|
|
46
|
-
* string `"1"` returned 1. A misinterpretation that validates is the failure
|
|
47
|
-
* this module exists to make impossible.
|
|
48
|
-
*
|
|
49
|
-
* # Inbound: the value core's output validator will accept
|
|
50
|
-
*
|
|
51
|
-
* Core validates adapter output in its `"runtime"` scope, which requires the
|
|
52
|
-
* *runtime* form of every scalar — `value instanceof Decimal` for a decimal
|
|
53
|
-
* **[CORE, runtime/output-validator.ts → normalizeScalarFieldValue]**. A
|
|
54
|
-
* `Decimal2` is not one, so an unconverted read fails core's own validation and
|
|
55
|
-
* the caller is told `A3000`.
|
|
56
|
-
*
|
|
57
|
-
* # The scalar identity comes from the model, never from the value
|
|
58
|
-
*
|
|
59
|
-
* Both directions are keyed by the field's discovered scalar, never by the runtime
|
|
60
|
-
* shape of the value. A `Json` column holding `{ "x": 1 }` and a `Decimal`
|
|
61
|
-
* reaching Prisma are both "an object", and a `Json` column holding the string
|
|
62
|
-
* `"12.5"` is indistinguishable from a decimal string: shape-sniffing would
|
|
63
|
-
* convert one of those sooner or later, and silently. The discovered model already
|
|
64
|
-
* knows, so it is asked.
|
|
65
|
-
*/
|
|
66
2
|
/** A value this adapter will not convert rather than misrepresent. */
|
|
67
3
|
export declare class PrismaScalarConversionError extends Error {
|
|
68
4
|
readonly name = "PrismaScalarConversionError";
|
|
@@ -1,56 +1,4 @@
|
|
|
1
1
|
import type { AdapterModel } from "@aventara/core";
|
|
2
|
-
/**
|
|
3
|
-
* # Pure, and that is the property to protect
|
|
4
|
-
*
|
|
5
|
-
* No client, no database, no I/O, no provider name. The only inputs are the
|
|
6
|
-
* discovered model and plain data, which is what makes the whole filter grammar
|
|
7
|
-
* exhaustively testable without an engine.
|
|
8
|
-
*
|
|
9
|
-
* # One direction, and no Prisma token the framework did not ask for
|
|
10
|
-
*
|
|
11
|
-
* Every emitted key comes from one of the two tables below, both of which are
|
|
12
|
-
* TOTAL over core's own capability unions — a member added to
|
|
13
|
-
* `ScalarFilterOperator` or `RelationFilterCapability` with no row here is a
|
|
14
|
-
* compile error, not a silently dropped predicate.
|
|
15
|
-
*
|
|
16
|
-
* The inverse matters more. A missing key loses a predicate and shows up as a
|
|
17
|
-
* wrong row count; an INVENTED key silently changes what the query means. So
|
|
18
|
-
* nothing is ever added to the output that the request did not carry: no `equals`
|
|
19
|
-
* wrapper around a bare value, no `is`/`isNot` wrapper around a to-one predicate,
|
|
20
|
-
* no `mode` nobody asked for.
|
|
21
|
-
*
|
|
22
|
-
* A predicate is a key AND an operand, and the operand is a value of the field's
|
|
23
|
-
* scalar type. Those values go out through `scalar.conversion.ts`, the one table
|
|
24
|
-
* that knows how each scalar crosses — the same answers `mutation.translator.ts`
|
|
25
|
-
* uses for a write, because it is the same boundary. {@link
|
|
26
|
-
* SCALAR_FILTER_EMISSIONS} records, per operator, *whether* its operand is such a
|
|
27
|
-
* value: `in` carries a list of them, `isEmpty` carries a boolean, `mode` carries
|
|
28
|
-
* a Prisma keyword, and `path`/`string*`/`array*` carry a position inside a JSON
|
|
29
|
-
* document rather than a value of the column. Converting indiscriminately would
|
|
30
|
-
* corrupt the second kind; converting none of them is what let a core `Decimal`
|
|
31
|
-
* reach Prisma, where it was not rejected but **misread** (measured on both
|
|
32
|
-
* engines, 2026-10-02):
|
|
33
|
-
*
|
|
34
|
-
* - `{ sDecimal: { gt: new Decimal("1") } }` → *"PrismaClientValidationError:
|
|
35
|
-
* Argument `_ref` is missing."* — Prisma read the object as a **FieldRef**;
|
|
36
|
-
* - `{ sDecimal: new Decimal("1") }` → **no error and 2 of 2 rows**, the same as
|
|
37
|
-
* no predicate at all, because core's `Decimal` keeps its digits in a private
|
|
38
|
-
* field and `Object.keys` is therefore empty: Prisma read an **empty
|
|
39
|
-
* `DecimalFilter`**. The string `"1"` returned 1 row.
|
|
40
|
-
*
|
|
41
|
-
* The second is why the bare-value branch below follows core's own discriminant —
|
|
42
|
-
* `isPlainRecord`, not "is an object" **[CORE, runtime/scalar-runtime.ts
|
|
43
|
-
* `normalizeScalarFilter`]**. A class instance is a VALUE; reading one as an
|
|
44
|
-
* operator record produced `{}`, and an empty filter constrains nothing.
|
|
45
|
-
*
|
|
46
|
-
* # Refusing is part of honouring
|
|
47
|
-
*
|
|
48
|
-
* The adapter assumes validated input and performs no limit checking. It does,
|
|
49
|
-
* however, refuse to EMIT an operator the discovered model does not advertise for
|
|
50
|
-
* that field. Core has already rejected such a request with `V1006`; if one ever
|
|
51
|
-
* arrives here, the model and the Contract have diverged and that is a defect, not
|
|
52
|
-
* a query.
|
|
53
|
-
*/
|
|
54
2
|
/** A predicate the model does not license, or a key no vocabulary recognises. */
|
|
55
3
|
export declare class PrismaWhereTranslationError extends Error {
|
|
56
4
|
readonly name = "PrismaWhereTranslationError";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aventara/prisma7-adapter",
|
|
3
|
-
"version": "0.1.0-pilot.
|
|
3
|
+
"version": "0.1.0-pilot.4",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "The Prisma 7 adapter for Aventara.",
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"LICENSE-ADDITIONAL-PERMISSION.md"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@aventara/core": "0.1.0-pilot.
|
|
32
|
+
"@aventara/core": "0.1.0-pilot.4"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@prisma/adapter-better-sqlite3": "^7.10.0",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
"aventara": {
|
|
56
56
|
"adapter": {
|
|
57
|
+
"alias": "prisma7",
|
|
57
58
|
"orm": "prisma",
|
|
58
59
|
"ormLabel": "Prisma",
|
|
59
60
|
"ormPackage": "@prisma/client",
|