@idealyst/cli 1.0.45 → 1.0.48

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.
Files changed (121) hide show
  1. package/dist/generators/fullstack.js +61 -3
  2. package/dist/generators/fullstack.js.map +1 -1
  3. package/dist/generators/native.js +12 -0
  4. package/dist/generators/native.js.map +1 -1
  5. package/dist/generators/utils.js +64 -31
  6. package/dist/generators/utils.js.map +1 -1
  7. package/dist/templates/api/README.md +207 -130
  8. package/dist/templates/api/package.json +5 -5
  9. package/dist/templates/api/src/controllers/TestController.ts +0 -0
  10. package/dist/templates/api/src/index.ts +2 -7
  11. package/dist/templates/api/src/lib/crud.ts +150 -0
  12. package/dist/templates/api/src/lib/database.ts +23 -0
  13. package/dist/templates/api/src/router/index.ts +104 -71
  14. package/dist/templates/api/src/routers/test.ts +59 -0
  15. package/dist/templates/api/src/routers/user.example.ts +83 -0
  16. package/dist/templates/api/src/server.ts +1 -1
  17. package/dist/templates/api/tsconfig.json +0 -1
  18. package/dist/templates/database/README.md +115 -1
  19. package/dist/templates/database/package.json +2 -0
  20. package/dist/templates/database/prisma/seed.ts +37 -1
  21. package/dist/templates/database/schema.prisma +11 -1
  22. package/dist/templates/native/index.js +1 -1
  23. package/dist/templates/native/metro.config.js +1 -1
  24. package/dist/templates/native/package.json +4 -0
  25. package/dist/templates/native/src/App.tsx +16 -0
  26. package/dist/templates/native/src/utils/trpc.ts +7 -127
  27. package/dist/templates/native/tsconfig.json +0 -2
  28. package/dist/templates/shared/README.md +31 -5
  29. package/dist/templates/shared/__tests__/shared.test.ts +17 -5
  30. package/dist/templates/shared/package.json +14 -30
  31. package/dist/templates/shared/src/components/App.tsx +57 -0
  32. package/dist/templates/shared/src/components/HelloWorld.tsx +307 -0
  33. package/dist/templates/shared/src/components/index.ts +1 -392
  34. package/dist/templates/shared/src/index.ts +9 -57
  35. package/dist/templates/shared/src/trpc/client.ts +39 -0
  36. package/dist/templates/shared/tsconfig.json +4 -7
  37. package/dist/templates/web/README.md +65 -8
  38. package/dist/templates/web/package.json +3 -3
  39. package/dist/templates/web/src/App-with-trpc-and-shared.tsx +11 -299
  40. package/dist/templates/web/src/components/TestDemo.tsx +164 -0
  41. package/dist/templates/web/src/utils/trpc.ts +7 -93
  42. package/dist/templates/web/tsconfig.json +0 -1
  43. package/dist/templates/workspace/.devcontainer/devcontainer.json +4 -9
  44. package/dist/templates/workspace/.devcontainer/docker-compose.yml +1 -2
  45. package/dist/templates/workspace/.devcontainer/setup.sh +1 -1
  46. package/dist/templates/workspace/.env.example +1 -1
  47. package/dist/templates/workspace/Dockerfile +4 -4
  48. package/dist/templates/workspace/docker/nginx/prod.conf +2 -2
  49. package/dist/templates/workspace/docker/nginx.conf +1 -1
  50. package/dist/templates/workspace/docker/prometheus/prometheus.yml +1 -1
  51. package/dist/templates/workspace/docker-compose.yml +4 -5
  52. package/dist/templates/workspace/tsconfig.json +0 -1
  53. package/package.json +1 -1
  54. package/templates/api/README.md +207 -130
  55. package/templates/api/package.json +5 -5
  56. package/templates/api/src/controllers/TestController.ts +0 -0
  57. package/templates/api/src/index.ts +2 -7
  58. package/templates/api/src/lib/crud.ts +150 -0
  59. package/templates/api/src/lib/database.ts +23 -0
  60. package/templates/api/src/router/index.ts +104 -71
  61. package/templates/api/src/routers/test.ts +59 -0
  62. package/templates/api/src/routers/user.example.ts +83 -0
  63. package/templates/api/src/server.ts +1 -1
  64. package/templates/api/tsconfig.json +0 -1
  65. package/templates/database/README.md +115 -1
  66. package/templates/database/package.json +2 -0
  67. package/templates/database/prisma/seed.ts +37 -1
  68. package/templates/database/schema.prisma +11 -1
  69. package/templates/native/index.js +1 -1
  70. package/templates/native/metro.config.js +1 -1
  71. package/templates/native/package.json +4 -0
  72. package/templates/native/src/App.tsx +16 -0
  73. package/templates/native/src/utils/trpc.ts +7 -127
  74. package/templates/native/tsconfig.json +0 -2
  75. package/templates/shared/README.md +31 -5
  76. package/templates/shared/__tests__/shared.test.ts +17 -5
  77. package/templates/shared/package.json +14 -30
  78. package/templates/shared/src/components/App.tsx +57 -0
  79. package/templates/shared/src/components/HelloWorld.tsx +307 -0
  80. package/templates/shared/src/components/index.ts +1 -392
  81. package/templates/shared/src/index.ts +9 -57
  82. package/templates/shared/src/trpc/client.ts +39 -0
  83. package/templates/shared/tsconfig.json +4 -7
  84. package/templates/web/README.md +65 -8
  85. package/templates/web/package.json +3 -3
  86. package/templates/web/src/App-with-trpc-and-shared.tsx +11 -299
  87. package/templates/web/src/components/TestDemo.tsx +164 -0
  88. package/templates/web/src/utils/trpc.ts +7 -93
  89. package/templates/web/tsconfig.json +0 -1
  90. package/templates/workspace/.devcontainer/devcontainer.json +4 -9
  91. package/templates/workspace/.devcontainer/docker-compose.yml +1 -2
  92. package/templates/workspace/.devcontainer/setup.sh +1 -1
  93. package/templates/workspace/.env.example +1 -1
  94. package/templates/workspace/Dockerfile +4 -4
  95. package/templates/workspace/docker/nginx/prod.conf +2 -2
  96. package/templates/workspace/docker/nginx.conf +1 -1
  97. package/templates/workspace/docker/prometheus/prometheus.yml +1 -1
  98. package/templates/workspace/docker-compose.yml +4 -5
  99. package/templates/workspace/tsconfig.json +0 -1
  100. package/dist/templates/api/src/controllers/UserController.ts +0 -102
  101. package/dist/templates/api/src/lib/controller.ts +0 -90
  102. package/dist/templates/api/src/lib/middleware.ts +0 -170
  103. package/dist/templates/api/src/middleware/auth.ts +0 -75
  104. package/dist/templates/api/src/middleware/common.ts +0 -103
  105. package/dist/templates/database/.env.example +0 -1
  106. package/dist/templates/native/App.tsx +0 -23
  107. package/dist/templates/native/src/App-with-trpc-and-shared.tsx +0 -266
  108. package/dist/templates/shared/rollup.config.js +0 -43
  109. package/dist/templates/shared/src/types/index.ts +0 -148
  110. package/dist/templates/shared/src/utils/index.ts +0 -278
  111. package/templates/api/src/controllers/UserController.ts +0 -102
  112. package/templates/api/src/lib/controller.ts +0 -90
  113. package/templates/api/src/lib/middleware.ts +0 -170
  114. package/templates/api/src/middleware/auth.ts +0 -75
  115. package/templates/api/src/middleware/common.ts +0 -103
  116. package/templates/database/.env.example +0 -1
  117. package/templates/native/App.tsx +0 -23
  118. package/templates/native/src/App-with-trpc-and-shared.tsx +0 -266
  119. package/templates/shared/rollup.config.js +0 -43
  120. package/templates/shared/src/types/index.ts +0 -148
  121. package/templates/shared/src/utils/index.ts +0 -278
