@pothos/plugin-drizzle 0.18.0 → 0.19.0
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 +351 -0
- package/README.md +784 -221
- package/dts/connection-helpers.d.ts +18 -8
- package/dts/connection-helpers.d.ts.map +1 -1
- package/dts/drizzle-field-builder.d.ts +4 -11
- package/dts/drizzle-field-builder.d.ts.map +1 -1
- package/dts/global-types.d.ts.map +1 -1
- package/dts/index.d.ts.map +1 -1
- package/dts/model-loader.d.ts +18 -17
- package/dts/model-loader.d.ts.map +1 -1
- package/dts/types.d.ts +81 -20
- package/dts/types.d.ts.map +1 -1
- package/dts/utils/adapter.d.ts +39 -0
- package/dts/utils/adapter.d.ts.map +1 -0
- package/dts/utils/await-selections.d.ts +12 -0
- package/dts/utils/await-selections.d.ts.map +1 -0
- package/dts/utils/config.d.ts +23 -3
- package/dts/utils/config.d.ts.map +1 -1
- package/dts/utils/cursors.d.ts +6 -6
- package/dts/utils/cursors.d.ts.map +1 -1
- package/dts/utils/map-query.d.ts +22 -21
- package/dts/utils/map-query.d.ts.map +1 -1
- package/dts/utils/path-info.d.ts +13 -0
- package/dts/utils/path-info.d.ts.map +1 -0
- package/dts/utils/relation-filter.d.ts +48 -0
- package/dts/utils/relation-filter.d.ts.map +1 -0
- package/dts/utils/selections.d.ts +2 -21
- package/dts/utils/selections.d.ts.map +1 -1
- package/esm/connection-helpers.d.ts +18 -8
- package/esm/connection-helpers.d.ts.map +1 -1
- package/esm/connection-helpers.js +52 -19
- package/esm/connection-helpers.js.map +1 -1
- package/esm/drizzle-field-builder.d.ts +4 -11
- package/esm/drizzle-field-builder.d.ts.map +1 -1
- package/esm/drizzle-field-builder.js +138 -96
- package/esm/drizzle-field-builder.js.map +1 -1
- package/esm/field-builder.js +61 -47
- package/esm/field-builder.js.map +1 -1
- package/esm/global-types.d.ts.map +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +37 -61
- package/esm/index.js.map +1 -1
- package/esm/model-loader.d.ts +18 -17
- package/esm/model-loader.d.ts.map +1 -1
- package/esm/model-loader.js +76 -45
- package/esm/model-loader.js.map +1 -1
- package/esm/schema-builder.js +40 -149
- package/esm/schema-builder.js.map +1 -1
- package/esm/types.d.ts +81 -20
- package/esm/types.d.ts.map +1 -1
- package/esm/types.js +1 -0
- package/esm/types.js.map +1 -1
- package/esm/utils/adapter.d.ts +39 -0
- package/esm/utils/adapter.d.ts.map +1 -0
- package/esm/utils/adapter.js +137 -0
- package/esm/utils/adapter.js.map +1 -0
- package/esm/utils/await-selections.d.ts +12 -0
- package/esm/utils/await-selections.d.ts.map +1 -0
- package/esm/utils/await-selections.js +19 -0
- package/esm/utils/await-selections.js.map +1 -0
- package/esm/utils/config.d.ts +23 -3
- package/esm/utils/config.d.ts.map +1 -1
- package/esm/utils/config.js +1 -4
- package/esm/utils/config.js.map +1 -1
- package/esm/utils/cursors.d.ts +6 -6
- package/esm/utils/cursors.d.ts.map +1 -1
- package/esm/utils/cursors.js +55 -90
- package/esm/utils/cursors.js.map +1 -1
- package/esm/utils/map-query.d.ts +22 -21
- package/esm/utils/map-query.d.ts.map +1 -1
- package/esm/utils/map-query.js +40 -336
- package/esm/utils/map-query.js.map +1 -1
- package/esm/utils/path-info.d.ts +13 -0
- package/esm/utils/path-info.d.ts.map +1 -0
- package/esm/utils/path-info.js +37 -0
- package/esm/utils/path-info.js.map +1 -0
- package/esm/utils/relation-filter.d.ts +48 -0
- package/esm/utils/relation-filter.d.ts.map +1 -0
- package/esm/utils/relation-filter.js +92 -0
- package/esm/utils/relation-filter.js.map +1 -0
- package/esm/utils/selections.d.ts +2 -21
- package/esm/utils/selections.d.ts.map +1 -1
- package/esm/utils/selections.js +1 -133
- package/esm/utils/selections.js.map +1 -1
- package/lib/connection-helpers.js +51 -18
- package/lib/connection-helpers.js.map +1 -1
- package/lib/drizzle-field-builder.js +136 -94
- package/lib/drizzle-field-builder.js.map +1 -1
- package/lib/field-builder.js +58 -44
- package/lib/field-builder.js.map +1 -1
- package/lib/index.js +36 -60
- package/lib/index.js.map +1 -1
- package/lib/model-loader.js +76 -45
- package/lib/model-loader.js.map +1 -1
- package/lib/schema-builder.js +40 -149
- package/lib/schema-builder.js.map +1 -1
- package/lib/types.js +4 -0
- package/lib/types.js.map +1 -1
- package/lib/utils/adapter.js +147 -0
- package/lib/utils/adapter.js.map +1 -0
- package/lib/utils/await-selections.js +20 -0
- package/lib/utils/await-selections.js.map +1 -0
- package/lib/utils/config.js +1 -4
- package/lib/utils/config.js.map +1 -1
- package/lib/utils/cursors.js +47 -88
- package/lib/utils/cursors.js.map +1 -1
- package/lib/utils/map-query.js +28 -341
- package/lib/utils/map-query.js.map +1 -1
- package/lib/utils/path-info.js +39 -0
- package/lib/utils/path-info.js.map +1 -0
- package/lib/utils/relation-filter.js +91 -0
- package/lib/utils/relation-filter.js.map +1 -0
- package/lib/utils/selections.js +3 -158
- package/lib/utils/selections.js.map +1 -1
- package/package.json +8 -6
- package/src/connection-helpers.ts +167 -53
- package/src/drizzle-field-builder.ts +296 -176
- package/src/field-builder.ts +110 -77
- package/src/global-types.ts +0 -32
- package/src/index.ts +42 -68
- package/src/model-loader.ts +110 -71
- package/src/schema-builder.ts +76 -169
- package/src/types.ts +176 -44
- package/src/utils/adapter.ts +197 -0
- package/src/utils/await-selections.ts +31 -0
- package/src/utils/config.ts +1 -5
- package/src/utils/cursors.ts +53 -81
- package/src/utils/map-query.ts +51 -708
- package/src/utils/path-info.ts +40 -0
- package/src/utils/relation-filter.ts +185 -0
- package/src/utils/selections.ts +2 -207
- package/dts/utils/deep-equal.d.ts +0 -2
- package/dts/utils/deep-equal.d.ts.map +0 -1
- package/dts/utils/drizzle-graphql.d.ts +0 -2
- package/dts/utils/drizzle-graphql.d.ts.map +0 -1
- package/dts/utils/loader-map.d.ts +0 -11
- package/dts/utils/loader-map.d.ts.map +0 -1
- package/dts/utils/usage.d.ts +0 -5
- package/dts/utils/usage.d.ts.map +0 -1
- package/esm/utils/deep-equal.d.ts +0 -2
- package/esm/utils/deep-equal.d.ts.map +0 -1
- package/esm/utils/deep-equal.js +0 -45
- package/esm/utils/deep-equal.js.map +0 -1
- package/esm/utils/drizzle-graphql.d.ts +0 -2
- package/esm/utils/drizzle-graphql.d.ts.map +0 -1
- package/esm/utils/drizzle-graphql.js +0 -232
- package/esm/utils/drizzle-graphql.js.map +0 -1
- package/esm/utils/loader-map.d.ts +0 -11
- package/esm/utils/loader-map.d.ts.map +0 -1
- package/esm/utils/loader-map.js +0 -35
- package/esm/utils/loader-map.js.map +0 -1
- package/esm/utils/usage.d.ts +0 -5
- package/esm/utils/usage.d.ts.map +0 -1
- package/esm/utils/usage.js +0 -59
- package/esm/utils/usage.js.map +0 -1
- package/lib/utils/deep-equal.js +0 -55
- package/lib/utils/deep-equal.js.map +0 -1
- package/lib/utils/drizzle-graphql.js +0 -236
- package/lib/utils/drizzle-graphql.js.map +0 -1
- package/lib/utils/loader-map.js +0 -56
- package/lib/utils/loader-map.js.map +0 -1
- package/lib/utils/usage.js +0 -83
- package/lib/utils/usage.js.map +0 -1
- package/src/utils/deep-equal.ts +0 -57
- package/src/utils/drizzle-graphql.ts +0 -274
- package/src/utils/loader-map.ts +0 -49
- package/src/utils/usage.ts +0 -62
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,356 @@
|
|
|
1
1
|
# @pothos/plugin-drizzle
|
|
2
2
|
|
|
3
|
+
## 0.19.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0c7565a: Selections can be built by async callbacks. New `AsyncSelections` flag in the schema types, off by
|
|
8
|
+
default.
|
|
9
|
+
- `AsyncSelections: true` widens what the selection callbacks accept: a field's `select` function,
|
|
10
|
+
a relation `query` callback, a `relationCount` / `relatedCount` `where` callback, and the
|
|
11
|
+
`select` / `query` callbacks of `prismaConnectionHelpers` and `drizzleConnectionHelpers` may all
|
|
12
|
+
return promises. Without the flag they are typed as synchronous and an async callback is a type
|
|
13
|
+
error, which is what the prisma plugin needed: it accepted an async `select` and silently
|
|
14
|
+
dropped the selection it resolved to.
|
|
15
|
+
- The plugins still build one query. Callbacks start in the same tick, and what they return is
|
|
16
|
+
merged after every synchronous selection, in document order. Async argument mappers (such as the
|
|
17
|
+
validation plugin's) are awaited before the field's `select` runs. Synchronous selection planning
|
|
18
|
+
remains synchronous and does not create promises solely to support async callbacks.
|
|
19
|
+
- Inside an async `select`, `await` the result of `nestedSelection` before adding it to the
|
|
20
|
+
selection. A `select` that returns while a nested selection it started is still pending throws,
|
|
21
|
+
naming the field.
|
|
22
|
+
- Everything the plugins generate settles its plan before your resolver runs, so a schema built
|
|
23
|
+
only from `t.relation`, `t.relationCount` / `t.relatedCount`, `t.prismaField` /
|
|
24
|
+
`t.drizzleField`, `t.prismaConnection` / `t.drizzleConnection` and `t.relatedConnection` can
|
|
25
|
+
turn the flag on and change nothing else. The `query()` builder handed to a `drizzleField` or
|
|
26
|
+
`drizzleConnection` resolver never returns a promise for the same reason.
|
|
27
|
+
- The places where your own code asks for a query or a selection are the ones to audit:
|
|
28
|
+
`queryFromInfo` (prisma), a connection helper's `getQuery` (both plugins), `nestedSelection`,
|
|
29
|
+
and `mergeNestedSelection`. `queryFromInfo` and `getQuery` build the query synchronously and
|
|
30
|
+
take an `awaitSelections` option; pass `awaitSelections: true` to get a `MaybePromise` and
|
|
31
|
+
`await` it. A call that did not ask for a promise throws, naming the option and what the call
|
|
32
|
+
was building — `queryFromInfo` the field, `getQuery` the connection's model or table, which is
|
|
33
|
+
as much as it is given — rather than returning one where the declared type said there was none:
|
|
34
|
+
a promise spread into a prisma or drizzle call is one unusable key and no type error. Two things
|
|
35
|
+
make the query async. One is a selection beneath the field, which is a property of the document
|
|
36
|
+
rather than of the call site. The other is the helper's own `select` or `query` callback: an
|
|
37
|
+
async one makes `getQuery` throw for a fully synchronous document, since it is the helper's own
|
|
38
|
+
callback that has not settled. The return type follows the option's literal type, so the default
|
|
39
|
+
keeps the plain query; a non-literal `boolean` gets the `MaybePromise`, since the call cannot
|
|
40
|
+
rely on the synchronous type either.
|
|
41
|
+
- A selection passed to drizzle's `query()` comes first, as it does for `queryFromInfo`: a
|
|
42
|
+
relation the document also plans with other arguments loads on its own.
|
|
43
|
+
|
|
44
|
+
- 1358f71: Cursors and node ids round trip for the column types a key holds — numbers, strings, bigints,
|
|
45
|
+
dates, booleans, decimals and byte arrays — and compound cursors are encoded with per-part type tags so
|
|
46
|
+
every value in one keeps its type, including booleans in Prisma compound unique keys.
|
|
47
|
+
|
|
48
|
+
A compound cursor was a plain JSON array of the raw values in the prisma plugin. That throws
|
|
49
|
+
outright on a bigint, so a connection whose cursor is a `@@id` or `@@unique` containing a `BigInt`
|
|
50
|
+
column failed on every edge of every page; it wrote a `DateTime` out as an ISO string that came
|
|
51
|
+
back as a string, so the millisecond a row was created on was gone by the time the value reached
|
|
52
|
+
the query; and it wrote a `Bytes` column out as the JSON form of a buffer. Every part now carries
|
|
53
|
+
its own type tag. The drizzle plugin already tagged each part; what changes there is that a
|
|
54
|
+
compound cursor can hold bytes, a decimal and a JSON value there too.
|
|
55
|
+
|
|
56
|
+
A null cursor value now round trips in both plugins. The prisma plugin threw "Unsupported cursor
|
|
57
|
+
type object" while building the edge of a single value cursor, so a connection whose cursor names a
|
|
58
|
+
nullable column failed the whole page rather than only a request that paged from that row; `Json`
|
|
59
|
+
and `Bytes` values could not be written there either. The drizzle plugin wrote the string `null`,
|
|
60
|
+
which is not a value the cursor format can hold, so the cursor came back as "Invalid cursor" the
|
|
61
|
+
moment a client paged from that edge. Both now write a null as a tagged chunk and read it back as
|
|
62
|
+
`null`.
|
|
63
|
+
|
|
64
|
+
Cursors issued before this release still parse, in both plugins, to the same values they always
|
|
65
|
+
did. That legacy handling is deprecated and is removed in the next major. The `GPC:` and `DC:`
|
|
66
|
+
prefixes are unchanged, so only compound cursors are written differently; a single value cursor is
|
|
67
|
+
byte for byte what it was, apart from the null that neither plugin could write usefully. A single
|
|
68
|
+
value string cursor also no longer loses everything after the first newline it contains.
|
|
69
|
+
|
|
70
|
+
Other values that did not survive a round trip:
|
|
71
|
+
- A cursor value on a float, real or `Decimal` column, in both plugins. It was read back with
|
|
72
|
+
`parseInt`, which truncates `1.75` to `1` and reads a large number's `1e+21` as `1`, so the page
|
|
73
|
+
resumed from the wrong row.
|
|
74
|
+
- A prisma node id built from a `DateTime` field. It was serialized with `String(date)`, whose
|
|
75
|
+
format carries no milliseconds, so `findUnique` looked for a row a fraction of a second before
|
|
76
|
+
the real one and the node resolved as not found. Ids already handed out in the old format still
|
|
77
|
+
parse. A drizzle node id built from a date column had the mirror problem on the way back: `new
|
|
78
|
+
Date` was given the epoch milliseconds the serializer writes as a string, which is not a format
|
|
79
|
+
it parses, so every such id resolved as an Invalid Date.
|
|
80
|
+
- A prisma node id built from a `Bytes` field. The base64 case was spelled `Byte`, which is not
|
|
81
|
+
what the datamodel calls the type, so the value was serialized as `String(bytes)` (the bytes
|
|
82
|
+
separated by commas) and parsed back as that string.
|
|
83
|
+
- A drizzle node id built by `builder.drizzleNode` with an `id.column` that is not the table's
|
|
84
|
+
primary key. The id was parsed back into a record keyed by the database column name, while the
|
|
85
|
+
serializer wrote, and the model loader reads, the typescript name; the loaded rows were then
|
|
86
|
+
matched back to the ids they were loaded for by primary key, which such a record does not carry.
|
|
87
|
+
Such a node now loads.
|
|
88
|
+
- A prisma compound node id (a `@@id` or `@@unique` used as `id.field`). It passed the field's
|
|
89
|
+
`kind` (always `scalar`) where the type was wanted, so a `Json` or `Bytes` part was written as
|
|
90
|
+
`String(value)` and could not be read back. Each part is now serialized by its scalar type, as
|
|
91
|
+
the parser already read them.
|
|
92
|
+
|
|
93
|
+
Two paging fixes that go with them:
|
|
94
|
+
- A connection asked for `last: 0` pages backwards in both plugins, as any other `last` does. `0`
|
|
95
|
+
was read as "no `last` given", so the query took rows forwards and `pageInfo` came back as
|
|
96
|
+
though the request had been a forward page: `hasNextPage` true and `hasPreviousPage` false on a
|
|
97
|
+
non-empty connection.
|
|
98
|
+
- A prisma compound cursor carrying the wrong number of values is rejected with a validation error
|
|
99
|
+
naming both counts, rather than building a query with a missing key (or silently dropping an
|
|
100
|
+
extra one) for prisma to reject. The drizzle plugin already checked this.
|
|
101
|
+
|
|
102
|
+
The tagging itself lives in `@pothos/core` (`encodeCursorChunk`, `encodeCursorTuple` and
|
|
103
|
+
`decodeCursorChunk`, alongside `encodeBase64Bytes` / `decodeBase64Bytes`) rather than being written
|
|
104
|
+
out once per plugin.
|
|
105
|
+
|
|
106
|
+
- 1358f71: `t.relatedCount` and a `t.relatedConnection`'s `totalCount` now count the rows the connection pages
|
|
107
|
+
over. The parent-to-child SQL is built by drizzle's `relationToSQL` instead of being reassembled
|
|
108
|
+
from the relation's source and target columns, so the plugin and the relational query builder agree
|
|
109
|
+
on what "related" means.
|
|
110
|
+
- New builder option `drizzle.filterConnectionTotalCount` (default `true`): `totalCount` on a
|
|
111
|
+
`t.relatedConnection` applies the `where` returned by the field's `query`, so it counts the same
|
|
112
|
+
rows the connection paginates. Previously it reported the unfiltered count. Set the option to
|
|
113
|
+
`false` to keep counting every related row regardless of the filter, matching the prisma plugin's
|
|
114
|
+
option.
|
|
115
|
+
- A count over a many-to-many relation (one defined with `.through(...)`) counts related rows. The
|
|
116
|
+
junction table was left out, which compared the parent's key to the target's key instead: the
|
|
117
|
+
count came back as the number of target rows that happen to share an id with the parent, with no
|
|
118
|
+
error. The same correction applies to the filter `t.relatedField` hands to its `select` callback.
|
|
119
|
+
- A count honours a `where` declared on the relation itself, and the `where` a relation without
|
|
120
|
+
`from`/`to` inherits from the relation it reverses. Both were dropped, so the count included rows
|
|
121
|
+
the connection does not page over.
|
|
122
|
+
- The count reads the relation's source column off the parent by its typescript name, as every
|
|
123
|
+
other read of a row does. A table declaring `postId: integer('id')` carries it as `postId`, so
|
|
124
|
+
the count bound `undefined` and the driver rejected the query with "undefined cannot be passed as
|
|
125
|
+
argument to the database".
|
|
126
|
+
- `totalCount` and the query that pages the relation are now the same predicate: the count selects
|
|
127
|
+
from what the page query selects from and repeats its `where` clause, minus the limit, the
|
|
128
|
+
ordering and the keyset clauses.
|
|
129
|
+
- A count over a many-to-many relation joins the junction table by its index. `t.relatedCount`
|
|
130
|
+
counts a related row once however many junction rows reach it; a `t.relatedConnection`'s
|
|
131
|
+
`totalCount` counts rows the way the page query returns them, so the two report different
|
|
132
|
+
totals for a relation whose junction holds duplicate rows.
|
|
133
|
+
- A `drizzleConnection` declared `nullable: false` no longer queries rows for a document that
|
|
134
|
+
selects only `totalCount`. The check that recognises a count-only selection read the field's
|
|
135
|
+
return type without unwrapping it, so a non-null connection never matched and always loaded a
|
|
136
|
+
page of rows it then discarded. Nullable connections were already unaffected.
|
|
137
|
+
|
|
138
|
+
- 1358f71: When a field's data is missing from the parent row it falls back to the model loader, which
|
|
139
|
+
reloads the row. That fallback now loads the right row, and loads more of it.
|
|
140
|
+
- The loaded row also carries the parent type's type-level `select`/`include` (prisma) or
|
|
141
|
+
type-level columns, relations and extras (drizzle), since that row replaces the parent the
|
|
142
|
+
resolver sees. Fallback queries therefore load more than before: the parent type's own columns
|
|
143
|
+
and its type-level relations. The field's own selection always wins — a type-level relation
|
|
144
|
+
whose arguments conflict with it is left out of that query — and when a prisma type-level
|
|
145
|
+
`_count` has several counts and one conflicts with the count a field selects for itself, the
|
|
146
|
+
loader keeps the other counts instead of dropping `_count` altogether.
|
|
147
|
+
- Drizzle: `t.relation`, `t.relatedCount` and `t.relatedConnection` fall back to the loader when
|
|
148
|
+
their data is missing from the parent row — most often because the row was returned by a
|
|
149
|
+
resolver that fetched it itself. Previously the loader was reached only when the field had no
|
|
150
|
+
loader mapping at all, and a row without the relation on it resolved as `undefined` or as an
|
|
151
|
+
empty page. `t.relatedConnection` decides what it has by reading its selection at resolve time
|
|
152
|
+
the same way the planner does, through fragments, `@skip`/`@include`, and a wrapping type, so a
|
|
153
|
+
row that carries the relation rows but not the count reloads rather than reporting `totalCount`
|
|
154
|
+
as `undefined`.
|
|
155
|
+
- Prisma: a model load that failed before its query was sent hung the request instead of returning
|
|
156
|
+
an error. The loader batches the rows it reloads and sends one query per row on the next tick. A
|
|
157
|
+
throw while building any of those queries, most reachably `findUnique: null`, which throws
|
|
158
|
+
`Missing findUnique for <type>`, abandoned every row it had not reached yet, so those fields
|
|
159
|
+
never resolved and never errored and the request never finished. Every row in the batch now
|
|
160
|
+
rejects with that error, matching what `@pothos/plugin-drizzle` already did.
|
|
161
|
+
- Prisma: the per-row fallback plan is cached. When a relation or related connection has a
|
|
162
|
+
user-supplied `resolve` and the planned query did not load it, the field's resolver plans the
|
|
163
|
+
field for itself; that planning ran again for every row of the list its parent came from. It is
|
|
164
|
+
now cached per `Type@path` per request, the way `ModelLoader` already caches its own entry point
|
|
165
|
+
and under the same key: the plan is settled once and played per call, so each row still gets a
|
|
166
|
+
query of its own and still records the same mappings under the same keys. On a document with 161
|
|
167
|
+
such resolutions the planning cost falls from about 405µs to about 68µs per request, with the
|
|
168
|
+
queries issued and the response unchanged.
|
|
169
|
+
|
|
170
|
+
- 220a1b1: The selection API is now typed to match what it actually does.
|
|
171
|
+
|
|
172
|
+
Two changes can stop existing code from compiling. In the first case that code already failed at
|
|
173
|
+
runtime:
|
|
174
|
+
- `t.relationCount` (prisma) and `t.relatedCount` (drizzle) accept only list relations. Calling
|
|
175
|
+
either on a to-one relation built a count query prisma or drizzle rejected.
|
|
176
|
+
- `LoaderMappings` (prisma) is a deprecated alias of the shared `Mappings` type. The record it
|
|
177
|
+
names is internal to the plugin, and the plugin no longer builds the `{ field, type, mappings,
|
|
178
|
+
indirectPath }` entries the old declaration described, so code that reads those keys off it no
|
|
179
|
+
longer compiles. Nothing in the plugin's API hands one to a schema.
|
|
180
|
+
|
|
181
|
+
New and widened types:
|
|
182
|
+
- `queryFromInfo` (prisma) is typed by what was passed: `{ include }` for a given `include`, and
|
|
183
|
+
`{ select }` keeping a given select's own type, so the selection round trips. Spread the result
|
|
184
|
+
into a prisma call and read the selected columns and relations back off the rows, with types. A
|
|
185
|
+
call with neither now returns `{ select?, include? }`, whichever of the two the type's mode
|
|
186
|
+
produced, rather than a `select` key that a type in include mode does not return.
|
|
187
|
+
- `nestedSelection` returns the relation query for the field's model or table (prisma:
|
|
188
|
+
`PrismaRelationQuery<Model>`; drizzle: the table's `DBQueryConfig`, a `many` config for a list
|
|
189
|
+
field), keeping the keys it was given as given, so a `select`/`columns` in them still narrows
|
|
190
|
+
the parent shape. Its argument is typed by that query when the field's type names a model, so
|
|
191
|
+
literals such as `select: { title: true }` are kept, and it accepts a callback or a promise as
|
|
192
|
+
the runtime always did. It used to return its argument's type.
|
|
193
|
+
- One `PathSegment` type (`string | { name: string; type?: string }`) for `queryFromInfo` paths
|
|
194
|
+
and `nestedSelection` paths, exported from `@pothos/selection-mapper` and re-exported by both
|
|
195
|
+
plugins, together with `IndirectPathSegment` (its `{ name, type? }` form) and `IndirectInclude`,
|
|
196
|
+
whose `path`/`paths` still take only `IndirectPathSegment` objects. A `{ name, type }` segment
|
|
197
|
+
given to `nestedSelection` now pins the implementation the field is found under at runtime, as
|
|
198
|
+
it already did for `queryFromInfo`.
|
|
199
|
+
- The `query` a `t.relation` fallback `resolve` receives (prisma) — the relation's own arguments
|
|
200
|
+
(`where`, `orderBy`, `take`, ...) alongside the planned `select`/`include` — has a name:
|
|
201
|
+
`QueryFromRelation`.
|
|
202
|
+
- `t.relatedField` (drizzle) accepts the ordinary field options (`deprecationReason`,
|
|
203
|
+
`extensions`, `authScopes`, ...), and forwards every one of them to the field it builds, merging
|
|
204
|
+
`extensions` rather than dropping them; `t.relatedCount`, which is built on it, gets the same.
|
|
205
|
+
Its `resolve` may be async and receives the resolve `info`. Exported as
|
|
206
|
+
`RelatedSelectionFieldOptions`.
|
|
207
|
+
- A query whose `select` key is optional but names columns (`{ select?: { email: true } }`)
|
|
208
|
+
narrows the row to those columns, rather than to no columns at all as `ShapeFromSelection` did
|
|
209
|
+
before: the columns are on the row whether or not the `select` is applied, since a row loaded
|
|
210
|
+
without a `select` carries every column.
|
|
211
|
+
|
|
212
|
+
The docs for both plugins now cover how a field gets its data, and when it costs a query of its
|
|
213
|
+
own. Also newly documented: prisma `findUnique: null`, `onNull`, `nestedSelection`'s typed
|
|
214
|
+
segments and third argument, `skipDeferredFragments`,
|
|
215
|
+
`prismaFieldWithInput`/`drizzleFieldWithInput`, drizzle
|
|
216
|
+
`drizzleInterface`/`drizzleInterfaceField(s)`, `t.variant(Ref, { select })`, connection size
|
|
217
|
+
options, the drizzle fallback loader, and the error two variants raise when their selections
|
|
218
|
+
conflict.
|
|
219
|
+
|
|
220
|
+
- 220a1b1: The prisma and drizzle plugins now plan their queries with one shared selection planner, the new
|
|
221
|
+
package `@pothos/selection-mapper`. Each plugin keeps its own adapter for its query format; the
|
|
222
|
+
walk from a GraphQL selection to a query is the same code in both.
|
|
223
|
+
|
|
224
|
+
The plugins' public API is unchanged: only internal helpers moved (each plugin's `map-query`,
|
|
225
|
+
`selections`, `loader-map` and `deep-equal`), and the loader mapping keys (internal) now carry the
|
|
226
|
+
full field path. Behaviour that differed between the two plugins for no reason now agrees. In
|
|
227
|
+
particular, prisma walks fragments the way drizzle did: fields under a fragment on an interface the
|
|
228
|
+
type implements, including interfaces not backed by a model, are planned for the type instead of
|
|
229
|
+
falling back to a query per row.
|
|
230
|
+
|
|
231
|
+
The package is an implementation detail of the two plugins. Its exports exist for them and change
|
|
232
|
+
with them: it is not a supported public API, and its versions carry no compatibility promise of
|
|
233
|
+
their own.
|
|
234
|
+
|
|
235
|
+
- 1358f71: Entering another type of the same model through a fragment (a variant under a model interface or
|
|
236
|
+
union) now merges that type's type-level selection, so resolvers relying on it find their data in
|
|
237
|
+
the same query. This can change the shape of queries a schema with variants issues, and it adds one
|
|
238
|
+
validation error.
|
|
239
|
+
- A variant without a type-level `select` switches the query to include mode (prisma) or every
|
|
240
|
+
column (drizzle).
|
|
241
|
+
- If the two types' type-level selections disagree on a relation's arguments, a validation error
|
|
242
|
+
names both types and the relation; move the relation arguments to a field-level `select` on one
|
|
243
|
+
of the types. The error is raised whichever route brought the two types together: a fragment
|
|
244
|
+
entering a variant, or two indirect-include path matches landing on different types of the one
|
|
245
|
+
model. Relation arguments are compared structurally, so equal arguments written
|
|
246
|
+
separately are fine. In drizzle, two types defining the same `extras` key with different
|
|
247
|
+
functions are rejected the same way, naming the extra: an extra shared across variants must be
|
|
248
|
+
the same function reference.
|
|
249
|
+
- The type-level selections of every variant entered at a selection set are merged before the
|
|
250
|
+
fields there are planned, so the result no longer depends on document order: a field-level
|
|
251
|
+
`select` whose relation arguments conflict with a variant's type-level selection falls back to
|
|
252
|
+
its own query whichever comes first, and only two type-level selections can conflict.
|
|
253
|
+
- A walk on an object type is a walk on rows of that type: the field's own type, the `typeName`
|
|
254
|
+
given to `queryFromInfo`, the type pinned by `nestedSelection`, or a node load. A fragment on
|
|
255
|
+
another object type of the same model cannot apply to those rows, so it is not entered; it is
|
|
256
|
+
entered while walking an interface, where rows may resolve to it. Prisma previously entered it
|
|
257
|
+
whenever the field's declared type was abstract, planning a sibling variant's selection for
|
|
258
|
+
rows that could never be it.
|
|
259
|
+
- A fragment that does not apply to the type still lets a nested fragment narrow back to it.
|
|
260
|
+
Drizzle previously stopped at the outer fragment and discarded what was nested inside it.
|
|
261
|
+
|
|
262
|
+
### Patch Changes
|
|
263
|
+
|
|
264
|
+
- 220a1b1: Drizzle plugin fixes.
|
|
265
|
+
- `t.relatedConnection` calls its `query` callback with the same `pathInfo` while resolving as
|
|
266
|
+
while planning, so a query that branches on `pathInfo` pages the rows it selected.
|
|
267
|
+
- `t.relatedConnection` no longer accepts a `resolve` option. It was silently discarded, so the
|
|
268
|
+
resolver never ran.
|
|
269
|
+
- `t.relation` evaluates a `query` callback once, with `pathInfo`. Previously it was called a
|
|
270
|
+
second time without `pathInfo`.
|
|
271
|
+
- `drizzleConnectionHelpers(builder, table)` can now be called without the options argument.
|
|
272
|
+
Previously it threw.
|
|
273
|
+
- `builder.drizzleInterfaceField(s)` given a table name resolves it to the interface registered for
|
|
274
|
+
that table, as the docs describe, instead of the object type.
|
|
275
|
+
- `pathInfo.path` handed to relation `query` callbacks now starts with the root field for queries
|
|
276
|
+
planned through `path`/`paths`, as it already did for queries planned directly for a field.
|
|
277
|
+
- `pathInfo.segments[].isList` is `true` for non-null list fields (`[Post!]!`). Previously only
|
|
278
|
+
nullable lists were reported as lists.
|
|
279
|
+
- The error for a `drizzleObject` and a `drizzleInterface` it implements being built on different
|
|
280
|
+
tables names drizzle rather than prisma. It read "must be based on the same prisma model as any
|
|
281
|
+
DrizzleInterfaces they extend"; it now says "the same drizzle table".
|
|
282
|
+
- Custom client adapters must now provide `select()` and its SQL builder chain, plus
|
|
283
|
+
`query.<table>.findMany()`, alongside relation metadata and `$count()`. Forward SQL construction
|
|
284
|
+
synchronously; do not wrap `select` in a promise or Effect. Full Drizzle clients already
|
|
285
|
+
provide these methods.
|
|
286
|
+
- Requires Drizzle `1.0.0-rc.2` or newer for the relation SQL API used by counts and predicates.
|
|
287
|
+
- Custom connection fields retain their rows when `totalCount` is selected.
|
|
288
|
+
- Connection helper `resolve()` returns a maybe-promise for async-enabled schemas; await it
|
|
289
|
+
before inspecting or spreading connection fields.
|
|
290
|
+
- Nested query callbacks passed to `nestedSelection` now receive `PathInfo` as their third
|
|
291
|
+
argument, after the field arguments and context.
|
|
292
|
+
|
|
293
|
+
- 1358f71: Fix how selections are found through fragments, paths and wrapper types, in both plugins. Each of
|
|
294
|
+
these left a field to load its own data per row, or planned the wrong selection for it.
|
|
295
|
+
- A path segment selected behind a fragment that narrows an interface or union
|
|
296
|
+
(`... on Impl { field }`), or a fragment on an interface that overlaps the list type, is now
|
|
297
|
+
found without needing to pin the type on the segment. Previously the field was skipped and the
|
|
298
|
+
plugin fell back to a separate query per row. Drizzle crashed on a fragment spread that narrows
|
|
299
|
+
an interface.
|
|
300
|
+
- When the same field is selected in several places (multiple fragments, several `paths`, or the
|
|
301
|
+
same response key under several fragments), every selection is merged into one query. Previously
|
|
302
|
+
`queryFromInfo` kept only the last one, and a field loaded through the fallback planned only its
|
|
303
|
+
first occurrence.
|
|
304
|
+
- A relation selected under both `nodes` and `edges { node }` of a connection is answered from the
|
|
305
|
+
loaded rows in both places. The loader mappings used to be keyed by field alias alone, so the
|
|
306
|
+
second path fell back to a query of its own.
|
|
307
|
+
- A `nestedSelection` path into a field selected through a fragment on the same type
|
|
308
|
+
(`... on Type { field }` or `...Fragment`) now merges the nested selection instead of producing
|
|
309
|
+
an empty selection.
|
|
310
|
+
- Fragment spreads and inline fragments left out by `@skip` / `@include` are no longer planned, so
|
|
311
|
+
they neither enter a variant nor add fields to the query.
|
|
312
|
+
- `queryFromInfo`'s `path` and `paths` accept `{ name, type }` segments alongside strings, in the
|
|
313
|
+
types and the docs as well as at runtime. A segment `type` pins the fragment type condition the
|
|
314
|
+
field must be found under, which is useful when several implementations share a field name. The
|
|
315
|
+
pin is applied wherever the field is looked for, not only where a fragment was crossed to reach
|
|
316
|
+
it: a field of the same name selected directly on a level that is not the pinned type is no
|
|
317
|
+
longer taken as the segment's, so the match no longer carries that level's return type instead
|
|
318
|
+
of the pinned type's. A segment `type` that does not exist in the schema is a validation error,
|
|
319
|
+
rather than a `TypeError` (prisma) or a path that silently matches nothing (drizzle).
|
|
320
|
+
- When several implementations share a field name, matches whose field returns a different model or
|
|
321
|
+
table than the one the query is being built for are ignored, so their selections are never merged
|
|
322
|
+
into the wrong query. Variants of the target model are walked with their own fields.
|
|
323
|
+
- A type carrying `pothosIndirectInclude` with `paths` only contributes its own selection when it
|
|
324
|
+
is backed by the model being queried. A plain wrapper, or a wrapper backed by another model, no
|
|
325
|
+
longer merges its selection into the target model's query.
|
|
326
|
+
- `queryFromInfo` with `path`/`paths` that select nothing now returns the `select`/`include`
|
|
327
|
+
(prisma) or `select` (drizzle) it was given, or `{}`, instead of an empty `select` (which prisma
|
|
328
|
+
rejects) or a query that dropped the caller's selection.
|
|
329
|
+
- The selection lookup handed to a field's `select` callback (the fourth argument) now looks
|
|
330
|
+
through wrappers on the field's return type and returns the first match. A `relatedConnection`
|
|
331
|
+
with `totalCount: true` wrapped by `@pothos/plugin-errors` now selects the count, and its
|
|
332
|
+
totalCount-only handling agrees with what was planned.
|
|
333
|
+
- A field `select` callback returning `false`, `null` or `undefined` is treated as selecting
|
|
334
|
+
nothing: the field is not answered from the parent row and loads its own data when resolved.
|
|
335
|
+
`false` used to switch the query to include mode and still record the field as loaded, so it
|
|
336
|
+
resolved from a row that held nothing for it; `null` and `undefined` threw.
|
|
337
|
+
- Relation arguments compare the same way whichever of two selections was planned first. The
|
|
338
|
+
structural equality both plugins use decided whether a value was an array, or a boxed value such
|
|
339
|
+
as a `Date`, by looking only at its left-hand argument: `{}` and `[]` compared equal one way
|
|
340
|
+
round and unequal the other, and so did `{}` and a `Date`. That helper answers whether two
|
|
341
|
+
selections of one relation ask for the same arguments, so an answer that depended on argument
|
|
342
|
+
order could let an incompatible selection merge and replace the arguments already planned, or
|
|
343
|
+
refuse a compatible one and issue a separate query for the field. Both guards now read both
|
|
344
|
+
sides. `orderBy` is the argument where this is easiest to hit, since prisma accepts an object and
|
|
345
|
+
an array there for the same meaning.
|
|
346
|
+
- @pothos/selection-mapper@0.1.0
|
|
347
|
+
|
|
348
|
+
## 0.18.1
|
|
349
|
+
|
|
350
|
+
### Patch Changes
|
|
351
|
+
|
|
352
|
+
- 6424480: Plan fragments on interfaces implemented by a Drizzle object against the object, so `select` declared on the interface's fields is merged into the query instead of being skipped and loaded separately. Export `DrizzleInterfaceRef` and the `DrizzleRef` type from the package index.
|
|
353
|
+
|
|
3
354
|
## 0.18.0
|
|
4
355
|
|
|
5
356
|
### Minor Changes
|