prisma-generator-express 1.66.0 → 1.67.0

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 (102) hide show
  1. package/README.md +37 -3476
  2. package/dist/client/encodeQueryParams.js +3 -1
  3. package/dist/client/encodeQueryParams.js.map +1 -1
  4. package/dist/copy/misc.d.ts +1 -0
  5. package/dist/copy/misc.js +14 -0
  6. package/dist/copy/misc.js.map +1 -1
  7. package/dist/copy/operationDefinitions.js +69 -6
  8. package/dist/copy/operationDefinitions.js.map +1 -1
  9. package/dist/generators/generateFastifyHandler.d.ts +2 -2
  10. package/dist/generators/generateFastifyHandler.js +15 -5
  11. package/dist/generators/generateFastifyHandler.js.map +1 -1
  12. package/dist/generators/generateHonoHandler.d.ts +2 -2
  13. package/dist/generators/generateHonoHandler.js +12 -5
  14. package/dist/generators/generateHonoHandler.js.map +1 -1
  15. package/dist/generators/generateImportPrismaStatement.d.ts +1 -0
  16. package/dist/generators/generateImportPrismaStatement.js +6 -0
  17. package/dist/generators/generateImportPrismaStatement.js.map +1 -1
  18. package/dist/generators/generateModelMetadata.js +20 -10
  19. package/dist/generators/generateModelMetadata.js.map +1 -1
  20. package/dist/generators/generateOperationCore.d.ts +3 -3
  21. package/dist/generators/generateOperationCore.js +51 -16
  22. package/dist/generators/generateOperationCore.js.map +1 -1
  23. package/dist/generators/generateRelationMeta.js +2 -2
  24. package/dist/generators/generateRelationMeta.js.map +1 -1
  25. package/dist/generators/generateRouteConfigType.d.ts +2 -2
  26. package/dist/generators/generateRouteConfigType.js +29 -11
  27. package/dist/generators/generateRouteConfigType.js.map +1 -1
  28. package/dist/generators/generateRouter.d.ts +7 -4
  29. package/dist/generators/generateRouter.js +107 -14
  30. package/dist/generators/generateRouter.js.map +1 -1
  31. package/dist/generators/generateRouterFastify.d.ts +7 -4
  32. package/dist/generators/generateRouterFastify.js +56 -28
  33. package/dist/generators/generateRouterFastify.js.map +1 -1
  34. package/dist/generators/generateRouterHono.d.ts +7 -4
  35. package/dist/generators/generateRouterHono.js +36 -23
  36. package/dist/generators/generateRouterHono.js.map +1 -1
  37. package/dist/generators/generateUnifiedDocs.d.ts +1 -1
  38. package/dist/generators/generateUnifiedDocs.js +15 -8
  39. package/dist/generators/generateUnifiedDocs.js.map +1 -1
  40. package/dist/generators/generateUnifiedHandler.d.ts +2 -2
  41. package/dist/generators/generateUnifiedHandler.js +11 -3
  42. package/dist/generators/generateUnifiedHandler.js.map +1 -1
  43. package/dist/guardOptions.js +12 -7
  44. package/dist/guardOptions.js.map +1 -1
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.js +22 -1
  47. package/dist/index.js.map +1 -1
  48. package/dist/utils/copyFiles.js +22 -6
  49. package/dist/utils/copyFiles.js.map +1 -1
  50. package/dist/utils/importExt.d.ts +1 -1
  51. package/dist/utils/pathCasing.d.ts +4 -0
  52. package/dist/utils/pathCasing.js +40 -0
  53. package/dist/utils/pathCasing.js.map +1 -0
  54. package/dist/utils/resolveImportStyle.js +13 -5
  55. package/dist/utils/resolveImportStyle.js.map +1 -1
  56. package/dist/utils/writeFileSafely.js.map +1 -1
  57. package/package.json +5 -3
  58. package/src/bin.ts +1 -1
  59. package/src/client/encodeQueryParams.ts +39 -35
  60. package/src/constants.ts +1 -1
  61. package/src/copy/autoIncludePlanner.ts +93 -27
  62. package/src/copy/autoIncludePlannerGuarded.ts +171 -48
  63. package/src/copy/autoIncludeRuntimeGuarded.ts +25 -7
  64. package/src/copy/buildModelOpenApi.ts +153 -50
  65. package/src/copy/concurrency.ts +10 -8
  66. package/src/copy/errorMapper.ts +68 -19
  67. package/src/copy/guardHelpers.ts +30 -9
  68. package/src/copy/materializedCount.ts +17 -5
  69. package/src/copy/misc.ts +88 -68
  70. package/src/copy/ndjson.ts +72 -0
  71. package/src/copy/operationDefinitions.ts +99 -21
  72. package/src/copy/operationRuntime.ts +100 -12
  73. package/src/copy/pagination.ts +25 -11
  74. package/src/copy/parseQueryParams.ts +47 -48
  75. package/src/copy/projectionDefaults.ts +6 -4
  76. package/src/copy/routeConfig.express.ts +16 -4
  77. package/src/copy/routeConfig.fastify.ts +16 -2
  78. package/src/copy/routeConfig.hono.ts +12 -9
  79. package/src/copy/routeConfig.ts +174 -39
  80. package/src/copy/scalarTypes.ts +7 -2
  81. package/src/copy/sse.ts +72 -19
  82. package/src/generators/generateFastifyHandler.ts +24 -13
  83. package/src/generators/generateHonoHandler.ts +21 -13
  84. package/src/generators/generateImportPrismaStatement.ts +93 -81
  85. package/src/generators/generateModelMetadata.ts +24 -12
  86. package/src/generators/generateOperationCore.ts +81 -33
  87. package/src/generators/generateRelationMeta.ts +23 -11
  88. package/src/generators/generateRouteConfigType.ts +39 -13
  89. package/src/generators/generateRouter.ts +114 -17
  90. package/src/generators/generateRouterFastify.ts +67 -31
  91. package/src/generators/generateRouterHono.ts +60 -30
  92. package/src/generators/generateUnifiedDocs.ts +29 -8
  93. package/src/generators/generateUnifiedHandler.ts +16 -8
  94. package/src/generators/generateUnifiedScalarUI.ts +1 -1
  95. package/src/guardOptions.ts +105 -92
  96. package/src/index.ts +46 -4
  97. package/src/utils/copyFiles.ts +199 -168
  98. package/src/utils/importExt.ts +2 -2
  99. package/src/utils/pathCasing.ts +42 -0
  100. package/src/utils/resolveImportStyle.ts +37 -15
  101. package/src/utils/strings.ts +2 -2
  102. package/src/utils/writeFileSafely.ts +6 -2
