@effectify/prisma 0.1.1

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 (67) hide show
  1. package/README.md +154 -0
  2. package/dist/src/cli.d.ts +2 -0
  3. package/dist/src/cli.js +17 -0
  4. package/dist/src/commands/generate-effect.d.ts +2 -0
  5. package/dist/src/commands/generate-effect.js +73 -0
  6. package/dist/src/commands/generate-sql-schema.d.ts +2 -0
  7. package/dist/src/commands/generate-sql-schema.js +72 -0
  8. package/dist/src/commands/init.d.ts +4 -0
  9. package/dist/src/commands/init.js +102 -0
  10. package/dist/src/effect-prisma.d.ts +2 -0
  11. package/dist/src/effect-prisma.js +1771 -0
  12. package/dist/src/generators/prisma-effect-generator.d.ts +1 -0
  13. package/dist/src/generators/prisma-effect-generator.js +446 -0
  14. package/dist/src/generators/sql-schema-generator.d.ts +1 -0
  15. package/dist/src/generators/sql-schema-generator.js +58 -0
  16. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  17. package/package.json +53 -0
  18. package/prisma/dev.db +0 -0
  19. package/prisma/generated/client.d.ts +1 -0
  20. package/prisma/generated/client.js +5 -0
  21. package/prisma/generated/default.d.ts +1 -0
  22. package/prisma/generated/default.js +5 -0
  23. package/prisma/generated/edge.d.ts +1 -0
  24. package/prisma/generated/edge.js +141 -0
  25. package/prisma/generated/effect/index.ts +397 -0
  26. package/prisma/generated/effect/prisma-repository.ts +954 -0
  27. package/prisma/generated/effect/prisma-schema.ts +94 -0
  28. package/prisma/generated/effect/schemas/enums.ts +6 -0
  29. package/prisma/generated/effect/schemas/index.ts +2 -0
  30. package/prisma/generated/effect/schemas/types.ts +40 -0
  31. package/prisma/generated/index-browser.js +172 -0
  32. package/prisma/generated/index.d.ts +2360 -0
  33. package/prisma/generated/index.js +141 -0
  34. package/prisma/generated/package.json +144 -0
  35. package/prisma/generated/query_compiler_bg.js +2 -0
  36. package/prisma/generated/query_compiler_bg.wasm +0 -0
  37. package/prisma/generated/query_compiler_bg.wasm-base64.js +2 -0
  38. package/prisma/generated/runtime/client.d.ts +3180 -0
  39. package/prisma/generated/runtime/client.js +86 -0
  40. package/prisma/generated/runtime/index-browser.d.ts +87 -0
  41. package/prisma/generated/runtime/index-browser.js +6 -0
  42. package/prisma/generated/runtime/wasm-compiler-edge.js +76 -0
  43. package/prisma/generated/schema.prisma +31 -0
  44. package/prisma/generated/wasm-edge-light-loader.mjs +5 -0
  45. package/prisma/generated/wasm-worker-loader.mjs +5 -0
  46. package/prisma/migrations/20250721164420_init/migration.sql +9 -0
  47. package/prisma/migrations/20250721191716_dumb/migration.sql +49 -0
  48. package/prisma/migrations/migration_lock.toml +3 -0
  49. package/prisma/schema.prisma +31 -0
  50. package/prisma.config.ts +8 -0
  51. package/project.json +48 -0
  52. package/scripts/cleanup-tests.ts +26 -0
  53. package/scripts/generate-test-files.ts +93 -0
  54. package/setup-tests.ts +10 -0
  55. package/src/cli.tsx +23 -0
  56. package/src/commands/generate-effect.ts +109 -0
  57. package/src/commands/generate-sql-schema.ts +109 -0
  58. package/src/commands/init.ts +155 -0
  59. package/src/effect-prisma.ts +1826 -0
  60. package/src/generators/prisma-effect-generator.ts +496 -0
  61. package/src/generators/sql-schema-generator.ts +75 -0
  62. package/test/prisma-model.test.ts +340 -0
  63. package/test/utils.ts +10 -0
  64. package/tsconfig.json +20 -0
  65. package/tsconfig.lib.json +24 -0
  66. package/tsconfig.spec.json +15 -0
  67. package/vitest.config.ts +23 -0