@@ -1,12 +1,34 @@
1
- # {{projectName}}
1
+ # {{projectName}} API
2
2
 
3
3
  {{description}}
4
4
 
5
+ A simplified tRPC API with automatic CRUD generation for Prisma models.
6
+
5
7
  This API project is built with:
6
- - **tRPC** - End-to-end typesafe APIs
7
- - **Zod** - TypeScript-first schema validation
8
+ - **tRPC** - End-to-end```typescript
9
+ import { z } from 'zod';
10
+ import { router, publicProcedure } from '../trpc.js';
11
+ import { createCrudRouter } from '../lib/crud.js';
12
+ import { prisma } from '../lib/database.js';
13
+
14
+ const baseCrudRouter = createCrudRouter('user', createUserSchema);
15
+
16
+ export const userRouter = router({
17
+ ...baseCrudRouter,
18
+
19
+ // Add custom procedures
20
+ getByEmail: publicProcedure
21
+ .input(z.object({ email: z.string().email() }))
22
+ .query(async ({ input }) => {
23
+ return await prisma.user.findUnique({
24
+ where: { email: input.email }
25
+ });
26
+ }),
27
+ });
28
+ ```Zod** - TypeScript-first schema validation
8
29
  - **Express.js** - Web framework for Node.js
9
30
  - **TypeScript** - Type-safe JavaScript