@@ -90,7 +90,10 @@ function guarded(
90
90
  return d.guard(shape, caller) as GuardedDelegate
91
91
  }
92
92
 
93
- function createClientGoneChecker(res: Response, signal?: AbortSignal): () => boolean {
93
+ function createClientGoneChecker(
94
+ res: Response,
95
+ signal?: AbortSignal,
96
+ ): () => boolean {
94
97
  return () => signal?.aborted === true || res.writableEnded || res.destroyed
95
98
  }
96
99
 
@@ -178,7 +181,10 @@ async function runStage(
178
181
 
179
182
  const targetModel = models[rel.type]
180
183
  if (!targetModel) {
181
- throw new HttpError(500, 'Target model not in relation metadata: ' + rel.type)
184
+ throw new HttpError(
185
+ 500,
186
+ 'Target model not in relation metadata: ' + rel.type,
187
+ )
182
188
  }
183
189
 
184
190
  const stageArgs: Record<string, unknown> = { ...stage.stageArgs }
@@ -289,14 +295,24 @@ async function runGuardedAutoIncludeSingle(
289
295
  if (!okField) return
290
296
  } catch (err) {
291
297
  if (isAborted()) return
292
- console.error(LOG_PREFIX, 'guarded stage failed:', stage.relationPath, err)
298
+ console.error(
299
+ LOG_PREFIX,
300
+ 'guarded stage failed:',
301
+ stage.relationPath,
302
+ err,
303
+ )
293
304
  stageErrorMessage = mapError(err).message
294
305
  return
295
306
  }
296
307
 
297
308
  if (isAborted()) return
298
309
  completed++
299
- const okProg = sendSSEProgress(res, stage.relationPath, completed, plan.stages.length)
310
+ const okProg = sendSSEProgress(
311
+ res,
312
+ stage.relationPath,
313
+ completed,
314
+ plan.stages.length,
315
+ )
300
316
  if (!okProg) return
301
317
  })
302
318
 
@@ -336,7 +352,8 @@ export async function runGuardedAutoIncludeProgressive(
336
352
  } catch (err) {
337
353
  return handleGuardedFallback(
338
354
  options,
339
- 'guarded auto-progressive fallback: getExtendedClient failed: ' + mapError(err).message,
355
+ 'guarded auto-progressive fallback: getExtendedClient failed: ' +
356
+ mapError(err).message,
340
357
  )
341
358
  }
342
359
 