@@ -0,0 +1,1771 @@
1
+ #!/usr/bin/env -S pnpm dlx tsx
2
+ /** biome-ignore-all lint/nursery/useMaxParams: <explanation> */
3
+ /** biome-ignore-all lint/nursery/noShadow: <todo> */
4
+ /** biome-ignore-all lint/complexity/noExcessiveCognitiveComplexity: <todo> */
5
+ import fs from 'node:fs/promises';
6
+ import path from 'node:path';
7
+ import generatorHelper from '@prisma/generator-helper';
8
+ const { generatorHandler } = generatorHelper;
9
+ const header = '// This file was generated by prisma-effect-generator, do not edit manually.\n';
10
+ // Utility function to convert PascalCase to camelCase
11
+ const prismaSchemaContent = `/**
12
+ * @since 1.0.0
13
+ */
14
+ import * as Cause from 'effect/Cause'
15
+ import * as Effect from 'effect/Effect'
16
+ import type * as Option from 'effect/Option'
17
+ import type { ParseError } from 'effect/ParseResult'
18
+ import * as Schema from 'effect/Schema'
19
+
20
+ /**
21
+ * Run a sql query with a request schema and a result schema.
22
+ *
23
+ * @since 1.0.0
24
+ * @category constructor
25
+ */
26
+ export const findAll = <IR, II, IA, AR, AI, A, R, E>(options: {
27
+ readonly Request: Schema.Schema<IA, II, IR>
28
+ readonly Result: Schema.Schema<A, AI, AR>
29
+ readonly execute: (request: II) => Effect.Effect<ReadonlyArray<unknown>, E, R>
30
+ }) => {
31
+ const encodeRequest = Schema.encode(options.Request)
32
+ const decode = Schema.decodeUnknown(Schema.Array(options.Result))
33
+ return (request: IA): Effect.Effect<ReadonlyArray<A>, E | ParseError, R | IR | AR> =>
34
+ Effect.flatMap(Effect.flatMap(encodeRequest(request), options.execute), decode)
35
+ }
36
+
37
+ const void_ = <IR, II, IA, R, E>(options: {
38
+ readonly Request: Schema.Schema<IA, II, IR>
39
+ readonly execute: (request: II) => Effect.Effect<unknown, E, R>
40
+ }) => {
41
+ const encode = Schema.encode(options.Request)
42
+ return (request: IA): Effect.Effect<void, E | ParseError, R | IR> =>
43
+ Effect.asVoid(Effect.flatMap(encode(request), options.execute))
44
+ }
45
+ export {
46
+ /**
47
+ * Run a sql query with a request schema and discard the result.
48
+ *
49
+ * @since 1.0.0
50
+ * @category constructor
51
+ */
52
+ void_ as void,
53
+ }
54
+
55
+ /**
56
+ * Run a sql query with a request schema and a result schema and return the first result.
57
+ *
58
+ * @since 1.0.0
59
+ * @category constructor
60
+ */
61
+ export const findOne = <IR, II, IA, AR, AI, A, R, E>(options: {
62
+ readonly Request: Schema.Schema<IA, II, IR>
63
+ readonly Result: Schema.Schema<A, AI, AR>
64
+ readonly execute: (request: II) => Effect.Effect<ReadonlyArray<unknown>, E, R>
65
+ }) => {
66
+ const encodeRequest = Schema.encode(options.Request)
67
+ const decode = Schema.decodeUnknown(options.Result)
68
+ return (request: IA): Effect.Effect<Option.Option<A>, E | ParseError, R | IR | AR> =>
69
+ Effect.flatMap(Effect.flatMap(encodeRequest(request), options.execute), (arr) =>
70
+ Array.isArray(arr) && arr.length > 0 ? Effect.asSome(decode(arr[0])) : Effect.succeedNone,
71
+ )
72
+ }
73
+
74
+ /**
75
+ * Run a sql query with a request schema and a result schema and return the first result.
76
+ *
77
+ * @since 1.0.0
78
+ * @category constructor
79
+ */
80
+ export const single = <IR, II, IA, AR, AI, A, R, E>(options: {
81
+ readonly Request: Schema.Schema<IA, II, IR>
82
+ readonly Result: Schema.Schema<A, AI, AR>
83
+ readonly execute: (request: II) => Effect.Effect<ReadonlyArray<unknown>, E, R>
84
+ }) => {
85
+ const encodeRequest = Schema.encode(options.Request)
86
+ const decode = Schema.decodeUnknown(options.Result)
87
+ return (request: IA): Effect.Effect<A, E | ParseError | Cause.NoSuchElementException, R | IR | AR> =>
88
+ Effect.flatMap(
89
+ Effect.flatMap(encodeRequest(request), options.execute),
90
+ (arr): Effect.Effect<A, ParseError | Cause.NoSuchElementException, AR> =>
91
+ Array.isArray(arr) && arr.length > 0 ? decode(arr[0]) : Effect.fail(new Cause.NoSuchElementException()),
92
+ )
93
+ }
94
+
95
+ export const many = <IR, II, IA, AR, AI, A, R, E>(options: {
96
+ readonly Request: Schema.Schema<IA, II, IR>
97
+ readonly Result: Schema.Schema<A, AI, AR>
98
+ readonly execute: (request: II) => Effect.Effect<Array<unknown>, E, R>
99
+ }) => {
100
+ const encodeRequest = Schema.encode(options.Request)
101
+ const decode = Schema.decodeUnknown(Schema.Array(options.Result))
102
+ return (request: IA): Effect.Effect<Array<A>, E | ParseError, R | IR | AR> =>
103
+ Effect.map(Effect.flatMap(Effect.flatMap(encodeRequest(request), options.execute), decode), (arr) => [...arr])
104
+ }
105
+ `;
106
+ const getPrismaModelContent = (clientImportPath) => `/** biome-ignore-all lint/suspicious/noExplicitAny: <todo> */
107
+ /** biome-ignore-all lint/style/useDefaultSwitchClause: <todo> */
108
+
109
+ import * as VariantSchema from '@effect/experimental/VariantSchema'
110
+ import { type PrismaClient as BasePrismaClient, Prisma as PrismaNamespace } from '${clientImportPath}'
111
+ import { PrismaClient } from './index.js'
112
+ import * as Data from 'effect/Data'
113
+ import * as Effect from 'effect/Effect'
114
+ import type * as Option from 'effect/Option'
115
+ import * as Schema from 'effect/Schema'
116
+ import * as SqlSchema from './prisma-schema.js'
117
+
118
+ export class PrismaUniqueConstraintError extends Data.TaggedError('PrismaUniqueConstraintError')<{
119
+ cause: PrismaNamespace.PrismaClientKnownRequestError
120
+ operation: string
121
+ model: string
122
+ }> {}
123
+
124
+ export class PrismaForeignKeyConstraintError extends Data.TaggedError('PrismaForeignKeyConstraintError')<{
125
+ cause: PrismaNamespace.PrismaClientKnownRequestError
126
+ operation: string
127
+ model: string
128
+ }> {}
129
+
130
+ export class PrismaRecordNotFoundError extends Data.TaggedError('PrismaRecordNotFoundError')<{
131
+ cause: PrismaNamespace.PrismaClientKnownRequestError
132
+ operation: string
133
+ model: string
134
+ }> {}
135
+
136
+ export class PrismaRelationViolationError extends Data.TaggedError('PrismaRelationViolationError')<{
137
+ cause: PrismaNamespace.PrismaClientKnownRequestError
138
+ operation: string
139
+ model: string
140
+ }> {}
141
+
142
+ export class PrismaRelatedRecordNotFoundError extends Data.TaggedError('PrismaRelatedRecordNotFoundError')<{
143
+ cause: PrismaNamespace.PrismaClientKnownRequestError
144
+ operation: string
145
+ model: string
146
+ }> {}
147
+
148
+ export class PrismaTransactionConflictError extends Data.TaggedError('PrismaTransactionConflictError')<{
149
+ cause: PrismaNamespace.PrismaClientKnownRequestError
150
+ operation: string
151
+ model: string
152
+ }> {}
153
+
154
+ export class PrismaValueTooLongError extends Data.TaggedError('PrismaValueTooLongError')<{
155
+ cause: PrismaNamespace.PrismaClientKnownRequestError
156
+ operation: string
157
+ model: string
158
+ }> {}
159
+
160
+ export class PrismaValueOutOfRangeError extends Data.TaggedError('PrismaValueOutOfRangeError')<{
161
+ cause: PrismaNamespace.PrismaClientKnownRequestError
162
+ operation: string
163
+ model: string
164
+ }> {}
165
+
166
+ export class PrismaDbConstraintError extends Data.TaggedError('PrismaDbConstraintError')<{
167
+ cause: PrismaNamespace.PrismaClientKnownRequestError
168
+ operation: string
169
+ model: string
170
+ }> {}
171
+
172
+ export class PrismaConnectionError extends Data.TaggedError('PrismaConnectionError')<{
173
+ cause: PrismaNamespace.PrismaClientKnownRequestError
174
+ operation: string
175
+ model: string
176
+ }> {}
177
+
178
+ export class PrismaMissingRequiredValueError extends Data.TaggedError('PrismaMissingRequiredValueError')<{
179
+ cause: PrismaNamespace.PrismaClientKnownRequestError
180
+ operation: string
181
+ model: string
182
+ }> {}
183
+
184
+ export class PrismaInputValidationError extends Data.TaggedError('PrismaInputValidationError')<{
185
+ cause: PrismaNamespace.PrismaClientKnownRequestError
186
+ operation: string
187
+ model: string
188
+ }> {}
189
+
190
+ export type PrismaCreateError =
191
+ | PrismaValueTooLongError
192
+ | PrismaUniqueConstraintError
193
+ | PrismaForeignKeyConstraintError
194
+ | PrismaDbConstraintError
195
+ | PrismaInputValidationError
196
+ | PrismaMissingRequiredValueError
197
+ | PrismaRelatedRecordNotFoundError
198
+ | PrismaValueOutOfRangeError
199
+ | PrismaConnectionError
200
+ | PrismaTransactionConflictError
201
+
202
+ export type PrismaUpdateError =
203
+ | PrismaValueTooLongError
204
+ | PrismaUniqueConstraintError
205
+ | PrismaForeignKeyConstraintError
206
+ | PrismaDbConstraintError
207
+ | PrismaInputValidationError
208
+ | PrismaMissingRequiredValueError
209
+ | PrismaRelationViolationError
210
+ | PrismaRelatedRecordNotFoundError
211
+ | PrismaValueOutOfRangeError
212
+ | PrismaConnectionError
213
+ | PrismaRecordNotFoundError
214
+ | PrismaTransactionConflictError
215
+
216
+ export type PrismaDeleteError =
217
+ | PrismaForeignKeyConstraintError
218
+ | PrismaRelationViolationError
219
+ | PrismaConnectionError
220
+ | PrismaRecordNotFoundError
221
+ | PrismaTransactionConflictError
222
+
223
+ export type PrismaFindOrThrowError =
224
+ | PrismaConnectionError
225
+ | PrismaRecordNotFoundError
226
+
227
+ export type PrismaFindError =
228
+ | PrismaConnectionError
229
+
230
+ export type PrismaDeleteManyError =
231
+ | PrismaForeignKeyConstraintError
232
+ | PrismaRelationViolationError
233
+ | PrismaConnectionError
234
+ | PrismaTransactionConflictError
235
+
236
+ export type PrismaUpdateManyError =
237
+ | PrismaValueTooLongError
238
+ | PrismaUniqueConstraintError
239
+ | PrismaForeignKeyConstraintError
240
+ | PrismaDbConstraintError
241
+ | PrismaInputValidationError
242
+ | PrismaMissingRequiredValueError
243
+ | PrismaValueOutOfRangeError
244
+ | PrismaConnectionError
245
+ | PrismaTransactionConflictError
246
+
247
+ // Create, Upsert
248
+ export const mapCreateError = (error: unknown, operation: string, model: string): PrismaCreateError => {
249
+ if (error instanceof PrismaNamespace.PrismaClientKnownRequestError) {
250
+ switch (error.code) {
251
+ case 'P2000':
252
+ return new PrismaValueTooLongError({ cause: error, operation, model })
253
+ case 'P2002':
254
+ return new PrismaUniqueConstraintError({ cause: error, operation, model })
255
+ case 'P2003':
256
+ return new PrismaForeignKeyConstraintError({ cause: error, operation, model })
257
+ case 'P2004':
258
+ return new PrismaDbConstraintError({ cause: error, operation, model })
259
+ case 'P2005':
260
+ case 'P2006':
261
+ case 'P2019':
262
+ return new PrismaInputValidationError({ cause: error, operation, model })
263
+ case 'P2011':
264
+ case 'P2012':
265
+ return new PrismaMissingRequiredValueError({ cause: error, operation, model })
266
+ case 'P2015':
267
+ case 'P2018':
268
+ return new PrismaRelatedRecordNotFoundError({ cause: error, operation, model })
269
+ case 'P2020':
270
+ return new PrismaValueOutOfRangeError({ cause: error, operation, model })
271
+ case 'P2024':
272
+ return new PrismaConnectionError({ cause: error, operation, model })
273
+ case 'P2034':
274
+ return new PrismaTransactionConflictError({ cause: error, operation, model })
275
+ }
276
+ }
277
+ throw error
278
+ }
279
+
280
+ // Update
281
+ export const mapUpdateError = (error: unknown, operation: string, model: string): PrismaUpdateError => {
282
+ if (error instanceof PrismaNamespace.PrismaClientKnownRequestError) {
283
+ switch (error.code) {
284
+ case "P2000":
285
+ return new PrismaValueTooLongError({ cause: error, operation, model });
286
+ case "P2002":
287
+ return new PrismaUniqueConstraintError({ cause: error, operation, model });
288
+ case "P2003":
289
+ return new PrismaForeignKeyConstraintError({ cause: error, operation, model });
290
+ case "P2004":
291
+ return new PrismaDbConstraintError({ cause: error, operation, model });
292
+ case "P2005":
293
+ case "P2006":
294
+ case "P2019":
295
+ return new PrismaInputValidationError({ cause: error, operation, model });
296
+ case "P2011":
297
+ case "P2012":
298
+ return new PrismaMissingRequiredValueError({ cause: error, operation, model });
299
+ case "P2014":
300
+ return new PrismaRelationViolationError({ cause: error, operation, model });
301
+ case "P2015":
302
+ case "P2018":
303
+ return new PrismaRelatedRecordNotFoundError({ cause: error, operation, model });
304
+ case "P2020":
305
+ return new PrismaValueOutOfRangeError({ cause: error, operation, model });
306
+ case "P2024":
307
+ return new PrismaConnectionError({ cause: error, operation, model });
308
+ case "P2025":
309
+ return new PrismaRecordNotFoundError({ cause: error, operation, model });
310
+ case "P2034":
311
+ return new PrismaTransactionConflictError({ cause: error, operation, model });
312
+ }
313
+ }
314
+ throw error;
315
+ }
316
+
317
+ // Delete
318
+ export const mapDeleteError = (error: unknown, operation: string, model: string): PrismaDeleteError => {
319
+ if (error instanceof PrismaNamespace.PrismaClientKnownRequestError) {
320
+ switch (error.code) {
321
+ case "P2003":
322
+ return new PrismaForeignKeyConstraintError({ cause: error, operation, model });
323
+ case "P2014":
324
+ return new PrismaRelationViolationError({ cause: error, operation, model });
325
+ case "P2024":
326
+ return new PrismaConnectionError({ cause: error, operation, model });
327
+ case "P2025":
328
+ return new PrismaRecordNotFoundError({ cause: error, operation, model });
329
+ case "P2034":
330
+ return new PrismaTransactionConflictError({ cause: error, operation, model });
331
+ }
332
+ }
333
+ throw error;
334
+ }
335
+
336
+ // FindOrThrow
337
+ export const mapFindOrThrowError = (error: unknown, operation: string, model: string): PrismaFindOrThrowError => {
338
+ if (error instanceof PrismaNamespace.PrismaClientKnownRequestError) {
339
+ switch (error.code) {
340
+ case "P2024":
341
+ return new PrismaConnectionError({ cause: error, operation, model });
342
+ case "P2025":
343
+ return new PrismaRecordNotFoundError({ cause: error, operation, model });
344
+ }
345
+ }
346
+ throw error;
347
+ }
348
+
349
+ // Find
350
+ export const mapFindError = (error: unknown, operation: string, model: string): PrismaFindError => {
351
+ if (error instanceof PrismaNamespace.PrismaClientKnownRequestError) {
352
+ switch (error.code) {
353
+ case "P2024":
354
+ return new PrismaConnectionError({ cause: error, operation, model });
355
+ }
356
+ }
357
+ throw error;
358
+ }
359
+
360
+ // DeleteMany
361
+ export const mapDeleteManyError = (error: unknown, operation: string, model: string): PrismaDeleteManyError => {
362
+ if (error instanceof PrismaNamespace.PrismaClientKnownRequestError) {
363
+ switch (error.code) {
364
+ case "P2003":
365
+ return new PrismaForeignKeyConstraintError({ cause: error, operation, model });
366
+ case "P2014":
367
+ return new PrismaRelationViolationError({ cause: error, operation, model });
368
+ case "P2024":
369
+ return new PrismaConnectionError({ cause: error, operation, model });
370
+ case "P2034":
371
+ return new PrismaTransactionConflictError({ cause: error, operation, model });
372
+ }
373
+ }
374
+ throw error;
375
+ }
376
+
377
+ // UpdateMany
378
+ export const mapUpdateManyError = (error: unknown, operation: string, model: string): PrismaUpdateManyError => {
379
+ if (error instanceof PrismaNamespace.PrismaClientKnownRequestError) {
380
+ switch (error.code) {
381
+ case "P2000":
382
+ return new PrismaValueTooLongError({ cause: error, operation, model });
383
+ case "P2002":
384
+ return new PrismaUniqueConstraintError({ cause: error, operation, model });
385
+ case "P2003":
386
+ return new PrismaForeignKeyConstraintError({ cause: error, operation, model });
387
+ case "P2004":
388
+ return new PrismaDbConstraintError({ cause: error, operation, model });
389
+ case "P2005":
390
+ case "P2006":
391
+ case "P2019":
392
+ return new PrismaInputValidationError({ cause: error, operation, model });
393
+ case "P2011":
394
+ case "P2012":
395
+ return new PrismaMissingRequiredValueError({ cause: error, operation, model });
396
+ case "P2020":
397
+ return new PrismaValueOutOfRangeError({ cause: error, operation, model });
398
+ case "P2024":
399
+ return new PrismaConnectionError({ cause: error, operation, model });
400
+ case "P2034":
401
+ return new PrismaTransactionConflictError({ cause: error, operation, model });
402
+ }
403
+ }
404
+ throw error;
405
+ }
406
+
407
+ const { Class, Field, FieldExcept, FieldOnly, Struct, Union, extract, fieldEvolve, fieldFromKey } = VariantSchema.make({
408
+ variants: [
409
+ 'findUnique',
410
+ 'findUniqueOrThrow',
411
+ 'findFirst',
412
+ 'findFirstOrThrow',
413
+ 'findMany',
414
+ 'create',
415
+ 'createMany',
416
+ 'createManyAndReturn',
417
+ 'update',
418
+ 'json',
419
+ 'jsonCreate',
420
+ 'jsonUpdate',
421
+ ],
422
+ defaultVariant: 'findUnique',
423
+ })
424
+
425
+ /**
426
+ * @since 1.0.0
427
+ * @category models
428
+ */
429
+ export type Any = Schema.Schema.Any & {
430
+ readonly fields: Schema.Struct.Fields
431
+ readonly findUnique: Schema.Schema.Any
432
+ readonly findUniqueOrThrow: Schema.Schema.Any
433
+ readonly findFirst: Schema.Schema.Any
434
+ readonly findFirstOrThrow: Schema.Schema.Any
435
+ readonly findMany: Schema.Schema.Any
436
+ readonly create: Schema.Schema.Any
437
+ readonly createMany: Schema.Schema.Any
438
+ readonly createManyAndReturn: Schema.Schema.Any
439
+ readonly update: Schema.Schema.Any
440
+ readonly json: Schema.Schema.Any
441
+ readonly jsonCreate: Schema.Schema.Any
442
+ readonly jsonUpdate: Schema.Schema.Any
443
+ }
444
+
445
+ /**
446
+ * @since 1.0.0
447
+ * @category models
448
+ */
449
+ export type AnyNoContext = Schema.Schema.AnyNoContext & {
450
+ readonly fields: Schema.Struct.Fields
451
+ readonly findUnique: Schema.Schema.AnyNoContext
452
+ readonly findUniqueOrThrow: Schema.Schema.AnyNoContext
453
+ readonly findFirst: Schema.Schema.AnyNoContext
454
+ readonly findFirstOrThrow: Schema.Schema.AnyNoContext
455
+ readonly findMany: Schema.Schema.AnyNoContext
456
+ readonly create: Schema.Schema.AnyNoContext
457
+ readonly createMany: Schema.Schema.AnyNoContext
458
+ readonly createManyAndReturn: Schema.Schema.AnyNoContext
459
+ readonly update: Schema.Schema.AnyNoContext
460
+ readonly json: Schema.Schema.AnyNoContext
461
+ readonly jsonCreate: Schema.Schema.AnyNoContext
462
+ readonly jsonUpdate: Schema.Schema.AnyNoContext
463
+ }
464
+
465
+ /**
466
+ * @since 1.0.0
467
+ * @category models
468
+ */
469
+ export type VariantsDatabase =
470
+ | 'findUnique'
471
+ | 'findUniqueOrThrow'
472
+ | 'findFirst'
473
+ | 'findFirstOrThrow'
474
+ | 'findMany'
475
+ | 'create'
476
+ | 'createMany'
477
+ | 'createManyAndReturn'
478
+ | 'update'
479
+
480
+ /**
481
+ * @since 1.0.0
482
+ * @category models
483
+ */
484
+ export type VariantsJson = 'json' | 'jsonCreate' | 'jsonUpdate'
485
+
486
+ export {
487
+ /**
488
+ * A base class used for creating domain model schemas.
489
+ *
490
+ * It supports common variants for database and JSON apis.
491
+ *
492
+ * @since 1.0.0
493
+ * @category constructors
494
+ * @example
495
+ * \`\`\`ts
496
+ * import { Schema } from "effect"
497
+ * import { Model } from "@effect/sql"
498
+ *
499
+ * export const GroupId = Schema.Number.pipe(Schema.brand("GroupId"))
500
+ *
501
+ * export class Group extends Model.Class<Group>("Group")({
502
+ * id: Model.Generated(GroupId),
503
+ * name: Schema.NonEmptyTrimmedString,
504
+ * createdAt: Model.DateTimeInsertFromDate,
505
+ * updatedAt: Model.DateTimeUpdateFromDate
506
+ * }) {}
507
+ *
508
+ * // schema used for selects
509
+ * Group
510
+ *
511
+ * // schema used for inserts
512
+ * Group.insert
513
+ *
514
+ * // schema used for updates
515
+ * Group.update
516
+ *
517
+ * // schema used for json api
518
+ * Group.json
519
+ * Group.jsonCreate
520
+ * Group.jsonUpdate
521
+ *
522
+ * // you can also turn them into classes
523
+ * class GroupJson extends Schema.Class<GroupJson>("GroupJson")(Group.json) {
524
+ * get upperName() {
525
+ * return this.name.toUpperCase()
526
+ * }
527
+ * }
528
+ * \`\`\`
529
+ */
530
+ Class,
531
+ /**
532
+ * @since 1.0.0
533
+ * @category extraction
534
+ */
535
+ extract,
536
+ /**
537
+ * @since 1.0.0
538
+ * @category fields
539
+ */
540
+ Field,
541
+ /**
542
+ * @since 1.0.0
543
+ * @category fields
544
+ */
545
+ fieldEvolve,
546
+ /**
547
+ * @since 1.0.0
548
+ * @category fields
549
+ */
550
+ FieldExcept,
551
+ /**
552
+ * @since 1.0.0
553
+ * @category fields
554
+ */
555
+ fieldFromKey,
556
+ /**
557
+ * @since 1.0.0
558
+ * @category fields
559
+ */
560
+ FieldOnly,
561
+ /**
562
+ * @since 1.0.0
563
+ * @category constructors
564
+ */
565
+ Struct,
566
+ /**
567
+ * @since 1.0.0
568
+ * @category constructors
569
+ */
570
+ Union,
571
+ }
572
+
573
+ /**
574
+ * Create a simple CRUD repository from a model.
575
+ *
576
+ * @since 1.0.0
577
+ * @category repository
578
+ */
579
+ export const make = <S extends Any, M extends keyof BasePrismaClient>(
580
+ Model: S,
581
+ options: {
582
+ readonly modelName: M extends string ? M : string
583
+ readonly spanPrefix: string
584
+ readonly uniqueKey?: string | ReadonlyArray<string>
585
+ },
586
+ ): Effect.Effect<
587
+ {
588
+ readonly findUnique: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'findUnique'>>(
589
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'findUnique'>>,
590
+ ) => Effect.Effect<Option.Option<S['Type']>, PrismaFindError, S['Context'] | S['findUnique']['Context']>
591
+
592
+ readonly findUniqueOrThrow: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'findUnique'>>(
593
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'findUnique'>>,
594
+ ) => Effect.Effect<S['Type'], PrismaFindOrThrowError, S['Context'] | S['findUniqueOrThrow']['Context']>
595
+
596
+ readonly findFirst: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'findFirst'>>(
597
+ args?: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'findFirst'>>
598
+ ) => Effect.Effect<Option.Option<S['Type']>, PrismaFindError, S['Context'] | S['findFirst']['Context']>
599
+
600
+ readonly findFirstOrThrow: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'findFirstOrThrow'>>(
601
+ args?: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'findFirstOrThrow'>>
602
+ ) => Effect.Effect<S['Type'], PrismaFindOrThrowError, S['Context'] | S['findFirstOrThrow']['Context']>
603
+
604
+ readonly findMany: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'findMany'>>(
605
+ args?: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'findMany'>>
606
+ ) => Effect.Effect<Array<S['Type']>, PrismaFindError, S['Context'] | S['findMany']['Context']>
607
+
608
+ readonly create: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'create'>>(
609
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'create'>>,
610
+ ) => Effect.Effect<S['Type'], PrismaCreateError, S['Context'] | S['create']['Context']>
611
+
612
+ readonly createMany: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'createMany'>>(
613
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'createMany'>>,
614
+ ) => Effect.Effect<PrismaNamespace.BatchPayload, PrismaCreateError, S['Context'] | S['createMany']['Context']>
615
+
616
+ readonly createManyAndReturn: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'createManyAndReturn'>>(
617
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'createManyAndReturn'>>,
618
+ ) => Effect.Effect<Array<S['Type']>, PrismaCreateError, S['Context'] | S['createManyAndReturn']['Context']>
619
+
620
+ readonly update: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'update'>>(
621
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'update'>>
622
+ ) => Effect.Effect<S['Type'], PrismaUpdateError, S['Context'] | S['update']['Context']>
623
+
624
+ readonly updateMany: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'updateMany'>>(
625
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'updateMany'>>
626
+ ) => Effect.Effect<PrismaNamespace.BatchPayload, PrismaUpdateManyError, S['Context'] | S['update']['Context']>
627
+
628
+ readonly delete: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'delete'>>(
629
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'delete'>>
630
+ ) => Effect.Effect<S['Type'], PrismaDeleteError, S['Context']>
631
+
632
+ readonly deleteMany: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'deleteMany'>>(
633
+ args?: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'deleteMany'>>
634
+ ) => Effect.Effect<PrismaNamespace.BatchPayload, PrismaDeleteManyError, S['Context']>
635
+
636
+ readonly upsert: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'upsert'>>(
637
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'upsert'>>
638
+ ) => Effect.Effect<S['Type'], PrismaCreateError, S['Context']>
639
+
640
+ readonly count: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'count'>>(
641
+ args?: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'count'>>
642
+ ) => Effect.Effect<unknown, PrismaFindError, S['Context']>
643
+
644
+ readonly aggregate: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'aggregate'>>(
645
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'aggregate'>>
646
+ ) => Effect.Effect<unknown, PrismaFindError, S['Context']>
647
+
648
+ readonly groupBy: <A extends PrismaNamespace.Args<BasePrismaClient[M], 'groupBy'>>(
649
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'groupBy'>>
650
+ ) => Effect.Effect<unknown, PrismaFindError, S['Context']>
651
+ },
652
+ never,
653
+ PrismaClient
654
+ > =>
655
+ Effect.gen(function* () {
656
+ const prisma = yield* PrismaClient
657
+
658
+ // Construye el schema del where para findUnique usando uniqueKey en modo builder
659
+ let findUniqueRequestSchema: Schema.Schema<any, any, any> = Schema.Unknown
660
+ if (options.uniqueKey) {
661
+ const keys = Array.isArray(options.uniqueKey) ? options.uniqueKey : [options.uniqueKey]
662
+ const shape: Record<string, Schema.Schema.Any> = {}
663
+ let valid = true
664
+ for (const key of keys) {
665
+ const field = (Model as any).fields?.[key]
666
+ if (!field) {
667
+ valid = false
668
+ break
669
+ }
670
+ shape[key] = field
671
+ }
672
+ if (valid) {
673
+ findUniqueRequestSchema = Schema.Struct(shape as any)
674
+ }
675
+ }
676
+
677
+ const findUniqueSchema = SqlSchema.findOne({
678
+ Request: findUniqueRequestSchema,
679
+ Result: Model,
680
+ execute: (request) =>
681
+ Effect.tryPromise({
682
+ try: () =>
683
+ ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).findUnique({ where: request }) as any,
684
+ catch: (error) => mapFindError(error, 'findUnique', options.modelName),
685
+ }).pipe(Effect.map((result) => (result ? [result] : []))),
686
+ })
687
+
688
+ const findUnique = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'findUnique'>>(
689
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'findUnique'>>,
690
+ ): Effect.Effect<Option.Option<S['Type']>, never, S['Context'] | S['findUnique']['Context']> =>
691
+ findUniqueSchema((args as any).where).pipe(
692
+ Effect.catchTag('ParseError', Effect.die),
693
+ Effect.withSpan(\`\${options.spanPrefix}.findUnique\`, {
694
+ captureStackTrace: false,
695
+ attributes: { ...(args as any).where },
696
+ }),
697
+ ) as any
698
+
699
+ const findUniqueOrThrowSchema = SqlSchema.single({
700
+ Request: findUniqueRequestSchema,
701
+ Result: Model,
702
+ execute: (request) =>
703
+ Effect.tryPromise({
704
+ try: () =>
705
+ ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).findUniqueOrThrow({
706
+ where: request,
707
+ }) as any,
708
+ catch: (error) => mapFindOrThrowError(error, 'findUniqueOrThrow', options.modelName),
709
+ }).pipe(Effect.map((result) => [result] as any)),
710
+ })
711
+
712
+ const findUniqueOrThrow = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'findUnique'>>(
713
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'findUnique'>>,
714
+ ): Effect.Effect<S['Type'], never, S['Context'] | S['findUniqueOrThrow']['Context']> =>
715
+ findUniqueOrThrowSchema((args as any).where).pipe(
716
+ Effect.map((result) => result as S['Type']),
717
+ Effect.catchTag('ParseError', Effect.die),
718
+ Effect.catchTag('NoSuchElementException', Effect.die),
719
+ Effect.withSpan(\`\${options.spanPrefix}.findUniqueOrThrow\`, {
720
+ captureStackTrace: false,
721
+ attributes: { ...(args as any).where },
722
+ }),
723
+ ) as any
724
+
725
+ const findFirstSchema = SqlSchema.findOne({
726
+ Request: Schema.Unknown,
727
+ Result: Model,
728
+ execute: (request) =>
729
+ Effect.tryPromise({
730
+ try: () =>
731
+ ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).findFirst(request) as any,
732
+ catch: (error) => mapFindError(error, 'findFirst', options.modelName),
733
+ }).pipe(Effect.map((result) => (result ? [result] : []))),
734
+ })
735
+
736
+ const findFirst = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'findFirst'>>(
737
+ args?: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'findFirst'>>
738
+ ): Effect.Effect<Option.Option<S['Type']>, never, S['Context'] | S['findFirst']['Context']> =>
739
+ findFirstSchema(args).pipe(
740
+ Effect.catchTag('ParseError', Effect.die),
741
+ Effect.withSpan(\`\${options.spanPrefix}.findFirst\`, {
742
+ captureStackTrace: false,
743
+ attributes: { ...(args as any) },
744
+ }),
745
+ ) as any
746
+
747
+ const findFirstOrThrowSchema = SqlSchema.single({
748
+ Request: Schema.Unknown,
749
+ Result: Model,
750
+ execute: (request) =>
751
+ Effect.tryPromise({
752
+ try: () =>
753
+ ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).findFirstOrThrow(request) as any,
754
+ catch: (error) => mapFindOrThrowError(error, 'findFirstOrThrow', options.modelName),
755
+ }).pipe(Effect.map((result) => [result] as any)),
756
+ })
757
+
758
+ const findFirstOrThrow = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'findFirstOrThrow'>>(
759
+ args?: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'findFirstOrThrow'>>
760
+ ): Effect.Effect<S['Type'], never, S['Context'] | S['findFirstOrThrow']['Context']> =>
761
+ findFirstOrThrowSchema(args).pipe(
762
+ Effect.map((result) => result as S['Type']),
763
+ Effect.catchTag('ParseError', Effect.die),
764
+ Effect.catchTag('NoSuchElementException', Effect.die),
765
+ Effect.withSpan(\`\${options.spanPrefix}.findFirstOrThrow\`, {
766
+ captureStackTrace: false,
767
+ attributes: { ...(args as any) },
768
+ }),
769
+ ) as any
770
+
771
+ const findManySchema = SqlSchema.many({
772
+ Request: Schema.Unknown,
773
+ Result: Model,
774
+ execute: (request) =>
775
+ Effect.tryPromise({
776
+ try: () =>
777
+ ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).findMany(request) as any,
778
+ catch: (error) => mapFindError(error, 'findMany', options.modelName),
779
+ }).pipe(Effect.map((result) => result as any)),
780
+ })
781
+
782
+ const findMany = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'findMany'>>(
783
+ args?: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'findMany'>>
784
+ ): Effect.Effect<Array<S['Type']>, never, S['Context'] | S['findMany']['Context']> =>
785
+ findManySchema(args).pipe(
786
+ Effect.catchTag('ParseError', Effect.die),
787
+ Effect.withSpan(\`\${options.spanPrefix}.findMany\`, {
788
+ captureStackTrace: false,
789
+ attributes: { ...(args as any) },
790
+ }),
791
+ ) as any
792
+
793
+ const createSchema = SqlSchema.single({
794
+ Request: Model.create,
795
+ Result: Model,
796
+ execute: (request) =>
797
+ Effect.tryPromise({
798
+ try: () => ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).create({ data: request }),
799
+ catch: (error) => mapCreateError(error, 'create', options.modelName),
800
+ }).pipe(Effect.map((result) => [result] as any)),
801
+ })
802
+
803
+ const create = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'create'>>(
804
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'create'>>,
805
+ ): Effect.Effect<S['Type'], never, S['Context'] | S['create']['Context']> =>
806
+ createSchema((args as any).data).pipe(
807
+ Effect.catchTag('ParseError', Effect.die),
808
+ Effect.catchTag('NoSuchElementException', Effect.die),
809
+ Effect.withSpan(\`\${options.spanPrefix}.create\`, {
810
+ captureStackTrace: false,
811
+ attributes: { ...(args as any).data },
812
+ }),
813
+ ) as any
814
+
815
+ const createManySchema = SqlSchema.single({
816
+ Request: Schema.Array(Model.createMany),
817
+ Result: Schema.Unknown,
818
+ execute: (request) =>
819
+ Effect.tryPromise({
820
+ try: () =>
821
+ ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).createMany({ data: request as any }),
822
+ catch: (error) => mapCreateError(error, 'createMany', options.modelName),
823
+ }).pipe(Effect.map((result) => [result] as any)),
824
+ })
825
+
826
+ const createMany = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'createMany'>>(
827
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'createMany'>>,
828
+ ): Effect.Effect<PrismaNamespace.BatchPayload, never, S['Context'] | S['createMany']['Context']> =>
829
+ createManySchema((args as any).data).pipe(
830
+ Effect.map((res) => res as unknown as PrismaNamespace.BatchPayload),
831
+ Effect.catchTag('ParseError', Effect.die),
832
+ Effect.catchTag('NoSuchElementException', Effect.die),
833
+ Effect.withSpan(\`\${options.spanPrefix}.createMany\`, {
834
+ captureStackTrace: false,
835
+ attributes: { ...(args as any).data },
836
+ }),
837
+ ) as any
838
+
839
+ const createManyAndReturnSchema = SqlSchema.many({
840
+ Request: Schema.Array(Model.createMany),
841
+ Result: Model,
842
+ execute: (request) =>
843
+ Effect.tryPromise({
844
+ try: () =>
845
+ ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).createManyAndReturn({
846
+ data: request as any,
847
+ }),
848
+ catch: (error) => mapCreateError(error, 'createManyAndReturn', options.modelName),
849
+ }),
850
+ })
851
+
852
+ const createManyAndReturn = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'createManyAndReturn'>>(
853
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'createManyAndReturn'>>,
854
+ ): Effect.Effect<Array<S['Type']>, never, S['Context'] | S['createManyAndReturn']['Context']> =>
855
+ createManyAndReturnSchema((args as any).data).pipe(
856
+ Effect.catchTag('ParseError', Effect.die),
857
+ Effect.withSpan(\`\${options.spanPrefix}.createManyAndReturn\`, {
858
+ captureStackTrace: false,
859
+ attributes: { ...(args as any).data },
860
+ }),
861
+ ) as any
862
+
863
+ const countSchema = SqlSchema.single({
864
+ Request: Schema.Unknown,
865
+ Result: Schema.Unknown,
866
+ execute: (request) =>
867
+ Effect.tryPromise({
868
+ try: () => ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).count(request),
869
+ catch: (error) => mapFindError(error, 'count', options.modelName),
870
+ }).pipe(Effect.map((result) => [result] as any)),
871
+ })
872
+
873
+ const count = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'count'>>(
874
+ args?: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'count'>>
875
+ ): Effect.Effect<unknown, never, S['Context']> =>
876
+ countSchema(args).pipe(
877
+ Effect.catchTag('ParseError', Effect.die),
878
+ Effect.catchTag('NoSuchElementException', Effect.die),
879
+ Effect.withSpan(\`\${options.spanPrefix}.count\`, {
880
+ captureStackTrace: false,
881
+ attributes: { ...(args as any) },
882
+ }),
883
+ ) as any
884
+
885
+ const updateSchema = SqlSchema.single({
886
+ Request: Schema.Unknown,
887
+ Result: Model,
888
+ execute: (request) =>
889
+ Effect.tryPromise({
890
+ try: () => ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).update(request),
891
+ catch: (error) => mapUpdateError(error, 'update', options.modelName),
892
+ }).pipe(Effect.map((result) => [result] as any)),
893
+ })
894
+
895
+ const update = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'update'>>(
896
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'update'>>
897
+ ): Effect.Effect<S['Type'], never, S['Context'] | S['update']['Context']> =>
898
+ updateSchema(args).pipe(
899
+ Effect.catchTag('ParseError', Effect.die),
900
+ Effect.catchTag('NoSuchElementException', Effect.die),
901
+ Effect.withSpan(\`\${options.spanPrefix}.update\`, {
902
+ captureStackTrace: false,
903
+ attributes: { ...(args as any) },
904
+ }),
905
+ ) as any
906
+
907
+ const deleteSchema = SqlSchema.single({
908
+ Request: Schema.Unknown,
909
+ Result: Model,
910
+ execute: (request) =>
911
+ Effect.tryPromise({
912
+ try: () => ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).delete(request),
913
+ catch: (error) => mapDeleteError(error, 'delete', options.modelName),
914
+ }).pipe(Effect.map((result) => [result] as any)),
915
+ })
916
+
917
+ const delete_ = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'delete'>>(
918
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'delete'>>
919
+ ): Effect.Effect<S['Type'], never, S['Context']> =>
920
+ deleteSchema(args).pipe(
921
+ Effect.catchTag('ParseError', Effect.die),
922
+ Effect.catchTag('NoSuchElementException', Effect.die),
923
+ Effect.withSpan(\`\${options.spanPrefix}.delete\`, {
924
+ captureStackTrace: false,
925
+ attributes: { ...(args as any) },
926
+ }),
927
+ ) as any
928
+
929
+ const upsertSchema = SqlSchema.single({
930
+ Request: Schema.Unknown,
931
+ Result: Model,
932
+ execute: (request) =>
933
+ Effect.tryPromise({
934
+ try: () => ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).upsert(request),
935
+ catch: (error) => mapCreateError(error, 'upsert', options.modelName),
936
+ }).pipe(Effect.map((result) => [result] as any)),
937
+ })
938
+
939
+ const upsert = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'upsert'>>(
940
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'upsert'>>
941
+ ): Effect.Effect<S['Type'], never, S['Context']> =>
942
+ upsertSchema(args).pipe(
943
+ Effect.catchTag('ParseError', Effect.die),
944
+ Effect.catchTag('NoSuchElementException', Effect.die),
945
+ Effect.withSpan(\`\${options.spanPrefix}.upsert\`, {
946
+ captureStackTrace: false,
947
+ attributes: { ...(args as any) },
948
+ }),
949
+ ) as any
950
+
951
+ const aggregateSchema = SqlSchema.single({
952
+ Request: Schema.Unknown,
953
+ Result: Schema.Unknown,
954
+ execute: (request) =>
955
+ Effect.tryPromise({
956
+ try: () => ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).aggregate(request),
957
+ catch: (error) => mapFindError(error, 'aggregate', options.modelName),
958
+ }).pipe(Effect.map((result) => [result] as any)),
959
+ })
960
+
961
+ const aggregate = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'aggregate'>>(
962
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'aggregate'>>
963
+ ): Effect.Effect<unknown, never, S['Context']> =>
964
+ aggregateSchema(args).pipe(
965
+ Effect.catchTag('ParseError', Effect.die),
966
+ Effect.catchTag('NoSuchElementException', Effect.die),
967
+ Effect.withSpan(\`\${options.spanPrefix}.aggregate\`, {
968
+ captureStackTrace: false,
969
+ attributes: { ...(args as any) },
970
+ }),
971
+ ) as any
972
+
973
+ const groupBySchema = SqlSchema.many({
974
+ Request: Schema.Unknown,
975
+ Result: Schema.Unknown,
976
+ execute: (request) =>
977
+ Effect.tryPromise({
978
+ try: () => ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).groupBy(request),
979
+ catch: (error) => mapFindError(error, 'groupBy', options.modelName),
980
+ }).pipe(Effect.map((result) => result as any)),
981
+ })
982
+
983
+ const groupBy = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'groupBy'>>(
984
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'groupBy'>>
985
+ ): Effect.Effect<unknown, never, S['Context']> =>
986
+ groupBySchema(args).pipe(
987
+ Effect.catchTag('ParseError', Effect.die),
988
+ Effect.withSpan(\`\${options.spanPrefix}.groupBy\`, {
989
+ captureStackTrace: false,
990
+ attributes: { ...(args as any) },
991
+ }),
992
+ ) as any
993
+
994
+ const updateManySchema = SqlSchema.single({
995
+ Request: Schema.Unknown,
996
+ Result: Schema.Unknown,
997
+ execute: (request) =>
998
+ Effect.tryPromise({
999
+ try: () => ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).updateMany(request),
1000
+ catch: (error) => mapUpdateManyError(error, 'updateMany', options.modelName),
1001
+ }).pipe(Effect.map((result) => [result] as any)),
1002
+ })
1003
+
1004
+ const updateMany = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'updateMany'>>(
1005
+ args: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'updateMany'>>
1006
+ ): Effect.Effect<PrismaNamespace.BatchPayload, never, S['Context'] | S['update']['Context']> =>
1007
+ updateManySchema(args).pipe(
1008
+ Effect.map((res) => res as unknown as PrismaNamespace.BatchPayload),
1009
+ Effect.catchTag('ParseError', Effect.die),
1010
+ Effect.catchTag('NoSuchElementException', Effect.die),
1011
+ Effect.withSpan(\`\${options.spanPrefix}.updateMany\`, {
1012
+ captureStackTrace: false,
1013
+ attributes: { ...(args as any) },
1014
+ }),
1015
+ ) as any
1016
+
1017
+ const deleteManySchema = SqlSchema.single({
1018
+ Request: Schema.Unknown,
1019
+ Result: Schema.Unknown,
1020
+ execute: (request) =>
1021
+ Effect.tryPromise({
1022
+ try: () => ((prisma.tx as BasePrismaClient)[options.modelName as M] as any).deleteMany(request),
1023
+ catch: (error) => mapDeleteManyError(error, 'deleteMany', options.modelName),
1024
+ }).pipe(Effect.map((result) => [result] as any)),
1025
+ })
1026
+
1027
+ const deleteMany = <A extends PrismaNamespace.Args<BasePrismaClient[M], 'deleteMany'>>(
1028
+ args?: PrismaNamespace.Exact<A, PrismaNamespace.Args<BasePrismaClient[M], 'deleteMany'>>
1029
+ ): Effect.Effect<PrismaNamespace.BatchPayload, never, S['Context']> =>
1030
+ deleteManySchema(args).pipe(
1031
+ Effect.map((res) => res as unknown as PrismaNamespace.BatchPayload),
1032
+ Effect.catchTag('ParseError', Effect.die),
1033
+ Effect.catchTag('NoSuchElementException', Effect.die),
1034
+ Effect.withSpan(\`\${options.spanPrefix}.deleteMany\`, {
1035
+ captureStackTrace: false,
1036
+ attributes: { ...(args as any) },
1037
+ }),
1038
+ ) as any
1039
+
1040
+ return {
1041
+ findUnique,
1042
+ findUniqueOrThrow,
1043
+ findFirst,
1044
+ findFirstOrThrow,
1045
+ findMany,
1046
+ create,
1047
+ createMany,
1048
+ createManyAndReturn,
1049
+ update,
1050
+ updateMany,
1051
+ delete: delete_,
1052
+ deleteMany,
1053
+ upsert,
1054
+ count,
1055
+ aggregate,
1056
+ groupBy
1057
+ } as const
1058
+
1059
+ })
1060
+ `;
1061
+ generatorHandler({
1062
+ onManifest() {
1063
+ return {
1064
+ defaultOutput: '../generated/effect',
1065
+ prettyName: 'Prisma Effect Generator',
1066
+ // No engines required - we only read the DMMF schema
1067
+ requiresEngines: [],
1068
+ };
1069
+ },
1070
+ async onGenerate(options) {
1071
+ const models = options.dmmf.datamodel.models;
1072
+ const outputDir = options.generator.output?.value;
1073
+ const schemaDir = path.dirname(options.schemaPath);
1074
+ const configPath = options.generator.config.clientImportPath;
1075
+ const clientImportPath = Array.isArray(configPath) ? configPath[0] : (configPath ?? '@prisma/client');
1076
+ const errorConfigRaw = options.generator.config.errorImportPath;
1077
+ const errorImportPathRaw = Array.isArray(errorConfigRaw) ? errorConfigRaw[0] : errorConfigRaw;
1078
+ const importExtConfigRaw = options.generator.config.importFileExtension;
1079
+ const importFileExtension = Array.isArray(importExtConfigRaw) ? importExtConfigRaw[0] : (importExtConfigRaw ?? '');
1080
+ if (!outputDir) {
1081
+ throw new Error('No output directory specified');
1082
+ }
1083
+ const addExtension = (filePath) => {
1084
+ if (!importFileExtension) {
1085
+ return filePath;
1086
+ }
1087
+ const ext = path.extname(filePath);
1088
+ if (ext) {
1089
+ return filePath;
1090
+ }
1091
+ return `${filePath}.${importFileExtension}`;
1092
+ };
1093
+ let errorImportPath;
1094
+ if (errorImportPathRaw) {
1095
+ const [modulePath, className] = errorImportPathRaw.split('#');
1096
+ if (!(modulePath && className)) {
1097
+ throw new Error(`Invalid errorImportPath format: "${errorImportPathRaw}". Expected "path/to/module#ErrorClassName"`);
1098
+ }
1099
+ if (modulePath.startsWith('.')) {
1100
+ const absoluteErrorPath = path.resolve(schemaDir, modulePath);
1101
+ const relativeToOutput = path.relative(outputDir, absoluteErrorPath);
1102
+ const normalizedPath = relativeToOutput.startsWith('.') ? relativeToOutput : `./${relativeToOutput}`;
1103
+ const pathWithExtension = addExtension(normalizedPath);
1104
+ errorImportPath = `${pathWithExtension}#${className}`;
1105
+ }
1106
+ else {
1107
+ errorImportPath = errorImportPathRaw;
1108
+ }
1109
+ }
1110
+ // Clean output directory
1111
+ // await fs.rm(outputDir, { recursive: true, force: true })
1112
+ await fs.mkdir(outputDir, { recursive: true });
1113
+ // Write static files
1114
+ await fs.writeFile(path.join(outputDir, 'prisma-schema.ts'), prismaSchemaContent);
1115
+ await fs.writeFile(path.join(outputDir, 'prisma-repository.ts'), getPrismaModelContent(clientImportPath));
1116
+ // Generate unified index file with PrismaService
1117
+ await generateUnifiedService([...models], outputDir, clientImportPath, errorImportPath);
1118
+ // Fix imports in schemas/index.ts
1119
+ await fixSchemaImports(outputDir);
1120
+ },
1121
+ });
1122
+ async function fixSchemaImports(outputDir) {
1123
+ const schemasDir = path.join(outputDir, 'schemas');
1124
+ const indexFile = path.join(schemasDir, 'index.ts');
1125
+ try {
1126
+ const content = await fs.readFile(indexFile, 'utf-8');
1127
+ const fixedContent = content
1128
+ .replace(/export \* from '\.\/enums'/g, "export * from './enums.js'")
1129
+ .replace(/export \* from '\.\/types'/g, "export * from './types.js'");
1130
+ if (content !== fixedContent) {
1131
+ await fs.writeFile(indexFile, fixedContent);
1132
+ }
1133
+ }
1134
+ catch (_error) {
1135
+ // Ignore if file doesn't exist
1136
+ }
1137
+ }
1138
+ function generateRawSqlOperations(customError) {
1139
+ const errorType = customError ? customError.className : 'PrismaError';
1140
+ return `
1141
+ $executeRaw: (args: PrismaNamespace.Sql | [PrismaNamespace.Sql, ...any[]]): Effect.Effect<number, ${errorType}, PrismaClient> =>
1142
+ Effect.flatMap(PrismaClient, ({ tx: client }) =>
1143
+ Effect.tryPromise({
1144
+ try: () => (Array.isArray(args) ? client.$executeRaw(args[0], ...args.slice(1)) : client.$executeRaw(args)),
1145
+ catch: (error) => mapError(error, "$executeRaw", "Prisma")
1146
+ })
1147
+ ),
1148
+
1149
+ $executeRawUnsafe: (query: string, ...values: any[]): Effect.Effect<number, ${errorType}, PrismaClient> =>
1150
+ Effect.flatMap(PrismaClient, ({ tx: client }) =>
1151
+ Effect.tryPromise({
1152
+ try: () => client.$executeRawUnsafe(query, ...values),
1153
+ catch: (error) => mapError(error, "$executeRawUnsafe", "Prisma")
1154
+ })
1155
+ ),
1156
+
1157
+ $queryRaw: <T = unknown>(args: PrismaNamespace.Sql | [PrismaNamespace.Sql, ...any[]]): Effect.Effect<T, ${errorType}, PrismaClient> =>
1158
+ Effect.flatMap(PrismaClient, ({ tx: client }) =>
1159
+ Effect.tryPromise({
1160
+ try: () => (Array.isArray(args) ? client.$queryRaw(args[0], ...args.slice(1)) : client.$queryRaw(args)) as Promise<T>,
1161
+ catch: (error) => mapError(error, "$queryRaw", "Prisma")
1162
+ })
1163
+ ),
1164
+
1165
+ $queryRawUnsafe: <T = unknown>(query: string, ...values: any[]): Effect.Effect<T, ${errorType}, PrismaClient> =>
1166
+ Effect.flatMap(PrismaClient, ({ tx: client }) =>
1167
+ Effect.tryPromise({
1168
+ try: () => client.$queryRawUnsafe(query, ...values) as Promise<T>,
1169
+ catch: (error) => mapError(error, "$queryRawUnsafe", "Prisma")
1170
+ })
1171
+ ),`;
1172
+ }
1173
+ function generateModelClasses(models) {
1174
+ const modelClasses = models
1175
+ .map((model) => {
1176
+ const modelName = model.name;
1177
+ const className = `${modelName}Model`;
1178
+ return `export class ${className} extends Model.Class<${className}>("${modelName}")({
1179
+ ..._${modelName}.fields
1180
+ }) {}`;
1181
+ })
1182
+ .join('\n\n');
1183
+ return modelClasses;
1184
+ }
1185
+ // Parse error import path like "./errors#PrismaError" into { path, className }
1186
+ function parseErrorImportPath(errorImportPath) {
1187
+ if (!errorImportPath) {
1188
+ return null;
1189
+ }
1190
+ const [path, className] = errorImportPath.split('#');
1191
+ if (!(path && className)) {
1192
+ throw new Error(`Invalid errorImportPath format: "${errorImportPath}". Expected "path/to/module#ErrorClassName"`);
1193
+ }
1194
+ return { path, className };
1195
+ }
1196
+ async function generateUnifiedService(models, outputDir, clientImportPath, errorImportPath) {
1197
+ const customError = parseErrorImportPath(errorImportPath);
1198
+ const rawSqlOperations = generateRawSqlOperations(customError);
1199
+ const modelClasses = generateModelClasses(models);
1200
+ // Generate different content based on whether custom error is configured
1201
+ const serviceContent = customError
1202
+ ? generateCustomErrorService(customError, clientImportPath, rawSqlOperations, modelClasses, models)
1203
+ : generateDefaultErrorService(clientImportPath, rawSqlOperations, modelClasses, models);
1204
+ await fs.writeFile(path.join(outputDir, 'index.ts'), serviceContent);
1205
+ }
1206
+ /**
1207
+ * Generate service with custom user-provided error class.
1208
+ */
1209
+ function generateCustomErrorService(customError, clientImportPath, rawSqlOperations, modelClasses, models) {
1210
+ const schemaImports = models.map((m) => `_${m.name}`).join(', ');
1211
+ return `${header}
1212
+ import { Context, Effect, Exit, Layer } from "effect"
1213
+ import { Service } from "effect/Effect"
1214
+ import { Prisma as PrismaNamespace, PrismaClient as BasePrismaClient } from "${clientImportPath}"
1215
+ import { ${customError.className}, mapPrismaError } from "${customError.path}"
1216
+ import * as Model from "./prisma-repository.js"
1217
+ import { ${schemaImports} } from "./schemas/index.js"
1218
+
1219
+ // Symbol used to identify intentional rollbacks vs actual errors
1220
+ const ROLLBACK = Symbol.for("prisma.effect.rollback")
1221
+
1222
+ // Type for the flat transaction client with commit/rollback control
1223
+ type FlatTransactionClient = PrismaNamespace.TransactionClient & {
1224
+ $commit: () => Promise<void>
1225
+ $rollback: () => Promise<void>
1226
+ }
1227
+
1228
+ /** Transaction options for $transaction and $isolatedTransaction */
1229
+ type TransactionOptions = {
1230
+ maxWait?: number
1231
+ timeout?: number
1232
+ isolationLevel?: PrismaNamespace.TransactionIsolationLevel
1233
+ }
1234
+
1235
+ /**
1236
+ * Context tag for the Prisma client instance.
1237
+ * Holds the transaction client (tx) and root client.
1238
+ */
1239
+ export class PrismaClient extends Context.Tag("PrismaClient")<
1240
+ PrismaClient,
1241
+ {
1242
+ tx: BasePrismaClient | PrismaNamespace.TransactionClient
1243
+ client: BasePrismaClient
1244
+ }
1245
+ >() {
1246
+ static layer = (
1247
+ ...args: ConstructorParameters<typeof BasePrismaClient>
1248
+ ) => Layer.scoped(
1249
+ PrismaClient,
1250
+ Effect.gen(function* () {
1251
+ const prisma = new BasePrismaClient(...args)
1252
+ yield* Effect.addFinalizer(() => Effect.promise(() => prisma.$disconnect()))
1253
+ return { tx: prisma, client: prisma }
1254
+ })
1255
+ )
1256
+
1257
+ static layerEffect = <R, E>(
1258
+ optionsEffect: Effect.Effect<ConstructorParameters<typeof BasePrismaClient>[0], E, R>
1259
+ ) => Layer.scoped(
1260
+ PrismaClient,
1261
+ Effect.gen(function* () {
1262
+ const options = yield* optionsEffect
1263
+ const prisma = new BasePrismaClient(options)
1264
+ yield* Effect.addFinalizer(() => Effect.promise(() => prisma.$disconnect()))
1265
+ return { tx: prisma, client: prisma }
1266
+ })
1267
+ )
1268
+ }
1269
+
1270
+ // Re-export the custom error type for convenience
1271
+ export { ${customError.className} }
1272
+
1273
+ // Use the user-provided error mapper
1274
+ const mapError = mapPrismaError
1275
+
1276
+ /**
1277
+ * Internal helper to begin a callback-free interactive transaction.
1278
+ */
1279
+ const $begin = (
1280
+ client: BasePrismaClient,
1281
+ options?: {
1282
+ maxWait?: number
1283
+ timeout?: number
1284
+ isolationLevel?: PrismaNamespace.TransactionIsolationLevel
1285
+ }
1286
+ ): Effect.Effect<FlatTransactionClient, ${customError.className}> =>
1287
+ Effect.async<FlatTransactionClient, ${customError.className}>((resume) => {
1288
+ let setTxClient: (txClient: PrismaNamespace.TransactionClient) => void
1289
+ let commit: () => void
1290
+ let rollback: () => void
1291
+
1292
+ const txClientPromise = new Promise<PrismaNamespace.TransactionClient>((res) => {
1293
+ setTxClient = res
1294
+ })
1295
+
1296
+ const txPromise = new Promise<void>((_res, _rej) => {
1297
+ commit = () => _res(undefined)
1298
+ rollback = () => _rej(ROLLBACK)
1299
+ })
1300
+
1301
+ const tx = client.$transaction((txClient) => {
1302
+ setTxClient(txClient)
1303
+ return txPromise
1304
+ }, options).catch((e) => {
1305
+ if (e === ROLLBACK) return
1306
+ throw e
1307
+ })
1308
+
1309
+ txClientPromise.then((innerTx) => {
1310
+ const proxy = new Proxy(innerTx, {
1311
+ get(target, prop) {
1312
+ if (prop === "$commit") return () => { commit(); return tx }
1313
+ if (prop === "$rollback") return () => { rollback(); return tx }
1314
+ return target[prop as keyof typeof target]
1315
+ },
1316
+ }) as FlatTransactionClient
1317
+ resume(Effect.succeed(proxy))
1318
+ }).catch((error) => {
1319
+ resume(Effect.fail(mapError(error, "$transaction", "Prisma")))
1320
+ })
1321
+ })
1322
+
1323
+ /**
1324
+ * The main Prisma service with all database operations.
1325
+ * Provides type-safe, effectful access to your Prisma models.
1326
+ */
1327
+ export class Prisma extends Service<Prisma>()("Prisma", {
1328
+ effect: Effect.gen(function* () {
1329
+ return {
1330
+ $transaction: <R, E, A>(
1331
+ effect: Effect.Effect<A, E, R>,
1332
+ options?: TransactionOptions
1333
+ ) =>
1334
+ Effect.flatMap(
1335
+ PrismaClient,
1336
+ ({ client, tx }): Effect.Effect<A, E | ${customError.className}, R> => {
1337
+ const isRootClient = "$transaction" in tx
1338
+ if (!isRootClient) {
1339
+ return effect
1340
+ }
1341
+
1342
+ return Effect.acquireUseRelease(
1343
+ $begin(client, options),
1344
+ (txClient) =>
1345
+ effect.pipe(
1346
+ Effect.provideService(PrismaClient, { tx: txClient, client })
1347
+ ),
1348
+ (txClient, exit) =>
1349
+ Exit.isSuccess(exit)
1350
+ ? Effect.promise(() => txClient.$commit())
1351
+ : Effect.promise(() => txClient.$rollback())
1352
+ )
1353
+ }
1354
+ ),
1355
+
1356
+ $isolatedTransaction: <R, E, A>(
1357
+ effect: Effect.Effect<A, E, R>,
1358
+ options?: TransactionOptions
1359
+ ) =>
1360
+ Effect.flatMap(
1361
+ PrismaClient,
1362
+ ({ client }): Effect.Effect<A, E | ${customError.className}, R> => {
1363
+ return Effect.acquireUseRelease(
1364
+ $begin(client, options),
1365
+ (txClient) =>
1366
+ effect.pipe(
1367
+ Effect.provideService(PrismaClient, { tx: txClient, client })
1368
+ ),
1369
+ (txClient, exit) =>
1370
+ Exit.isSuccess(exit)
1371
+ ? Effect.promise(() => txClient.$commit())
1372
+ : Effect.promise(() => txClient.$rollback())
1373
+ )
1374
+ }
1375
+ ),
1376
+ ${rawSqlOperations}
1377
+ }
1378
+ })
1379
+ }) {
1380
+ static layer = (
1381
+ ...args: ConstructorParameters<typeof BasePrismaClient>
1382
+ ) => Layer.merge(PrismaClient.layer(...args), Prisma.Default)
1383
+
1384
+ static layerEffect = <R, E>(
1385
+ optionsEffect: Effect.Effect<ConstructorParameters<typeof BasePrismaClient>[0], E, R>
1386
+ ) => Layer.merge(PrismaClient.layerEffect(optionsEffect), Prisma.Default)
1387
+
1388
+ }
1389
+
1390
+ // ============================================================================
1391
+ // Deprecated aliases for backward compatibility
1392
+ // ============================================================================
1393
+
1394
+ export const PrismaClientService = PrismaClient
1395
+ export const PrismaService = Prisma
1396
+ export const makePrismaLayer = PrismaClient.layer
1397
+ export const makePrismaLayerEffect = PrismaClient.layerEffect
1398
+
1399
+ ${modelClasses}
1400
+ `;
1401
+ }
1402
+ /**
1403
+ * Generate service with default tagged error classes.
1404
+ */
1405
+ function generateDefaultErrorService(clientImportPath, rawSqlOperations, modelClasses, models) {
1406
+ const schemaImports = models.map((m) => `_${m.name}`).join(', ');
1407
+ return `${header}
1408
+ import { Context, Data, Effect, Exit, Layer } from "effect"
1409
+ import { Service } from "effect/Effect"
1410
+ import { Prisma as PrismaNamespace, PrismaClient as BasePrismaClient } from "${clientImportPath}"
1411
+ import * as Model from "./prisma-repository.js"
1412
+ import { ${schemaImports} } from "./schemas/index.js"
1413
+
1414
+ // Symbol used to identify intentional rollbacks vs actual errors
1415
+ const ROLLBACK = Symbol.for("prisma.effect.rollback")
1416
+
1417
+ // Type for the flat transaction client with commit/rollback control
1418
+ type FlatTransactionClient = PrismaNamespace.TransactionClient & {
1419
+ $commit: () => Promise<void>
1420
+ $rollback: () => Promise<void>
1421
+ }
1422
+
1423
+ /** Transaction options for $transaction and $isolatedTransaction */
1424
+ type TransactionOptions = {
1425
+ maxWait?: number
1426
+ timeout?: number
1427
+ isolationLevel?: PrismaNamespace.TransactionIsolationLevel
1428
+ }
1429
+
1430
+ /**
1431
+ * Context tag for the Prisma client instance.
1432
+ * Holds the transaction client (tx) and root client.
1433
+ */
1434
+ export class PrismaClient extends Context.Tag("PrismaClient")<
1435
+ PrismaClient,
1436
+ {
1437
+ tx: BasePrismaClient | PrismaNamespace.TransactionClient
1438
+ client: BasePrismaClient
1439
+ }
1440
+ >() {
1441
+ static layer = (
1442
+ ...args: ConstructorParameters<typeof BasePrismaClient>
1443
+ ) => Layer.scoped(
1444
+ PrismaClient,
1445
+ Effect.gen(function* () {
1446
+ const prisma = new BasePrismaClient(...args)
1447
+ yield* Effect.addFinalizer(() => Effect.promise(() => prisma.$disconnect()))
1448
+ return { tx: prisma, client: prisma }
1449
+ })
1450
+ )
1451
+
1452
+ static layerEffect = <R, E>(
1453
+ optionsEffect: Effect.Effect<ConstructorParameters<typeof BasePrismaClient>[0], E, R>
1454
+ ) => Layer.scoped(
1455
+ PrismaClient,
1456
+ Effect.gen(function* () {
1457
+ const options = yield* optionsEffect
1458
+ const prisma = new BasePrismaClient(options)
1459
+ yield* Effect.addFinalizer(() => Effect.promise(() => prisma.$disconnect()))
1460
+ return { tx: prisma, client: prisma }
1461
+ })
1462
+ )
1463
+ }
1464
+
1465
+ export class PrismaUniqueConstraintError extends Data.TaggedError("PrismaUniqueConstraintError")<{
1466
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1467
+ operation: string
1468
+ model: string
1469
+ }> {}
1470
+
1471
+ export class PrismaForeignKeyConstraintError extends Data.TaggedError("PrismaForeignKeyConstraintError")<{
1472
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1473
+ operation: string
1474
+ model: string
1475
+ }> {}
1476
+
1477
+ export class PrismaRecordNotFoundError extends Data.TaggedError("PrismaRecordNotFoundError")<{
1478
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1479
+ operation: string
1480
+ model: string
1481
+ }> {}
1482
+
1483
+ export class PrismaRelationViolationError extends Data.TaggedError("PrismaRelationViolationError")<{
1484
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1485
+ operation: string
1486
+ model: string
1487
+ }> {}
1488
+
1489
+ export class PrismaRelatedRecordNotFoundError extends Data.TaggedError("PrismaRelatedRecordNotFoundError")<{
1490
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1491
+ operation: string
1492
+ model: string
1493
+ }> {}
1494
+
1495
+ export class PrismaTransactionConflictError extends Data.TaggedError("PrismaTransactionConflictError")<{
1496
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1497
+ operation: string
1498
+ model: string
1499
+ }> {}
1500
+
1501
+ export class PrismaValueTooLongError extends Data.TaggedError("PrismaValueTooLongError")<{
1502
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1503
+ operation: string
1504
+ model: string
1505
+ }> {}
1506
+
1507
+ export class PrismaValueOutOfRangeError extends Data.TaggedError("PrismaValueOutOfRangeError")<{
1508
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1509
+ operation: string
1510
+ model: string
1511
+ }> {}
1512
+
1513
+ export class PrismaDbConstraintError extends Data.TaggedError("PrismaDbConstraintError")<{
1514
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1515
+ operation: string
1516
+ model: string
1517
+ }> {}
1518
+
1519
+ export class PrismaConnectionError extends Data.TaggedError("PrismaConnectionError")<{
1520
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1521
+ operation: string
1522
+ model: string
1523
+ }> {}
1524
+
1525
+ export class PrismaMissingRequiredValueError extends Data.TaggedError("PrismaMissingRequiredValueError")<{
1526
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1527
+ operation: string
1528
+ model: string
1529
+ }> {}
1530
+
1531
+ export class PrismaInputValidationError extends Data.TaggedError("PrismaInputValidationError")<{
1532
+ cause: PrismaNamespace.PrismaClientKnownRequestError
1533
+ operation: string
1534
+ model: string
1535
+ }> {}
1536
+
1537
+ export type PrismaCreateError =
1538
+ | PrismaValueTooLongError
1539
+ | PrismaUniqueConstraintError
1540
+ | PrismaForeignKeyConstraintError
1541
+ | PrismaDbConstraintError
1542
+ | PrismaInputValidationError
1543
+ | PrismaMissingRequiredValueError
1544
+ | PrismaRelatedRecordNotFoundError
1545
+ | PrismaValueOutOfRangeError
1546
+ | PrismaConnectionError
1547
+ | PrismaTransactionConflictError
1548
+
1549
+ export type PrismaUpdateError =
1550
+ | PrismaValueTooLongError
1551
+ | PrismaUniqueConstraintError
1552
+ | PrismaForeignKeyConstraintError
1553
+ | PrismaDbConstraintError
1554
+ | PrismaInputValidationError
1555
+ | PrismaMissingRequiredValueError
1556
+ | PrismaRelationViolationError
1557
+ | PrismaRelatedRecordNotFoundError
1558
+ | PrismaValueOutOfRangeError
1559
+ | PrismaConnectionError
1560
+ | PrismaRecordNotFoundError
1561
+ | PrismaTransactionConflictError
1562
+
1563
+ export type PrismaDeleteError =
1564
+ | PrismaForeignKeyConstraintError
1565
+ | PrismaRelationViolationError
1566
+ | PrismaConnectionError
1567
+ | PrismaRecordNotFoundError
1568
+ | PrismaTransactionConflictError
1569
+
1570
+ export type PrismaFindOrThrowError =
1571
+ | PrismaConnectionError
1572
+ | PrismaRecordNotFoundError
1573
+
1574
+ export type PrismaFindError =
1575
+ | PrismaConnectionError
1576
+
1577
+ export type PrismaDeleteManyError =
1578
+ | PrismaForeignKeyConstraintError
1579
+ | PrismaRelationViolationError
1580
+ | PrismaConnectionError
1581
+ | PrismaTransactionConflictError
1582
+
1583
+ export type PrismaUpdateManyError =
1584
+ | PrismaValueTooLongError
1585
+ | PrismaUniqueConstraintError
1586
+ | PrismaForeignKeyConstraintError
1587
+ | PrismaDbConstraintError
1588
+ | PrismaInputValidationError
1589
+ | PrismaMissingRequiredValueError
1590
+ | PrismaValueOutOfRangeError
1591
+ | PrismaConnectionError
1592
+ | PrismaTransactionConflictError
1593
+
1594
+ export type PrismaError =
1595
+ | PrismaValueTooLongError
1596
+ | PrismaUniqueConstraintError
1597
+ | PrismaForeignKeyConstraintError
1598
+ | PrismaDbConstraintError
1599
+ | PrismaInputValidationError
1600
+ | PrismaMissingRequiredValueError
1601
+ | PrismaRelationViolationError
1602
+ | PrismaRelatedRecordNotFoundError
1603
+ | PrismaValueOutOfRangeError
1604
+ | PrismaConnectionError
1605
+ | PrismaRecordNotFoundError
1606
+ | PrismaTransactionConflictError
1607
+
1608
+ // Generic mapper for raw operations and fallback
1609
+ const mapError = (error: unknown, operation: string, model: string): PrismaError => {
1610
+ if (error instanceof PrismaNamespace.PrismaClientKnownRequestError) {
1611
+ switch (error.code) {
1612
+ case "P2000":
1613
+ return new PrismaValueTooLongError({ cause: error, operation, model });
1614
+ case "P2002":
1615
+ return new PrismaUniqueConstraintError({ cause: error, operation, model });
1616
+ case "P2003":
1617
+ return new PrismaForeignKeyConstraintError({ cause: error, operation, model });
1618
+ case "P2004":
1619
+ return new PrismaDbConstraintError({ cause: error, operation, model });
1620
+ case "P2005":
1621
+ case "P2006":
1622
+ case "P2019":
1623
+ return new PrismaInputValidationError({ cause: error, operation, model });
1624
+ case "P2011":
1625
+ case "P2012":
1626
+ return new PrismaMissingRequiredValueError({ cause: error, operation, model });
1627
+ case "P2014":
1628
+ return new PrismaRelationViolationError({ cause: error, operation, model });
1629
+ case "P2015":
1630
+ case "P2018":
1631
+ return new PrismaRelatedRecordNotFoundError({ cause: error, operation, model });
1632
+ case "P2020":
1633
+ return new PrismaValueOutOfRangeError({ cause: error, operation, model });
1634
+ case "P2024":
1635
+ return new PrismaConnectionError({ cause: error, operation, model });
1636
+ case "P2025":
1637
+ return new PrismaRecordNotFoundError({ cause: error, operation, model });
1638
+ case "P2034":
1639
+ return new PrismaTransactionConflictError({ cause: error, operation, model });
1640
+ }
1641
+ }
1642
+ // Unknown errors are not handled and will be treated as defects
1643
+ throw error;
1644
+ }
1645
+
1646
+ /**
1647
+ * Internal helper to begin a callback-free interactive transaction.
1648
+ */
1649
+ const $begin = (
1650
+ client: BasePrismaClient,
1651
+ options?: {
1652
+ maxWait?: number
1653
+ timeout?: number
1654
+ isolationLevel?: PrismaNamespace.TransactionIsolationLevel
1655
+ }
1656
+ ): Effect.Effect<FlatTransactionClient, PrismaError> =>
1657
+ Effect.async<FlatTransactionClient, PrismaError>((resume) => {
1658
+ let setTxClient: (txClient: PrismaNamespace.TransactionClient) => void
1659
+ let commit: () => void
1660
+ let rollback: () => void
1661
+
1662
+ const txClientPromise = new Promise<PrismaNamespace.TransactionClient>((res) => {
1663
+ setTxClient = res
1664
+ })
1665
+
1666
+ const txPromise = new Promise<void>((_res, _rej) => {
1667
+ commit = () => _res(undefined)
1668
+ rollback = () => _rej(ROLLBACK)
1669
+ })
1670
+
1671
+ const tx = client.$transaction((txClient) => {
1672
+ setTxClient(txClient)
1673
+ return txPromise
1674
+ }, options).catch((e) => {
1675
+ if (e === ROLLBACK) return
1676
+ throw e
1677
+ })
1678
+
1679
+ txClientPromise.then((innerTx) => {
1680
+ const proxy = new Proxy(innerTx, {
1681
+ get(target, prop) {
1682
+ if (prop === "$commit") return () => { commit(); return tx }
1683
+ if (prop === "$rollback") return () => { rollback(); return tx }
1684
+ return target[prop as keyof typeof target]
1685
+ },
1686
+ }) as FlatTransactionClient
1687
+ resume(Effect.succeed(proxy))
1688
+ }).catch((error) => {
1689
+ resume(Effect.fail(mapError(error, "$transaction", "Prisma")))
1690
+ })
1691
+ })
1692
+
1693
+ /**
1694
+ * The main Prisma service with all database operations.
1695
+ * Provides type-safe, effectful access to your Prisma models.
1696
+ */
1697
+ export class Prisma extends Service<Prisma>()("Prisma", {
1698
+ effect: Effect.gen(function* () {
1699
+ return {
1700
+ $transaction: <R, E, A>(
1701
+ effect: Effect.Effect<A, E, R>,
1702
+ options?: TransactionOptions
1703
+ ) =>
1704
+ Effect.flatMap(
1705
+ PrismaClient,
1706
+ ({ client, tx }): Effect.Effect<A, E | PrismaError, R> => {
1707
+ const isRootClient = "$transaction" in tx
1708
+ if (!isRootClient) {
1709
+ return effect
1710
+ }
1711
+
1712
+ return Effect.acquireUseRelease(
1713
+ $begin(client, options),
1714
+ (txClient) =>
1715
+ effect.pipe(
1716
+ Effect.provideService(PrismaClient, { tx: txClient, client })
1717
+ ),
1718
+ (txClient, exit) =>
1719
+ Exit.isSuccess(exit)
1720
+ ? Effect.promise(() => txClient.$commit())
1721
+ : Effect.promise(() => txClient.$rollback())
1722
+ )
1723
+ }
1724
+ ),
1725
+
1726
+ $isolatedTransaction: <R, E, A>(
1727
+ effect: Effect.Effect<A, E, R>,
1728
+ options?: TransactionOptions
1729
+ ) =>
1730
+ Effect.flatMap(
1731
+ PrismaClient,
1732
+ ({ client }): Effect.Effect<A, E | PrismaError, R> => {
1733
+ return Effect.acquireUseRelease(
1734
+ $begin(client, options),
1735
+ (txClient) =>
1736
+ effect.pipe(
1737
+ Effect.provideService(PrismaClient, { tx: txClient, client })
1738
+ ),
1739
+ (txClient, exit) =>
1740
+ Exit.isSuccess(exit)
1741
+ ? Effect.promise(() => txClient.$commit())
1742
+ : Effect.promise(() => txClient.$rollback())
1743
+ )
1744
+ }
1745
+ ),
1746
+ ${rawSqlOperations}
1747
+ }
1748
+ })
1749
+ }) {
1750
+ static layer = (
1751
+ ...args: ConstructorParameters<typeof BasePrismaClient>
1752
+ ) => Layer.merge(PrismaClient.layer(...args), Prisma.Default)
1753
+
1754
+ static layerEffect = <R, E>(
1755
+ optionsEffect: Effect.Effect<ConstructorParameters<typeof BasePrismaClient>[0], E, R>
1756
+ ) => Layer.merge(PrismaClient.layerEffect(optionsEffect), Prisma.Default)
1757
+
1758
+ }
1759
+
1760
+ // ============================================================================
1761
+ // Deprecated aliases for backward compatibility
1762
+ // ============================================================================
1763
+
1764
+ export const PrismaClientService = PrismaClient
1765
+ export const PrismaService = Prisma
1766
+ export const makePrismaLayer = PrismaClient.layer
1767
+ export const makePrismaLayerEffect = PrismaClient.layerEffect
1768
+
1769
+ ${modelClasses}
1770
+ `;
1771
+ }