prisma-generator-express 1.57.0 → 1.58.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.
- package/README.md +111 -29
- package/dist/copy/misc.js +25 -6
- package/dist/copy/misc.js.map +1 -1
- package/dist/generators/generateFastifyHandler.js +11 -0
- package/dist/generators/generateFastifyHandler.js.map +1 -1
- package/dist/generators/generateHonoHandler.js +14 -20
- package/dist/generators/generateHonoHandler.js.map +1 -1
- package/dist/generators/generateImportPrismaStatement.js +7 -1
- package/dist/generators/generateImportPrismaStatement.js.map +1 -1
- package/dist/generators/generateOperationCore.js +58 -17
- package/dist/generators/generateOperationCore.js.map +1 -1
- package/dist/generators/generateRouteConfigType.js +12 -7
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.js +57 -32
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.js +235 -191
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.js +121 -87
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/copy/autoIncludeRuntime.ts +9 -5
- package/src/copy/buildModelOpenApi.ts +96 -0
- package/src/copy/docsRenderer.ts +577 -174
- package/src/copy/materializedRouter.ts +40 -1
- package/src/copy/misc.ts +23 -6
- package/src/copy/operationDefinitions.ts +10 -0
- package/src/copy/operationRuntime.ts +28 -9
- package/src/copy/routeConfig.express.ts +9 -9
- package/src/copy/routeConfig.hono.ts +63 -5
- package/src/copy/routeConfig.ts +44 -22
- package/src/generators/generateFastifyHandler.ts +12 -0
- package/src/generators/generateHonoHandler.ts +15 -20
- package/src/generators/generateImportPrismaStatement.ts +10 -1
- package/src/generators/generateOperationCore.ts +58 -17
- package/src/generators/generateRouteConfigType.ts +13 -8
- package/src/generators/generateRouter.ts +57 -32
- package/src/generators/generateRouterFastify.ts +235 -191
- package/src/generators/generateRouterHono.ts +121 -87
- package/src/index.ts +6 -4
|
@@ -50,10 +50,9 @@ export function generateHonoRouterFunction({
|
|
|
50
50
|
}))
|
|
51
51
|
|
|
52
52
|
return `import { Hono } from 'hono'
|
|
53
|
-
import type { Context
|
|
53
|
+
import type { Context } from 'hono'
|
|
54
54
|
import type { ContentfulStatusCode } from 'hono/utils/http-status'
|
|
55
55
|
import { HTTPException } from 'hono/http-exception'
|
|
56
|
-
import { startQueryBuilder } from '../queryBuilder${ext}'
|
|
57
56
|
import {
|
|
58
57
|
${modelName}FindUnique,
|
|
59
58
|
${modelName}FindUniqueOrThrow,
|
|
@@ -73,32 +72,32 @@ import {
|
|
|
73
72
|
${modelName}Aggregate,
|
|
74
73
|
${modelName}Count,
|
|
75
74
|
${modelName}GroupBy,
|
|
75
|
+
${modelName}UpdateEach,
|
|
76
76
|
} from './${modelName}Handlers${ext}'
|
|
77
77
|
import type {
|
|
78
78
|
RouteConfig,
|
|
79
|
-
|
|
79
|
+
HonoBeforeHook,
|
|
80
|
+
HonoAfterHook,
|
|
80
81
|
HonoEnvBase,
|
|
81
82
|
HonoInternalVariables,
|
|
82
83
|
GeneratedHonoEnv,
|
|
83
84
|
WriteStrategy,
|
|
84
|
-
FindManyPaginatedMode,
|
|
85
85
|
PaginationConfig,
|
|
86
86
|
} from '../routeConfig.target${ext}'
|
|
87
87
|
import { parseQueryParams } from '../parseQueryParams${ext}'
|
|
88
|
-
import {
|
|
88
|
+
import { normalizePrefix, getEnv, sanitizeKeys } from '../misc${ext}'
|
|
89
89
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
90
|
+
import { validateCountSourceWhere } from '../routeConfig${ext}'
|
|
90
91
|
import {
|
|
91
92
|
mapError,
|
|
92
93
|
transformResult,
|
|
93
94
|
mergePaginationConfig,
|
|
94
|
-
type OperationContext,
|
|
95
95
|
} from '../operationRuntime${ext}'
|
|
96
96
|
|
|
97
|
-
${generateRouteConfigType(modelName, '
|
|
97
|
+
${generateRouteConfigType(modelName, 'HonoBeforeHook', guardShapesImport, importStyle, 'hono')}
|
|
98
98
|
const _env = getEnv()
|
|
99
99
|
|
|
100
100
|
const WRITE_STRATEGY: WriteStrategy = '${writeStrategy}'
|
|
101
|
-
const FIND_MANY_PAGINATED_MODE: FindManyPaginatedMode = '${findManyPaginatedMode}'
|
|
102
101
|
const DROP_GUARD = ${dropGuard} || _env.E2E === 'true'
|
|
103
102
|
|
|
104
103
|
const MODEL_FIELDS = ${JSON.stringify(fieldsMeta, null, 2)} as const
|
|
@@ -106,8 +105,8 @@ const MODEL_FIELDS = ${JSON.stringify(fieldsMeta, null, 2)} as const
|
|
|
106
105
|
const MODEL_ENUMS = ${JSON.stringify(enumsMeta, null, 2)} as const
|
|
107
106
|
|
|
108
107
|
type OperationConfigLike<TEnv extends HonoEnvBase> = {
|
|
109
|
-
before?:
|
|
110
|
-
after?:
|
|
108
|
+
before?: HonoBeforeHook<TEnv>[]
|
|
109
|
+
after?: HonoAfterHook<TEnv>[]
|
|
111
110
|
shape?: Record<string, unknown>
|
|
112
111
|
pagination?: Partial<PaginationConfig>
|
|
113
112
|
}
|
|
@@ -117,20 +116,7 @@ const defaultOpConfig = Object.freeze({
|
|
|
117
116
|
after: Object.freeze([]),
|
|
118
117
|
}) as unknown as OperationConfigLike<HonoEnvBase>
|
|
119
118
|
|
|
120
|
-
type HandlerContext = Context<{ Variables: HonoInternalVariables
|
|
121
|
-
|
|
122
|
-
function isQueryBuilderEnabled(config: RouteConfig): boolean {
|
|
123
|
-
if (config.queryBuilder === false) return false
|
|
124
|
-
if (typeof config.queryBuilder === 'object' && config.queryBuilder.enabled === false) return false
|
|
125
|
-
if (_env.NODE_ENV === 'production') return false
|
|
126
|
-
return true
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function getQueryBuilderConfig(config: RouteConfig) {
|
|
130
|
-
if (config.queryBuilder === false) return null
|
|
131
|
-
if (typeof config.queryBuilder === 'object') return config.queryBuilder
|
|
132
|
-
return {}
|
|
133
|
-
}
|
|
119
|
+
type HandlerContext = Context<{ Variables: HonoInternalVariables }>
|
|
134
120
|
|
|
135
121
|
async function parseQueryMiddleware(c: HandlerContext): Promise<void> {
|
|
136
122
|
const raw = c.req.query() as Record<string, unknown>
|
|
@@ -162,7 +148,20 @@ async function parseWriteBodyMiddleware(c: HandlerContext): Promise<void> {
|
|
|
162
148
|
if (!body || typeof body !== 'object' || Array.isArray(body)) {
|
|
163
149
|
throw new HTTPException(400, { message: 'Request body must be a JSON object' })
|
|
164
150
|
}
|
|
165
|
-
c.set('body',
|
|
151
|
+
c.set('body', body)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function parseUpdateEachBodyMiddleware(c: HandlerContext): Promise<void> {
|
|
155
|
+
let body: unknown
|
|
156
|
+
try {
|
|
157
|
+
body = await c.req.json()
|
|
158
|
+
} catch {
|
|
159
|
+
throw new HTTPException(400, { message: 'updateEach body must be an array of { where, data } items' })
|
|
160
|
+
}
|
|
161
|
+
if (!Array.isArray(body)) {
|
|
162
|
+
throw new HTTPException(400, { message: 'updateEach body must be an array of { where, data } items' })
|
|
163
|
+
}
|
|
164
|
+
c.set('body', body)
|
|
166
165
|
}
|
|
167
166
|
|
|
168
167
|
function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
@@ -174,7 +173,6 @@ function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
|
174
173
|
if (merged) {
|
|
175
174
|
c.set('routeConfig', { pagination: merged })
|
|
176
175
|
}
|
|
177
|
-
;(c as unknown as HandlerContext).set('findManyPaginatedMode', FIND_MANY_PAGINATED_MODE)
|
|
178
176
|
const headerName = config.guard?.variantHeader || 'x-api-variant'
|
|
179
177
|
const headerValue = c.req.header(headerName)
|
|
180
178
|
const caller = config.guard?.resolveVariant?.(c) ?? headerValue ?? undefined
|
|
@@ -185,26 +183,24 @@ function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
|
185
183
|
}
|
|
186
184
|
}
|
|
187
185
|
|
|
188
|
-
async function
|
|
189
|
-
hooks:
|
|
186
|
+
async function runBeforeHooks<TEnv extends HonoEnvBase>(
|
|
187
|
+
hooks: HonoBeforeHook<TEnv>[],
|
|
190
188
|
c: Context<GeneratedHonoEnv<TEnv>>,
|
|
191
189
|
): Promise<Response | undefined> {
|
|
192
190
|
for (const hook of hooks) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
191
|
+
const result = await hook(c)
|
|
192
|
+
if (result instanceof Response) return result
|
|
193
|
+
}
|
|
194
|
+
return undefined
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function runAfterHooks<TEnv extends HonoEnvBase>(
|
|
198
|
+
hooks: HonoAfterHook<TEnv>[],
|
|
199
|
+
c: Context<GeneratedHonoEnv<TEnv>>,
|
|
200
|
+
): Promise<Response | undefined> {
|
|
201
|
+
for (const hook of hooks) {
|
|
202
|
+
const result = await hook(c)
|
|
198
203
|
if (result instanceof Response) return result
|
|
199
|
-
if (!advanced) {
|
|
200
|
-
if (_env.NODE_ENV !== 'production') {
|
|
201
|
-
console.warn(
|
|
202
|
-
'[hono-router] Hook returned without calling next() or returning a Response. ' +
|
|
203
|
-
'Use \`return c.json(...)\` to short-circuit, or \`await next()\` to continue.',
|
|
204
|
-
)
|
|
205
|
-
}
|
|
206
|
-
return c.body(null) ?? undefined
|
|
207
|
-
}
|
|
208
204
|
}
|
|
209
205
|
return undefined
|
|
210
206
|
}
|
|
@@ -219,69 +215,81 @@ function sendResult(c: HandlerContext): Response {
|
|
|
219
215
|
}
|
|
220
216
|
|
|
221
217
|
function sendError(c: HandlerContext, error: unknown): Response {
|
|
218
|
+
if (error instanceof HTTPException) {
|
|
219
|
+
return c.json({ message: error.message }, error.status as ContentfulStatusCode)
|
|
220
|
+
}
|
|
222
221
|
const httpError = mapError(error)
|
|
223
222
|
return c.json({ message: httpError.message }, httpError.status as ContentfulStatusCode)
|
|
224
223
|
}
|
|
225
224
|
|
|
226
225
|
export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extends HonoEnvBase = HonoEnvBase>(config: ${modelName}RouteConfig<TCtx, TPrisma, TEnv> = {}): Hono<GeneratedHonoEnv<TEnv>> {
|
|
226
|
+
validateCountSourceWhere(config.pagination?.countSource, '${modelName} pagination')
|
|
227
|
+
validateCountSourceWhere(
|
|
228
|
+
(config.findManyPaginated && typeof config.findManyPaginated === 'object' ? config.findManyPaginated : undefined)?.pagination?.countSource,
|
|
229
|
+
'${modelName} findManyPaginated pagination',
|
|
230
|
+
)
|
|
231
|
+
|
|
227
232
|
const app = new Hono<GeneratedHonoEnv<TEnv>>()
|
|
228
233
|
|
|
234
|
+
const isEnabled = (value: unknown): boolean => value !== false && !!(config.enableAll || value)
|
|
235
|
+
|
|
229
236
|
const customPrefix = normalizePrefix(config.customUrlPrefix || '')
|
|
230
237
|
const modelPrefix = config.addModelPrefix !== false ? '/${modelNameLower}' : ''
|
|
231
238
|
const basePath = customPrefix + modelPrefix
|
|
232
239
|
|
|
233
240
|
const openApiDisabled = config.disableOpenApi === true
|
|
234
241
|
|| (config.disableOpenApi !== false && (
|
|
235
|
-
_env.
|
|
236
|
-
|| _env.
|
|
242
|
+
_env.NODE_ENV === 'production'
|
|
243
|
+
|| _env.DISABLE_OPENAPI === 'true'
|
|
237
244
|
))
|
|
238
245
|
|
|
239
246
|
const postReadsEnabled = !config.disablePostReads
|
|
240
247
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
248
|
+
let _openApiJsonCache: unknown = undefined
|
|
249
|
+
const getOpenApiJson = (): unknown => {
|
|
250
|
+
if (_openApiJsonCache === undefined) {
|
|
251
|
+
_openApiJsonCache = buildModelOpenApi(
|
|
244
252
|
'${modelName}',
|
|
245
253
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
246
254
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
247
255
|
config as RouteConfig,
|
|
248
256
|
{ format: 'json', writeStrategy: WRITE_STRATEGY },
|
|
249
257
|
)
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
258
|
+
}
|
|
259
|
+
return _openApiJsonCache
|
|
260
|
+
}
|
|
261
|
+
let _openApiYamlCache: string | undefined = undefined
|
|
262
|
+
const getOpenApiYaml = (): string => {
|
|
263
|
+
if (_openApiYamlCache === undefined) {
|
|
264
|
+
_openApiYamlCache = buildModelOpenApi(
|
|
253
265
|
'${modelName}',
|
|
254
266
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
255
267
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
256
268
|
config as RouteConfig,
|
|
257
269
|
{ format: 'yaml', writeStrategy: WRITE_STRATEGY },
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
if (isQueryBuilderEnabled(config as RouteConfig)) {
|
|
261
|
-
const qbConfig = getQueryBuilderConfig(config as RouteConfig)
|
|
262
|
-
if (qbConfig) {
|
|
263
|
-
try {
|
|
264
|
-
startQueryBuilder(qbConfig)
|
|
265
|
-
} catch (err) {
|
|
266
|
-
if (_env.NODE_ENV !== 'production') console.warn('[query-builder]', err)
|
|
267
|
-
}
|
|
270
|
+
) as string
|
|
268
271
|
}
|
|
272
|
+
return _openApiYamlCache
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (config.queryBuilder && config.queryBuilder !== false && _env.NODE_ENV !== 'production') {
|
|
276
|
+
console.warn(
|
|
277
|
+
'[${modelName}Router] queryBuilder config is present but Hono target does not auto-start it. ' +
|
|
278
|
+
'Run \`npx prisma-query-builder-ui\` in a separate process.',
|
|
279
|
+
)
|
|
269
280
|
}
|
|
270
281
|
|
|
271
282
|
app.onError((err, c) => {
|
|
272
|
-
if (err instanceof HTTPException) {
|
|
273
|
-
return c.json({ message: err.message }, err.status as ContentfulStatusCode)
|
|
274
|
-
}
|
|
275
283
|
return sendError(c as HandlerContext, err)
|
|
276
284
|
})
|
|
277
285
|
|
|
278
286
|
if (!openApiDisabled) {
|
|
279
287
|
const openapiJsonPath = basePath ? \`\${basePath}/openapi.json\` : '/openapi.json'
|
|
280
288
|
const openapiYamlPath = basePath ? \`\${basePath}/openapi.yaml\` : '/openapi.yaml'
|
|
281
|
-
app.get(openapiJsonPath, (c) => c.json(
|
|
289
|
+
app.get(openapiJsonPath, (c) => c.json(getOpenApiJson() as Record<string, unknown>))
|
|
282
290
|
app.get(openapiYamlPath, (c) => {
|
|
283
291
|
c.header('Content-Type', 'application/yaml')
|
|
284
|
-
return c.body(
|
|
292
|
+
return c.body(getOpenApiYaml())
|
|
285
293
|
})
|
|
286
294
|
}
|
|
287
295
|
|
|
@@ -294,10 +302,10 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
294
302
|
await parseFn(c as unknown as HandlerContext)
|
|
295
303
|
makeShapeMiddleware<TCtx, TPrisma, TEnv>(config, opConfig)(c)
|
|
296
304
|
const { before = [], after = [] } = opConfig
|
|
297
|
-
const beforeResp = await
|
|
305
|
+
const beforeResp = await runBeforeHooks<TEnv>(before, c)
|
|
298
306
|
if (beforeResp) return beforeResp
|
|
299
307
|
await handlerFn(c as unknown as HandlerContext)
|
|
300
|
-
const afterResp = await
|
|
308
|
+
const afterResp = await runAfterHooks<TEnv>(after, c)
|
|
301
309
|
if (afterResp) return afterResp
|
|
302
310
|
return sendResult(c as unknown as HandlerContext)
|
|
303
311
|
} catch (error: unknown) {
|
|
@@ -313,10 +321,10 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
313
321
|
await parseWriteBodyMiddleware(c as unknown as HandlerContext)
|
|
314
322
|
makeShapeMiddleware<TCtx, TPrisma, TEnv>(config, opConfig)(c)
|
|
315
323
|
const { before = [], after = [] } = opConfig
|
|
316
|
-
const beforeResp = await
|
|
324
|
+
const beforeResp = await runBeforeHooks<TEnv>(before, c)
|
|
317
325
|
if (beforeResp) return beforeResp
|
|
318
326
|
await handlerFn(c as unknown as HandlerContext)
|
|
319
|
-
const afterResp = await
|
|
327
|
+
const afterResp = await runAfterHooks<TEnv>(after, c)
|
|
320
328
|
if (afterResp) return afterResp
|
|
321
329
|
return sendResult(c as unknown as HandlerContext)
|
|
322
330
|
} catch (error: unknown) {
|
|
@@ -329,55 +337,55 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
329
337
|
?? (defaultOpConfig as OperationConfigLike<TEnv>)
|
|
330
338
|
}
|
|
331
339
|
|
|
332
|
-
if (config.
|
|
340
|
+
if (isEnabled(config.findFirst)) {
|
|
333
341
|
const opConfig = opFor('findFirst')
|
|
334
342
|
const path = basePath ? \`\${basePath}/first\` : '/first'
|
|
335
343
|
app.get(path, handleRead(opConfig, ${modelName}FindFirst, parseQueryMiddleware))
|
|
336
344
|
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}FindFirst, parseBodyAsQueryMiddleware))
|
|
337
345
|
}
|
|
338
|
-
if (config.
|
|
346
|
+
if (isEnabled(config.findFirstOrThrow)) {
|
|
339
347
|
const opConfig = opFor('findFirstOrThrow')
|
|
340
348
|
const path = basePath ? \`\${basePath}/first/strict\` : '/first/strict'
|
|
341
349
|
app.get(path, handleRead(opConfig, ${modelName}FindFirstOrThrow, parseQueryMiddleware))
|
|
342
350
|
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}FindFirstOrThrow, parseBodyAsQueryMiddleware))
|
|
343
351
|
}
|
|
344
|
-
if (config.
|
|
352
|
+
if (isEnabled(config.findManyPaginated)) {
|
|
345
353
|
const opConfig = opFor('findManyPaginated')
|
|
346
354
|
const path = basePath ? \`\${basePath}/paginated\` : '/paginated'
|
|
347
355
|
app.get(path, handleRead(opConfig, ${modelName}FindManyPaginated, parseQueryMiddleware))
|
|
348
356
|
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}FindManyPaginated, parseBodyAsQueryMiddleware))
|
|
349
357
|
}
|
|
350
|
-
if (config.
|
|
358
|
+
if (isEnabled(config.aggregate)) {
|
|
351
359
|
const opConfig = opFor('aggregate')
|
|
352
360
|
const path = basePath ? \`\${basePath}/aggregate\` : '/aggregate'
|
|
353
361
|
app.get(path, handleRead(opConfig, ${modelName}Aggregate, parseQueryMiddleware))
|
|
354
362
|
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}Aggregate, parseBodyAsQueryMiddleware))
|
|
355
363
|
}
|
|
356
|
-
if (config.
|
|
364
|
+
if (isEnabled(config.count)) {
|
|
357
365
|
const opConfig = opFor('count')
|
|
358
366
|
const path = basePath ? \`\${basePath}/count\` : '/count'
|
|
359
367
|
app.get(path, handleRead(opConfig, ${modelName}Count, parseQueryMiddleware))
|
|
360
368
|
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}Count, parseBodyAsQueryMiddleware))
|
|
361
369
|
}
|
|
362
|
-
if (config.
|
|
370
|
+
if (isEnabled(config.groupBy)) {
|
|
363
371
|
const opConfig = opFor('groupBy')
|
|
364
372
|
const path = basePath ? \`\${basePath}/groupby\` : '/groupby'
|
|
365
373
|
app.get(path, handleRead(opConfig, ${modelName}GroupBy, parseQueryMiddleware))
|
|
366
374
|
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}GroupBy, parseBodyAsQueryMiddleware))
|
|
367
375
|
}
|
|
368
|
-
if (config.
|
|
376
|
+
if (isEnabled(config.findUniqueOrThrow)) {
|
|
369
377
|
const opConfig = opFor('findUniqueOrThrow')
|
|
370
378
|
const path = basePath ? \`\${basePath}/unique/strict\` : '/unique/strict'
|
|
371
379
|
app.get(path, handleRead(opConfig, ${modelName}FindUniqueOrThrow, parseQueryMiddleware))
|
|
372
380
|
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}FindUniqueOrThrow, parseBodyAsQueryMiddleware))
|
|
373
381
|
}
|
|
374
|
-
if (config.
|
|
382
|
+
if (isEnabled(config.findUnique)) {
|
|
375
383
|
const opConfig = opFor('findUnique')
|
|
376
384
|
const path = basePath ? \`\${basePath}/unique\` : '/unique'
|
|
377
385
|
app.get(path, handleRead(opConfig, ${modelName}FindUnique, parseQueryMiddleware))
|
|
378
386
|
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}FindUnique, parseBodyAsQueryMiddleware))
|
|
379
387
|
}
|
|
380
|
-
if (config.
|
|
388
|
+
if (isEnabled(config.findMany)) {
|
|
381
389
|
const opConfig = opFor('findMany')
|
|
382
390
|
const path = basePath || '/'
|
|
383
391
|
app.get(path, handleRead(opConfig, ${modelName}FindMany, parseQueryMiddleware))
|
|
@@ -387,52 +395,78 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
387
395
|
}
|
|
388
396
|
}
|
|
389
397
|
|
|
390
|
-
if (config.
|
|
398
|
+
if (isEnabled(config.createManyAndReturn)) {
|
|
391
399
|
const opConfig = opFor('createManyAndReturn')
|
|
392
400
|
const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
|
|
393
401
|
app.post(path, handleWrite(opConfig, ${modelName}CreateManyAndReturn))
|
|
394
402
|
}
|
|
395
|
-
if (config.
|
|
403
|
+
if (isEnabled(config.createMany)) {
|
|
396
404
|
const opConfig = opFor('createMany')
|
|
397
405
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
398
406
|
app.post(path, handleWrite(opConfig, ${modelName}CreateMany))
|
|
399
407
|
}
|
|
400
|
-
if (config.
|
|
408
|
+
if (isEnabled(config.create)) {
|
|
401
409
|
const opConfig = opFor('create')
|
|
402
410
|
const path = basePath || '/'
|
|
403
411
|
app.post(path, handleWrite(opConfig, ${modelName}Create))
|
|
404
412
|
}
|
|
405
|
-
if (config.
|
|
413
|
+
if (isEnabled(config.updateManyAndReturn)) {
|
|
406
414
|
const opConfig = opFor('updateManyAndReturn')
|
|
407
415
|
const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
|
|
408
416
|
app.put(path, handleWrite(opConfig, ${modelName}UpdateManyAndReturn))
|
|
409
417
|
}
|
|
410
|
-
if (config.
|
|
418
|
+
if (isEnabled(config.updateMany)) {
|
|
411
419
|
const opConfig = opFor('updateMany')
|
|
412
420
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
413
421
|
app.put(path, handleWrite(opConfig, ${modelName}UpdateMany))
|
|
414
422
|
}
|
|
415
|
-
if (config.
|
|
423
|
+
if (isEnabled(config.update)) {
|
|
416
424
|
const opConfig = opFor('update')
|
|
417
425
|
const path = basePath || '/'
|
|
418
426
|
app.put(path, handleWrite(opConfig, ${modelName}Update))
|
|
419
427
|
}
|
|
420
|
-
if (config.
|
|
428
|
+
if (isEnabled(config.upsert)) {
|
|
421
429
|
const opConfig = opFor('upsert')
|
|
422
430
|
const path = basePath || '/'
|
|
423
431
|
app.patch(path, handleWrite(opConfig, ${modelName}Upsert))
|
|
424
432
|
}
|
|
425
|
-
if (config.
|
|
433
|
+
if (isEnabled(config.deleteMany)) {
|
|
426
434
|
const opConfig = opFor('deleteMany')
|
|
427
435
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
428
436
|
app.delete(path, handleWrite(opConfig, ${modelName}DeleteMany))
|
|
429
437
|
}
|
|
430
|
-
if (config.
|
|
438
|
+
if (isEnabled(config.delete)) {
|
|
431
439
|
const opConfig = opFor('delete')
|
|
432
440
|
const path = basePath || '/'
|
|
433
441
|
app.delete(path, handleWrite(opConfig, ${modelName}Delete))
|
|
434
442
|
}
|
|
435
443
|
|
|
444
|
+
if (config.updateEach) {
|
|
445
|
+
const opConfig = (config.updateEach as unknown as OperationConfigLike<TEnv> | undefined) ?? (defaultOpConfig as OperationConfigLike<TEnv>)
|
|
446
|
+
if ((!opConfig.before || opConfig.before.length === 0) && _env.NODE_ENV !== 'production') {
|
|
447
|
+
console.warn(
|
|
448
|
+
'[${modelName}Router] updateEach is enabled without a before hook. ' +
|
|
449
|
+
'This endpoint bypasses guard shapes and should be protected by authentication middleware.',
|
|
450
|
+
)
|
|
451
|
+
}
|
|
452
|
+
const path = basePath ? \`\${basePath}/each\` : '/each'
|
|
453
|
+
app.post(path, async (c: Context<GeneratedHonoEnv<TEnv>>): Promise<Response> => {
|
|
454
|
+
try {
|
|
455
|
+
await parseUpdateEachBodyMiddleware(c as unknown as HandlerContext)
|
|
456
|
+
makeShapeMiddleware<TCtx, TPrisma, TEnv>(config, opConfig)(c)
|
|
457
|
+
const { before = [], after = [] } = opConfig
|
|
458
|
+
const beforeResp = await runBeforeHooks<TEnv>(before, c)
|
|
459
|
+
if (beforeResp) return beforeResp
|
|
460
|
+
await ${modelName}UpdateEach(c as unknown as HandlerContext)
|
|
461
|
+
const afterResp = await runAfterHooks<TEnv>(after, c)
|
|
462
|
+
if (afterResp) return afterResp
|
|
463
|
+
return sendResult(c as unknown as HandlerContext)
|
|
464
|
+
} catch (error: unknown) {
|
|
465
|
+
return sendError(c as unknown as HandlerContext, error)
|
|
466
|
+
}
|
|
467
|
+
})
|
|
468
|
+
}
|
|
469
|
+
|
|
436
470
|
return app
|
|
437
471
|
}
|
|
438
472
|
`
|
package/src/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
FindManyPaginatedMode,
|
|
33
33
|
} from './constants'
|
|
34
34
|
|
|
35
|
-
const GENERATOR_OFF_RE =
|
|
35
|
+
const GENERATOR_OFF_RE = /^\s*generator off\s*$/m
|
|
36
36
|
|
|
37
37
|
function getTarget(options: GeneratorOptions): Target {
|
|
38
38
|
const raw = String(
|
|
@@ -101,7 +101,7 @@ generatorHandler({
|
|
|
101
101
|
onManifest() {
|
|
102
102
|
return {
|
|
103
103
|
version: require('../package.json').version,
|
|
104
|
-
defaultOutput: '../generated/
|
|
104
|
+
defaultOutput: '../generated/output',
|
|
105
105
|
prettyName: GENERATOR_NAME,
|
|
106
106
|
}
|
|
107
107
|
},
|
|
@@ -116,7 +116,7 @@ generatorHandler({
|
|
|
116
116
|
__dirname,
|
|
117
117
|
'..',
|
|
118
118
|
'generated',
|
|
119
|
-
|
|
119
|
+
'output',
|
|
120
120
|
)
|
|
121
121
|
const currentOutput = options.generator.output?.value
|
|
122
122
|
const isUnsetOrManifestDefault =
|
|
@@ -136,7 +136,9 @@ generatorHandler({
|
|
|
136
136
|
console.log(` Import style: ${importStyle}`)
|
|
137
137
|
console.log(` Write strategy: ${writeStrategy}`)
|
|
138
138
|
console.log(` findManyPaginated mode: ${findManyPaginatedMode}`)
|
|
139
|
-
console.log(
|
|
139
|
+
console.log(
|
|
140
|
+
` Drop guard (generator): ${dropGuard}${dropGuard ? '' : ' (runtime E2E=true will also drop guard)'}`,
|
|
141
|
+
)
|
|
140
142
|
|
|
141
143
|
if (options.dmmf.datamodel.models.length > 0) {
|
|
142
144
|
validateClientGeneratorPresent(options)
|