@@ -352,7 +369,8 @@ export async function runGuardedAutoIncludeProgressive(
352
369
  } catch (err) {
353
370
  return handleGuardedFallback(
354
371
  options,
355
- 'guarded auto-progressive fallback: resolve failed: ' + mapError(err).message,
372
+ 'guarded auto-progressive fallback: resolve failed: ' +
373
+ mapError(err).message,
356
374
  )
357
375
  }
358
376
 
@@ -376,4 +394,4 @@ export async function runGuardedAutoIncludeProgressive(
376
394
  }
377
395
 
378
396
  return runGuardedAutoIncludeSingle(options, plan, extended)
379
- }
397
+ }
@@ -55,22 +55,59 @@ type BuildOptions = {
55
55
  description?: string
56
56
  version?: string
57
57
  writeStrategy?: WriteStrategy
58
+ pathSegment?: string
58
59
  }
59
60
 
60
- const WHERE_PROP: SchemaObject = { type: 'object', description: 'Filter conditions' }
61
- const TAKE_PROP: SchemaObject = { type: 'integer', description: 'Limit results' }
61
+ const WHERE_PROP: SchemaObject = {
62
+ type: 'object',
63
+ description: 'Filter conditions',
64
+ }
65
+ const TAKE_PROP: SchemaObject = {
66
+ type: 'integer',
67
+ description: 'Limit results',
68
+ }
62
69
  const SKIP_PROP: SchemaObject = { type: 'integer', description: 'Skip results' }
63
- const CURSOR_PROP: SchemaObject = { type: 'object', description: 'Cursor for pagination' }
64
- const ORDERBY_PROP: SchemaObject = { description: 'Sort order (object or array of objects)' }
65
- const SELECT_PROP: SchemaObject = { type: 'object', description: 'Select fields' }
66
- const INCLUDE_PROP: SchemaObject = { type: 'object', description: 'Include relations' }
67
- const OMIT_PROP: SchemaObject = { type: 'object', description: 'Omit fields from response' }
68
- const DISTINCT_PROP: SchemaObject = { description: 'Distinct fields (string or array of strings)' }
69
- const AGG_COUNT: SchemaObject = { description: 'Count aggregate (true or field selection object)' }
70
- const AGG_AVG: SchemaObject = { type: 'object', description: 'Average aggregate (field selection object)' }
71
- const AGG_SUM: SchemaObject = { type: 'object', description: 'Sum aggregate (field selection object)' }
72
- const AGG_MIN: SchemaObject = { type: 'object', description: 'Min aggregate (field selection object)' }
73
- const AGG_MAX: SchemaObject = { type: 'object', description: 'Max aggregate (field selection object)' }
70
+ const CURSOR_PROP: SchemaObject = {
71
+ type: 'object',
72
+ description: 'Cursor for pagination',
73
+ }
74
+ const ORDERBY_PROP: SchemaObject = {
75
+ description: 'Sort order (object or array of objects)',
76
+ }
77
+ const SELECT_PROP: SchemaObject = {
78
+ type: 'object',
79
+ description: 'Select fields',
80
+ }
81
+ const INCLUDE_PROP: SchemaObject = {
82
+ type: 'object',
83
+ description: 'Include relations',
84
+ }
85
+ const OMIT_PROP: SchemaObject = {
86
+ type: 'object',
87
+ description: 'Omit fields from response',
88
+ }
89
+ const DISTINCT_PROP: SchemaObject = {
90
+ description: 'Distinct fields (string or array of strings)',
91
+ }
92
+ const AGG_COUNT: SchemaObject = {
93
+ description: 'Count aggregate (true or field selection object)',
94
+ }
95
+ const AGG_AVG: SchemaObject = {
96
+ type: 'object',
97
+ description: 'Average aggregate (field selection object)',
98
+ }
99
+ const AGG_SUM: SchemaObject = {
100
+ type: 'object',
101
+ description: 'Sum aggregate (field selection object)',
102
+ }
103
+ const AGG_MIN: SchemaObject = {
104
+ type: 'object',
105
+ description: 'Min aggregate (field selection object)',
106
+ }
107
+ const AGG_MAX: SchemaObject = {
108
+ type: 'object',
109
+ description: 'Max aggregate (field selection object)',
110
+ }
74
111
 
