prisma-generator-express 1.45.1 → 1.47.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/dist/client/encodeQueryParams.js +4 -0
- package/dist/client/encodeQueryParams.js.map +1 -1
- package/dist/copy/misc.d.ts +4 -2
- package/dist/copy/misc.js +35 -24
- package/dist/copy/misc.js.map +1 -1
- package/dist/generators/generateFastifyHandler.js +2 -4
- package/dist/generators/generateFastifyHandler.js.map +1 -1
- package/dist/generators/generateHonoHandler.js +2 -4
- package/dist/generators/generateHonoHandler.js.map +1 -1
- package/dist/generators/generateImportPrismaStatement.d.ts +0 -1
- package/dist/generators/generateImportPrismaStatement.js +2 -20
- package/dist/generators/generateImportPrismaStatement.js.map +1 -1
- package/dist/generators/generateOperationCore.js +37 -1
- package/dist/generators/generateOperationCore.js.map +1 -1
- package/dist/generators/generateQueryBuilderHelper.js +9 -0
- package/dist/generators/generateQueryBuilderHelper.js.map +1 -1
- package/dist/generators/generateRelationMeta.js +0 -10
- package/dist/generators/generateRelationMeta.js.map +1 -1
- package/dist/generators/generateRouteConfigType.js +33 -12
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.d.ts +0 -1
- package/dist/generators/generateRouter.js +96 -70
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.js +83 -89
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.js +257 -237
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/generators/generateUnifiedDocs.d.ts +2 -2
- package/dist/generators/generateUnifiedDocs.js +90 -252
- package/dist/generators/generateUnifiedDocs.js.map +1 -1
- package/dist/generators/generateUnifiedHandler.js +2 -4
- package/dist/generators/generateUnifiedHandler.js.map +1 -1
- package/dist/index.js +16 -8
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.js +3 -2
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/strings.d.ts +0 -1
- package/dist/utils/strings.js +0 -9
- package/dist/utils/strings.js.map +1 -1
- package/package.json +1 -1
- package/src/client/encodeQueryParams.ts +7 -15
- package/src/copy/autoIncludePlanner.ts +4 -17
- package/src/copy/autoIncludeRuntime.ts +11 -19
- package/src/copy/buildModelOpenApi.ts +11 -14
- package/src/copy/docsRenderer.ts +8 -14
- package/src/copy/misc.ts +28 -23
- package/src/copy/operationRuntime.ts +61 -43
- package/src/copy/parseQueryParams.ts +5 -14
- package/src/copy/routeConfig.express.ts +24 -18
- package/src/copy/routeConfig.fastify.ts +1 -1
- package/src/copy/routeConfig.hono.ts +34 -6
- package/src/copy/routeConfig.ts +3 -2
- package/src/generators/generateFastifyHandler.ts +2 -5
- package/src/generators/generateHonoHandler.ts +2 -5
- package/src/generators/generateImportPrismaStatement.ts +3 -35
- package/src/generators/generateOperationCore.ts +37 -1
- package/src/generators/generateQueryBuilderHelper.ts +9 -0
- package/src/generators/generateRelationMeta.ts +0 -10
- package/src/generators/generateRouteConfigType.ts +34 -10
- package/src/generators/generateRouter.ts +96 -71
- package/src/generators/generateRouterFastify.ts +83 -89
- package/src/generators/generateRouterHono.ts +257 -237
- package/src/generators/generateUnifiedDocs.ts +89 -267
- package/src/generators/generateUnifiedHandler.ts +2 -4
- package/src/index.ts +45 -14
- package/src/utils/copyFiles.ts +2 -2
- package/src/utils/strings.ts +0 -8
- package/src/copy/createOutputValidatorMiddleware.ts +0 -47
- package/src/copy/createValidatorMiddleware.ts +0 -62
- package/src/copy/transformZod.ts +0 -139
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { DMMF } from '@prisma/generator-helper'
|
|
2
|
-
import { toCamelCase } from '../utils/strings'
|
|
3
2
|
import { generateRouteConfigType } from './generateRouteConfigType'
|
|
4
3
|
import { ImportStyle } from '../utils/resolveImportStyle'
|
|
5
4
|
import { importExt } from '../utils/importExt'
|
|
@@ -17,9 +16,8 @@ export function generateHonoRouterFunction({
|
|
|
17
16
|
}): string {
|
|
18
17
|
const ext = importExt(importStyle)
|
|
19
18
|
const modelName = model.name
|
|
20
|
-
const prefix = toCamelCase(modelName)
|
|
21
19
|
const modelNameLower = modelName.toLowerCase()
|
|
22
|
-
const routerFunctionName = `${
|
|
20
|
+
const routerFunctionName = `${modelName}Router`
|
|
23
21
|
|
|
24
22
|
const fieldsMeta = model.fields.map((f) => ({
|
|
25
23
|
name: f.name,
|
|
@@ -46,350 +44,372 @@ export function generateHonoRouterFunction({
|
|
|
46
44
|
|
|
47
45
|
return `import { Hono } from 'hono'
|
|
48
46
|
import type { Context, Next } from 'hono'
|
|
47
|
+
import type { ContentfulStatusCode } from 'hono/utils/http-status'
|
|
49
48
|
import { HTTPException } from 'hono/http-exception'
|
|
49
|
+
import { startQueryBuilder } from '../queryBuilder${ext}'
|
|
50
50
|
import {
|
|
51
|
-
${
|
|
52
|
-
${
|
|
53
|
-
${
|
|
54
|
-
${
|
|
55
|
-
${
|
|
56
|
-
${
|
|
57
|
-
${
|
|
58
|
-
${
|
|
59
|
-
${
|
|
60
|
-
${
|
|
61
|
-
${
|
|
62
|
-
${
|
|
63
|
-
${
|
|
64
|
-
${
|
|
65
|
-
${
|
|
66
|
-
${
|
|
67
|
-
${
|
|
68
|
-
${
|
|
51
|
+
${modelName}FindUnique,
|
|
52
|
+
${modelName}FindUniqueOrThrow,
|
|
53
|
+
${modelName}FindFirst,
|
|
54
|
+
${modelName}FindFirstOrThrow,
|
|
55
|
+
${modelName}FindMany,
|
|
56
|
+
${modelName}FindManyPaginated,
|
|
57
|
+
${modelName}Create,
|
|
58
|
+
${modelName}CreateMany,
|
|
59
|
+
${modelName}CreateManyAndReturn,
|
|
60
|
+
${modelName}Update,
|
|
61
|
+
${modelName}UpdateMany,
|
|
62
|
+
${modelName}UpdateManyAndReturn,
|
|
63
|
+
${modelName}Upsert,
|
|
64
|
+
${modelName}Delete,
|
|
65
|
+
${modelName}DeleteMany,
|
|
66
|
+
${modelName}Aggregate,
|
|
67
|
+
${modelName}Count,
|
|
68
|
+
${modelName}GroupBy,
|
|
69
69
|
} from './${modelName}Handlers${ext}'
|
|
70
|
-
import type {
|
|
70
|
+
import type {
|
|
71
|
+
RouteConfig,
|
|
72
|
+
HonoHookHandler,
|
|
73
|
+
HonoEnvBase,
|
|
74
|
+
HonoInternalVariables,
|
|
75
|
+
GeneratedHonoEnv,
|
|
76
|
+
} from '../routeConfig.target${ext}'
|
|
71
77
|
import { parseQueryParams } from '../parseQueryParams${ext}'
|
|
72
|
-
import { sanitizeKeys } from '../misc${ext}'
|
|
78
|
+
import { sanitizeKeys, normalizePrefix, getEnv } from '../misc${ext}'
|
|
73
79
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
74
|
-
import { mapError, transformResult,
|
|
80
|
+
import { mapError, transformResult, type OperationContext } from '../operationRuntime${ext}'
|
|
75
81
|
|
|
76
82
|
${generateRouteConfigType(modelName, 'HonoHookHandler', guardShapesImport, importStyle, 'hono')}
|
|
77
|
-
|
|
78
|
-
type HonoVariables = {
|
|
79
|
-
prisma: unknown
|
|
80
|
-
postgres?: unknown
|
|
81
|
-
sqlite?: unknown
|
|
82
|
-
parsedQuery?: Record<string, unknown>
|
|
83
|
-
body?: unknown
|
|
84
|
-
routeConfig?: { pagination?: OperationContext['paginationConfig'] }
|
|
85
|
-
guardShape?: Record<string, unknown>
|
|
86
|
-
guardCaller?: string
|
|
87
|
-
resultData?: unknown
|
|
88
|
-
resultStatus?: number
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
type HonoEnv = { Variables: HonoVariables }
|
|
92
|
-
|
|
93
|
-
const _env = typeof process !== 'undefined' && process.env ? process.env : {} as Record<string, string | undefined>
|
|
83
|
+
const _env = getEnv()
|
|
94
84
|
|
|
95
85
|
const MODEL_FIELDS = ${JSON.stringify(fieldsMeta, null, 2)} as const
|
|
96
86
|
|
|
97
87
|
const MODEL_ENUMS = ${JSON.stringify(enumsMeta, null, 2)} as const
|
|
98
88
|
|
|
99
|
-
type OperationConfigLike = {
|
|
100
|
-
before?: HonoHookHandler[]
|
|
101
|
-
after?: HonoHookHandler[]
|
|
89
|
+
type OperationConfigLike<TEnv extends HonoEnvBase> = {
|
|
90
|
+
before?: HonoHookHandler<TEnv>[]
|
|
91
|
+
after?: HonoHookHandler<TEnv>[]
|
|
102
92
|
shape?: Record<string, unknown>
|
|
103
93
|
}
|
|
104
94
|
|
|
105
|
-
const defaultOpConfig
|
|
106
|
-
before: [],
|
|
107
|
-
after: [],
|
|
95
|
+
const defaultOpConfig = Object.freeze({
|
|
96
|
+
before: Object.freeze([]),
|
|
97
|
+
after: Object.freeze([]),
|
|
98
|
+
}) as unknown as OperationConfigLike<HonoEnvBase>
|
|
99
|
+
|
|
100
|
+
type HandlerContext = Context<{ Variables: HonoInternalVariables }>
|
|
101
|
+
|
|
102
|
+
function isQueryBuilderEnabled(config: RouteConfig): boolean {
|
|
103
|
+
if (config.queryBuilder === false) return false
|
|
104
|
+
if (typeof config.queryBuilder === 'object' && config.queryBuilder.enabled === false) return false
|
|
105
|
+
if (_env.NODE_ENV === 'production') return false
|
|
106
|
+
return true
|
|
108
107
|
}
|
|
109
108
|
|
|
110
|
-
function
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
while (result.length > 1 && result.endsWith('/')) result = result.slice(0, -1)
|
|
115
|
-
if (result === '/') return ''
|
|
116
|
-
return result
|
|
109
|
+
function getQueryBuilderConfig(config: RouteConfig) {
|
|
110
|
+
if (config.queryBuilder === false) return null
|
|
111
|
+
if (typeof config.queryBuilder === 'object') return config.queryBuilder
|
|
112
|
+
return {}
|
|
117
113
|
}
|
|
118
114
|
|
|
119
|
-
async function
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
throw new HttpError(400, 'Invalid JSON in request body')
|
|
115
|
+
async function parseQueryMiddleware(c: HandlerContext): Promise<void> {
|
|
116
|
+
const raw = c.req.query() as Record<string, unknown>
|
|
117
|
+
if (raw && Object.keys(raw).length > 0) {
|
|
118
|
+
c.set('parsedQuery', parseQueryParams(raw) as Record<string, unknown>)
|
|
124
119
|
}
|
|
125
120
|
}
|
|
126
121
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const modelPrefix = config.addModelPrefix !== false ? '/${modelNameLower}' : ''
|
|
134
|
-
const basePath = customPrefix + modelPrefix
|
|
135
|
-
|
|
136
|
-
const openApiDisabled = config.disableOpenApi === true
|
|
137
|
-
|| (config.disableOpenApi !== false && (
|
|
138
|
-
_env.DISABLE_OPENAPI === 'true'
|
|
139
|
-
|| _env.NODE_ENV === 'production'
|
|
140
|
-
))
|
|
141
|
-
|
|
142
|
-
const postReadsEnabled = !config.disablePostReads
|
|
143
|
-
|
|
144
|
-
app.onError((err, c) => {
|
|
145
|
-
if (err instanceof HTTPException) {
|
|
146
|
-
return c.json({ message: err.message }, err.status)
|
|
147
|
-
}
|
|
148
|
-
const httpError = mapError(err)
|
|
149
|
-
return c.json({ message: httpError.message }, httpError.status as Parameters<typeof c.json>[1])
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
const parseQueryMw = async (c: Context<HonoEnv>, next: Next): Promise<void> => {
|
|
153
|
-
const raw = c.req.query()
|
|
154
|
-
if (raw && Object.keys(raw).length > 0) {
|
|
155
|
-
c.set(
|
|
156
|
-
'parsedQuery',
|
|
157
|
-
parseQueryParams(raw as Record<string, unknown>) as Record<string, unknown>,
|
|
158
|
-
)
|
|
159
|
-
}
|
|
160
|
-
await next()
|
|
122
|
+
async function parseBodyAsQueryMiddleware(c: HandlerContext): Promise<void> {
|
|
123
|
+
let body: unknown
|
|
124
|
+
try {
|
|
125
|
+
body = await c.req.json()
|
|
126
|
+
} catch {
|
|
127
|
+
throw new HTTPException(400, { message: 'Request body must be a JSON object' })
|
|
161
128
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const body = await safeParseBody(c)
|
|
165
|
-
if (!body || typeof body !== 'object' || Array.isArray(body)) {
|
|
166
|
-
throw new HttpError(400, 'Request body must be a JSON object')
|
|
167
|
-
}
|
|
168
|
-
c.set('parsedQuery', sanitizeKeys(body as Record<string, unknown>))
|
|
169
|
-
await next()
|
|
129
|
+
if (!body || typeof body !== 'object' || Array.isArray(body)) {
|
|
130
|
+
throw new HTTPException(400, { message: 'Request body must be a JSON object' })
|
|
170
131
|
}
|
|
132
|
+
c.set('parsedQuery', sanitizeKeys(body as Record<string, unknown>))
|
|
133
|
+
}
|
|
171
134
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
await
|
|
135
|
+
async function parseWriteBodyMiddleware(c: HandlerContext): Promise<void> {
|
|
136
|
+
let body: unknown
|
|
137
|
+
try {
|
|
138
|
+
body = await c.req.json()
|
|
139
|
+
} catch {
|
|
140
|
+
throw new HTTPException(400, { message: 'Request body must be a JSON object' })
|
|
141
|
+
}
|
|
142
|
+
if (!body || typeof body !== 'object' || Array.isArray(body)) {
|
|
143
|
+
throw new HTTPException(400, { message: 'Request body must be a JSON object' })
|
|
176
144
|
}
|
|
145
|
+
c.set('body', sanitizeKeys(body as Record<string, unknown>))
|
|
146
|
+
}
|
|
177
147
|
|
|
178
|
-
|
|
148
|
+
function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
149
|
+
config: ${modelName}RouteConfig<TCtx, TPrisma, TEnv>,
|
|
150
|
+
opConfig: OperationConfigLike<TEnv>,
|
|
151
|
+
) {
|
|
152
|
+
return (c: Context<GeneratedHonoEnv<TEnv>>): void => {
|
|
179
153
|
const paginationConfig = (config as { pagination?: OperationContext['paginationConfig'] }).pagination
|
|
180
154
|
if (paginationConfig) {
|
|
181
155
|
c.set('routeConfig', { pagination: paginationConfig })
|
|
182
156
|
}
|
|
157
|
+
const headerName = config.guard?.variantHeader || 'x-api-variant'
|
|
158
|
+
const headerValue = c.req.header(headerName)
|
|
159
|
+
const caller = config.guard?.resolveVariant?.(c) ?? headerValue ?? undefined
|
|
160
|
+
if (caller) c.set('guardCaller', caller)
|
|
183
161
|
if (opConfig.shape) {
|
|
184
162
|
c.set('guardShape', opConfig.shape)
|
|
185
|
-
const headerName = config.guard?.variantHeader || 'x-api-variant'
|
|
186
|
-
const caller = config.guard?.resolveVariant?.(c as Context)
|
|
187
|
-
?? c.req.header(headerName)
|
|
188
|
-
?? undefined
|
|
189
|
-
if (caller) {
|
|
190
|
-
c.set('guardCaller', caller)
|
|
191
|
-
}
|
|
192
163
|
}
|
|
193
|
-
await next()
|
|
194
164
|
}
|
|
165
|
+
}
|
|
195
166
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
167
|
+
async function runHooks<TEnv extends HonoEnvBase>(
|
|
168
|
+
hooks: HonoHookHandler<TEnv>[],
|
|
169
|
+
c: Context<GeneratedHonoEnv<TEnv>>,
|
|
170
|
+
): Promise<Response | undefined> {
|
|
171
|
+
for (const hook of hooks) {
|
|
172
|
+
let advanced = false
|
|
173
|
+
const next: Next = async () => {
|
|
174
|
+
advanced = true
|
|
175
|
+
}
|
|
176
|
+
const result = await hook(c, next)
|
|
177
|
+
if (result instanceof Response) return result
|
|
178
|
+
if (!advanced) {
|
|
179
|
+
if (_env.NODE_ENV !== 'production') {
|
|
180
|
+
console.warn(
|
|
181
|
+
'[hono-router] Hook returned without calling next() or returning a Response. ' +
|
|
182
|
+
'Use \`return c.json(...)\` to short-circuit, or \`await next()\` to continue.',
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
return c.body(null) ?? undefined
|
|
201
186
|
}
|
|
202
|
-
return c.json(
|
|
203
|
-
transformResult(data) as Parameters<typeof c.json>[0],
|
|
204
|
-
status as Parameters<typeof c.json>[1],
|
|
205
|
-
)
|
|
206
187
|
}
|
|
188
|
+
return undefined
|
|
189
|
+
}
|
|
207
190
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
191
|
+
function sendResult(c: HandlerContext): Response {
|
|
192
|
+
const data = c.get('resultData')
|
|
193
|
+
const status = (c.get('resultStatus') as number | undefined) ?? 200
|
|
194
|
+
if (data === undefined) {
|
|
195
|
+
throw new HTTPException(500, { message: 'No data set by handler' })
|
|
196
|
+
}
|
|
197
|
+
return c.json(transformResult(data) as Record<string, unknown>, status as ContentfulStatusCode)
|
|
198
|
+
}
|
|
213
199
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
200
|
+
function sendError(c: HandlerContext, error: unknown): Response {
|
|
201
|
+
const httpError = mapError(error)
|
|
202
|
+
return c.json({ message: httpError.message }, httpError.status as ContentfulStatusCode)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extends HonoEnvBase = HonoEnvBase>(config: ${modelName}RouteConfig<TCtx, TPrisma, TEnv> = {}): Hono<GeneratedHonoEnv<TEnv>> {
|
|
206
|
+
const app = new Hono<GeneratedHonoEnv<TEnv>>()
|
|
207
|
+
|
|
208
|
+
const customPrefix = normalizePrefix(config.customUrlPrefix || '')
|
|
209
|
+
const modelPrefix = config.addModelPrefix !== false ? '/${modelNameLower}' : ''
|
|
210
|
+
const basePath = customPrefix + modelPrefix
|
|
211
|
+
|
|
212
|
+
const openApiDisabled = config.disableOpenApi === true
|
|
213
|
+
|| (config.disableOpenApi !== false && (
|
|
214
|
+
_env.DISABLE_OPENAPI === 'true'
|
|
215
|
+
|| _env.NODE_ENV === 'production'
|
|
216
|
+
))
|
|
217
217
|
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
const postReadsEnabled = !config.disablePostReads
|
|
219
|
+
|
|
220
|
+
const openApiJsonSpec = openApiDisabled
|
|
221
|
+
? null
|
|
222
|
+
: buildModelOpenApi(
|
|
220
223
|
'${modelName}',
|
|
221
224
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
222
225
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
223
|
-
config,
|
|
226
|
+
config as RouteConfig,
|
|
224
227
|
{ format: 'json' },
|
|
225
228
|
)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
app.get(openapiYamlPath, (c) => {
|
|
230
|
-
const yaml = buildModelOpenApi(
|
|
229
|
+
const openApiYamlSpec = openApiDisabled
|
|
230
|
+
? null
|
|
231
|
+
: buildModelOpenApi(
|
|
231
232
|
'${modelName}',
|
|
232
233
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
233
234
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
234
|
-
config,
|
|
235
|
+
config as RouteConfig,
|
|
235
236
|
{ format: 'yaml' },
|
|
236
|
-
)
|
|
237
|
-
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
if (isQueryBuilderEnabled(config as RouteConfig)) {
|
|
240
|
+
const qbConfig = getQueryBuilderConfig(config as RouteConfig)
|
|
241
|
+
if (qbConfig) {
|
|
242
|
+
try {
|
|
243
|
+
startQueryBuilder(qbConfig)
|
|
244
|
+
} catch (err) {
|
|
245
|
+
if (_env.NODE_ENV !== 'production') console.warn('[query-builder]', err)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
app.onError((err, c) => {
|
|
251
|
+
if (err instanceof HTTPException) {
|
|
252
|
+
return c.json({ message: err.message }, err.status as ContentfulStatusCode)
|
|
253
|
+
}
|
|
254
|
+
return sendError(c as HandlerContext, err)
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
if (!openApiDisabled) {
|
|
258
|
+
const openapiJsonPath = basePath ? \`\${basePath}/openapi.json\` : '/openapi.json'
|
|
259
|
+
const openapiYamlPath = basePath ? \`\${basePath}/openapi.yaml\` : '/openapi.yaml'
|
|
260
|
+
app.get(openapiJsonPath, (c) => c.json(openApiJsonSpec as Record<string, unknown>))
|
|
261
|
+
app.get(openapiYamlPath, (c) => {
|
|
262
|
+
c.header('Content-Type', 'application/yaml')
|
|
263
|
+
return c.body(openApiYamlSpec as string)
|
|
238
264
|
})
|
|
239
265
|
}
|
|
240
266
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
267
|
+
const handleRead = (
|
|
268
|
+
opConfig: OperationConfigLike<TEnv>,
|
|
269
|
+
handlerFn: (c: HandlerContext) => Promise<void>,
|
|
270
|
+
parseFn: (c: HandlerContext) => Promise<void>,
|
|
271
|
+
) => async (c: Context<GeneratedHonoEnv<TEnv>>): Promise<Response> => {
|
|
272
|
+
try {
|
|
273
|
+
await parseFn(c)
|
|
274
|
+
makeShapeMiddleware<TCtx, TPrisma, TEnv>(config, opConfig)(c)
|
|
275
|
+
const { before = [], after = [] } = opConfig
|
|
276
|
+
const beforeResp = await runHooks<TEnv>(before, c)
|
|
277
|
+
if (beforeResp) return beforeResp
|
|
278
|
+
await handlerFn(c)
|
|
279
|
+
const afterResp = await runHooks<TEnv>(after, c)
|
|
280
|
+
if (afterResp) return afterResp
|
|
281
|
+
return sendResult(c)
|
|
282
|
+
} catch (error: unknown) {
|
|
283
|
+
return sendError(c, error)
|
|
248
284
|
}
|
|
249
285
|
}
|
|
250
286
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
287
|
+
const handleWrite = (
|
|
288
|
+
opConfig: OperationConfigLike<TEnv>,
|
|
289
|
+
handlerFn: (c: HandlerContext) => Promise<void>,
|
|
290
|
+
) => async (c: Context<GeneratedHonoEnv<TEnv>>): Promise<Response> => {
|
|
291
|
+
try {
|
|
292
|
+
await parseWriteBodyMiddleware(c)
|
|
293
|
+
makeShapeMiddleware<TCtx, TPrisma, TEnv>(config, opConfig)(c)
|
|
294
|
+
const { before = [], after = [] } = opConfig
|
|
295
|
+
const beforeResp = await runHooks<TEnv>(before, c)
|
|
296
|
+
if (beforeResp) return beforeResp
|
|
297
|
+
await handlerFn(c)
|
|
298
|
+
const afterResp = await runHooks<TEnv>(after, c)
|
|
299
|
+
if (afterResp) return afterResp
|
|
300
|
+
return sendResult(c)
|
|
301
|
+
} catch (error: unknown) {
|
|
302
|
+
return sendError(c, error)
|
|
258
303
|
}
|
|
259
304
|
}
|
|
260
305
|
|
|
306
|
+
const opFor = <K extends keyof ${modelName}RouteConfig<TCtx, TPrisma, TEnv>>(key: K): OperationConfigLike<TEnv> => {
|
|
307
|
+
return (config[key] as unknown as OperationConfigLike<TEnv> | undefined)
|
|
308
|
+
?? (defaultOpConfig as OperationConfigLike<TEnv>)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (config.enableAll || config.findFirst) {
|
|
312
|
+
const opConfig = opFor('findFirst')
|
|
313
|
+
const path = basePath ? \`\${basePath}/first\` : '/first'
|
|
314
|
+
app.get(path, handleRead(opConfig, ${modelName}FindFirst, parseQueryMiddleware))
|
|
315
|
+
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}FindFirst, parseBodyAsQueryMiddleware))
|
|
316
|
+
}
|
|
317
|
+
if (config.enableAll || config.findFirstOrThrow) {
|
|
318
|
+
const opConfig = opFor('findFirstOrThrow')
|
|
319
|
+
const path = basePath ? \`\${basePath}/first/strict\` : '/first/strict'
|
|
320
|
+
app.get(path, handleRead(opConfig, ${modelName}FindFirstOrThrow, parseQueryMiddleware))
|
|
321
|
+
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}FindFirstOrThrow, parseBodyAsQueryMiddleware))
|
|
322
|
+
}
|
|
261
323
|
if (config.enableAll || config.findManyPaginated) {
|
|
262
|
-
const opConfig
|
|
263
|
-
const { before = [], after = [] } = opConfig
|
|
324
|
+
const opConfig = opFor('findManyPaginated')
|
|
264
325
|
const path = basePath ? \`\${basePath}/paginated\` : '/paginated'
|
|
265
|
-
app.get(path,
|
|
266
|
-
if (postReadsEnabled) {
|
|
267
|
-
app.post(path, parseBodyAsQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}FindManyPaginated), ...after, sendResultMw)
|
|
268
|
-
}
|
|
326
|
+
app.get(path, handleRead(opConfig, ${modelName}FindManyPaginated, parseQueryMiddleware))
|
|
327
|
+
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}FindManyPaginated, parseBodyAsQueryMiddleware))
|
|
269
328
|
}
|
|
270
|
-
|
|
271
329
|
if (config.enableAll || config.aggregate) {
|
|
272
|
-
const opConfig
|
|
273
|
-
const { before = [], after = [] } = opConfig
|
|
330
|
+
const opConfig = opFor('aggregate')
|
|
274
331
|
const path = basePath ? \`\${basePath}/aggregate\` : '/aggregate'
|
|
275
|
-
app.get(path,
|
|
276
|
-
if (postReadsEnabled) {
|
|
277
|
-
app.post(path, parseBodyAsQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}Aggregate), ...after, sendResultMw)
|
|
278
|
-
}
|
|
332
|
+
app.get(path, handleRead(opConfig, ${modelName}Aggregate, parseQueryMiddleware))
|
|
333
|
+
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}Aggregate, parseBodyAsQueryMiddleware))
|
|
279
334
|
}
|
|
280
|
-
|
|
281
335
|
if (config.enableAll || config.count) {
|
|
282
|
-
const opConfig
|
|
283
|
-
const { before = [], after = [] } = opConfig
|
|
336
|
+
const opConfig = opFor('count')
|
|
284
337
|
const path = basePath ? \`\${basePath}/count\` : '/count'
|
|
285
|
-
app.get(path,
|
|
286
|
-
if (postReadsEnabled) {
|
|
287
|
-
app.post(path, parseBodyAsQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}Count), ...after, sendResultMw)
|
|
288
|
-
}
|
|
338
|
+
app.get(path, handleRead(opConfig, ${modelName}Count, parseQueryMiddleware))
|
|
339
|
+
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}Count, parseBodyAsQueryMiddleware))
|
|
289
340
|
}
|
|
290
|
-
|
|
291
341
|
if (config.enableAll || config.groupBy) {
|
|
292
|
-
const opConfig
|
|
293
|
-
const { before = [], after = [] } = opConfig
|
|
342
|
+
const opConfig = opFor('groupBy')
|
|
294
343
|
const path = basePath ? \`\${basePath}/groupby\` : '/groupby'
|
|
295
|
-
app.get(path,
|
|
296
|
-
if (postReadsEnabled) {
|
|
297
|
-
app.post(path, parseBodyAsQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}GroupBy), ...after, sendResultMw)
|
|
298
|
-
}
|
|
344
|
+
app.get(path, handleRead(opConfig, ${modelName}GroupBy, parseQueryMiddleware))
|
|
345
|
+
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}GroupBy, parseBodyAsQueryMiddleware))
|
|
299
346
|
}
|
|
300
|
-
|
|
301
347
|
if (config.enableAll || config.findUniqueOrThrow) {
|
|
302
|
-
const opConfig
|
|
303
|
-
const { before = [], after = [] } = opConfig
|
|
348
|
+
const opConfig = opFor('findUniqueOrThrow')
|
|
304
349
|
const path = basePath ? \`\${basePath}/unique/strict\` : '/unique/strict'
|
|
305
|
-
app.get(path,
|
|
306
|
-
if (postReadsEnabled) {
|
|
307
|
-
app.post(path, parseBodyAsQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}FindUniqueOrThrow), ...after, sendResultMw)
|
|
308
|
-
}
|
|
350
|
+
app.get(path, handleRead(opConfig, ${modelName}FindUniqueOrThrow, parseQueryMiddleware))
|
|
351
|
+
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}FindUniqueOrThrow, parseBodyAsQueryMiddleware))
|
|
309
352
|
}
|
|
310
|
-
|
|
311
353
|
if (config.enableAll || config.findUnique) {
|
|
312
|
-
const opConfig
|
|
313
|
-
const { before = [], after = [] } = opConfig
|
|
354
|
+
const opConfig = opFor('findUnique')
|
|
314
355
|
const path = basePath ? \`\${basePath}/unique\` : '/unique'
|
|
315
|
-
app.get(path,
|
|
316
|
-
if (postReadsEnabled) {
|
|
317
|
-
app.post(path, parseBodyAsQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}FindUnique), ...after, sendResultMw)
|
|
318
|
-
}
|
|
356
|
+
app.get(path, handleRead(opConfig, ${modelName}FindUnique, parseQueryMiddleware))
|
|
357
|
+
if (postReadsEnabled) app.post(path, handleRead(opConfig, ${modelName}FindUnique, parseBodyAsQueryMiddleware))
|
|
319
358
|
}
|
|
320
|
-
|
|
321
359
|
if (config.enableAll || config.findMany) {
|
|
322
|
-
const opConfig
|
|
323
|
-
const { before = [], after = [] } = opConfig
|
|
360
|
+
const opConfig = opFor('findMany')
|
|
324
361
|
const path = basePath || '/'
|
|
325
|
-
app.get(path,
|
|
362
|
+
app.get(path, handleRead(opConfig, ${modelName}FindMany, parseQueryMiddleware))
|
|
326
363
|
if (postReadsEnabled) {
|
|
327
364
|
const postPath = basePath ? \`\${basePath}/read\` : '/read'
|
|
328
|
-
app.post(postPath,
|
|
365
|
+
app.post(postPath, handleRead(opConfig, ${modelName}FindMany, parseBodyAsQueryMiddleware))
|
|
329
366
|
}
|
|
330
367
|
}
|
|
331
368
|
|
|
332
369
|
if (config.enableAll || config.createManyAndReturn) {
|
|
333
|
-
const opConfig
|
|
334
|
-
const { before = [], after = [] } = opConfig
|
|
370
|
+
const opConfig = opFor('createManyAndReturn')
|
|
335
371
|
const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
|
|
336
|
-
app.post(path,
|
|
372
|
+
app.post(path, handleWrite(opConfig, ${modelName}CreateManyAndReturn))
|
|
337
373
|
}
|
|
338
|
-
|
|
339
374
|
if (config.enableAll || config.createMany) {
|
|
340
|
-
const opConfig
|
|
341
|
-
const { before = [], after = [] } = opConfig
|
|
375
|
+
const opConfig = opFor('createMany')
|
|
342
376
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
343
|
-
app.post(path,
|
|
377
|
+
app.post(path, handleWrite(opConfig, ${modelName}CreateMany))
|
|
344
378
|
}
|
|
345
|
-
|
|
346
379
|
if (config.enableAll || config.create) {
|
|
347
|
-
const opConfig
|
|
348
|
-
const { before = [], after = [] } = opConfig
|
|
380
|
+
const opConfig = opFor('create')
|
|
349
381
|
const path = basePath || '/'
|
|
350
|
-
app.post(path,
|
|
382
|
+
app.post(path, handleWrite(opConfig, ${modelName}Create))
|
|
351
383
|
}
|
|
352
|
-
|
|
353
384
|
if (config.enableAll || config.updateManyAndReturn) {
|
|
354
|
-
const opConfig
|
|
355
|
-
const { before = [], after = [] } = opConfig
|
|
385
|
+
const opConfig = opFor('updateManyAndReturn')
|
|
356
386
|
const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
|
|
357
|
-
app.put(path,
|
|
387
|
+
app.put(path, handleWrite(opConfig, ${modelName}UpdateManyAndReturn))
|
|
358
388
|
}
|
|
359
|
-
|
|
360
389
|
if (config.enableAll || config.updateMany) {
|
|
361
|
-
const opConfig
|
|
362
|
-
const { before = [], after = [] } = opConfig
|
|
390
|
+
const opConfig = opFor('updateMany')
|
|
363
391
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
364
|
-
app.put(path,
|
|
392
|
+
app.put(path, handleWrite(opConfig, ${modelName}UpdateMany))
|
|
365
393
|
}
|
|
366
|
-
|
|
367
394
|
if (config.enableAll || config.update) {
|
|
368
|
-
const opConfig
|
|
369
|
-
const { before = [], after = [] } = opConfig
|
|
395
|
+
const opConfig = opFor('update')
|
|
370
396
|
const path = basePath || '/'
|
|
371
|
-
app.put(path,
|
|
397
|
+
app.put(path, handleWrite(opConfig, ${modelName}Update))
|
|
372
398
|
}
|
|
373
|
-
|
|
374
399
|
if (config.enableAll || config.upsert) {
|
|
375
|
-
const opConfig
|
|
376
|
-
const { before = [], after = [] } = opConfig
|
|
400
|
+
const opConfig = opFor('upsert')
|
|
377
401
|
const path = basePath || '/'
|
|
378
|
-
app.patch(path,
|
|
402
|
+
app.patch(path, handleWrite(opConfig, ${modelName}Upsert))
|
|
379
403
|
}
|
|
380
|
-
|
|
381
404
|
if (config.enableAll || config.deleteMany) {
|
|
382
|
-
const opConfig
|
|
383
|
-
const { before = [], after = [] } = opConfig
|
|
405
|
+
const opConfig = opFor('deleteMany')
|
|
384
406
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
385
|
-
app.delete(path,
|
|
407
|
+
app.delete(path, handleWrite(opConfig, ${modelName}DeleteMany))
|
|
386
408
|
}
|
|
387
|
-
|
|
388
409
|
if (config.enableAll || config.delete) {
|
|
389
|
-
const opConfig
|
|
390
|
-
const { before = [], after = [] } = opConfig
|
|
410
|
+
const opConfig = opFor('delete')
|
|
391
411
|
const path = basePath || '/'
|
|
392
|
-
app.delete(path,
|
|
412
|
+
app.delete(path, handleWrite(opConfig, ${modelName}Delete))
|
|
393
413
|
}
|
|
394
414
|
|
|
395
415
|
return app
|