@kood/claude-code 0.1.6 → 0.1.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/dist/index.js +109 -216
- package/package.json +8 -2
- package/templates/hono/CLAUDE.md +59 -328
- package/templates/hono/docs/architecture/architecture.md +93 -747
- package/templates/hono/docs/deployment/cloudflare.md +59 -513
- package/templates/hono/docs/deployment/docker.md +41 -356
- package/templates/hono/docs/deployment/index.md +54 -190
- package/templates/hono/docs/deployment/railway.md +36 -306
- package/templates/hono/docs/deployment/vercel.md +49 -434
- package/templates/hono/docs/library/ai-sdk/index.md +53 -290
- package/templates/hono/docs/library/ai-sdk/openrouter.md +19 -387
- package/templates/hono/docs/library/ai-sdk/providers.md +28 -394
- package/templates/hono/docs/library/ai-sdk/streaming.md +52 -353
- package/templates/hono/docs/library/ai-sdk/structured-output.md +63 -395
- package/templates/hono/docs/library/ai-sdk/tools.md +62 -431
- package/templates/hono/docs/library/hono/env-setup.md +24 -313
- package/templates/hono/docs/library/hono/error-handling.md +34 -295
- package/templates/hono/docs/library/hono/index.md +29 -121
- package/templates/hono/docs/library/hono/middleware.md +21 -188
- package/templates/hono/docs/library/hono/rpc.md +40 -341
- package/templates/hono/docs/library/hono/validation.md +35 -195
- package/templates/hono/docs/library/pino/index.md +42 -333
- package/templates/hono/docs/library/prisma/cloudflare-d1.md +64 -367
- package/templates/hono/docs/library/prisma/config.md +19 -260
- package/templates/hono/docs/library/prisma/index.md +67 -320
- package/templates/hono/docs/library/zod/index.md +53 -257
- package/templates/npx/CLAUDE.md +62 -274
- package/templates/npx/docs/references/patterns.md +160 -0
- package/templates/tanstack-start/CLAUDE.md +100 -256
- package/templates/tanstack-start/docs/architecture/architecture.md +44 -589
- package/templates/tanstack-start/docs/deployment/cloudflare.md +37 -424
- package/templates/tanstack-start/docs/deployment/index.md +57 -286
- package/templates/tanstack-start/docs/deployment/nitro.md +36 -318
- package/templates/tanstack-start/docs/deployment/railway.md +40 -409
- package/templates/tanstack-start/docs/deployment/vercel.md +43 -465
- package/templates/tanstack-start/docs/design/components.md +77 -311
- package/templates/tanstack-start/docs/design/index.md +113 -69
- package/templates/tanstack-start/docs/design/safe-area.md +51 -250
- package/templates/tanstack-start/docs/design/tailwind-setup.md +45 -359
- package/templates/tanstack-start/docs/guides/conventions.md +103 -0
- package/templates/tanstack-start/docs/guides/env-setup.md +34 -340
- package/templates/tanstack-start/docs/guides/getting-started.md +22 -209
- package/templates/tanstack-start/docs/guides/hooks.md +166 -0
- package/templates/tanstack-start/docs/guides/routes.md +166 -0
- package/templates/tanstack-start/docs/guides/services.md +143 -0
- package/templates/tanstack-start/docs/library/better-auth/2fa.md +27 -115
- package/templates/tanstack-start/docs/library/better-auth/advanced.md +22 -105
- package/templates/tanstack-start/docs/library/better-auth/index.md +17 -66
- package/templates/tanstack-start/docs/library/better-auth/plugins.md +11 -88
- package/templates/tanstack-start/docs/library/better-auth/session.md +12 -92
- package/templates/tanstack-start/docs/library/better-auth/setup.md +9 -91
- package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +30 -358
- package/templates/tanstack-start/docs/library/prisma/config.md +27 -327
- package/templates/tanstack-start/docs/library/prisma/crud.md +46 -174
- package/templates/tanstack-start/docs/library/prisma/index.md +23 -113
- package/templates/tanstack-start/docs/library/prisma/relations.md +31 -153
- package/templates/tanstack-start/docs/library/prisma/schema.md +40 -217
- package/templates/tanstack-start/docs/library/prisma/setup.md +12 -112
- package/templates/tanstack-start/docs/library/prisma/transactions.md +20 -110
- package/templates/tanstack-start/docs/library/tanstack-query/index.md +26 -97
- package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +28 -107
- package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +44 -146
- package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +33 -127
- package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +49 -149
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +19 -112
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +33 -80
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +28 -106
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +21 -118
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +34 -246
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +6 -39
- package/templates/tanstack-start/docs/library/zod/complex-types.md +32 -156
- package/templates/tanstack-start/docs/library/zod/index.md +31 -144
- package/templates/tanstack-start/docs/library/zod/transforms.md +20 -129
- package/templates/tanstack-start/docs/library/zod/validation.md +39 -155
- package/templates/hono/docs/commands/git.md +0 -145
- package/templates/hono/docs/mcp/context7.md +0 -106
- package/templates/hono/docs/mcp/index.md +0 -176
- package/templates/hono/docs/mcp/sequential-thinking.md +0 -101
- package/templates/hono/docs/mcp/serena.md +0 -269
- package/templates/hono/docs/mcp/sgrep.md +0 -105
- package/templates/hono/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/hono/docs/skills/gemini-review/references/checklists.md +0 -136
- package/templates/hono/docs/skills/gemini-review/references/prompt-templates.md +0 -303
- package/templates/npx/docs/commands/git.md +0 -145
- package/templates/npx/docs/mcp/index.md +0 -60
- package/templates/npx/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/npx/docs/skills/gemini-review/references/checklists.md +0 -134
- package/templates/npx/docs/skills/gemini-review/references/prompt-templates.md +0 -301
- package/templates/tanstack-start/docs/commands/git.md +0 -145
- package/templates/tanstack-start/docs/design/accessibility.md +0 -433
- package/templates/tanstack-start/docs/design/color.md +0 -235
- package/templates/tanstack-start/docs/design/spacing.md +0 -341
- package/templates/tanstack-start/docs/design/typography.md +0 -324
- package/templates/tanstack-start/docs/guides/best-practices.md +0 -950
- package/templates/tanstack-start/docs/guides/husky-lint-staged.md +0 -303
- package/templates/tanstack-start/docs/guides/prettier.md +0 -189
- package/templates/tanstack-start/docs/guides/project-templates.md +0 -710
- package/templates/tanstack-start/docs/library/tanstack-query/setup.md +0 -107
- package/templates/tanstack-start/docs/library/zod/basic-types.md +0 -186
- package/templates/tanstack-start/docs/mcp/context7.md +0 -204
- package/templates/tanstack-start/docs/mcp/index.md +0 -177
- package/templates/tanstack-start/docs/mcp/sequential-thinking.md +0 -180
- package/templates/tanstack-start/docs/mcp/serena.md +0 -269
- package/templates/tanstack-start/docs/mcp/sgrep.md +0 -174
- package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +0 -144
- package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +0 -292
|
@@ -2,29 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
> Type-safe 데이터베이스 ORM
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
@config.md
|
|
6
|
+
@cloudflare-d1.md
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
---
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
## 버전 주의
|
|
10
11
|
|
|
11
12
|
```prisma
|
|
12
13
|
generator client {
|
|
13
|
-
provider = "prisma-client"
|
|
14
|
-
output = "./generated/client"
|
|
14
|
+
provider = "prisma-client" // ✅ v7 (prisma-client-js 아님!)
|
|
15
|
+
output = "./generated/client" // ✅ output 필수
|
|
15
16
|
}
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
---
|
|
19
20
|
|
|
20
|
-
##
|
|
21
|
+
## 금지 사항
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
| 명령 | 설명 |
|
|
24
|
+
|------|------|
|
|
25
|
+
| `prisma db push` | 자동 실행 금지 |
|
|
26
|
+
| `prisma migrate` | 자동 실행 금지 |
|
|
27
|
+
| `prisma generate` | 자동 실행 금지 |
|
|
28
|
+
| schema 변경 | 요청된 것만 |
|
|
28
29
|
|
|
29
30
|
---
|
|
30
31
|
|
|
@@ -37,108 +38,40 @@ npm install -D prisma
|
|
|
37
38
|
|
|
38
39
|
---
|
|
39
40
|
|
|
40
|
-
##
|
|
41
|
-
|
|
42
|
-
### ⚠️ 필수: Multi-File 구조 사용
|
|
43
|
-
|
|
44
|
-
Prisma 스키마는 **반드시 Multi-File 구조**로 작성합니다.
|
|
41
|
+
## Multi-File 구조 (필수)
|
|
45
42
|
|
|
46
43
|
```
|
|
47
|
-
prisma/
|
|
48
|
-
├──
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
│ ├── post.prisma # Post 모델
|
|
53
|
-
│ └── ... # 기타 모델별 파일
|
|
44
|
+
prisma/schema/
|
|
45
|
+
├── +base.prisma # datasource, generator
|
|
46
|
+
├── +enum.prisma # enum 정의
|
|
47
|
+
├── user.prisma # User 모델 (한글 주석 필수)
|
|
48
|
+
└── post.prisma # Post 모델
|
|
54
49
|
```
|
|
55
50
|
|
|
56
|
-
###
|
|
57
|
-
|
|
58
|
-
**Prisma Multi-File의 모든 요소에 한글 주석을 작성해야 합니다.**
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
✅ 파일별 목적 주석
|
|
62
|
-
✅ 모델별 설명 주석
|
|
63
|
-
✅ 필드별 설명 주석 (용도가 명확하지 않은 경우)
|
|
64
|
-
✅ 관계 설명 주석
|
|
65
|
-
✅ enum 값 설명 주석
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### Multi-File 스키마 예시
|
|
69
|
-
|
|
70
|
-
#### +base.prisma (기본 설정)
|
|
51
|
+
### +base.prisma
|
|
71
52
|
|
|
72
53
|
```prisma
|
|
73
|
-
//
|
|
74
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
75
|
-
// Prisma 기본 설정 파일
|
|
76
|
-
// datasource 및 generator 설정
|
|
77
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
78
|
-
|
|
79
|
-
// 데이터베이스 연결 설정
|
|
54
|
+
// datasource, generator 설정
|
|
80
55
|
datasource db {
|
|
81
56
|
provider = "postgresql"
|
|
82
57
|
url = env("DATABASE_URL")
|
|
83
58
|
}
|
|
84
59
|
|
|
85
|
-
// Prisma Client 생성 설정
|
|
86
60
|
generator client {
|
|
87
|
-
provider = "prisma-client"
|
|
61
|
+
provider = "prisma-client"
|
|
88
62
|
output = "./generated/client"
|
|
89
63
|
}
|
|
90
64
|
```
|
|
91
65
|
|
|
92
|
-
|
|
66
|
+
### user.prisma
|
|
93
67
|
|
|
94
68
|
```prisma
|
|
95
|
-
// prisma/schema/+enum.prisma
|
|
96
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
97
|
-
// 모든 열거형(enum) 정의 파일
|
|
98
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
99
|
-
|
|
100
|
-
// 사용자 권한 열거형
|
|
101
|
-
enum Role {
|
|
102
|
-
USER // 일반 사용자
|
|
103
|
-
ADMIN // 관리자
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
#### user.prisma (User 모델)
|
|
108
|
-
|
|
109
|
-
```prisma
|
|
110
|
-
// prisma/schema/user.prisma
|
|
111
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
112
69
|
// 사용자 모델
|
|
113
|
-
// 시스템의 모든 사용자 정보를 저장
|
|
114
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
115
|
-
|
|
116
70
|
model User {
|
|
117
71
|
id String @id @default(cuid())
|
|
118
|
-
email String @unique // 로그인 이메일
|
|
119
|
-
name String? // 표시 이름
|
|
120
|
-
posts Post[] //
|
|
121
|
-
createdAt DateTime @default(now())
|
|
122
|
-
updatedAt DateTime @updatedAt
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
#### post.prisma (Post 모델)
|
|
127
|
-
|
|
128
|
-
```prisma
|
|
129
|
-
// prisma/schema/post.prisma
|
|
130
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
131
|
-
// 게시글 모델
|
|
132
|
-
// 사용자가 작성한 게시글 정보
|
|
133
|
-
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
134
|
-
|
|
135
|
-
model Post {
|
|
136
|
-
id String @id @default(cuid())
|
|
137
|
-
title String // 게시글 제목
|
|
138
|
-
content String? // 게시글 본문 (선택)
|
|
139
|
-
published Boolean @default(false) // 공개 여부
|
|
140
|
-
author User @relation(fields: [authorId], references: [id]) // 작성자 관계
|
|
141
|
-
authorId String // 작성자 ID (외래키)
|
|
72
|
+
email String @unique // 로그인 이메일
|
|
73
|
+
name String? // 표시 이름
|
|
74
|
+
posts Post[] // 작성 게시글
|
|
142
75
|
createdAt DateTime @default(now())
|
|
143
76
|
updatedAt DateTime @updatedAt
|
|
144
77
|
}
|
|
@@ -146,14 +79,11 @@ model Post {
|
|
|
146
79
|
|
|
147
80
|
---
|
|
148
81
|
|
|
149
|
-
## Prisma Client
|
|
150
|
-
|
|
151
|
-
### database/prisma.ts
|
|
82
|
+
## Prisma Client
|
|
152
83
|
|
|
153
84
|
```typescript
|
|
154
85
|
import { PrismaClient } from '../prisma/generated/client'
|
|
155
86
|
|
|
156
|
-
// 싱글톤 패턴
|
|
157
87
|
const globalForPrisma = globalThis as unknown as {
|
|
158
88
|
prisma: PrismaClient | undefined
|
|
159
89
|
}
|
|
@@ -171,235 +101,79 @@ if (process.env.NODE_ENV !== 'production') {
|
|
|
171
101
|
|
|
172
102
|
---
|
|
173
103
|
|
|
174
|
-
## CRUD
|
|
104
|
+
## CRUD
|
|
175
105
|
|
|
176
106
|
### Create
|
|
177
107
|
|
|
178
108
|
```typescript
|
|
179
|
-
// 단일 생성
|
|
180
109
|
const user = await prisma.user.create({
|
|
181
|
-
data: {
|
|
182
|
-
email: 'user@example.com',
|
|
183
|
-
name: 'John',
|
|
184
|
-
},
|
|
110
|
+
data: { email: 'user@example.com', name: 'John' },
|
|
185
111
|
})
|
|
186
112
|
|
|
187
|
-
// 관계와 함께
|
|
113
|
+
// 관계와 함께
|
|
188
114
|
const userWithPosts = await prisma.user.create({
|
|
189
115
|
data: {
|
|
190
116
|
email: 'user@example.com',
|
|
191
|
-
|
|
192
|
-
posts: {
|
|
193
|
-
create: [
|
|
194
|
-
{ title: 'Post 1', content: 'Content 1' },
|
|
195
|
-
{ title: 'Post 2', content: 'Content 2' },
|
|
196
|
-
],
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
include: {
|
|
200
|
-
posts: true,
|
|
117
|
+
posts: { create: [{ title: 'Post 1' }] },
|
|
201
118
|
},
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// 다수 생성
|
|
205
|
-
const users = await prisma.user.createMany({
|
|
206
|
-
data: [
|
|
207
|
-
{ email: 'user1@example.com', name: 'User 1' },
|
|
208
|
-
{ email: 'user2@example.com', name: 'User 2' },
|
|
209
|
-
],
|
|
210
|
-
skipDuplicates: true,
|
|
119
|
+
include: { posts: true },
|
|
211
120
|
})
|
|
212
121
|
```
|
|
213
122
|
|
|
214
123
|
### Read
|
|
215
124
|
|
|
216
125
|
```typescript
|
|
217
|
-
|
|
218
|
-
const user = await prisma.user.
|
|
219
|
-
where: { id: 'user-id' },
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
// 필수 조회 (없으면 에러)
|
|
223
|
-
const user = await prisma.user.findUniqueOrThrow({
|
|
224
|
-
where: { id: 'user-id' },
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
// 조건 조회
|
|
228
|
-
const user = await prisma.user.findFirst({
|
|
229
|
-
where: { email: { contains: '@example.com' } },
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
// 다수 조회
|
|
126
|
+
const user = await prisma.user.findUnique({ where: { id } })
|
|
127
|
+
const user = await prisma.user.findUniqueOrThrow({ where: { id } })
|
|
233
128
|
const users = await prisma.user.findMany({
|
|
234
129
|
where: { name: { not: null } },
|
|
235
130
|
orderBy: { createdAt: 'desc' },
|
|
236
131
|
take: 10,
|
|
237
|
-
skip: 0,
|
|
238
132
|
})
|
|
239
133
|
|
|
240
134
|
// 관계 포함
|
|
241
135
|
const userWithPosts = await prisma.user.findUnique({
|
|
242
|
-
where: { id
|
|
243
|
-
include: {
|
|
244
|
-
posts: {
|
|
245
|
-
where: { published: true },
|
|
246
|
-
orderBy: { createdAt: 'desc' },
|
|
247
|
-
},
|
|
248
|
-
},
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
// 특정 필드만 선택
|
|
252
|
-
const userEmail = await prisma.user.findUnique({
|
|
253
|
-
where: { id: 'user-id' },
|
|
254
|
-
select: {
|
|
255
|
-
id: true,
|
|
256
|
-
email: true,
|
|
257
|
-
},
|
|
136
|
+
where: { id },
|
|
137
|
+
include: { posts: { where: { published: true } } },
|
|
258
138
|
})
|
|
259
139
|
```
|
|
260
140
|
|
|
261
141
|
### Update
|
|
262
142
|
|
|
263
143
|
```typescript
|
|
264
|
-
// 단일 수정
|
|
265
144
|
const user = await prisma.user.update({
|
|
266
|
-
where: { id
|
|
145
|
+
where: { id },
|
|
267
146
|
data: { name: 'New Name' },
|
|
268
147
|
})
|
|
269
148
|
|
|
270
|
-
//
|
|
271
|
-
const users = await prisma.user.updateMany({
|
|
272
|
-
where: { name: null },
|
|
273
|
-
data: { name: 'Anonymous' },
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
// 없으면 생성 (Upsert)
|
|
149
|
+
// Upsert
|
|
277
150
|
const user = await prisma.user.upsert({
|
|
278
151
|
where: { email: 'user@example.com' },
|
|
279
|
-
update: { name: 'Updated
|
|
280
|
-
create: { email: 'user@example.com', name: 'New
|
|
152
|
+
update: { name: 'Updated' },
|
|
153
|
+
create: { email: 'user@example.com', name: 'New' },
|
|
281
154
|
})
|
|
282
155
|
```
|
|
283
156
|
|
|
284
157
|
### Delete
|
|
285
158
|
|
|
286
159
|
```typescript
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
where: { id: 'user-id' },
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
// 다수 삭제
|
|
293
|
-
const users = await prisma.user.deleteMany({
|
|
294
|
-
where: { email: { contains: '@test.com' } },
|
|
295
|
-
})
|
|
160
|
+
await prisma.user.delete({ where: { id } })
|
|
161
|
+
await prisma.user.deleteMany({ where: { email: { contains: '@test.com' } } })
|
|
296
162
|
```
|
|
297
163
|
|
|
298
164
|
---
|
|
299
165
|
|
|
300
166
|
## 필터링
|
|
301
167
|
|
|
302
|
-
### 비교 연산자
|
|
303
|
-
|
|
304
168
|
```typescript
|
|
305
169
|
await prisma.user.findMany({
|
|
306
170
|
where: {
|
|
307
|
-
age: { gt: 18 },
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
},
|
|
314
|
-
})
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### 문자열 필터
|
|
318
|
-
|
|
319
|
-
```typescript
|
|
320
|
-
await prisma.user.findMany({
|
|
321
|
-
where: {
|
|
322
|
-
email: { contains: '@gmail.com' },
|
|
323
|
-
email: { startsWith: 'admin' },
|
|
324
|
-
email: { endsWith: '.com' },
|
|
325
|
-
name: { mode: 'insensitive' }, // 대소문자 무시
|
|
326
|
-
},
|
|
327
|
-
})
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### 논리 연산자
|
|
331
|
-
|
|
332
|
-
```typescript
|
|
333
|
-
await prisma.user.findMany({
|
|
334
|
-
where: {
|
|
335
|
-
AND: [
|
|
336
|
-
{ email: { contains: '@' } },
|
|
337
|
-
{ name: { not: null } },
|
|
338
|
-
],
|
|
339
|
-
OR: [
|
|
340
|
-
{ role: 'admin' },
|
|
341
|
-
{ role: 'moderator' },
|
|
342
|
-
],
|
|
343
|
-
NOT: {
|
|
344
|
-
status: 'banned',
|
|
345
|
-
},
|
|
346
|
-
},
|
|
347
|
-
})
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
### 배열 필터
|
|
351
|
-
|
|
352
|
-
```typescript
|
|
353
|
-
await prisma.user.findMany({
|
|
354
|
-
where: {
|
|
355
|
-
id: { in: ['id1', 'id2', 'id3'] },
|
|
356
|
-
role: { notIn: ['banned', 'suspended'] },
|
|
357
|
-
},
|
|
358
|
-
})
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
---
|
|
362
|
-
|
|
363
|
-
## 관계 쿼리
|
|
364
|
-
|
|
365
|
-
### Include (전체 데이터)
|
|
366
|
-
|
|
367
|
-
```typescript
|
|
368
|
-
const user = await prisma.user.findUnique({
|
|
369
|
-
where: { id: 'user-id' },
|
|
370
|
-
include: {
|
|
371
|
-
posts: true,
|
|
372
|
-
profile: true,
|
|
373
|
-
},
|
|
374
|
-
})
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
### Select (특정 필드)
|
|
378
|
-
|
|
379
|
-
```typescript
|
|
380
|
-
const user = await prisma.user.findUnique({
|
|
381
|
-
where: { id: 'user-id' },
|
|
382
|
-
select: {
|
|
383
|
-
id: true,
|
|
384
|
-
email: true,
|
|
385
|
-
posts: {
|
|
386
|
-
select: { id: true, title: true },
|
|
387
|
-
},
|
|
388
|
-
},
|
|
389
|
-
})
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
### 관계 필터링
|
|
393
|
-
|
|
394
|
-
```typescript
|
|
395
|
-
// 관계 조건으로 필터
|
|
396
|
-
const usersWithPublishedPosts = await prisma.user.findMany({
|
|
397
|
-
where: {
|
|
398
|
-
posts: {
|
|
399
|
-
some: { published: true }, // 하나라도 만족
|
|
400
|
-
// every: { published: true }, // 모두 만족
|
|
401
|
-
// none: { published: true }, // 하나도 없음
|
|
402
|
-
},
|
|
171
|
+
age: { gt: 18, lte: 65 }, // 비교
|
|
172
|
+
email: { contains: '@gmail.com' }, // 문자열
|
|
173
|
+
AND: [{ email: { contains: '@' } }, { name: { not: null } }],
|
|
174
|
+
OR: [{ role: 'admin' }, { role: 'moderator' }],
|
|
175
|
+
id: { in: ['id1', 'id2'] }, // 배열
|
|
176
|
+
posts: { some: { published: true } }, // 관계
|
|
403
177
|
},
|
|
404
178
|
})
|
|
405
179
|
```
|
|
@@ -408,33 +182,18 @@ const usersWithPublishedPosts = await prisma.user.findMany({
|
|
|
408
182
|
|
|
409
183
|
## 트랜잭션
|
|
410
184
|
|
|
411
|
-
### Sequential 트랜잭션
|
|
412
|
-
|
|
413
185
|
```typescript
|
|
186
|
+
// Sequential
|
|
414
187
|
const [user, post] = await prisma.$transaction([
|
|
415
188
|
prisma.user.create({ data: { email: 'user@example.com' } }),
|
|
416
189
|
prisma.post.create({ data: { title: 'New Post', authorId: 'user-id' } }),
|
|
417
190
|
])
|
|
418
|
-
```
|
|
419
191
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
```typescript
|
|
192
|
+
// Interactive
|
|
423
193
|
const result = await prisma.$transaction(async (tx) => {
|
|
424
|
-
const user = await tx.user.findUnique({ where: { id
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
throw new Error('User not found')
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const post = await tx.post.create({
|
|
431
|
-
data: {
|
|
432
|
-
title: 'New Post',
|
|
433
|
-
authorId: user.id,
|
|
434
|
-
},
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
return { user, post }
|
|
194
|
+
const user = await tx.user.findUnique({ where: { id } })
|
|
195
|
+
if (!user) throw new Error('User not found')
|
|
196
|
+
return tx.post.create({ data: { title: 'Post', authorId: user.id } })
|
|
438
197
|
})
|
|
439
198
|
```
|
|
440
199
|
|
|
@@ -451,31 +210,24 @@ import { prisma } from '@/database/prisma'
|
|
|
451
210
|
|
|
452
211
|
const app = new Hono()
|
|
453
212
|
|
|
454
|
-
|
|
455
|
-
email: z.email(),
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
app.post('/users', zValidator('json', createUserSchema), async (c) => {
|
|
460
|
-
const data = c.req.valid('json')
|
|
213
|
+
app.post('/users',
|
|
214
|
+
zValidator('json', z.object({ email: z.email(), name: z.string().optional() })),
|
|
215
|
+
async (c) => {
|
|
216
|
+
const data = c.req.valid('json')
|
|
461
217
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
218
|
+
const existing = await prisma.user.findUnique({ where: { email: data.email } })
|
|
219
|
+
if (existing) {
|
|
220
|
+
throw new HTTPException(409, { message: 'Email already exists' })
|
|
221
|
+
}
|
|
466
222
|
|
|
467
|
-
|
|
468
|
-
|
|
223
|
+
const user = await prisma.user.create({ data })
|
|
224
|
+
return c.json({ user }, 201)
|
|
469
225
|
}
|
|
470
|
-
|
|
471
|
-
const user = await prisma.user.create({ data })
|
|
472
|
-
return c.json({ user }, 201)
|
|
473
|
-
})
|
|
226
|
+
)
|
|
474
227
|
|
|
475
228
|
app.get('/users/:id', async (c) => {
|
|
476
|
-
const id = c.req.param('id')
|
|
477
229
|
const user = await prisma.user.findUnique({
|
|
478
|
-
where: { id },
|
|
230
|
+
where: { id: c.req.param('id') },
|
|
479
231
|
include: { posts: true },
|
|
480
232
|
})
|
|
481
233
|
|
|
@@ -485,16 +237,11 @@ app.get('/users/:id', async (c) => {
|
|
|
485
237
|
|
|
486
238
|
return c.json({ user })
|
|
487
239
|
})
|
|
488
|
-
|
|
489
|
-
export default app
|
|
490
240
|
```
|
|
491
241
|
|
|
492
242
|
---
|
|
493
243
|
|
|
494
244
|
## 관련 문서
|
|
495
245
|
|
|
496
|
-
- [Config 파일](./config.md) - prisma.config.ts 설정
|
|
497
|
-
- [
|
|
498
|
-
- [Relations](./relations.md)
|
|
499
|
-
- [Transactions](./transactions.md)
|
|
500
|
-
- [Cloudflare D1](./cloudflare-d1.md) - D1 서버리스 데이터베이스 연동
|
|
246
|
+
- [Config 파일](./config.md) - prisma.config.ts 설정
|
|
247
|
+
- [Cloudflare D1](./cloudflare-d1.md)
|