31
+ - **Prisma** - Next-generation ORM for database access
10
32
 
11
33
  ## Quick Start
12
34
 
@@ -20,178 +42,233 @@ This API project is built with:
20
42
  yarn install
21
43
  ```
22
44
 
23
- 3. **Start development server:**
45
+ 3. **Setup database:**
46
+ ```bash
47
+ # Generate Prisma client
48
+ yarn prisma:generate
49
+
50
+ # Run migrations
51
+ yarn prisma:migrate
52
+
53
+ # Seed database with sample data
54
+ yarn prisma:seed
55
+ ```
56
+
57
+ 4. **Start development server:**
24
58
  ```bash
25
59
  yarn dev
26
60
  ```
27
61
 
28
62
  The API will be available at `http://localhost:3000`
29
63
 
30
- ## Available Scripts
64
+ ## Creating CRUD APIs
31
65
 
32
- - `yarn dev` - Start development server with hot reload
33
- - `yarn build` - Build for production
34
- - `yarn start` - Start production server
35
- - `yarn lint` - Run ESLint
36
- - `yarn type-check` - Run TypeScript type checking
66
+ This template provides a simple way to create type-safe APIs with automatic CRUD operations for your Prisma models.
37
67
 
38
- ## API Endpoints
68
+ ### 1. Define Your Prisma Model
39
69
 
40
- ### tRPC Routes
70
+ Add models to `packages/database/schema.prisma`:
41
71
 
42
- All tRPC routes are available at `/trpc/[procedure]`
72
+ ```prisma
73
+ model User {
74
+ id String @id @default(cuid())
75
+ email String @unique
76
+ name String
77
+ createdAt DateTime @default(now())
78
+ updatedAt DateTime @updatedAt
79
+ }
80
+ ```
43
81
 
44
- #### Example Routes
45
- - `hello` - Simple greeting endpoint (accepts optional name parameter)
46
- - `health` - API health check with timestamp
82
+ ### 2. Create a Router
47
83
 
48
- ### REST Endpoints
49
- - `GET /` - API information
50
- - `GET /health` - Health check
84
+ Create `src/routers/user.ts`:
51
85
 
52
- ## Connecting to a Database
86
+ ```typescript
87
+ import { z } from 'zod';
88
+ import { createCrudRouter } from '../lib/crud.js';
53
89
 
54
- For database functionality, create a separate database package using:
55
- ```bash
56
- idealyst create my-database --type database
57
- ```
90
+ const createUserSchema = z.object({
91
+ email: z.string().email(),
92
+ name: z.string().min(1),
93
+ });
58
94
 
59
- Then import and use it in your API:
60
- ```typescript
61
- // In your API context or controllers
62
- import { db } from '@your-org/my-database';
95
+ const updateUserSchema = z.object({
96
+ email: z.string().email().optional(),
97
+ name: z.string().min(1).optional(),
98
+ });
63
99
 
64
- // Use the database client
65
- const users = await db.user.findMany();
100
+ export const userRouter = createCrudRouter(
101
+ 'user',
102
+ createUserSchema,
103
+ updateUserSchema
104
+ );
66
105
  ```
67
106
 
68
- ## Development
107
+ ### 3. Add to Main Router
69
108
 
70
- ### Adding New Routes
109
+ Update `src/router/index.ts`:
71
110
 
72
- You can add routes in two ways:
111
+ ```typescript
112
+ import { userRouter } from '../routers/user.js';
73
113
 
