prisma-generator-express 1.59.0 → 1.60.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 +19 -23
- package/dist/client/encodeQueryParams.js.map +1 -1
- package/dist/copy/operationDefinitions.d.ts +37 -0
- package/dist/copy/operationDefinitions.js +412 -0
- package/dist/copy/operationDefinitions.js.map +1 -0
- package/dist/generators/generateFastifyHandler.js +10 -41
- package/dist/generators/generateFastifyHandler.js.map +1 -1
- package/dist/generators/generateHonoHandler.js +10 -41
- package/dist/generators/generateHonoHandler.js.map +1 -1
- package/dist/generators/generateModelMetadata.d.ts +8 -0
- package/dist/generators/generateModelMetadata.js +77 -0
- package/dist/generators/generateModelMetadata.js.map +1 -0
- package/dist/generators/generateOperationCore.js +20 -30
- package/dist/generators/generateOperationCore.js.map +1 -1
- package/dist/generators/generateQueryBuilderHelper.js +1 -1
- package/dist/generators/generateQueryBuilderHelper.js.map +1 -1
- package/dist/generators/generateRouteConfigType.js +11 -57
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.js +64 -177
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.js +59 -169
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.js +52 -152
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/generators/generateUnifiedHandler.js +7 -30
- package/dist/generators/generateUnifiedHandler.js.map +1 -1
- package/dist/generators/generateUnifiedScalarUI.js +9 -74
- package/dist/generators/generateUnifiedScalarUI.js.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.js +7 -0
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/writeFileSafely.js +5 -12
- package/dist/utils/writeFileSafely.js.map +1 -1
- package/package.json +12 -2
- package/src/client/encodeQueryParams.ts +23 -36
- package/src/copy/autoIncludePlanner.ts +14 -23
- package/src/copy/autoIncludeRuntime.ts +117 -228
- package/src/copy/buildModelOpenApi.ts +248 -628
- package/src/copy/concurrency.ts +20 -0
- package/src/copy/docsRenderer.ts +63 -333
- package/src/copy/errorMapper.ts +126 -0
- package/src/copy/guardHelpers.ts +56 -0
- package/src/copy/materializedCount.ts +68 -0
- package/src/copy/materializedRouter.ts +33 -29
- package/src/copy/operationDefinitions.ts +359 -35
- package/src/copy/operationRuntime.ts +11 -605
- package/src/copy/pagination.ts +151 -0
- package/src/copy/scalarTypes.ts +2 -0
- package/src/copy/sse.ts +296 -0
- package/src/generators/generateFastifyHandler.ts +13 -47
- package/src/generators/generateHonoHandler.ts +13 -47
- package/src/generators/generateModelMetadata.ts +92 -0
- package/src/generators/generateOperationCore.ts +19 -32
- package/src/generators/generateQueryBuilderHelper.ts +1 -1
- package/src/generators/generateRouteConfigType.ts +9 -60
- package/src/generators/generateRouter.ts +88 -180
- package/src/generators/generateRouterFastify.ts +65 -172
- package/src/generators/generateRouterHono.ts +58 -155
- package/src/generators/generateUnifiedHandler.ts +8 -33
- package/src/generators/generateUnifiedScalarUI.ts +9 -91
- package/src/index.ts +13 -1
- package/src/utils/copyFiles.ts +7 -0
- package/src/utils/writeFileSafely.ts +5 -11
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { Request, Response } from 'express'
|
|
2
|
+
import { HttpError, LOG_PREFIX, mapError } from './errorMapper'
|
|
2
3
|
import {
|
|
3
|
-
initSSE,
|
|
4
|
-
endSSE,
|
|
5
|
-
startSSEKeepalive,
|
|
6
4
|
sendSSEField,
|
|
7
5
|
sendSSEResult,
|
|
8
6
|
sendSSEError,
|
|
@@ -13,18 +11,23 @@ import {
|
|
|
13
11
|
sendSSEPageMeta,
|
|
14
12
|
runSingleResultSSE,
|
|
15
13
|
emitTerminalSSEError,
|
|
14
|
+
safeSendError,
|
|
16
15
|
setByPath,
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
withSSE,
|
|
17
|
+
} from './sse'
|
|
18
|
+
import {
|
|
19
19
|
applyPaginationLimits,
|
|
20
20
|
countForPagination,
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
} from './pagination'
|
|
22
|
+
import {
|
|
23
|
+
getDelegate,
|
|
24
|
+
getExtendedClient,
|
|
23
25
|
type OperationContext,
|
|
24
26
|
type PrismaDelegate,
|
|
25
27
|
type FindManyPaginatedMode,
|
|
26
28
|
} from './operationRuntime'
|
|
27
29
|
import { isPlainObject } from './misc'
|
|
30
|
+
import { mapLimited } from './concurrency'
|
|
28
31
|
import {
|
|
29
32
|
planAutoInclude,
|
|
30
33
|
type AutoIncludePlan,
|
|
@@ -36,8 +39,6 @@ import type { AutoIncludeProgressiveVariantConfig } from './routeConfig'
|
|
|
36
39
|
const STAGE_CONCURRENCY = 4
|
|
37
40
|
const MAX_IN_CHUNK = 1000
|
|
38
41
|
|
|
39
|
-
type IntervalHandle = ReturnType<typeof setInterval>
|
|
40
|
-
|
|
41
42
|
export type AutoIncludeBaseOp =
|
|
42
43
|
| 'findUnique'
|
|
43
44
|
| 'findUniqueOrThrow'
|
|
@@ -69,6 +70,10 @@ type ParentEntry = RowPair & {
|
|
|
69
70
|
locator: Array<number | string>
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
function createClientGoneChecker(res: Response, signal?: AbortSignal): () => boolean {
|
|
74
|
+
return () => signal?.aborted === true || res.writableEnded || res.destroyed
|
|
75
|
+
}
|
|
76
|
+
|
|
72
77
|
function readPath(source: Record<string, unknown>, path: string): unknown {
|
|
73
78
|
if (path === '') return source
|
|
74
79
|
const parts = path.split('.')
|
|
@@ -85,16 +90,11 @@ function stripInternalAtScope(
|
|
|
85
90
|
internalPaths: string[],
|
|
86
91
|
scopePath: string,
|
|
87
92
|
): void {
|
|
93
|
+
const prefix = scopePath === '' ? '' : scopePath + '.'
|
|
88
94
|
for (const fullPath of internalPaths) {
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
continue
|
|
94
|
-
}
|
|
95
|
-
if (!fullPath.startsWith(scopePath + '.')) continue
|
|
96
|
-
const relative = fullPath.slice(scopePath.length + 1)
|
|
97
|
-
if (relative.includes('.')) continue
|
|
95
|
+
if (!fullPath.startsWith(prefix)) continue
|
|
96
|
+
const relative = fullPath.slice(prefix.length)
|
|
97
|
+
if (relative === '' || relative.includes('.')) continue
|
|
98
98
|
delete target[relative]
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -132,22 +132,14 @@ function buildPublicForStage(
|
|
|
132
132
|
internalFieldPaths: string[],
|
|
133
133
|
scopePath: string,
|
|
134
134
|
): unknown {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const copy: Record<string, unknown> = { ...item }
|
|
139
|
-
stripInternalAtScope(copy, internalFieldPaths, scopePath)
|
|
140
|
-
return copy
|
|
141
|
-
}
|
|
142
|
-
return item
|
|
143
|
-
})
|
|
144
|
-
}
|
|
145
|
-
if (isPlainObject(result)) {
|
|
146
|
-
const copy: Record<string, unknown> = { ...result }
|
|
135
|
+
const process = (item: unknown): unknown => {
|
|
136
|
+
if (!isPlainObject(item)) return item
|
|
137
|
+
const copy: Record<string, unknown> = { ...item }
|
|
147
138
|
stripInternalAtScope(copy, internalFieldPaths, scopePath)
|
|
148
139
|
return copy
|
|
149
140
|
}
|
|
150
|
-
return result
|
|
141
|
+
if (Array.isArray(result)) return result.map(process)
|
|
142
|
+
return process(result)
|
|
151
143
|
}
|
|
152
144
|
|
|
153
145
|
function normalizeKey(v: unknown): string {
|
|
@@ -170,26 +162,6 @@ function groupStagesByDepth(stages: AutoIncludeStage[]): AutoIncludeStage[][] {
|
|
|
170
162
|
.map((d) => byDepth.get(d) as AutoIncludeStage[])
|
|
171
163
|
}
|
|
172
164
|
|
|
173
|
-
async function runConcurrent<T>(
|
|
174
|
-
items: T[],
|
|
175
|
-
limit: number,
|
|
176
|
-
fn: (item: T) => Promise<void>,
|
|
177
|
-
): Promise<void> {
|
|
178
|
-
let index = 0
|
|
179
|
-
const workers: Promise<void>[] = []
|
|
180
|
-
const workerCount = Math.min(limit, items.length)
|
|
181
|
-
for (let w = 0; w < workerCount; w++) {
|
|
182
|
-
workers.push((async () => {
|
|
183
|
-
for (;;) {
|
|
184
|
-
const i = index++
|
|
185
|
-
if (i >= items.length) return
|
|
186
|
-
await fn(items[i])
|
|
187
|
-
}
|
|
188
|
-
})())
|
|
189
|
-
}
|
|
190
|
-
await Promise.all(workers)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
165
|
function handleAutoIncludeFallback(
|
|
194
166
|
options: RunAutoIncludeOptions,
|
|
195
167
|
message: string,
|
|
@@ -322,7 +294,7 @@ async function runOneStageSingle(options: {
|
|
|
322
294
|
|
|
323
295
|
const targetModel = models[stage.relationField.type]
|
|
324
296
|
if (!targetModel) {
|
|
325
|
-
throw new
|
|
297
|
+
throw new HttpError(500, 'Target model not in relation metadata: ' + stage.relationField.type)
|
|
326
298
|
}
|
|
327
299
|
|
|
328
300
|
const finalArgs: Record<string, unknown> = { ...stage.stageArgs }
|
|
@@ -336,14 +308,14 @@ async function runOneStageSingle(options: {
|
|
|
336
308
|
|
|
337
309
|
const appliedInternal = setByPath(internal, stage.relationPath, result)
|
|
338
310
|
if (!appliedInternal) {
|
|
339
|
-
throw new
|
|
311
|
+
throw new HttpError(500, 'Failed to apply internal patch for ' + stage.relationPath)
|
|
340
312
|
}
|
|
341
313
|
|
|
342
314
|
const publicResult = buildPublicForStage(result, internalFieldPaths, stage.relationPath)
|
|
343
315
|
|
|
344
316
|
const appliedPublic = setByPath(publicState, stage.relationPath, publicResult)
|
|
345
317
|
if (!appliedPublic) {
|
|
346
|
-
throw new
|
|
318
|
+
throw new HttpError(500, 'Failed to apply public patch for ' + stage.relationPath)
|
|
347
319
|
}
|
|
348
320
|
|
|
349
321
|
sendSSEField(res, stage.relationPath, publicResult)
|
|
@@ -354,16 +326,9 @@ async function runAutoIncludeSingle(
|
|
|
354
326
|
plan: AutoIncludePlan,
|
|
355
327
|
): Promise<void> {
|
|
356
328
|
const { res, ctx, baseOp, delegateKey, models, signal } = options
|
|
329
|
+
const isClientGone = createClientGoneChecker(res, signal)
|
|
357
330
|
|
|
358
|
-
|
|
359
|
-
signal?.aborted === true || res.writableEnded || res.destroyed
|
|
360
|
-
|
|
361
|
-
let keepalive: IntervalHandle | null = null
|
|
362
|
-
try {
|
|
363
|
-
initSSE(res)
|
|
364
|
-
keepalive = startSSEKeepalive(res)
|
|
365
|
-
if (isClientGone()) return
|
|
366
|
-
|
|
331
|
+
await withSSE({ res, signal, label: 'single' }, async () => {
|
|
367
332
|
const extended = await getExtendedClient(ctx)
|
|
368
333
|
if (isClientGone()) return
|
|
369
334
|
|
|
@@ -374,7 +339,7 @@ async function runAutoIncludeSingle(
|
|
|
374
339
|
rootResult = await rootDelegate[baseOp as Exclude<AutoIncludeBaseOp, 'findMany' | 'findManyPaginated'>](plan.rootArgs)
|
|
375
340
|
} catch (err) {
|
|
376
341
|
if (isClientGone()) return
|
|
377
|
-
console.error('
|
|
342
|
+
console.error(LOG_PREFIX, 'root query failed:', err)
|
|
378
343
|
sendSSEError(res, mapError(err).message)
|
|
379
344
|
return
|
|
380
345
|
}
|
|
@@ -414,7 +379,7 @@ async function runAutoIncludeSingle(
|
|
|
414
379
|
if (isClientGone()) return
|
|
415
380
|
if (stageErrorMessage) break
|
|
416
381
|
|
|
417
|
-
await
|
|
382
|
+
await mapLimited(group, STAGE_CONCURRENCY, async (stage) => {
|
|
418
383
|
if (isAborted()) return
|
|
419
384
|
try {
|
|
420
385
|
await runOneStageSingle({
|
|
@@ -429,7 +394,7 @@ async function runAutoIncludeSingle(
|
|
|
429
394
|
})
|
|
430
395
|
} catch (err) {
|
|
431
396
|
if (isAborted()) return
|
|
432
|
-
console.error('
|
|
397
|
+
console.error(LOG_PREFIX, 'stage failed:', stage.relationPath, err)
|
|
433
398
|
stageErrorMessage = mapError(err).message
|
|
434
399
|
return
|
|
435
400
|
}
|
|
@@ -443,23 +408,13 @@ async function runAutoIncludeSingle(
|
|
|
443
408
|
if (isClientGone()) return
|
|
444
409
|
|
|
445
410
|
if (stageErrorMessage) {
|
|
446
|
-
|
|
447
|
-
sendSSEError(res, stageErrorMessage)
|
|
448
|
-
}
|
|
411
|
+
safeSendError(res, stageErrorMessage)
|
|
449
412
|
return
|
|
450
413
|
}
|
|
451
414
|
|
|
452
415
|
if (res.writableEnded || res.destroyed) return
|
|
453
416
|
sendSSEResult(res, publicState)
|
|
454
|
-
}
|
|
455
|
-
if (isClientGone()) return
|
|
456
|
-
console.error('[auto-progressive] dispatch error:', err)
|
|
457
|
-
if (!res.writableEnded && !res.destroyed) {
|
|
458
|
-
sendSSEError(res, mapError(err).message)
|
|
459
|
-
}
|
|
460
|
-
} finally {
|
|
461
|
-
endSSE(res, keepalive)
|
|
462
|
-
}
|
|
417
|
+
})
|
|
463
418
|
}
|
|
464
419
|
|
|
465
420
|
function buildStageQueryArgs(
|
|
@@ -487,11 +442,7 @@ function buildStageQueryArgs(
|
|
|
487
442
|
}
|
|
488
443
|
|
|
489
444
|
if (baseOmit && baseOmit[childKey] === true) {
|
|
490
|
-
const
|
|
491
|
-
for (const [k, v] of Object.entries(baseOmit)) {
|
|
492
|
-
if (k === childKey) continue
|
|
493
|
-
nextOmit[k] = v
|
|
494
|
-
}
|
|
445
|
+
const { [childKey]: _drop, ...nextOmit } = baseOmit
|
|
495
446
|
if (Object.keys(nextOmit).length > 0) {
|
|
496
447
|
finalArgs.omit = nextOmit
|
|
497
448
|
} else {
|
|
@@ -559,7 +510,7 @@ async function runOneStageMany(options: {
|
|
|
559
510
|
|
|
560
511
|
const targetModel = models[rel.type]
|
|
561
512
|
if (!targetModel) {
|
|
562
|
-
throw new
|
|
513
|
+
throw new HttpError(500, 'Target model not in relation metadata: ' + rel.type)
|
|
563
514
|
}
|
|
564
515
|
|
|
565
516
|
if (parentEntries.length === 0) {
|
|
@@ -681,7 +632,7 @@ async function processFindManyStages(args: {
|
|
|
681
632
|
if (signal?.aborted === true || res.writableEnded || res.destroyed) return stageErrorMessage
|
|
682
633
|
if (stageErrorMessage) break
|
|
683
634
|
|
|
684
|
-
await
|
|
635
|
+
await mapLimited(group, STAGE_CONCURRENCY, async (stage) => {
|
|
685
636
|
if (isAborted()) return
|
|
686
637
|
const parentEntries = collectParentEntries(rootPairs, stage.parentPath)
|
|
687
638
|
try {
|
|
@@ -696,7 +647,7 @@ async function processFindManyStages(args: {
|
|
|
696
647
|
})
|
|
697
648
|
} catch (err) {
|
|
698
649
|
if (isAborted()) return
|
|
699
|
-
console.error('
|
|
650
|
+
console.error(LOG_PREFIX, 'stage failed:', stage.relationPath, err)
|
|
700
651
|
stageErrorMessage = mapError(err).message
|
|
701
652
|
return
|
|
702
653
|
}
|
|
@@ -709,6 +660,29 @@ async function processFindManyStages(args: {
|
|
|
709
660
|
return stageErrorMessage
|
|
710
661
|
}
|
|
711
662
|
|
|
663
|
+
async function fetchRootAndCount(args: {
|
|
664
|
+
delegate: PrismaDelegate
|
|
665
|
+
rawClient: unknown
|
|
666
|
+
rootArgs: Record<string, unknown>
|
|
667
|
+
distinctCountLimit: number | undefined
|
|
668
|
+
countSource: NonNullable<OperationContext['paginationConfig']>['countSource'] | undefined
|
|
669
|
+
}): Promise<{ data: unknown[]; count: number }> {
|
|
670
|
+
const { delegate, rawClient, rootArgs, distinctCountLimit, countSource } = args
|
|
671
|
+
const [data, count] = await Promise.all([
|
|
672
|
+
delegate.findMany(rootArgs),
|
|
673
|
+
countForPagination(
|
|
674
|
+
delegate,
|
|
675
|
+
rootArgs,
|
|
676
|
+
undefined,
|
|
677
|
+
undefined,
|
|
678
|
+
distinctCountLimit,
|
|
679
|
+
countSource,
|
|
680
|
+
rawClient,
|
|
681
|
+
),
|
|
682
|
+
])
|
|
683
|
+
return { data: data as unknown[], count }
|
|
684
|
+
}
|
|
685
|
+
|
|
712
686
|
async function runPaginatedRoot(args: {
|
|
713
687
|
extended: unknown
|
|
714
688
|
delegateKey: string
|
|
@@ -730,160 +704,81 @@ async function runPaginatedRoot(args: {
|
|
|
730
704
|
'findManyPaginatedMode="transaction" requires transaction support on the Prisma client',
|
|
731
705
|
)
|
|
732
706
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
distinctCountLimit,
|
|
743
|
-
countSource,
|
|
744
|
-
tx,
|
|
745
|
-
),
|
|
746
|
-
])
|
|
747
|
-
return { data, count }
|
|
748
|
-
})
|
|
749
|
-
return { data: result.data as unknown[], count: result.count }
|
|
707
|
+
return txClient.$transaction((tx: unknown) =>
|
|
708
|
+
fetchRootAndCount({
|
|
709
|
+
delegate: getDelegate(tx, delegateKey),
|
|
710
|
+
rawClient: tx,
|
|
711
|
+
rootArgs,
|
|
712
|
+
distinctCountLimit,
|
|
713
|
+
countSource,
|
|
714
|
+
}),
|
|
715
|
+
)
|
|
750
716
|
}
|
|
751
717
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
undefined,
|
|
760
|
-
distinctCountLimit,
|
|
761
|
-
countSource,
|
|
762
|
-
extended,
|
|
763
|
-
),
|
|
764
|
-
])
|
|
765
|
-
return { data: data as unknown[], count }
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
async function runAutoIncludeMany(
|
|
769
|
-
options: RunAutoIncludeOptions,
|
|
770
|
-
plan: AutoIncludePlan,
|
|
771
|
-
): Promise<void> {
|
|
772
|
-
const { res, ctx, delegateKey, models, signal } = options
|
|
773
|
-
|
|
774
|
-
const isClientGone = () =>
|
|
775
|
-
signal?.aborted === true || res.writableEnded || res.destroyed
|
|
776
|
-
|
|
777
|
-
let keepalive: IntervalHandle | null = null
|
|
778
|
-
try {
|
|
779
|
-
initSSE(res)
|
|
780
|
-
keepalive = startSSEKeepalive(res)
|
|
781
|
-
if (isClientGone()) return
|
|
782
|
-
|
|
783
|
-
const extended = await getExtendedClient(ctx)
|
|
784
|
-
if (isClientGone()) return
|
|
785
|
-
|
|
786
|
-
const rootDelegate = getDelegate(extended, delegateKey)
|
|
787
|
-
const rootArgs = applyPaginationLimits(plan.rootArgs, ctx.paginationConfig, !!ctx.guardShape)
|
|
788
|
-
|
|
789
|
-
let rootResult: unknown
|
|
790
|
-
try {
|
|
791
|
-
rootResult = await rootDelegate.findMany(rootArgs)
|
|
792
|
-
} catch (err) {
|
|
793
|
-
if (isClientGone()) return
|
|
794
|
-
console.error('[auto-progressive] root findMany failed:', err)
|
|
795
|
-
sendSSEError(res, mapError(err).message)
|
|
796
|
-
return
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
if (isClientGone()) return
|
|
800
|
-
|
|
801
|
-
if (!Array.isArray(rootResult)) {
|
|
802
|
-
sendSSEError(res, 'auto-progressive: unexpected non-array root result for findMany')
|
|
803
|
-
return
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
const { publicRows, rootPairs } = buildRootPairs(rootResult, plan.internalFieldPaths)
|
|
807
|
-
|
|
808
|
-
sendSSERootArray(res, publicRows)
|
|
809
|
-
sendSSEProgress(res, 'root', 0, plan.stages.length)
|
|
810
|
-
|
|
811
|
-
const stageError = await processFindManyStages({
|
|
812
|
-
extended, models, plan, rootPairs, res, signal,
|
|
813
|
-
})
|
|
814
|
-
|
|
815
|
-
if (isClientGone()) return
|
|
816
|
-
|
|
817
|
-
if (stageError) {
|
|
818
|
-
if (!res.writableEnded && !res.destroyed) {
|
|
819
|
-
sendSSEError(res, stageError)
|
|
820
|
-
}
|
|
821
|
-
return
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
if (res.writableEnded || res.destroyed) return
|
|
825
|
-
sendSSEResult(res, publicRows)
|
|
826
|
-
} catch (err) {
|
|
827
|
-
if (isClientGone()) return
|
|
828
|
-
console.error('[auto-progressive] many dispatch error:', err)
|
|
829
|
-
if (!res.writableEnded && !res.destroyed) {
|
|
830
|
-
sendSSEError(res, mapError(err).message)
|
|
831
|
-
}
|
|
832
|
-
} finally {
|
|
833
|
-
endSSE(res, keepalive)
|
|
834
|
-
}
|
|
718
|
+
return fetchRootAndCount({
|
|
719
|
+
delegate: getDelegate(extended, delegateKey),
|
|
720
|
+
rawClient: extended,
|
|
721
|
+
rootArgs,
|
|
722
|
+
distinctCountLimit,
|
|
723
|
+
countSource,
|
|
724
|
+
})
|
|
835
725
|
}
|
|
836
726
|
|
|
837
|
-
async function
|
|
727
|
+
async function runAutoIncludeManyOrPaginated(
|
|
838
728
|
options: RunAutoIncludeOptions,
|
|
839
729
|
plan: AutoIncludePlan,
|
|
730
|
+
isPaginated: boolean,
|
|
840
731
|
): Promise<void> {
|
|
841
732
|
const { res, ctx, delegateKey, models, signal } = options
|
|
733
|
+
const isClientGone = createClientGoneChecker(res, signal)
|
|
842
734
|
|
|
843
|
-
|
|
844
|
-
signal?.aborted === true || res.writableEnded || res.destroyed
|
|
845
|
-
|
|
846
|
-
let keepalive: IntervalHandle | null = null
|
|
847
|
-
try {
|
|
848
|
-
initSSE(res)
|
|
849
|
-
keepalive = startSSEKeepalive(res)
|
|
850
|
-
if (isClientGone()) return
|
|
851
|
-
|
|
735
|
+
await withSSE({ res, signal, label: isPaginated ? 'paginated' : 'many' }, async () => {
|
|
852
736
|
const extended = await getExtendedClient(ctx)
|
|
853
737
|
if (isClientGone()) return
|
|
854
738
|
|
|
855
739
|
const rootArgs = applyPaginationLimits(plan.rootArgs, ctx.paginationConfig, !!ctx.guardShape)
|
|
856
|
-
const mode: FindManyPaginatedMode = ctx.findManyPaginatedMode ?? 'promiseAll'
|
|
857
740
|
|
|
858
741
|
let rootRows: unknown[]
|
|
859
|
-
let total
|
|
742
|
+
let total = 0
|
|
743
|
+
let hasMore = false
|
|
744
|
+
|
|
860
745
|
try {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
delegateKey,
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
746
|
+
if (isPaginated) {
|
|
747
|
+
const mode: FindManyPaginatedMode = ctx.findManyPaginatedMode ?? 'promiseAll'
|
|
748
|
+
const r = await runPaginatedRoot({ extended, delegateKey, rootArgs, ctx, mode })
|
|
749
|
+
rootRows = r.data
|
|
750
|
+
total = r.count
|
|
751
|
+
const skip = typeof rootArgs.skip === 'number' ? rootArgs.skip : 0
|
|
752
|
+
const takeRaw = typeof rootArgs.take === 'number' ? rootArgs.take : rootRows.length
|
|
753
|
+
const absTake = Math.abs(takeRaw)
|
|
754
|
+
hasMore = absTake > 0 && rootRows.length >= absTake && skip + rootRows.length < total
|
|
755
|
+
} else {
|
|
756
|
+
const rootDelegate = getDelegate(extended, delegateKey)
|
|
757
|
+
const result = await rootDelegate.findMany(rootArgs)
|
|
758
|
+
if (!Array.isArray(result)) {
|
|
759
|
+
safeSendError(res, 'auto-progressive: unexpected non-array root result for findMany')
|
|
760
|
+
return
|
|
761
|
+
}
|
|
762
|
+
rootRows = result
|
|
763
|
+
}
|
|
870
764
|
} catch (err) {
|
|
871
765
|
if (isClientGone()) return
|
|
872
|
-
console.error(
|
|
766
|
+
console.error(
|
|
767
|
+
LOG_PREFIX,
|
|
768
|
+
isPaginated ? 'root findManyPaginated failed:' : 'root findMany failed:',
|
|
769
|
+
err,
|
|
770
|
+
)
|
|
873
771
|
sendSSEError(res, mapError(err).message)
|
|
874
772
|
return
|
|
875
773
|
}
|
|
876
774
|
|
|
877
775
|
if (isClientGone()) return
|
|
878
776
|
|
|
879
|
-
const skip = typeof rootArgs.skip === 'number' ? rootArgs.skip : 0
|
|
880
|
-
const takeRaw = typeof rootArgs.take === 'number' ? rootArgs.take : rootRows.length
|
|
881
|
-
const absTake = Math.abs(takeRaw)
|
|
882
|
-
const hasMore = absTake > 0 && rootRows.length >= absTake && skip + rootRows.length < total
|
|
883
|
-
|
|
884
777
|
const { publicRows, rootPairs } = buildRootPairs(rootRows, plan.internalFieldPaths)
|
|
885
778
|
|
|
886
|
-
|
|
779
|
+
if (isPaginated) {
|
|
780
|
+
sendSSEPageMeta(res, total, hasMore)
|
|
781
|
+
}
|
|
887
782
|
sendSSERootArray(res, publicRows)
|
|
888
783
|
sendSSEProgress(res, 'root', 0, plan.stages.length)
|
|
889
784
|
|
|
@@ -894,23 +789,17 @@ async function runAutoIncludePaginated(
|
|
|
894
789
|
if (isClientGone()) return
|
|
895
790
|
|
|
896
791
|
if (stageError) {
|
|
897
|
-
|
|
898
|
-
sendSSEError(res, stageError)
|
|
899
|
-
}
|
|
792
|
+
safeSendError(res, stageError)
|
|
900
793
|
return
|
|
901
794
|
}
|
|
902
795
|
|
|
903
796
|
if (res.writableEnded || res.destroyed) return
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
if (!res.writableEnded && !res.destroyed) {
|
|
909
|
-
sendSSEError(res, mapError(err).message)
|
|
797
|
+
if (isPaginated) {
|
|
798
|
+
sendSSEResult(res, { data: publicRows, total, hasMore })
|
|
799
|
+
} else {
|
|
800
|
+
sendSSEResult(res, publicRows)
|
|
910
801
|
}
|
|
911
|
-
}
|
|
912
|
-
endSSE(res, keepalive)
|
|
913
|
-
}
|
|
802
|
+
})
|
|
914
803
|
}
|
|
915
804
|
|
|
916
805
|
export async function runAutoIncludeProgressive(
|
|
@@ -950,10 +839,10 @@ export async function runAutoIncludeProgressive(
|
|
|
950
839
|
}
|
|
951
840
|
|
|
952
841
|
if (options.baseOp === 'findMany') {
|
|
953
|
-
return
|
|
842
|
+
return runAutoIncludeManyOrPaginated(options, plan, false)
|
|
954
843
|
}
|
|
955
844
|
if (options.baseOp === 'findManyPaginated') {
|
|
956
|
-
return
|
|
845
|
+
return runAutoIncludeManyOrPaginated(options, plan, true)
|
|
957
846
|
}
|
|
958
847
|
return runAutoIncludeSingle(options, plan)
|
|
959
848
|
}
|