@vantreeseba/drizzle-graphql 13.1.1 → 14.0.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/README.md +81 -5
- package/dist/index.cjs +299 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -7
- package/dist/index.d.ts +66 -7
- package/dist/index.js +299 -81
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -189,14 +189,16 @@ const { schema } = buildSchema(db, {
|
|
|
189
189
|
- The table is still fully readable — this decides which operations it offers, not whether
|
|
190
190
|
it is in the schema at all. For that, use `exclude` below
|
|
191
191
|
- `nestedWrites` is the one flag that stays build-wide: its plans are computed once over
|
|
192
|
-
the whole relation graph, and a nested write reaches a second table by definition
|
|
192
|
+
the whole relation graph, and a nested write reaches a second table by definition. What
|
|
193
|
+
it offers on each relation still follows the *target* table's flags — see
|
|
194
|
+
[Nested writes](#nested-writes)
|
|
193
195
|
- `Mutation` is omitted when *no* table generates a mutation, and kept when one still does
|
|
194
196
|
- Some operations are built out of others, and the generator knows which. A table that
|
|
195
197
|
asks for `upsert` while its `insert` or `update` is off — an upsert is a second write
|
|
196
198
|
path past the operation you turned off — warns on the console at build time, naming the
|
|
197
199
|
tables, rather than leaving that to be discovered later. So does asking for `updateMany`
|
|
198
|
-
without `update`, `groupBy` without `aggregates`, `countMutations` with neither plural
|
|
199
|
-
write
|
|
200
|
+
without `update`, `groupBy` without `aggregates`, or `countMutations` with neither plural
|
|
201
|
+
write. `nestedWrites` notes the nested inputs it left out because their table's write is off
|
|
200
202
|
|
|
201
203
|
## Excluding tables and columns
|
|
202
204
|
|
|
@@ -1531,6 +1533,32 @@ mutation {
|
|
|
1531
1533
|
- A `set` that carries only relation fields is a valid update: it changes what the row is
|
|
1532
1534
|
attached to without rewriting the row
|
|
1533
1535
|
|
|
1536
|
+
### The target table's own rules
|
|
1537
|
+
|
|
1538
|
+
A nested write is a write to another table, so it follows that table's rules, not just the
|
|
1539
|
+
root field's:
|
|
1540
|
+
|
|
1541
|
+
- **`scope`** narrows the rows `connect` / `disconnect` / `set` can reach, and
|
|
1542
|
+
**`contextValues`** stamp the rows a nested `create` inserts
|
|
1543
|
+
- **`features`**: each nested input is generated only when the table it writes has that
|
|
1544
|
+
write turned on. Whatever is left out is noted on the console at build time, and a
|
|
1545
|
+
relation with nothing left loses its field altogether
|
|
1546
|
+
|
|
1547
|
+
| Input | Needs, on the table it writes |
|
|
1548
|
+
| --- | --- |
|
|
1549
|
+
| `create` | the target's `insert` (and its `update` too on a to-one whose nullable key lives on the target, since attaching detaches the previous row) |
|
|
1550
|
+
| `connect` / `disconnect` / `set`, key on the target | the target's `update` |
|
|
1551
|
+
| `connect` / `disconnect`, key on the parent | nothing — only the parent's own row changes |
|
|
1552
|
+
| many-to-many `connect` | the junction's `insert` |
|
|
1553
|
+
| many-to-many `disconnect` | the junction's `delete` |
|
|
1554
|
+
| many-to-many `set` | the junction's `insert` and `delete` |
|
|
1555
|
+
|
|
1556
|
+
An excluded junction table takes its relation's inputs with it. A table whose writes are
|
|
1557
|
+
reserved for a hand-written mutation (`insert: false`) can therefore no longer be written
|
|
1558
|
+
by another table's nested `create` either
|
|
1559
|
+
- **`onWrite`**: the hooks of the table a nested statement writes run too — see
|
|
1560
|
+
[Nested writes and hooks](#nested-writes-and-hooks)
|
|
1561
|
+
|
|
1534
1562
|
### Many-to-many relations
|
|
1535
1563
|
|
|
1536
1564
|
A relation declared with `.through()` is written by inserting and deleting rows of its
|
|
@@ -2161,6 +2189,7 @@ The payload:
|
|
|
2161
2189
|
| `rows` | the post-write rows **as the database returned them**, before the output mapper — the selected columns plus the hook's [`columns`](#which-columns-rows-holds) |
|
|
2162
2190
|
| `context`, `info` | the GraphQL context value and resolve info |
|
|
2163
2191
|
| `tx` | the executor the mutation ran on |
|
|
2192
|
+
| `nested` | `{ parentTable, relation, op }` when a [nested write](#nested-writes-and-hooks) wrote the rows; `undefined` at the mutation field's own table |
|
|
2164
2193
|
|
|
2165
2194
|
- **`tx` is the executor the mutation itself used** — one you supplied under
|
|
2166
2195
|
`drizzleExecutorKey`, the request's auto-transaction, or, for a field that would otherwise
|
|
@@ -2170,11 +2199,58 @@ The payload:
|
|
|
2170
2199
|
already does.
|
|
2171
2200
|
- **`rows` is empty** at the `before` position, and on MySQL, whose mutations return no rows.
|
|
2172
2201
|
The `before` position and `args` still work there.
|
|
2173
|
-
-
|
|
2174
|
-
|
|
2202
|
+
- With `nestedWrites`, the hooks of **every table a nested write reaches** fire too —
|
|
2203
|
+
below.
|
|
2175
2204
|
|
|
2176
2205
|
A build with no `onWrite` opens exactly the transactions it did before.
|
|
2177
2206
|
|
|
2207
|
+
### Nested writes and hooks
|
|
2208
|
+
|
|
2209
|
+
A nested `create` / `connect` / `disconnect` / `set` runs the `before` and `after` hooks of the
|
|
2210
|
+
table its statement writes, on the same `tx`, with `payload.nested` saying where it came from:
|
|
2211
|
+
|
|
2212
|
+
```Typescript
|
|
2213
|
+
onWrite: {
|
|
2214
|
+
todos: {
|
|
2215
|
+
before: async ({ nested, args, tx }) => { /* runs ahead of the nested statement too */ },
|
|
2216
|
+
after: async ({ operation, rows, nested, tx }) => {
|
|
2217
|
+
// createProjectsSingle(values: { …, todos: { create: [ … ] } }) arrives here as
|
|
2218
|
+
// operation: 'insert', nested: { parentTable: 'projects', relation: 'todos', op: 'create' }
|
|
2219
|
+
for (const row of rows) await assertOwnsProject(tx, row.projectId)
|
|
2220
|
+
},
|
|
2221
|
+
columns: ['projectId'],
|
|
2222
|
+
},
|
|
2223
|
+
}
|
|
2224
|
+
```
|
|
2225
|
+
|
|
2226
|
+
| Nested input | `table` | `operation` |
|
|
2227
|
+
| --- | --- | --- |
|
|
2228
|
+
| `create` | the target | `insert` |
|
|
2229
|
+
| `connect` / `disconnect` / `set`, key on the target | the target | `update` (the foreign key moved; nothing is deleted) |
|
|
2230
|
+
| `connect` / `disconnect`, key on the parent | — | no target hook: only the parent's row changes, and its own hook sees that |
|
|
2231
|
+
| many-to-many `connect` | the junction | `insert` |
|
|
2232
|
+
| many-to-many `disconnect` | the junction | `delete` |
|
|
2233
|
+
| many-to-many `set` | the junction | `delete` (the old links), then `insert` (the new ones) |
|
|
2234
|
+
|
|
2235
|
+
- **`nested`** is `{ parentTable, relation, op }` — the Drizzle schema key of the table whose
|
|
2236
|
+
input carried the relation field, the relation's name, and which of its inputs this is.
|
|
2237
|
+
It is `undefined` at the mutation field's own table, so a hook that only cares about root
|
|
2238
|
+
writes starts with `if (payload.nested) return`
|
|
2239
|
+
- **One call per input and operation**, not per row: a nested `create` of three rows is one
|
|
2240
|
+
`insert` call with three rows, and an update whose `where` matched several parents hands
|
|
2241
|
+
the hook every child it wrote across all of them. A to-one `connect` that also detaches
|
|
2242
|
+
the row attached before is one `update` call holding both rows; a detached row's key is
|
|
2243
|
+
`null`
|
|
2244
|
+
- **`rows`** hold the table's primary key and the join column(s) the statement changed — a
|
|
2245
|
+
nested write has no client selection of its own — plus whatever the hook names in
|
|
2246
|
+
`columns`
|
|
2247
|
+
- **`args`, `context` and `info`** are the root mutation field's; **`single`** says whether the
|
|
2248
|
+
relation is a to-one
|
|
2249
|
+
- **`before`** runs ahead of that input's first statement, **`after`** once its last has
|
|
2250
|
+
returned, and both inside the transaction every nested write opens — so a hook on a child
|
|
2251
|
+
table can roll the whole tree back, the parent row included, even when the root field has
|
|
2252
|
+
no hook of its own
|
|
2253
|
+
|
|
2178
2254
|
|
|
2179
2255
|
## Relations & N+1 handling
|
|
2180
2256
|
|