pothos-drizzle-generator 0.1.21 → 0.1.23
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 +288 -148
- package/dist/cjs/PothosDrizzleGenerator.js +4 -4
- package/dist/cjs/PothosDrizzleGenerator.js.map +1 -1
- package/dist/cjs/generator.js +17 -16
- package/dist/cjs/generator.js.map +1 -1
- package/dist/cjs/global-types.d.ts +99 -0
- package/dist/cjs/global-types.js.map +1 -1
- package/dist/cjs/libs/operations.d.ts +41 -1
- package/dist/cjs/libs/operations.js +40 -1
- package/dist/cjs/libs/operations.js.map +1 -1
- package/dist/cjs/libs/utils.d.ts +0 -10
- package/dist/cjs/libs/utils.js +4 -16
- package/dist/cjs/libs/utils.js.map +1 -1
- package/dist/esm/PothosDrizzleGenerator.js +5 -5
- package/dist/esm/PothosDrizzleGenerator.js.map +1 -1
- package/dist/esm/generator.js +18 -17
- package/dist/esm/generator.js.map +1 -1
- package/dist/esm/global-types.d.ts +99 -0
- package/dist/esm/global-types.js.map +1 -1
- package/dist/esm/libs/operations.d.ts +41 -1
- package/dist/esm/libs/operations.js +40 -1
- package/dist/esm/libs/operations.js.map +1 -1
- package/dist/esm/libs/utils.d.ts +0 -10
- package/dist/esm/libs/utils.js +3 -14
- package/dist/esm/libs/utils.js.map +1 -1
- package/package.json +7 -9
package/README.md
CHANGED
|
@@ -1,220 +1,360 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Pothos Drizzle Generator
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://www.npmjs.com/package/pothos-drizzle-generator)
|
|
5
|
-
[](https://www.npmjs.com/package/pothos-drizzle-generator)
|
|
6
|
-
[](https://deepwiki.com/node-libraries/pothos-drizzle-generator)
|
|
3
|
+
**Pothos Drizzle Generator** is a robust Pothos plugin designed to automatically generate a complete GraphQL schema (Queries & Mutations) directly from your Drizzle ORM schema definitions.
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
By automating the creation of types, input objects, and resolvers for standard CRUD operations, this tool significantly reduces boilerplate code. It also provides granular control over permissions, complex filtering, and field visibility, ensuring your API remains secure and performant.
|
|
6
|
+
|
|
7
|
+
- Screenshot in ApolloExplorer
|
|
9
8
|
|
|
10
9
|

|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
## 🚀 Key Features
|
|
12
|
+
|
|
13
|
+
- **Automated CRUD Generation**: Instantly generates `findMany`, `findFirst`, `create`, `update`, and `delete` operations.
|
|
14
|
+
- **End-to-End Type Safety**: Ensures fully typed inputs and outputs that stay in sync with your Drizzle schema.
|
|
15
|
+
- **Deep Relational Filtering**: Apply filters, sorting, and pagination **not just to the main resource, but also to any nested relations** (e.g., "Find users and their _published_ posts").
|
|
16
|
+
- **Advanced Filtering**: Built-in support for complex queries, including `AND`, `OR`, `gt` (greater than), `contains`, and more.
|
|
17
|
+
- **Granular Access Control**: Configure visibility and permissions globally or on a per-model basis.
|
|
18
|
+
- **Smart Relations**: Seamlessly handles join tables and nested relationships.
|
|
19
|
+
|
|
20
|
+
## 🔗 Sample Repository
|
|
21
|
+
|
|
22
|
+
Explore a working implementation in the sample repository:
|
|
23
|
+
[https://github.com/SoraKumo001/pothos-drizzle-generator-sample](https://github.com/SoraKumo001/pothos-drizzle-generator-sample)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 📦 Getting Started
|
|
28
|
+
|
|
29
|
+
### Requirements
|
|
30
|
+
|
|
31
|
+
Ensure your environment meets the following dependencies:
|
|
32
|
+
|
|
33
|
+
- **drizzle-orm**: `v1.0.0-beta.8`+
|
|
34
|
+
- **@pothos/core**: `v4.0.0`+
|
|
35
|
+
- **@pothos/plugin-drizzle**: `v0.16.0`+
|
|
36
|
+
|
|
37
|
+
### Installation
|
|
38
|
+
|
|
39
|
+
Install the generator alongside the required Pothos and Drizzle packages:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# npm
|
|
43
|
+
npm install pothos-drizzle-generator @pothos/core @pothos/plugin-drizzle drizzle-orm graphql
|
|
44
|
+
|
|
45
|
+
# pnpm
|
|
46
|
+
pnpm add pothos-drizzle-generator @pothos/core @pothos/plugin-drizzle drizzle-orm graphql
|
|
47
|
+
|
|
48
|
+
# yarn
|
|
49
|
+
yarn add pothos-drizzle-generator @pothos/core @pothos/plugin-drizzle drizzle-orm graphql
|
|
13
50
|
|
|
14
|
-
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## ⚡ Quick Start
|
|
56
|
+
|
|
57
|
+
Follow these steps to integrate the generator into your SchemaBuilder.
|
|
15
58
|
|
|
16
|
-
|
|
59
|
+
### 1. Setup & Initialization
|
|
17
60
|
|
|
18
|
-
|
|
61
|
+
Register the `PothosDrizzleGeneratorPlugin` and configure your Drizzle client.
|
|
19
62
|
|
|
20
63
|
```ts
|
|
21
64
|
import "dotenv/config";
|
|
22
65
|
import SchemaBuilder from "@pothos/core";
|
|
23
66
|
import DrizzlePlugin from "@pothos/plugin-drizzle";
|
|
67
|
+
import PothosDrizzleGeneratorPlugin from "pothos-drizzle-generator";
|
|
24
68
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
25
69
|
import { getTableConfig } from "drizzle-orm/pg-core";
|
|
26
70
|
import { relations } from "./db/relations";
|
|
27
|
-
import PothosDrizzleGeneratorPlugin from "pothos-drizzle-generator";
|
|
28
71
|
|
|
72
|
+
// 1. Initialize Drizzle Client
|
|
29
73
|
const db = drizzle({
|
|
30
74
|
connection: process.env.DATABASE_URL!,
|
|
31
75
|
relations,
|
|
32
76
|
logger: true,
|
|
33
77
|
});
|
|
34
78
|
|
|
79
|
+
// 2. Define Context & Types
|
|
35
80
|
export interface PothosTypes {
|
|
36
81
|
DrizzleRelations: typeof relations;
|
|
37
82
|
Context: { userId?: string };
|
|
38
83
|
}
|
|
39
84
|
|
|
85
|
+
// 3. Initialize Builder
|
|
40
86
|
const builder = new SchemaBuilder<PothosTypes>({
|
|
41
87
|
plugins: [
|
|
42
88
|
DrizzlePlugin,
|
|
43
|
-
PothosDrizzleGeneratorPlugin, //
|
|
89
|
+
PothosDrizzleGeneratorPlugin, // Register the generator plugin
|
|
44
90
|
],
|
|
45
91
|
drizzle: {
|
|
46
92
|
client: () => db,
|
|
47
93
|
relations,
|
|
48
94
|
getTableConfig,
|
|
49
95
|
},
|
|
96
|
+
// 4. Generator Configuration
|
|
97
|
+
pothosDrizzleGenerator: {
|
|
98
|
+
// Define your global and model-specific rules here
|
|
99
|
+
},
|
|
50
100
|
});
|
|
51
101
|
|
|
102
|
+
// 5. Build Schema
|
|
52
103
|
const schema = builder.toSchema();
|
|
53
104
|
```
|
|
54
105
|
|
|
55
|
-
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## ⚙️ Configuration Guide
|
|
109
|
+
|
|
110
|
+
The `pothosDrizzleGenerator` option offers a layered configuration approach, giving you full control over the generated schema.
|
|
111
|
+
|
|
112
|
+
Rules are applied in the following order:
|
|
56
113
|
|
|
57
|
-
|
|
114
|
+
1. **Selection (`use`)**: Define which tables to process.
|
|
115
|
+
2. **Global Defaults (`all`)**: Apply baseline rules to _every_ model.
|
|
116
|
+
3. **Model Overrides (`models`)**: Apply specific rules to individual models, overriding defaults.
|
|
117
|
+
|
|
118
|
+
### 1. Table Selection (`use`)
|
|
119
|
+
|
|
120
|
+
Control which tables are exposed in the GraphQL schema. This is useful for hiding internal tables or many-to-many join tables.
|
|
58
121
|
|
|
59
122
|
```ts
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// Specify the maximum value for the query's limit
|
|
84
|
-
limit: ({ ctx, modelName, operation }) => $limit$,
|
|
85
|
-
// Override the query's orderBy
|
|
86
|
-
orderBy: ({ ctx, modelName, operation }) => $orderBy$,
|
|
87
|
-
// Add query conditions
|
|
88
|
-
where: ({ ctx, modelName, operation }) => $where$,
|
|
89
|
-
// Specifying input fields
|
|
90
|
-
inputFields: { include: [$fields$], exclude: [$fields$] },
|
|
91
|
-
// Overwriting input data
|
|
92
|
-
inputData: ({ ctx, modelName, operation }) => $inputData$,
|
|
93
|
-
},
|
|
94
|
-
// Apply to individual models
|
|
95
|
-
models: {
|
|
96
|
-
[$modelName$]: {
|
|
97
|
-
// Specifying fields to use in queries
|
|
98
|
-
fields: ({ modelName }) => { include: [...$fields$], exclude: [...$fields$] },
|
|
99
|
-
// Specifying the method of operation for the model
|
|
100
|
-
operations: ({ modelName }) => { include: [...$operation$], exclude: [...$operation$] },
|
|
101
|
-
// Runtime Permission Check
|
|
102
|
-
executable: ({ ctx, modelName, operation }) => $permission$,
|
|
103
|
-
// Specify the maximum value for the query's limit
|
|
104
|
-
limit: ({ ctx, modelName, operation }) => $limit$,
|
|
105
|
-
// Override the query's orderBy
|
|
106
|
-
orderBy: ({ ctx, modelName, operation }) => $orderBy$,
|
|
107
|
-
// Add query conditions
|
|
108
|
-
where: ({ ctx, modelName, operation }) => $where$,
|
|
109
|
-
// Specifying input fields
|
|
110
|
-
inputFields: { include: [$fields$], exclude: [$fields$] },
|
|
111
|
-
// Overwriting input data
|
|
112
|
-
inputData: ({ ctx, modelName, operation }) => $inputData$,
|
|
113
|
-
},
|
|
123
|
+
pothosDrizzleGenerator: {
|
|
124
|
+
// Option A: Allowlist (Only generate these tables)
|
|
125
|
+
use: { include: ["users", "posts", "comments"] },
|
|
126
|
+
|
|
127
|
+
// Option B: Blocklist (Generate all EXCEPT these)
|
|
128
|
+
use: { exclude: ["users_to_groups", "audit_logs"] },
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 2. Global Defaults (`all`)
|
|
134
|
+
|
|
135
|
+
Use the `all` key to establish project-wide conventions, such as security policies, default query limits, or field visibility.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
pothosDrizzleGenerator: {
|
|
139
|
+
all: {
|
|
140
|
+
// Security: Require authentication for all write operations
|
|
141
|
+
executable: ({ ctx, operation }) => {
|
|
142
|
+
if (['create', 'update', 'delete'].includes(operation)) {
|
|
143
|
+
return !!ctx.userId; // Must be logged in
|
|
144
|
+
}
|
|
145
|
+
return true; // Read operations are public
|
|
114
146
|
},
|
|
115
|
-
|
|
116
|
-
|
|
147
|
+
// Performance: Set a default limit for all queries
|
|
148
|
+
limit: () => 50,
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 3. Model Overrides (`models`)
|
|
155
|
+
|
|
156
|
+
Target specific tables by name to override global settings.
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
pothosDrizzleGenerator: {
|
|
160
|
+
models: {
|
|
161
|
+
users: {
|
|
162
|
+
// Privacy: Users can only query their own record
|
|
163
|
+
where: ({ ctx }) => ({ id: { eq: ctx.userId } }),
|
|
164
|
+
// Security: Prevent user deletion via API
|
|
165
|
+
operations: () => ({ exclude: ["delete"] })
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 4. API Reference
|
|
173
|
+
|
|
174
|
+
The following callbacks can be used within both `all` and `models`.
|
|
175
|
+
|
|
176
|
+
| Property | Purpose | Arguments | Expected Return |
|
|
177
|
+
| ------------- | ---------------------------------------------------------- | ------------------------------- | -------------------------------- |
|
|
178
|
+
| `executable` | Authorization check. Return `false` to block execution. | `{ ctx, modelName, operation }` | `boolean` |
|
|
179
|
+
| `fields` | Control output field visibility. | `{ modelName }` | `{ include?: [], exclude?: [] }` |
|
|
180
|
+
| `inputFields` | Control input field visibility (for mutations). | `{ modelName }` | `{ include?: [], exclude?: [] }` |
|
|
181
|
+
| `operations` | Select which CRUD operations to generate. | `{ modelName }` | `{ include?: [], exclude?: [] }` |
|
|
182
|
+
| `where` | Apply mandatory filters (e.g., multi-tenancy). | `{ ctx, modelName, operation }` | `FilterObject` |
|
|
183
|
+
| `limit` | Set default max records for `findMany`. | `{ ctx, modelName, operation }` | `number` |
|
|
184
|
+
| `depthLimit` | Prevent deeply nested queries. | `{ ctx, modelName, operation }` | `number` |
|
|
185
|
+
| `orderBy` | Set default sort order. | `{ ctx, modelName, operation }` | `{ [col]: 'asc' \| 'desc' }` |
|
|
186
|
+
| `inputData` | Inject server-side values (e.g., `userId`) into mutations. | `{ ctx, modelName, operation }` | `Object` |
|
|
187
|
+
|
|
188
|
+
### 5. Helper Functions
|
|
189
|
+
|
|
190
|
+
Import `isOperation` to simplify conditional logic within your callbacks.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import { isOperation } from "pothos-drizzle-generator";
|
|
194
|
+
|
|
195
|
+
// Usage Example
|
|
196
|
+
executable: ({ ctx, operation }) => {
|
|
197
|
+
// Check if operation is a mutation (create/update/delete)
|
|
198
|
+
if (isOperation("mutation", operation)) {
|
|
199
|
+
return !!ctx.user;
|
|
200
|
+
}
|
|
201
|
+
return true;
|
|
202
|
+
},
|
|
203
|
+
|
|
117
204
|
```
|
|
118
205
|
|
|
119
|
-
|
|
206
|
+
**Available Operation Categories:**
|
|
207
|
+
|
|
208
|
+
- `OperationFind`: `findFirst`, `findMany`
|
|
209
|
+
- `OperationQuery`: `findFirst`, `findMany`, `count`
|
|
210
|
+
- `OperationCreate`: `createOne`, `createMany`
|
|
211
|
+
- `OperationUpdate`: `update`
|
|
212
|
+
- `OperationDelete`: `delete`
|
|
213
|
+
- `OperationMutation`: All write operations.
|
|
214
|
+
- `OperationAll`: Everything.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 🛡️ Comprehensive Configuration Example
|
|
219
|
+
|
|
220
|
+
This example demonstrates a production-ready setup combining global security rules with specific model overrides.
|
|
120
221
|
|
|
121
222
|
```ts
|
|
223
|
+
import { isOperation } from "pothos-drizzle-generator";
|
|
224
|
+
|
|
122
225
|
const builder = new SchemaBuilder<PothosTypes>({
|
|
123
|
-
plugins
|
|
124
|
-
DrizzlePlugin,
|
|
125
|
-
PothosDrizzleGeneratorPlugin, // Set plugin
|
|
126
|
-
],
|
|
127
|
-
drizzle: {
|
|
128
|
-
client: () => db,
|
|
129
|
-
relations,
|
|
130
|
-
getTableConfig,
|
|
131
|
-
},
|
|
226
|
+
// ... plugins setup
|
|
132
227
|
pothosDrizzleGenerator: {
|
|
133
|
-
//
|
|
228
|
+
// 1. Exclude join tables from the schema
|
|
134
229
|
use: { exclude: ["postsToCategories"] },
|
|
230
|
+
|
|
231
|
+
// 2. Global Defaults
|
|
135
232
|
all: {
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// Prohibit write operations if the user is not authenticated
|
|
140
|
-
if (isOperation(OperationMutation, operation) && !ctx.get("user")) {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
233
|
+
// Security: Read-only for guests, Writes for logged-in users
|
|
234
|
+
executable: ({ ctx, operation }) => {
|
|
235
|
+
if (isOperation("mutation", operation)) return !!ctx.user;
|
|
143
236
|
return true;
|
|
144
237
|
},
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
238
|
+
// Privacy: Hide sensitive fields everywhere
|
|
239
|
+
fields: () => ({ exclude: ["password", "secretKey"] }),
|
|
240
|
+
// Integrity: Protect system fields from manual input
|
|
241
|
+
inputFields: () => ({ exclude: ["createdAt", "updatedAt"] }),
|
|
242
|
+
// Logic: Filter out soft-deleted records (except when actually deleting)
|
|
243
|
+
where: ({ operation }) => {
|
|
244
|
+
if (operation !== "delete") return { deletedAt: { isNull: true } };
|
|
245
|
+
return {};
|
|
148
246
|
},
|
|
247
|
+
// Performance: Default limits
|
|
248
|
+
limit: () => 50,
|
|
249
|
+
depthLimit: () => 5,
|
|
149
250
|
},
|
|
251
|
+
|
|
252
|
+
// 3. Model Overrides
|
|
150
253
|
models: {
|
|
254
|
+
users: {
|
|
255
|
+
// Privacy: Users see only themselves
|
|
256
|
+
where: ({ ctx }) => ({ id: { eq: ctx.user?.id } }),
|
|
257
|
+
limit: () => 1,
|
|
258
|
+
operations: () => ({ exclude: ["delete"] }),
|
|
259
|
+
},
|
|
151
260
|
posts: {
|
|
152
|
-
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const user = ctx.get("user");
|
|
157
|
-
if (!user) throw new Error("No permission");
|
|
158
|
-
return { authorId: user.id };
|
|
159
|
-
},
|
|
261
|
+
limit: () => 100,
|
|
262
|
+
// Automation: Attach current user as author
|
|
263
|
+
inputData: ({ ctx }) => ({ authorId: ctx.user?.id }),
|
|
264
|
+
// Logic: Public posts OR User's own posts
|
|
160
265
|
where: ({ ctx, operation }) => {
|
|
161
|
-
|
|
162
|
-
if (isOperation(OperationQuery, operation)) {
|
|
266
|
+
if (isOperation("find", operation)) {
|
|
163
267
|
return {
|
|
164
|
-
OR: [
|
|
165
|
-
{ published: true },
|
|
166
|
-
{ authorId: { eq: ctx.get("user")?.id } },
|
|
167
|
-
],
|
|
268
|
+
OR: [{ published: true }, { authorId: { eq: ctx.user?.id } }],
|
|
168
269
|
};
|
|
169
270
|
}
|
|
170
|
-
//
|
|
171
|
-
if (isOperation(
|
|
172
|
-
return { authorId: ctx.
|
|
271
|
+
// Security: Only edit/delete own posts
|
|
272
|
+
if (isOperation(["update", "delete"], operation)) {
|
|
273
|
+
return { authorId: ctx.user?.id };
|
|
173
274
|
}
|
|
174
275
|
},
|
|
175
276
|
},
|
|
277
|
+
audit_logs: {
|
|
278
|
+
// Security: Admin access only
|
|
279
|
+
executable: ({ ctx }) => !!ctx.user?.isAdmin,
|
|
280
|
+
},
|
|
176
281
|
},
|
|
177
282
|
},
|
|
178
283
|
});
|
|
179
284
|
```
|
|
180
285
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
##
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
-
|
|
190
|
-
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
-
|
|
214
|
-
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## 💡 Generated Schema Capabilities
|
|
289
|
+
|
|
290
|
+
### Optimized Data Retrieval (Solving N+1)
|
|
291
|
+
|
|
292
|
+
The generator's `findMany` operation is engineered for performance and flexibility.
|
|
293
|
+
|
|
294
|
+
- **Deep Filtering & Sorting**: You aren't limited to filtering the root node. You can apply specific `where` clauses, `limit`, and `orderBy` arguments **to any related field deep in the graph**.
|
|
295
|
+
- **Single Query Execution**: It consolidates fetching the main resource, related records, and counts into a **single, optimized SQL query**. This utilizes complex `JOIN` and `LATERAL` clauses to eliminate the N+1 problem.
|
|
296
|
+
|
|
297
|
+
**Example Query:**
|
|
298
|
+
_Fetching users and specifically only their 'published' posts._
|
|
299
|
+
|
|
300
|
+
```graphql
|
|
301
|
+
query {
|
|
302
|
+
findManyUser {
|
|
303
|
+
id
|
|
304
|
+
name
|
|
305
|
+
# Filter related records directly
|
|
306
|
+
posts(where: { published: { eq: true } }, orderBy: { createdAt: desc }, limit: 5) {
|
|
307
|
+
title
|
|
308
|
+
createdAt
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Transactional Mutations
|
|
315
|
+
|
|
316
|
+
Write operations ensure data integrity through automatic transaction wrapping.
|
|
317
|
+
|
|
318
|
+
- **Atomic Operations**: When creating a record with related data (e.g., a Post with Categories), the entire process runs within a database transaction (`BEGIN` ... `COMMIT`).
|
|
319
|
+
- **Consistency**: If any part of the operation fails (e.g., inserting a relation), the entire action is rolled back, preventing orphaned data.
|
|
320
|
+
|
|
321
|
+
**Example Mutation:**
|
|
322
|
+
|
|
323
|
+
```graphql
|
|
324
|
+
mutation {
|
|
325
|
+
createOnePost(
|
|
326
|
+
input: {
|
|
327
|
+
title: "My New Post"
|
|
328
|
+
content: "Hello World"
|
|
329
|
+
# Handles many-to-many relation automatically
|
|
330
|
+
categories: { set: [{ id: "cat-1" }, { id: "cat-2" }] }
|
|
331
|
+
}
|
|
332
|
+
) {
|
|
333
|
+
id
|
|
334
|
+
categories {
|
|
335
|
+
name
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## 🔍 Supported Features Checklist
|
|
344
|
+
|
|
345
|
+
### Operations
|
|
346
|
+
|
|
347
|
+
- **Queries**: `findMany`, `findFirst`, `count`
|
|
348
|
+
- **Mutations**: `create`, `update`, `delete`
|
|
349
|
+
|
|
350
|
+
### Advanced Filtering (`where`)
|
|
351
|
+
|
|
352
|
+
- **Logical**: `AND`, `OR`, `NOT`
|
|
353
|
+
- **Comparators**: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`
|
|
354
|
+
- **Existence**: `isNull`, `isNotNull`
|
|
355
|
+
- **String Matching**: `like`, `notLike`, `ilike`, `notIlike`
|
|
356
|
+
- **Array Operations**: `arrayContained`, `arrayOverlaps`, `arrayContains`
|
|
357
|
+
|
|
358
|
+
## License
|
|
359
|
+
|
|
360
|
+
MIT
|
|
@@ -172,7 +172,7 @@ class PothosDrizzleGenerator extends core_1.BasePlugin {
|
|
|
172
172
|
limit: limit?.({ modelName, ctx, operation }),
|
|
173
173
|
where: where?.({ modelName, ctx, operation }),
|
|
174
174
|
orderBy: orderBy?.({ modelName, ctx, operation }),
|
|
175
|
-
input: (0, operations_js_1.isOperation)(
|
|
175
|
+
input: (0, operations_js_1.isOperation)("mutation", operation)
|
|
176
176
|
? inputData?.({ modelName, ctx, operation })
|
|
177
177
|
: undefined,
|
|
178
178
|
};
|
|
@@ -347,7 +347,7 @@ class PothosDrizzleGenerator extends core_1.BasePlugin {
|
|
|
347
347
|
return client
|
|
348
348
|
.insert(table)
|
|
349
349
|
.values(combinedInputs)
|
|
350
|
-
.then((v) => Array(v.rowCount
|
|
350
|
+
.then((v) => Array(v.rowCount).fill({}));
|
|
351
351
|
}
|
|
352
352
|
return client.transaction(async (tx) => tx
|
|
353
353
|
.insert(table)
|
|
@@ -400,7 +400,7 @@ class PothosDrizzleGenerator extends core_1.BasePlugin {
|
|
|
400
400
|
.update(table)
|
|
401
401
|
.set(combinedInput)
|
|
402
402
|
.where(whereQuery)
|
|
403
|
-
.then((v) => Array(v.rowCount
|
|
403
|
+
.then((v) => Array(v.rowCount).fill({}));
|
|
404
404
|
}
|
|
405
405
|
return client.transaction(async (tx) => tx
|
|
406
406
|
.update(table)
|
|
@@ -492,7 +492,7 @@ class PothosDrizzleGenerator extends core_1.BasePlugin {
|
|
|
492
492
|
.getClient(ctx)
|
|
493
493
|
.delete(table)
|
|
494
494
|
.where(whereQuery)
|
|
495
|
-
.then((v) => Array(v.rowCount
|
|
495
|
+
.then((v) => Array(v.rowCount).fill({}));
|
|
496
496
|
},
|
|
497
497
|
}),
|
|
498
498
|
}),
|