74
- #### 1. Simple tRPC Procedures (Traditional)
75
- 1. Create a new router file in `src/router/`
76
- 2. Define your procedures with Zod schemas for validation
77
- 3. Export the router and add it to `src/router/index.ts`
114
+ export const appRouter = router({
115
+ // ... existing routes
116
+ users: userRouter,
117
+ });
118
+ ```
78
119
 
79
- #### 2. Controller & Middleware System (Recommended)
80
- This template includes a powerful controller and middleware system:
120
+ ### 4. Use in Frontend
81
121
 
82
- 1. **Create a Controller:**
83
122
  ```typescript
84
- // src/controllers/PostController.ts
85
- import { z } from 'zod';
86
- import { BaseController, controllerToRouter } from '../lib/controller.js';
87
- import { requireAuth, requireAdmin } from '../middleware/auth.js';
88
- import { logger, rateLimit } from '../middleware/common.js';
89
-
90
- const createPostSchema = z.object({
91
- title: z.string().min(1),
92
- content: z.string(),
123
+ // Get all users
124
+ const { data: users } = trpc.users.getAll.useQuery();
125
+
126
+ // Create user
127
+ const createUser = trpc.users.create.useMutation();
128
+ await createUser.mutateAsync({
129
+ email: 'user@example.com',
130
+ name: 'John Doe'
93
131
  });
94
132
 
95
- export class PostController extends BaseController {
96
- // Public endpoint
97
- getAll = this.createQuery(
98
- z.object({ published: z.boolean().optional() }),
99
- async (input, ctx) => {
100
- // Mock data - replace with your database calls
101
- return [
102
- { id: '1', title: 'Post 1', content: 'Content 1', published: true },
103
- { id: '2', title: 'Post 2', content: 'Content 2', published: false },
104
- ];
105
- }
106
- );
107
-
108
- // Protected endpoint with middleware
109
- create = this.createMutationWithMiddleware(
110
- createPostSchema,
111
- [logger, rateLimit(5, 60000), requireAuth],
112
- async (input, ctx) => {
113
- // Mock creation - replace with your database calls
114
- return { id: '3', ...input, published: false };
115
- }
116
- );
117
-
118
- // Admin-only endpoint
119
- delete = this.createMutationWithMiddleware(
120
- z.object({ id: z.string() }),
121
- [requireAuth, requireAdmin],
122
- async (input, ctx) => {
123
- // Mock deletion - replace with your database calls
124
- return { success: true, deletedId: input.id };
125
- }
126
- );
127
- }
128
-
129
- export const postRouter = controllerToRouter({
130
- getAll: new PostController({} as any).getAll,
131
- create: new PostController({} as any).create,
132
- delete: new PostController({} as any).delete,
133
+ // Update user
134
+ const updateUser = trpc.users.update.useMutation();
135
+ await updateUser.mutateAsync({
136
+ id: 'user-id',
137
+ data: { name: 'Jane Doe' }
133
138
  });
139
+
140
+ // Delete user
141
+ const deleteUser = trpc.users.delete.useMutation();
142
+ await deleteUser.mutateAsync({ id: 'user-id' });
134
143
  ```
135
144
 
136
- 2. **Add to Main Router:**
137
- ```typescript
138
- // src/router/index.ts
139
- import { postRouter } from '../controllers/PostController.js';
145
+ ## Generated CRUD Operations
140
146
 
141
- export const appRouter = router({
142
- posts: postRouter,
143
- // ... other routes
144
- });
145
- ```
147
+ Each `createCrudRouter` call generates:
146
148
 
147
- ### Available Middleware
149
+ - `getAll({ skip?, take?, orderBy? })` - List with pagination
150
+ - `getById({ id })` - Get single record
151
+ - `create(data)` - Create new record
152
+ - `update({ id, data })` - Update existing record
153
+ - `delete({ id })` - Delete record
154
+ - `count({ where? })` - Count records
148
155
 
149
- #### Authentication
150
- - `requireAuth` - Requires Bearer token authentication
151
- - `requireRole(role)` - Requires specific user role
152
- - `requireAdmin` - Requires admin role
156
+ ## Available Scripts
153
157
 
154
- #### Utility Middleware
155
- - `logger` - Request/response logging with timing
156
- - `rateLimit(maxRequests, windowMs)` - Rate limiting per IP
157
- - `responseTime` - Adds X-Response-Time header
158
- - `requestId` - Adds unique X-Request-ID header
159
- - `errorHandler` - Centralized error handling
158
+ - `yarn dev` - Start development server with hot reload
159
+ - `yarn build` - Build production bundle
160
+ - `yarn start` - Start production server
161
+ - `yarn test` - Run tests
162
+ - `yarn lint` - Lint code
163
+ - `yarn type-check` - Check TypeScript types
160
164
 
161
- ### Example tRPC Client Usage
165
+ ## Project Structure
162
166
 
163
- ```typescript
164
- import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
165
- import type { AppRouter } from './path/to/your/api';
167
+ ```
168
+ src/
169
+ ├── router/
170
+ │ └── index.ts # Main router definition
171
+ ├── routers/
172
+ │ ├── test.ts # Example CRUD router for Test model
173
+ │ └── user.example.ts # Example CRUD router for User model
174
+ ├── lib/
175
+ │ ├── crud.ts # CRUD router generator
176
+ │ └── database.ts # Database connection
177
+ ├── context.ts # tRPC context
178
+ ├── trpc.ts # tRPC setup
179
+ └── server.ts # Express server setup
180
+ ```
166
181
 
167
- const client = createTRPCProxyClient<AppRouter>({
168
- links: [
169
- httpBatchLink({
170
- url: 'http://localhost:3000/trpc',
182
+ ## Advanced Usage
183
+
184
+ ### Custom Procedures
185
+
186
+ Extend generated routers with custom procedures:
187
+
188
+ ```typescript
189
+ import { router, publicProcedure } from '../trpc.js';
190
+ import { createCrudRouter } from '../lib/crud.js';
191
+
192
+ const baseCrudRouter = createCrudRouter('user', createUserSchema);
193
+
194
+ export const userRouter = router({
195
+ ...baseCrudRouter,
196
+
197
+ // Add custom procedures
198
+ getByEmail: publicProcedure
199
+ .input(z.object({ email: z.string().email() }))
200
+ .query(async ({ input }) => {
201
+ return await db.user.findUnique({
202
+ where: { email: input.email }
203
+ });
171
204
  }),
172
- ],
173
205
  });
206
+ ```
207
+
208
+ ### Authentication
209
+
210
+ For protected routes, you can add authentication middleware to the tRPC setup or create protected procedures:
174
211
 
175
- // Use the client
176
- const greeting = await client.hello.query({ name: 'John' });
177
- const healthStatus = await client.health.query();
212
+ ```typescript
213
+ import { protectedProcedure } from '../trpc.js';
214
+
215
+ // Use protectedProcedure instead of publicProcedure in your CRUD router
178
216
  ```
179
217
 
218
+ ## Development
219
+
220
+ 1. **Add New Model**:
221
+ - Add to Prisma schema
222
+ - Run `yarn db:migrate`
223
+ - Create router with `createCrudRouter`
224
+ - Add to main router
225
+
226
+ 2. **Test API**:
227
+ - Start development: `yarn dev`
228
+ - API available at `http://localhost:3000/trpc`
229
+
230
+ 3. **Type Safety**:
231
+ - All operations are fully type-safe
232
+ - Frontend gets autocomplete and validation
233
+ - Schemas ensure data integrity
234
+
235
+ This simplified approach removes controller complexity while maintaining full type safety and providing powerful CRUD operations for all your Prisma models.
236
+
180
237
  ## Environment Variables
181
238
 
182
- Copy `.env.example` to `.env` and configure:
239
+ Create a `.env` file with:
183
240
 
184
- - `PORT` - Server port (default: 3000)
185
- - `NODE_ENV` - Environment (development/production)
186
- - `CORS_ORIGIN` - CORS origin for client requests
241
+ ```env
242
+ # Database
243
+ DATABASE_URL="file:./dev.db"
187
244
 
188
- ## Deployment
245
+ # API
246
+ PORT=3000
247
+ NODE_ENV=development
189
248
 
190
- 1. Build the project: `yarn build`
191
- 2. Start the server: `yarn start`
249
+ # Add your environment variables here
250
+ ```
251
+
252
+ ## Testing
192
253
 
193
- ## Learn More
254
+ The project includes Jest for testing:
194
255
 
195
- - [tRPC Documentation](https://trpc.io/)
196
- - [Zod Documentation](https://zod.dev/)
197
- - [Express.js Documentation](https://expressjs.com/)
256
+ ```typescript
257
+ import { createContext } from '../src/context.js';
258
+ import { appRouter } from '../src/router/index.js';
259
+
260
+ describe('API Tests', () => {
261
+ test('should get test records', async () => {
262
+ const ctx = createContext({} as any);
263
+ const caller = appRouter.createCaller(ctx);
264
+
265
+ const tests = await caller.test.getAll({});
266
+ expect(tests).toBeDefined();
267
+ });
268
+ });
269
+ ```
270
+
271
+ Run tests with:
272
+ ```bash
273
+ yarn test
274
+ ```
@@ -3,12 +3,12 @@
3
3
  "version": "{{version}}",
4
4
  "description": "{{description}}",
5
5
  "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
6
+ "main": "src/index.ts",
7
+ "types": "src/index.ts",
8
8
  "exports": {
9
9
  ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
10
+ "types": "./src/index.ts",
11
+ "import": "./src/index.ts"
12
12
  }
13
13
  },
14
14
  "scripts": {
@@ -23,7 +23,7 @@
23
23
  "type-check": "tsc --noEmit"
24
24
  },
25
25
  "dependencies": {
26
- "@trpc/server": "^10.44.1",
26
+ "@trpc/server": "^11.5.1",
27
27
  "cors": "^2.8.5",
28
28
  "dotenv": "^16.3.1",
29
29
  "express": "^4.18.2",
@@ -5,10 +5,5 @@ export type { AppRouter } from './router/index.js';
5
5
  // Export context type for client usage
6
6
  export type { Context } from './context.js';
7
7
 
8
- // Export middleware for potential external usage
9
- export * from './middleware/auth.js';
10
- export * from './middleware/common.js';
11
-
12
- // Export controller base classes for extensions
13
- export { BaseController, controllerToRouter } from './lib/controller.js';
14
- export type { MiddlewareFn } from './lib/controller.js';
8
+ // Export CRUD utilities for creating routers
9
+ export { createCrudRouter } from './lib/crud.js';
@@ -0,0 +1,150 @@
1
+ import type { Prisma } from '@{{workspaceScope}}/database/client';
2
+ import { z } from 'zod';
3
+ import { prisma } from '../lib/database.js';
4
+ import { publicProcedure, router } from '../trpc.js';
5
+
6
+ /**
7
+ * Creates a standard CRUD router for any Prisma model
8
+ *
9
+ * @param modelName - The name of the Prisma model (e.g., 'user', 'post', 'test')
10
+ * @param createSchema - Zod schema for creating new records
11
+ * @param updateSchema - Zod schema for updating records (optional, defaults to createSchema.partial())
12
+ * @returns tRPC router with standard CRUD operations
13
+ */
14
+ export function createCrudRouter<
15
+ TModelName extends Prisma.ModelName,
16
+ TCreateInput extends Record<string, any>,
17
+ TUpdateInput extends Record<string, any> = Partial<TCreateInput>
18
+ >(
19
+ modelName: TModelName,
20
+ createSchema: z.ZodSchema<TCreateInput>,
21
+ updateSchema?: z.ZodSchema<TUpdateInput>
22
+ ) {
23
+ const model = (prisma as any)[modelName];
24
+ const updateSchemaToUse = updateSchema || createSchema.partial();
25
+
26
+ return router({
27
+ // Get all records
28
+ getAll: publicProcedure
29
+ .input(z.object({
30
+ skip: z.number().min(0).optional(),
31
+ take: z.number().min(1).max(100).optional(),
32
+ orderBy: z.record(z.enum(['asc', 'desc'])).optional(),
33
+ }))
34
+ .query(async ({ input }) => {
35
+ return await model.findMany({
36
+ skip: input.skip,
37
+ take: input.take || 10,
38
+ orderBy: input.orderBy,
39
+ });
40
+ }),
41
+
42
+ // Get record by ID
43
+ getById: publicProcedure
44
+ .input(z.object({ id: z.string() }))
45
+ .query(async ({ input }) => {
46
+ const record = await model.findUnique({
47
+ where: { id: input.id },
48
+ });
49
+
50
+ if (!record) {
51
+ throw new Error(`${modelName} not found`);
52
+ }
53
+
54
+ return record;
55
+ }),
56
+
57
+ // Create new record
58
+ create: publicProcedure
59
+ .input(createSchema)
60
+ .mutation(async ({ input }) => {
61
+ return await model.create({
62
+ data: input,
63
+ });
64
+ }),
65
+
66
+ // Update record
67
+ update: publicProcedure
68
+ .input(z.object({
69
+ id: z.string(),
70
+ data: updateSchemaToUse,
71
+ }))
72
+ .mutation(async ({ input }) => {
73
+ const existingRecord = await model.findUnique({
74
+ where: { id: input.id },
75
+ });
76
+
77
+ if (!existingRecord) {
78
+ throw new Error(`${modelName} not found`);
79
+ }
80
+
81
+ return await model.update({
82
+ where: { id: input.id },
83
+ data: input.data,
84
+ });
85
+ }),
86
+
87
+ // Delete record
88
+ delete: publicProcedure
89
+ .input(z.object({ id: z.string() }))
90
+ .mutation(async ({ input }) => {
91
+ const existingRecord = await model.findUnique({
92
+ where: { id: input.id },
93
+ });
94
+
95
+ if (!existingRecord) {
96
+ throw new Error(`${modelName} not found`);
97
+ }
98
+
99
+ return await model.delete({
100
+ where: { id: input.id },
101
+ });
102
+ }),
103
+
104
+ // Get count
105
+ count: publicProcedure
106
+ .input(z.object({
107
+ where: z.record(z.any()).optional(),
108
+ }))
109
+ .query(async ({ input }) => {
110
+ return await model.count({
111
+ where: input.where,
112
+ });
113
+ }),
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Example usage:
119
+ *
120
+ * ```typescript
121
+ * import { z } from 'zod';
122
+ * import { createCrudRouter } from '../lib/crud.js';
123
+ *
124
+ * // Define schemas for your model
125
+ * const createUserSchema = z.object({
126
+ * email: z.string().email(),
127
+ * name: z.string(),
128
+ * });
129
+ *
130
+ * const updateUserSchema = z.object({
131
+ * email: z.string().email().optional(),
132
+ * name: z.string().optional(),
133
+ * });
134
+ *
135
+ * // Create the CRUD router
136
+ * export const userRouter = createCrudRouter(
137
+ * 'user',
138
+ * createUserSchema,
139
+ * updateUserSchema
140
+ * );
141
+ * ```
142
+ *
143
+ * This will generate:
144
+ * - users.getAll() - Get all users with pagination
145
+ * - users.getById({ id }) - Get user by ID
146
+ * - users.create({ email, name }) - Create new user
147
+ * - users.update({ id, data: { email?, name? } }) - Update user
148
+ * - users.delete({ id }) - Delete user
149
+ * - users.count() - Get user count
150
+ */
@@ -0,0 +1,23 @@
1
+ import { PrismaClient } from '@{{workspaceScope}}/database/client';
2
+
3
+ // Initialize Prisma Client
4
+ declare global {
5
+ // eslint-disable-next-line no-var
6
+ var __prisma: PrismaClient | undefined;
7
+ }
8
+
9
+ // Prevent multiple instances of Prisma Client in development
10
+ export const prisma = globalThis.__prisma || new PrismaClient({
11
+ log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
12
+ });
13
+
14
+ if (process.env.NODE_ENV !== 'production') {
15
+ globalThis.__prisma = prisma;
16
+ }
17
+
18
+ // Graceful shutdown
19
+ process.on('beforeExit', async () => {
20
+ await prisma.$disconnect();
21
+ });
22
+
23
+ export default prisma;