75
112
  const PROJECTION_PROPS: Record<string, SchemaObject> = {
76
113
  select: SELECT_PROP,
@@ -330,8 +367,18 @@ function applyWriteStrategy(
330
367
  verb: string
331
368
  targetOp: string
332
369
  }> = [
333
- { method: 'post', successCode: '201', verb: 'Create', targetOp: 'createManyAndReturn' },
334
- { method: 'put', successCode: '200', verb: 'Update', targetOp: 'updateManyAndReturn' },
370
+ {
371
+ method: 'post',
372
+ successCode: '201',
373
+ verb: 'Create',
374
+ targetOp: 'createManyAndReturn',
375
+ },
376
+ {
377
+ method: 'put',
378
+ successCode: '200',
379
+ verb: 'Update',
380
+ targetOp: 'updateManyAndReturn',
381
+ },
335
382
  ]
336
383
 
337
384
  for (const entry of forceReturnOps) {
@@ -341,9 +388,11 @@ function applyWriteStrategy(
341
388
  target,
342
389
  entry.successCode,
343
390
  entry.verb + ' many ' + modelName + ' (forceReturn)',
344
- 'writeStrategy="forceReturn": this endpoint silently invokes ' + entry.targetOp +
345
- ' and returns the ' + (entry.verb === 'Create' ? 'created' : 'updated') +
346
- ' records instead of { count }.',
391
+ 'writeStrategy="forceReturn": this endpoint silently invokes ' +
392
+ entry.targetOp +
393
+ ' and returns the ' +
394
+ (entry.verb === 'Create' ? 'created' : 'updated') +
395
+ ' records instead of { count }.',
347
396
  )
348
397
  }
349
398
  }
