@aventara/prisma7-adapter 1.0.0-rc.4 → 1.0.0-rc.9
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/CHANGELOG.md +62 -0
- package/README.md +6 -4
- package/dist/discovery/discovery-artifact.interface.d.ts +4 -2
- package/dist/discovery/model.discoverer.js +8 -1
- package/dist/execution/operation.executor.js +17 -3
- package/dist/execution/scoped-cursor.resolver.d.ts +11 -0
- package/dist/execution/scoped-cursor.resolver.js +47 -0
- package/dist/generate/artifact.emitter.js +1 -1
- package/dist/prisma-adapter.description.js +1 -1
- package/dist/translation/operation.translator.d.ts +11 -0
- package/dist/translation/operation.translator.js +32 -3
- package/dist/translation/order-pagination.translator.d.ts +19 -0
- package/dist/translation/order-pagination.translator.js +15 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,67 @@
|
|
|
1
1
|
# @aventara/prisma7-adapter
|
|
2
2
|
|
|
3
|
+
## 1.0.0-rc.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [205a379]
|
|
8
|
+
- Updated dependencies [a0bb05e]
|
|
9
|
+
- Updated dependencies [86ab319]
|
|
10
|
+
- Updated dependencies [fdf52e6]
|
|
11
|
+
- @aventara/core@1.0.0-rc.9
|
|
12
|
+
|
|
13
|
+
## 1.0.0-rc.8
|
|
14
|
+
|
|
15
|
+
1.0.0-rc.5, rc.6 and rc.7 were tagged but never published; 1.0.0-rc.8 contains everything listed under them and the changes below.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 1c8e4ee: The discovery artifact's referential actions say `referenceFields` where they said `references`: in
|
|
20
|
+
`referentialActions.<Resource>.owningEdges[]`, the fields of the Resource itself that hold the reference
|
|
21
|
+
(`@relation(fields: [...])`). The model's relation fields already use `references` for the target's fields
|
|
22
|
+
(`@relation(references: [...])`) and `referenceFields` for these, so the same word meant two different lists in one
|
|
23
|
+
file. The generated `discovery.artifact.ts` changes on the next `aventara:prepare` (it runs on install, build and
|
|
24
|
+
start), and only in those keys: `modelHash` is unchanged, since the referential actions are outside it, and so is the
|
|
25
|
+
prebuilt Contracts file `aventara-build` writes. Code that read `owningEdges[i].references` reads
|
|
26
|
+
`owningEdges[i].referenceFields`.
|
|
27
|
+
- Updated dependencies [1c8e4ee]
|
|
28
|
+
- @aventara/core@1.0.0-rc.8
|
|
29
|
+
|
|
30
|
+
## 1.0.0-rc.7
|
|
31
|
+
|
|
32
|
+
1.0.0-rc.5 and 1.0.0-rc.6 were tagged but never published; 1.0.0-rc.7 contains everything listed under them and the changes below.
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- Updated dependencies [f917c1c]
|
|
37
|
+
- @aventara/core@1.0.0-rc.7
|
|
38
|
+
|
|
39
|
+
## 1.0.0-rc.6
|
|
40
|
+
|
|
41
|
+
1.0.0-rc.5 was tagged but never published. 1.0.0-rc.6 contains everything listed under 1.0.0-rc.5 and the fix below.
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- Updated dependencies [1cf72e0]
|
|
46
|
+
- @aventara/core@1.0.0-rc.6
|
|
47
|
+
|
|
48
|
+
## 1.0.0-rc.5
|
|
49
|
+
|
|
50
|
+
### Patch Changes
|
|
51
|
+
|
|
52
|
+
- 4795ff1: Two additions for policy engines. A Framework without a policy, and every Contract a caller is served, are unchanged.
|
|
53
|
+
|
|
54
|
+
- A policy engine can check a create whose row reaches another Resource through a relation. Discovery now states, on the end of a relation that holds the reference, which of the target's fields its reference fields name, pair by pair (`Note.campaign`: `referenceFields: ["campaignId"]`, `references: ["id"]`). An engine reads them from the model it is built from (a Prisma discovery artifact's `model`) or from `framework.contracts.core`, and asks one `exists` about the row they name: "a player creates a note only in a campaign they play in". Only the adapter's model and the Core Contract carry them. The Application, Client and Agent Contracts, `/_contract`, the MCP tools and every ClientContract hash are unchanged. The discovery artifact's model hash, and so a prebuilt Contracts file's fingerprint, change: regenerate the artifact and rebuild the prebuilt file.
|
|
55
|
+
- `fieldsOf({ access: "write" })` also names the action that writes the record, `action: "create" | "update"` (an upsert's branches each their own, a nested record its directive's), so an engine can lock a field on update and still let a create write it. A read question names none. An engine that ignores it keeps working.
|
|
56
|
+
|
|
57
|
+
- 9e178ca: Fixes for applications that check requests with a policy engine. A Framework without a policy behaves as before.
|
|
58
|
+
|
|
59
|
+
- A cursor on a row the caller cannot read is answered exactly as a cursor on a row that does not exist, at the root and in a to-many relation, whatever values the caller sends beside the identifier. Before, the page started at the hidden row, so it told that the row exists and where its values sort. The Prisma adapter reads the cursor's row under the read scope first: one statement more for a cursor on a readable row, and only that read for one on a row the caller cannot read.
|
|
60
|
+
- A unique update with a nested write (`$create`, `$connect`, …) on a row the caller can read but not change answers `A4002`, as the same update without one does. It answered `A2003`. A row the caller cannot read still answers `A2003`.
|
|
61
|
+
- The `exists` questions a policy asks select the Resource's primary identifier, never another unique field such as a governed `email`.
|
|
62
|
+
- `policy.principal` may answer with a promise. A synchronous principal works as before; a rejection answers `A3000`, as a throw does.
|
|
63
|
+
- `AvConstructionError.message` names the first problem and how many more there are, for example `Aventara framework configuration validation failed: CONFIG_INVALID_TYPE at adapter.execute: adapter.execute must be a function (+2 more)`. `stage` and `diagnostics` are unchanged.
|
|
64
|
+
|
|
3
65
|
## 1.0.0-rc.4
|
|
4
66
|
|
|
5
67
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -529,10 +529,10 @@ discovery.referentialActions;
|
|
|
529
529
|
// {
|
|
530
530
|
// Shop: { owningEdges: [] },
|
|
531
531
|
// Item: { owningEdges: [{ field: "shop", target: "Shop",
|
|
532
|
-
// cardinality: "one",
|
|
532
|
+
// cardinality: "one", referenceFields: ["shopId"],
|
|
533
533
|
// onDelete: "cascade", onUpdate: "cascade" }] },
|
|
534
534
|
// Clerk: { owningEdges: [{ field: "shop", target: "Shop",
|
|
535
|
-
// cardinality: "one",
|
|
535
|
+
// cardinality: "one", referenceFields: ["shopId"],
|
|
536
536
|
// onDelete: "set-null", onUpdate: "cascade" }] },
|
|
537
537
|
// }
|
|
538
538
|
```
|
|
@@ -544,7 +544,7 @@ read the enclosing Resource key: above, that is `Item` (cascade) and `Clerk` (se
|
|
|
544
544
|
that sentence are Resource names and nothing in the shape tells them apart, so reading it backwards
|
|
545
545
|
produces no error, only a plan that reasons backwards.
|
|
546
546
|
|
|
547
|
-
`
|
|
547
|
+
`referenceFields` are the edge's `@relation(fields: […])`, the scalars that hold the reference (the relation field's `referenceFields` in the model; its `references` are the target's fields). A record
|
|
548
548
|
that writes both a relation and one of its reference fields (`shopId` and `shop: { $connect: … }`,
|
|
549
549
|
whether the relation is required or optional) is refused before the database is reached: `A2004` with
|
|
550
550
|
a `V1012` issue at the relation, message `Set "shopId" or "shop", not both.` The reference fields are
|
|
@@ -668,7 +668,9 @@ Resource or operation for one to wrap.
|
|
|
668
668
|
- A record written through a relation cannot write that relation, or its reference fields, back: Prisma's nested
|
|
669
669
|
input for it leaves them out (a post created in `author.posts` has no `author` or `authorId`; a category created in
|
|
670
670
|
a post's `category` has no `posts`). The artifact states each relation's other end (`inverse`, paired by relation
|
|
671
|
-
name), the fields that hold its reference (`referenceFields`, from `@relation(fields: …)`) and
|
|
671
|
+
name), the fields that hold its reference (`referenceFields`, from `@relation(fields: …)`) and the target's fields
|
|
672
|
+
they hold, pair by pair (`references`, from `@relation(references: …)`, which `@aventara/core` keeps in the Core
|
|
673
|
+
Contract only, for a policy engine), and no relation
|
|
672
674
|
writable at the `"loopback"` position, so `@aventara/core` refuses such a write before any
|
|
673
675
|
guard or SQL, `A2004` with a `V1012` issue at the field written back, and the types do not offer it. Where a layer
|
|
674
676
|
hides the other end, Prisma's client refuses the write instead and the adapter answers that refusal the same way.
|
|
@@ -42,9 +42,11 @@ export type AvPrismaReferentialEdge = {
|
|
|
42
42
|
readonly cardinality: "one" | "many";
|
|
43
43
|
/**
|
|
44
44
|
* The scalar fields of the enclosing resource that hold the reference: the
|
|
45
|
-
* relation's `@relation(fields: […])`, in schema order.
|
|
45
|
+
* relation's `@relation(fields: […])`, in schema order. Named as the relation
|
|
46
|
+
* field's `referenceFields` in the model: its `references` are the TARGET's
|
|
47
|
+
* fields (`@relation(references: […])`).
|
|
46
48
|
*/
|
|
47
|
-
readonly
|
|
49
|
+
readonly referenceFields: readonly string[];
|
|
48
50
|
/** What deleting a `target` row does to rows of the enclosing resource. */
|
|
49
51
|
readonly onDelete: AvPrismaReferentialAction;
|
|
50
52
|
/** The same for an update of the referenced key. Read independently of `onDelete`. */
|
|
@@ -245,10 +245,17 @@ function composeResource(input) {
|
|
|
245
245
|
const referenceFields = firstReference === undefined
|
|
246
246
|
? undefined
|
|
247
247
|
: [firstReference, ...moreReferences];
|
|
248
|
+
const [firstTarget, ...moreTargets] = field.relation?.references ?? [];
|
|
249
|
+
const references = referenceFields === undefined ||
|
|
250
|
+
firstTarget === undefined ||
|
|
251
|
+
moreTargets.length + 1 !== referenceFields.length
|
|
252
|
+
? undefined
|
|
253
|
+
: [firstTarget, ...moreTargets];
|
|
248
254
|
fields[projection.name] = {
|
|
249
255
|
...projection.field,
|
|
250
256
|
...(inverse === undefined ? {} : { inverse: inverse.relation }),
|
|
251
257
|
...(referenceFields === undefined ? {} : { referenceFields }),
|
|
258
|
+
...(references === undefined ? {} : { references }),
|
|
252
259
|
capabilities: deriveRelationCapabilities({
|
|
253
260
|
surface: relationSurface,
|
|
254
261
|
}),
|
|
@@ -259,7 +266,7 @@ function composeResource(input) {
|
|
|
259
266
|
field: projection.edge.field,
|
|
260
267
|
target: projection.edge.target,
|
|
261
268
|
cardinality: projection.edge.cardinality,
|
|
262
|
-
|
|
269
|
+
referenceFields: [...(referenceFields ?? [])],
|
|
263
270
|
onDelete: projection.edge.onDelete,
|
|
264
271
|
onUpdate: projection.edge.onUpdate,
|
|
265
272
|
});
|
|
@@ -2,9 +2,10 @@ import { locateBackReferenceWrite, } from "../errors/back-reference.locator.js";
|
|
|
2
2
|
import { locateUnboundBigint } from "../errors/bigint-binding.locator.js";
|
|
3
3
|
import { classifyPrismaError, prismaNestedWriteFailure, prismaOutcomeFailure, prismaValueFailure, } from "../errors/error.normalizer.js";
|
|
4
4
|
import { prismaDelegates, } from "../prisma-client.interface.js";
|
|
5
|
-
import { PRISMA_VARIANT_DISPATCH, translateOperation, } from "../translation/operation.translator.js";
|
|
5
|
+
import { PRISMA_VARIANT_DISPATCH, translateOperation, translateScopedCursorLookup, } from "../translation/operation.translator.js";
|
|
6
6
|
import { runFirstVariantEmulation } from "./first-variant.emulator.js";
|
|
7
7
|
import { shapeCount, shapeRow, shapeRows, } from "./result.shaper.js";
|
|
8
|
+
import { resolveScopedCursors } from "./scoped-cursor.resolver.js";
|
|
8
9
|
export class AvPrismaExecutionError extends Error {
|
|
9
10
|
name = "AvPrismaExecutionError";
|
|
10
11
|
}
|
|
@@ -21,8 +22,9 @@ export function createPrismaOperationExecutor(dependencies) {
|
|
|
21
22
|
: {}),
|
|
22
23
|
});
|
|
23
24
|
return {
|
|
24
|
-
async execute(
|
|
25
|
-
const result = resultKindOf(dispatchOf(
|
|
25
|
+
async execute(sent) {
|
|
26
|
+
const result = resultKindOf(dispatchOf(sent));
|
|
27
|
+
const operation = await withScopedCursorsResolved(dependencies, sent, (call) => issueClassified(issue, call, sent, locatorFor(sent)));
|
|
26
28
|
const translation = translateOperation({
|
|
27
29
|
model: dependencies.model,
|
|
28
30
|
translation: dependencies.translation,
|
|
@@ -53,6 +55,18 @@ export function createPrismaOperationExecutor(dependencies) {
|
|
|
53
55
|
},
|
|
54
56
|
};
|
|
55
57
|
}
|
|
58
|
+
async function withScopedCursorsResolved(dependencies, operation, issue) {
|
|
59
|
+
const args = operation.arguments;
|
|
60
|
+
const resolved = await resolveScopedCursors(dependencies.model, operation.resource, args, async (resource, cursor) => (await issue(translateScopedCursorLookup({
|
|
61
|
+
model: dependencies.model,
|
|
62
|
+
translation: dependencies.translation,
|
|
63
|
+
resource,
|
|
64
|
+
cursor,
|
|
65
|
+
}))) !== null);
|
|
66
|
+
return resolved === args
|
|
67
|
+
? operation
|
|
68
|
+
: { ...operation, arguments: resolved };
|
|
69
|
+
}
|
|
56
70
|
async function withUnit(dependencies, work) {
|
|
57
71
|
if (dependencies.scope === "transaction") {
|
|
58
72
|
return work(dependencies.client);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AvAdapterModel } from "@aventara/core";
|
|
2
|
+
type Level = Readonly<Record<string, unknown>>;
|
|
3
|
+
/** Whether the row `cursor` (with its `AND`) names on `resource` meets its conditions. */
|
|
4
|
+
export type PrismaScopedCursorLookup = (resource: string, cursor: Level) => Promise<boolean>;
|
|
5
|
+
/**
|
|
6
|
+
* The operation's arguments with every cursor that carries `AND` resolved: its
|
|
7
|
+
* address alone when the row meets the conditions, otherwise no cursor and
|
|
8
|
+
* `limit: 0`. The same object when no cursor carries `AND`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveScopedCursors(model: AvAdapterModel, resource: string, args: Level, lookup: PrismaScopedCursorLookup): Promise<Level>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export async function resolveScopedCursors(model, resource, args, lookup) {
|
|
2
|
+
return (await resolveLevel(model, resource, args, lookup)) ?? args;
|
|
3
|
+
}
|
|
4
|
+
async function resolveLevel(model, resource, level, lookup) {
|
|
5
|
+
let resolved;
|
|
6
|
+
const cursor = level.cursor;
|
|
7
|
+
if (isRecord(cursor) && Object.hasOwn(cursor, "AND")) {
|
|
8
|
+
const { AND: _conditions, ...address } = cursor;
|
|
9
|
+
const { cursor: _cursor, ...rest } = level;
|
|
10
|
+
resolved = (await lookup(resource, cursor))
|
|
11
|
+
? { ...rest, cursor: address }
|
|
12
|
+
: { ...rest, limit: 0 };
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(level.select)) {
|
|
15
|
+
const select = await resolveSelect(model, resource, level.select, lookup);
|
|
16
|
+
if (select !== undefined) {
|
|
17
|
+
resolved = { ...(resolved ?? level), select };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return resolved;
|
|
21
|
+
}
|
|
22
|
+
async function resolveSelect(model, resource, select, lookup) {
|
|
23
|
+
let changed = false;
|
|
24
|
+
const entries = [];
|
|
25
|
+
for (const entry of select) {
|
|
26
|
+
if (!isRecord(entry)) {
|
|
27
|
+
entries.push(entry);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const rewritten = {};
|
|
31
|
+
for (const [name, value] of Object.entries(entry)) {
|
|
32
|
+
const field = model.resources[resource]?.fields[name];
|
|
33
|
+
const inner = field?.kind === "relation" && isRecord(value)
|
|
34
|
+
? await resolveLevel(model, field.target, value, lookup)
|
|
35
|
+
: undefined;
|
|
36
|
+
if (inner !== undefined) {
|
|
37
|
+
changed = true;
|
|
38
|
+
}
|
|
39
|
+
rewritten[name] = inner ?? value;
|
|
40
|
+
}
|
|
41
|
+
entries.push(rewritten);
|
|
42
|
+
}
|
|
43
|
+
return changed ? entries : undefined;
|
|
44
|
+
}
|
|
45
|
+
function isRecord(value) {
|
|
46
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
47
|
+
}
|
|
@@ -19,7 +19,7 @@ const REFERENTIAL_ACTIONS_DOC = [
|
|
|
19
19
|
"/**",
|
|
20
20
|
" * The schema's referential actions, per Resource: the relation fields that",
|
|
21
21
|
" * declare `@relation(fields: …)`, each with the fields holding its reference",
|
|
22
|
-
" * (`
|
|
22
|
+
" * (`referenceFields`) and its resolved `onDelete` and `onUpdate`. An edge under",
|
|
23
23
|
" * Resource `R` reads:",
|
|
24
24
|
" *",
|
|
25
25
|
" * deleting a `target` row does `onDelete` to rows of `R`.",
|
|
@@ -144,3 +144,14 @@ export type PrismaOperationTranslationInput = {
|
|
|
144
144
|
* addresses no row — never a silently narrowed or widened call.
|
|
145
145
|
*/
|
|
146
146
|
export declare function translateOperation(input: PrismaOperationTranslationInput): PrismaOperationTranslation;
|
|
147
|
+
/**
|
|
148
|
+
* The unique read that tells whether the row a core cursor names meets the
|
|
149
|
+
* `AND` conditions it carries: `findUnique` by the cursor's address with the
|
|
150
|
+
* conditions, translated against `resource`, in its selector.
|
|
151
|
+
*/
|
|
152
|
+
export declare function translateScopedCursorLookup(input: {
|
|
153
|
+
readonly model: AvAdapterModel;
|
|
154
|
+
readonly translation: Readonly<Record<string, PrismaResourceTranslation>>;
|
|
155
|
+
readonly resource: string;
|
|
156
|
+
readonly cursor: Readonly<Record<string, unknown>>;
|
|
157
|
+
}): PrismaCall;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { addressIdentifier } from "./identifier.addressing.js";
|
|
2
2
|
import { translateMutationData } from "./mutation.translator.js";
|
|
3
|
-
import { translateOrderBy, translatePagination, } from "./order-pagination.translator.js";
|
|
3
|
+
import { translateCursorLookup, translateOrderBy, translatePagination, } from "./order-pagination.translator.js";
|
|
4
4
|
import { translateProjection, } from "./projection.translator.js";
|
|
5
5
|
import { translateWhere } from "./where.translator.js";
|
|
6
6
|
const FIRST_VARIANT_WRITE_ROUTE = {
|
|
@@ -256,10 +256,39 @@ function paginationArguments(context) {
|
|
|
256
256
|
...(typeof context.args.offset === "number"
|
|
257
257
|
? { offset: context.args.offset }
|
|
258
258
|
: {}),
|
|
259
|
-
...(
|
|
259
|
+
...cursorArguments(context.args.cursor),
|
|
260
260
|
identifiers: identifiersOf(context, context.resource),
|
|
261
261
|
});
|
|
262
262
|
}
|
|
263
|
+
function cursorArguments(cursor) {
|
|
264
|
+
if (!isRecord(cursor)) {
|
|
265
|
+
return {};
|
|
266
|
+
}
|
|
267
|
+
if (Object.hasOwn(cursor, "AND")) {
|
|
268
|
+
throw new AvPrismaOperationTranslationError("cursor: its `AND` conditions reach no Prisma `cursor`; the executor resolves them before translation");
|
|
269
|
+
}
|
|
270
|
+
return { cursor };
|
|
271
|
+
}
|
|
272
|
+
export function translateScopedCursorLookup(input) {
|
|
273
|
+
const { AND: conditions, ...address } = input.cursor;
|
|
274
|
+
const identifiers = input.translation[input.resource]?.identifierKeys;
|
|
275
|
+
if (identifiers === undefined) {
|
|
276
|
+
throw new AvPrismaOperationTranslationError(`Resource "${input.resource}" has no Prisma addressing in the translation table`);
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
model: input.resource,
|
|
280
|
+
action: "findUnique",
|
|
281
|
+
args: translateCursorLookup({
|
|
282
|
+
cursor: address,
|
|
283
|
+
conditions: translateWhere({
|
|
284
|
+
model: input.model,
|
|
285
|
+
resource: input.resource,
|
|
286
|
+
where: { AND: conditions },
|
|
287
|
+
}),
|
|
288
|
+
identifiers,
|
|
289
|
+
}),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
263
292
|
function mutationData(context, stage, argument) {
|
|
264
293
|
return translateMutationData({
|
|
265
294
|
model: context.model,
|
|
@@ -322,7 +351,7 @@ function relationArgumentTranslator(context) {
|
|
|
322
351
|
Object.assign(emitted, translatePagination({
|
|
323
352
|
...(typeof args.limit === "number" ? { limit: args.limit } : {}),
|
|
324
353
|
...(typeof args.offset === "number" ? { offset: args.offset } : {}),
|
|
325
|
-
...(
|
|
354
|
+
...cursorArguments(args.cursor),
|
|
326
355
|
identifiers: identifiersOf(context, target),
|
|
327
356
|
}));
|
|
328
357
|
return emitted;
|
|
@@ -30,4 +30,23 @@ export type OrderByTranslation = {
|
|
|
30
30
|
readonly orderBy: unknown;
|
|
31
31
|
};
|
|
32
32
|
export declare function translatePagination(input: PaginationTranslation): PrismaPaginationArguments;
|
|
33
|
+
/**
|
|
34
|
+
* The Aventara cursor carries the active ordered scalar fields; core guarantees
|
|
35
|
+
* that they include a complete identifier (`V1009` — *"orderBy must include a
|
|
36
|
+
* complete Resource identifier as an explicit tie-breaker"*). Prisma's `cursor`
|
|
37
|
+
* is an ADDRESS, so the identifier is what is emitted: the remaining ordered
|
|
38
|
+
* fields are the ordering, which `orderBy` already carries, and adding them as
|
|
39
|
+
* equality members of a where-unique would narrow the address rather than
|
|
40
|
+
* sharpen it.
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* The unique read that tells whether the row a cursor names meets `conditions`
|
|
44
|
+
* (a translated `<M>WhereInput`): its address, the conditions in `AND`, and the
|
|
45
|
+
* address's members selected.
|
|
46
|
+
*/
|
|
47
|
+
export declare function translateCursorLookup(input: {
|
|
48
|
+
readonly cursor: Readonly<Record<string, unknown>>;
|
|
49
|
+
readonly conditions: Readonly<Record<string, unknown>>;
|
|
50
|
+
readonly identifiers: readonly PrismaIdentifierAddress[];
|
|
51
|
+
}): Readonly<Record<string, unknown>>;
|
|
33
52
|
export declare function translateOrderBy(input: OrderByTranslation): PrismaOrderByInput | readonly PrismaOrderByInput[];
|
|
@@ -24,6 +24,21 @@ export function translatePagination(input) {
|
|
|
24
24
|
}
|
|
25
25
|
return emitted;
|
|
26
26
|
}
|
|
27
|
+
export function translateCursorLookup(input) {
|
|
28
|
+
const addressed = addressIdentifier({
|
|
29
|
+
addresses: input.identifiers,
|
|
30
|
+
values: input.cursor,
|
|
31
|
+
match: "subset",
|
|
32
|
+
emit: (_member, value) => value,
|
|
33
|
+
});
|
|
34
|
+
if (addressed === undefined) {
|
|
35
|
+
throw new AvPrismaOrderTranslationError(`cursor: no identifier is complete in { ${Object.keys(input.cursor).join(", ")} }, so it addresses no row`);
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
where: { ...addressed.where, AND: [input.conditions] },
|
|
39
|
+
select: Object.fromEntries(addressed.address.members.map((member) => [member, true])),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
27
42
|
function addressCursor(cursor, identifiers) {
|
|
28
43
|
const addressed = addressIdentifier({
|
|
29
44
|
addresses: identifiers,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aventara/prisma7-adapter",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.9",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "The Prisma 7 adapter for Aventara.",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"CHANGELOG.md"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@aventara/core": "1.0.0-rc.
|
|
33
|
+
"@aventara/core": "1.0.0-rc.9"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@prisma/adapter-better-sqlite3": "^7.10.0",
|