Skip to content

Commit 31f0dba

Browse files
authored
Merge pull request #69 from constructive-io/devin/1774125055-orm-relations-composite-keys-docs
docs: M:N ORM methods, composite PKs, expose_in_api, filter type-safety
2 parents ac1b7fc + a0b43de commit 31f0dba

4 files changed

Lines changed: 315 additions & 27 deletions

File tree

.agents/skills/constructive-graphql/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ See [search.md](./references/search.md) for the decision matrix and combined que
167167
| [codegen-hooks-patterns.md](./references/codegen-hooks-patterns.md) | React Query hook patterns | Using generated hooks in React components |
168168
| [codegen-hooks-output.md](./references/codegen-hooks-output.md) | Hooks generated output structure | Understanding hook file structure |
169169
| [codegen-error-handling.md](./references/codegen-error-handling.md) | Error handling patterns | `.unwrap()`, `.unwrapOr()`, discriminated unions |
170-
| [codegen-relations.md](./references/codegen-relations.md) | Relation queries | Nested selects, belongsTo, hasMany, manyToMany |
170+
| [codegen-relations.md](./references/codegen-relations.md) | Relation queries and M:N mutations | Nested selects, belongsTo, hasMany, manyToMany, composite PKs, `expose_in_api`, add/remove methods |
171171
| [codegen-query-keys.md](./references/codegen-query-keys.md) | Query key factory | Cache invalidation, `invalidate.*`, `remove.*` |
172172
| [codegen-node-http-adapter.md](./references/codegen-node-http-adapter.md) | Node.js HTTP adapter | Subdomain routing in Node.js |
173173

.agents/skills/constructive-graphql/references/codegen-orm-output.md

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ Reference for Prisma-like ORM client generated by `@constructive-io/graphql-code
66

77
```
88
generated/orm/
9-
├── index.ts # Main export (createClient, types)
10-
├── client.ts # createClient() function
11-
├── types.ts # All TypeScript types
12-
└── models/ # Entity model implementations
13-
├── user.ts
14-
├── post.ts
15-
└── ...
9+
|- index.ts # Main export (createClient, types)
10+
|- client.ts # createClient() function
11+
|- types.ts # All TypeScript types
12+
'- models/ # Entity model implementations
13+
|- user.ts
14+
|- post.ts
15+
|- postTag.ts # Junction table model (M:N)
16+
'- ...
1617
```
1718

1819
## Generated Files
@@ -75,6 +76,39 @@ db.user.update(options) // Update existing
7576
db.user.delete(options) // Delete
7677
```
7778

79+
### M:N Convenience Methods
80+
81+
When `_meta` enrichment provides M:N relation metadata, entity models also get:
82+
83+
```typescript
84+
// Generated on entities with M:N relations
85+
db.post.addTag(postId, tagId) // Creates junction row
86+
db.post.removeTag(postId, tagId) // Deletes junction row by composite PK
87+
db.tag.addPost(tagId, postId) // Reverse direction
88+
db.tag.removePost(tagId, postId)
89+
```
90+
91+
Method signatures use actual PK types from the junction table:
92+
93+
```typescript
94+
// UUID PKs -> string parameters
95+
addTag(postId: string, tagId: string): QueryBuilder<...>
96+
97+
// Integer PKs -> number parameters
98+
addStudent(courseId: number, studentId: number): QueryBuilder<...>
99+
```
100+
101+
### Junction Table Models
102+
103+
Junction tables get full CRUD models with composite PK support:
104+
105+
```typescript
106+
// Standard CRUD on junction table
107+
db.postTag.create({ data: { postId, tagId } })
108+
db.postTag.findMany({ where: { postId: { equalTo: id } } })
109+
db.postTag.delete({ where: { postId, tagId } }) // Composite PK delete
110+
```
111+
78112
## Query Methods
79113

80114
### findMany
@@ -170,9 +204,15 @@ const result = await db.user.update({
170204
Delete item:
171205

172206
```typescript
207+
// Single PK
173208
const result = await db.user.delete({
174209
id: '123',
175210
}).execute();
211+
212+
// Composite PK (junction table)
213+
const result = await db.postTag.delete({
214+
where: { postId: POST_1, tagId: TAG_TECH },
215+
}).execute();
176216
```
177217

178218
## Select and Type Inference
@@ -233,6 +273,7 @@ const users = await db.user.findMany({
233273
### ManyToMany
234274

235275
```typescript
276+
// Query through M:N shortcut (when expose_in_api = true)
236277
const posts = await db.post.findMany({
237278
select: {
238279
id: true,
@@ -241,6 +282,14 @@ const posts = await db.post.findMany({
241282
},
242283
},
243284
}).execute();
285+
286+
// Mutate via convenience methods
287+
await db.post.addTag(postId, tagId).execute();
288+
await db.post.removeTag(postId, tagId).execute();
289+
290+
// Or via junction table directly
291+
await db.postTag.create({ data: { postId, tagId } }).execute();
292+
await db.postTag.delete({ where: { postId, tagId } }).execute();
244293
```
245294

246295
### Deeply Nested

0 commit comments

Comments
 (0)