@@ -382,7 +431,9 @@ export function buildModelOpenApi(
382
431
  const basePath =
383
432
  normalizePrefix(prefixSource) +
384
433
  removeTrailingSlash(
385
- config.addModelPrefix !== false ? `/${modelName.toLowerCase()}` : '',
434
+ config.addModelPrefix !== false
435
+ ? `/${options.pathSegment ?? modelName.toLowerCase()}`
436
+ : '',
386
437
  )
387
438
 
388
439
  const referencedEnumTypes = new Set(
@@ -794,20 +845,47 @@ function generatePaths(
794
845
  config: RouteConfig,
795
846
  fields: ModelField[],
796
847
  ) {
797
- const postReads = !config.disablePostReads
848
+ const postReadsFor = (op: string): boolean => {
849
+ const raw: unknown = (config as Record<string, unknown>)[op]
850
+ const opValue =
851
+ raw && typeof raw === 'object'
852
+ ? (raw as { disablePostReads?: boolean }).disablePostReads
853
+ : undefined
854
+ return !(opValue ?? config.disablePostReads ?? false)
855
+ }
798
856
 
799
- const createInputRef = { $ref: `#/components/schemas/${modelName}CreateInput` }
800
- const updateInputRef = { $ref: `#/components/schemas/${modelName}UpdateInput` }
801
- const createManyInputRef = { $ref: `#/components/schemas/${modelName}CreateManyInput` }
802
- const updateManyMutationRef = { $ref: `#/components/schemas/${modelName}UpdateManyMutationInput` }
857
+ const createInputRef = {
858
+ $ref: `#/components/schemas/${modelName}CreateInput`,
859
+ }
860
+ const updateInputRef = {
861
+ $ref: `#/components/schemas/${modelName}UpdateInput`,
862
+ }
863
+ const createManyInputRef = {
864
+ $ref: `#/components/schemas/${modelName}CreateManyInput`,
865
+ }
866
+ const updateManyMutationRef = {
867
+ $ref: `#/components/schemas/${modelName}UpdateManyMutationInput`,
868
+ }
803
869
  const responseRef = { $ref: `#/components/schemas/${modelName}Response` }
804
- const nullableResponseSchema = { oneOf: [responseRef, { type: 'null' as const }] }
805
- const batchCountRef = { $ref: `#/components/schemas/${modelName}BatchCountResponse` }
870
+ const nullableResponseSchema = {
871
+ oneOf: [responseRef, { type: 'null' as const }],
872
+ }
873
+ const batchCountRef = {
874
+ $ref: `#/components/schemas/${modelName}BatchCountResponse`,
875
+ }
806
876
  const listRef = { $ref: `#/components/schemas/${modelName}ListResponse` }
807
- const aggregateRef = { $ref: `#/components/schemas/${modelName}AggregateResponse` }
808
- const groupByItemRef = { $ref: `#/components/schemas/${modelName}GroupByItem` }
809
- const updateEachItemRef = { $ref: `#/components/schemas/${modelName}UpdateEachItemInput` }
810
- const updateEachResponseRef = { $ref: `#/components/schemas/${modelName}UpdateEachResponse` }
877
+ const aggregateRef = {
878
+ $ref: `#/components/schemas/${modelName}AggregateResponse`,
879
+ }
880
+ const groupByItemRef = {
881
+ $ref: `#/components/schemas/${modelName}GroupByItem`,
882
+ }
883
+ const updateEachItemRef = {
884
+ $ref: `#/components/schemas/${modelName}UpdateEachItemInput`,
885
+ }
886
+ const updateEachResponseRef = {
887
+ $ref: `#/components/schemas/${modelName}UpdateEachResponse`,
888
+ }
811
889
 
812
890
  if (opEnabled(config, 'findMany')) {
813
891
  const meta = OPERATION_BY_NAME['findMany']
@@ -830,7 +908,7 @@ function generatePaths(
830
908
  addErrorResponses(op, meta.errors)
831
909
  addPath(spec, opPath(basePath, 'findMany'), 'get', op)
832
910
 
833
- if (postReads) {
911
+ if (postReadsFor('findMany')) {
834
912
  addPostReadOperation(
835
913
  spec,
836
914
  postReadPath(basePath, 'findMany'),
@@ -862,7 +940,7 @@ function generatePaths(
862
940
  addErrorResponses(op, meta.errors)
863
941
  addPath(spec, opPath(basePath, 'findUnique'), 'get', op)
864
942
 
865
- if (postReads) {
943
+ if (postReadsFor('findUnique')) {
866
944
  addPostReadOperation(
867
945
  spec,
868
946
  postReadPath(basePath, 'findUnique'),
@@ -893,7 +971,7 @@ function generatePaths(
893
971
  addErrorResponses(op, meta.errors)
894
972
  addPath(spec, opPath(basePath, 'findUniqueOrThrow'), 'get', op)
895
973
 
896
- if (postReads) {
974
+ if (postReadsFor('findUniqueOrThrow')) {
897
975
  addPostReadOperation(
898
976
  spec,
899
977
  postReadPath(basePath, 'findUniqueOrThrow'),
@@ -924,7 +1002,7 @@ function generatePaths(
924
1002
  addErrorResponses(op, meta.errors)
925
1003
  addPath(spec, opPath(basePath, 'findFirst'), 'get', op)
926
1004
 
927
- if (postReads) {
1005
+ if (postReadsFor('findFirst')) {
928
1006
  addPostReadOperation(
929
1007
  spec,
930
1008
  postReadPath(basePath, 'findFirst'),
@@ -955,7 +1033,7 @@ function generatePaths(
955
1033
  addErrorResponses(op, meta.errors)
956
1034
  addPath(spec, opPath(basePath, 'findFirstOrThrow'), 'get', op)
957
1035
 
958
- if (postReads) {
1036
+ if (postReadsFor('findFirstOrThrow')) {
959
1037
  addPostReadOperation(
960
1038
  spec,
961
1039
  postReadPath(basePath, 'findFirstOrThrow'),
@@ -987,7 +1065,7 @@ function generatePaths(
987
1065
  addErrorResponses(op, meta.errors)
988
1066
  addPath(spec, opPath(basePath, 'findManyPaginated'), 'get', op)
989
1067
 
990
- if (postReads) {
1068
+ if (postReadsFor('findManyPaginated')) {
991
1069
  addPostReadOperation(
992
1070
  spec,
993
1071
  postReadPath(basePath, 'findManyPaginated'),
@@ -1327,7 +1405,8 @@ function generatePaths(
1327
1405
  },
1328
1406
  {
1329
1407
  type: 'object',
1330
- description: 'Per-field count object when select is provided',
1408
+ description:
1409
+ 'Per-field count object when select is provided',
1331
1410
  },
1332
1411
  ],
1333
1412
  },
@@ -1339,7 +1418,7 @@ function generatePaths(
1339
1418
  addErrorResponses(op, meta.errors)
1340
1419
  addPath(spec, opPath(basePath, 'count'), 'get', op)
1341
1420
 
1342
- if (postReads) {
1421
+ if (postReadsFor('count')) {
1343
1422
  addPostReadOperation(
1344
1423
  spec,
1345
1424
  postReadPath(basePath, 'count'),
@@ -1380,7 +1459,7 @@ function generatePaths(
1380
1459
  addErrorResponses(op, meta.errors)
1381
1460
  addPath(spec, opPath(basePath, 'aggregate'), 'get', op)
1382
1461
 
1383
- if (postReads) {
1462
+ if (postReadsFor('aggregate')) {
1384
1463
  addPostReadOperation(
1385
1464
  spec,
1386
1465
  postReadPath(basePath, 'aggregate'),
@@ -1416,7 +1495,7 @@ function generatePaths(
1416
1495
  addErrorResponses(op, meta.errors)
1417
1496
  addPath(spec, opPath(basePath, 'groupBy'), 'get', op)
1418
1497
 
1419
- if (postReads) {
1498
+ if (postReadsFor('groupBy')) {
1420
1499
  addPostReadOperation(
1421
1500
  spec,
1422
1501
  postReadPath(basePath, 'groupBy'),
@@ -1581,12 +1660,30 @@ function mapFieldToSchema(field: ModelField): SchemaObject | RefObject {
1581
1660
  }
1582
1661
 
1583
1662
  function nestedListRelationOps(fieldType: string): SchemaObject {
1584
- const createInput: SchemaObject = { type: 'object', description: `${fieldType} create input` }
1585
- const uniqueId: SchemaObject = { type: 'object', description: 'Unique identifier' }
1586
- const uniqueConnect: SchemaObject = { type: 'object', description: 'Unique identifier to connect' }
1587
- const uniqueDisconnect: SchemaObject = { type: 'object', description: 'Unique identifier to disconnect' }
1588
- const uniqueDelete: SchemaObject = { type: 'object', description: 'Unique identifier to delete' }
1589
- const whereFilter: SchemaObject = { type: 'object', description: 'Where filter' }
1663
+ const createInput: SchemaObject = {
1664
+ type: 'object',
1665
+ description: `${fieldType} create input`,
1666
+ }
1667
+ const uniqueId: SchemaObject = {
1668
+ type: 'object',
1669
+ description: 'Unique identifier',
1670
+ }
1671
+ const uniqueConnect: SchemaObject = {
1672
+ type: 'object',
1673
+ description: 'Unique identifier to connect',
1674
+ }
1675
+ const uniqueDisconnect: SchemaObject = {
1676
+ type: 'object',
1677
+ description: 'Unique identifier to disconnect',
1678
+ }
1679
+ const uniqueDelete: SchemaObject = {
1680
+ type: 'object',
1681
+ description: 'Unique identifier to delete',
1682
+ }
1683
+ const whereFilter: SchemaObject = {
1684
+ type: 'object',
1685
+ description: 'Where filter',
1686
+ }
1590
1687
  const whereCreatePair: SchemaObject = {
1591
1688
  type: 'object',
1592
1689
  description: '{ where, create } pair',
@@ -1648,12 +1745,16 @@ function nestedSingleRelationOps(fieldType: string): SchemaObject {
1648
1745
  description: '{ where, create } pair',
1649
1746
  properties: { where: { type: 'object' }, create: { type: 'object' } },
1650
1747
  },
1651
- disconnect: { type: 'boolean', description: 'Disconnect the related record' },
1748
+ disconnect: {
1749
+ type: 'boolean',
1750
+ description: 'Disconnect the related record',
1751
+ },
1652
1752
  delete: { type: 'boolean', description: 'Delete the related record' },
1653
1753
  update: { type: 'object', description: `${fieldType} update input` },
1654
1754
  upsert: {
1655
1755
  type: 'object',
1656
- description: '{ create, update } pair — create if not exists, update if exists',
1756
+ description:
1757
+ '{ create, update } pair — create if not exists, update if exists',
1657
1758
  properties: {
1658
1759
  create: { type: 'object', description: `${fieldType} create input` },
1659
1760
  update: { type: 'object', description: `${fieldType} update input` },
@@ -1668,7 +1769,9 @@ function mapFieldToWriteSchema(
1668
1769
  mode: 'create' | 'update',
1669
1770
  ): SchemaObject | RefObject {
1670
1771
  if (field.kind === 'object') {
1671
- return field.isList ? nestedListRelationOps(field.type) : nestedSingleRelationOps(field.type)
1772
+ return field.isList
1773
+ ? nestedListRelationOps(field.type)
1774
+ : nestedSingleRelationOps(field.type)
1672
1775
  }
1673
1776
 
1674
1777
  let baseSchema: SchemaObject | RefObject
@@ -1733,4 +1836,4 @@ function mapScalarType(type: string): SchemaObject {
1733
1836
  },
1734
1837
  }
1735
1838
  return typeMap[type] || { type: 'string' }
1736
- }
1839
+ }
@@ -8,13 +8,15 @@ export async function mapLimited<T>(
8
8
  const workerCount = Math.min(limit, items.length)
9
9
  const workers: Promise<void>[] = []
10
10
  for (let w = 0; w < workerCount; w++) {
11
- workers.push((async () => {
12
- for (;;) {
13
- const i = index++
14
- if (i >= items.length) return
15
- await fn(items[i], i)
16
- }
17
- })())
11
+ workers.push(
12
+ (async () => {
13
+ for (;;) {
14
+ const i = index++
15
+ if (i >= items.length) return
16
+ await fn(items[i], i)
17
+ }
18
+ })(),
19
+ )
18
20
  }
19
21
  await Promise.all(workers)
20
- }
22
+ }
@@ -36,10 +36,19 @@ const PRISMA_ERROR_MAP: Record<string, { status: number; message: string }> = {
36
36
  P2023: { status: 500, message: 'Inconsistent column data' },
37
37
  P2024: { status: 503, message: 'Connection pool timeout' },
38
38
  P2025: { status: 404, message: 'Record not found' },
39
- P2026: { status: 501, message: 'Feature not supported by the current database provider' },
40
- P2027: { status: 400, message: 'Multiple errors occurred during transaction execution' },
39
+ P2026: {
40
+ status: 501,
41
+ message: 'Feature not supported by the current database provider',
42
+ },
43
+ P2027: {
44
+ status: 400,
45
+ message: 'Multiple errors occurred during transaction execution',
46
+ },
41
47
  P2028: { status: 500, message: 'Transaction API error' },
42
- P2030: { status: 400, message: 'Cannot find a fulltext index for the search' },
48
+ P2030: {
49
+ status: 400,
50
+ message: 'Cannot find a fulltext index for the search',
51
+ },
43
52
  P2033: { status: 400, message: 'Number out of range for the field type' },
44
53
  P2034: { status: 409, message: 'Transaction conflict, please retry' },
45
54
  }
@@ -59,11 +68,20 @@ function asErrorShape(error: unknown): ErrorShape {
59
68
  }
60
69
 
61
70
  function isProduction(): boolean {
62
- return typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'production'
71
+ return (
72
+ typeof process !== 'undefined' &&
73
+ process.env &&
74
+ process.env.NODE_ENV === 'production'
75
+ )
63
76
  }
64
77
 
65
78
  function isHttpStatus(value: unknown): value is number {
66
- return typeof value === 'number' && Number.isInteger(value) && value >= 400 && value <= 599
79
+ return (
80
+ typeof value === 'number' &&
81
+ Number.isInteger(value) &&
82
+ value >= 400 &&
83
+ value <= 599
84
+ )
67
85
  }
68
86
 
69
87
  export function mapError(error: unknown): HttpError {
@@ -77,18 +95,27 @@ export function mapError(error: unknown): HttpError {
77
95
  ? e.statusCode
78
96
  : null
79
97
  if (duckStatus !== null) {
80
- const detail = typeof e.message === 'string' && e.message ? e.message : 'Internal server error'
98
+ const detail =
99
+ typeof e.message === 'string' && e.message
100
+ ? e.message
101
+ : 'Internal server error'
81
102
  return new HttpError(duckStatus, detail)
82
103
  }
83
104
 
84
- if (e.name === 'ShapeError') return new HttpError(400, e.message || 'Shape validation failed')
85
- if (e.name === 'CallerError') return new HttpError(400, e.message || 'Caller validation failed')
86
- if (e.name === 'PolicyError') return new HttpError(403, e.message || 'Policy denied')
105
+ if (e.name === 'ShapeError')
106
+ return new HttpError(400, e.message || 'Shape validation failed')
107
+ if (e.name === 'CallerError')
108
+ return new HttpError(400, e.message || 'Caller validation failed')
109
+ if (e.name === 'PolicyError')
110
+ return new HttpError(403, e.message || 'Policy denied')
87
111
  if (e.name === 'ZodError') {
88
112
  const issues = e.issues
89
113
  const message = Array.isArray(issues)
90
- ? (issues as Array<{ message?: string }>).map((i) => i.message ?? '').filter(Boolean).join('; ')
91
- : (e.message || 'Validation failed')
114
+ ? (issues as Array<{ message?: string }>)
115
+ .map((i) => i.message ?? '')
116
+ .filter(Boolean)
117
+ .join('; ')
118
+ : e.message || 'Validation failed'
92
119
  return new HttpError(400, message)
93
120
  }
94
121
  if (typeof e.code === 'string') {
@@ -98,7 +125,9 @@ export function mapError(error: unknown): HttpError {
98
125
  const shouldStripDetail = isProd && mapped.status >= 500
99
126
  return new HttpError(
100
127
  mapped.status,
101
- !shouldStripDetail && detail ? mapped.message + ': ' + detail : mapped.message,
128
+ !shouldStripDetail && detail
129
+ ? mapped.message + ': ' + detail
130
+ : mapped.message,
102
131
  )
103
132
  }
104
133
  if (e.code.startsWith('P')) {
@@ -108,19 +137,39 @@ export function mapError(error: unknown): HttpError {
108
137
  }
109
138
  }
110
139
  if (typeof e.name === 'string') {
111
- if (e.name === 'PrismaClientValidationError') return new HttpError(400, e.message || 'Invalid query parameters')
112
- if (e.name === 'PrismaClientKnownRequestError') return new HttpError(400, e.message || 'Database request error')
140
+ if (e.name === 'PrismaClientValidationError')
141
+ return new HttpError(400, e.message || 'Invalid query parameters')
142
+ if (e.name === 'PrismaClientKnownRequestError')
143
+ return new HttpError(400, e.message || 'Database request error')
113
144
  if (e.name === 'PrismaClientInitializationError') {
114
- return new HttpError(503, isProd ? 'Service unavailable' : (e.message || 'Database connection failed'))
145
+ return new HttpError(
146
+ 503,
147
+ isProd
148
+ ? 'Service unavailable'
149
+ : e.message || 'Database connection failed',
150
+ )
115
151
  }
116
152
  if (e.name === 'PrismaClientRustPanicError') {
117
- return new HttpError(500, isProd ? 'Internal server error' : (e.message || 'Internal database engine error'))
153
+ return new HttpError(
154
+ 500,
155
+ isProd
156
+ ? 'Internal server error'
157
+ : e.message || 'Internal database engine error',
158
+ )
118
159
  }
119
160
  if (e.name === 'PrismaClientUnknownRequestError') {
120
- return new HttpError(500, isProd ? 'Internal server error' : (e.message || 'Unknown database error'))
161
+ return new HttpError(
162
+ 500,
163
+ isProd
164
+ ? 'Internal server error'
165
+ : e.message || 'Unknown database error',
166
+ )
121
167
  }
122
168
  }
123
169
  const msg = error instanceof Error ? error.message : String(error)
124
170
  console.error(LOG_PREFIX, 'Unhandled error:', error)
125
- return new HttpError(500, isProd ? 'Internal server error' : (msg || 'Internal server error'))
126
- }
171
+ return new HttpError(
172
+ 500,
173
+ isProd ? 'Internal server error' : msg || 'Internal server error',
174
+ )
175
+ }
@@ -3,12 +3,17 @@ import { HttpError } from './errorMapper'
3
3
  export type PrismaDelegateLike = {
4
4
  count: (args?: unknown) => Promise<unknown>
5
5
  findMany: (args?: unknown) => Promise<unknown>
6
- guard?: (shape: Record<string, unknown>, caller?: string) => PrismaDelegateLike
6
+ guard?: (
7
+ shape: Record<string, unknown>,
8
+ caller?: string,
9
+ ) => PrismaDelegateLike
7
10
  }
8
11
 
9
- export function assertGuard(
10
- delegate: PrismaDelegateLike,
11
- ): asserts delegate is PrismaDelegateLike & { guard: NonNullable<PrismaDelegateLike['guard']> } {
12
+ export function assertGuard<T extends PrismaDelegateLike>(
13
+ delegate: T,
14
+ ): asserts delegate is T & {
15
+ guard: NonNullable<T['guard']>
16
+ } {
12
17
  if (typeof delegate.guard !== 'function') {
13
18
  throw new HttpError(
14
19
  500,
@@ -18,9 +23,24 @@ export function assertGuard(
18
23
  }
19
24
 
20
25
  export const GUARD_SHAPE_CONFIG_KEYS = new Set([
21
- 'data', 'create', 'update', 'where', 'include', 'select', 'orderBy',
22
- 'cursor', 'take', 'skip', 'distinct', 'having', '_count', '_avg',
23
- '_sum', '_min', '_max', 'by',
26
+ 'data',
27
+ 'create',
28
+ 'update',
29
+ 'where',
30
+ 'include',
31
+ 'select',
32
+ 'orderBy',
33
+ 'cursor',
34
+ 'take',
35
+ 'skip',
36
+ 'distinct',
37
+ 'having',
38
+ '_count',
39
+ '_avg',
40
+ '_sum',
41
+ '_min',
42
+ '_max',
43
+ 'by',
24
44
  ])
25
45
 
26
46
  function keepWhereOnly(obj: Record<string, unknown>): Record<string, unknown> {
@@ -39,7 +59,8 @@ export function buildCountShape(
39
59
  return (...args: unknown[]) => keepWhereOnly(fn(...args))
40
60
  }
41
61
  const keys = Object.keys(shape)
42
- const isSingleShape = keys.length === 0 || keys.every((k) => GUARD_SHAPE_CONFIG_KEYS.has(k))
62
+ const isSingleShape =
63
+ keys.length === 0 || keys.every((k) => GUARD_SHAPE_CONFIG_KEYS.has(k))
43
64
  if (isSingleShape) return keepWhereOnly(shape)
44
65
  const result: Record<string, unknown> = {}
45
66
  for (const [key, variant] of Object.entries(shape)) {
@@ -53,4 +74,4 @@ export function buildCountShape(
53
74
  }
54
75
  }
55
76
  return result
56
- }
77
+ }