prisma-generator-express 1.60.0 → 1.61.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.
@@ -15,10 +15,7 @@ import {
15
15
  setByPath,
16
16
  withSSE,
17
17
  } from './sse'
18
- import {
19
- applyPaginationLimits,
20
- countForPagination,
21
- } from './pagination'
18
+ import { applyPaginationLimits, countForPagination } from './pagination'
22
19
  import {
23
20
  getDelegate,
24
21
  getExtendedClient,
@@ -35,6 +32,10 @@ import {
35
32
  type AutoIncludeStage,
36
33
  } from './autoIncludePlanner'
37
34
  import type { AutoIncludeProgressiveVariantConfig } from './routeConfig'
35
+ import {
36
+ isGuardedAutoIncludeBaseOp,
37
+ runGuardedAutoIncludeProgressive,
38
+ } from './autoIncludeRuntimeGuarded'
38
39
 
39
40
  const STAGE_CONCURRENCY = 4
40
41
  const MAX_IN_CHUNK = 1000
@@ -70,7 +71,10 @@ type ParentEntry = RowPair & {
70
71
  locator: Array<number | string>
71
72
  }
72
73
 
73
- function createClientGoneChecker(res: Response, signal?: AbortSignal): () => boolean {
74
+ function createClientGoneChecker(
75
+ res: Response,
76
+ signal?: AbortSignal,
77
+ ): () => boolean {
74
78
  return () => signal?.aborted === true || res.writableEnded || res.destroyed
75
79
  }
76
80
 
@@ -103,7 +107,8 @@ function mergeWhere(
103
107
  userWhere: unknown,
104
108
  linkFilter: Record<string, unknown>,
105
109
  ): Record<string, unknown> {
106
- if (!isPlainObject(userWhere) || Object.keys(userWhere).length === 0) return linkFilter
110
+ if (!isPlainObject(userWhere) || Object.keys(userWhere).length === 0)
111
+ return linkFilter
107
112
  return { AND: [userWhere, linkFilter] }
108
113
  }
109
114
 
@@ -269,7 +274,16 @@ async function runOneStageSingle(options: {
269
274
  res: Response
270
275
  isAborted: () => boolean
271
276
  }): Promise<void> {
272
- const { extended, models, stage, internal, publicState, internalFieldPaths, res, isAborted } = options
277
+ const {
278
+ extended,
279
+ models,
280
+ stage,
281
+ internal,
282
+ publicState,
283
+ internalFieldPaths,
284
+ res,
285
+ isAborted,
286
+ } = options
273
287
  if (isAborted()) return
274
288
 
275
289
  const parentRaw = readPath(internal, stage.parentPath)
@@ -294,28 +308,46 @@ async function runOneStageSingle(options: {
294
308
 
295
309
  const targetModel = models[stage.relationField.type]
296
310
  if (!targetModel) {
297
- throw new HttpError(500, 'Target model not in relation metadata: ' + stage.relationField.type)
311
+ throw new HttpError(
312
+ 500,
313
+ 'Target model not in relation metadata: ' + stage.relationField.type,
314
+ )
298
315
  }
299
316
 
300
317
  const finalArgs: Record<string, unknown> = { ...stage.stageArgs }
301
318
  finalArgs.where = mergeWhere(stage.stageArgs.where, linkFilter)
302
319
 
303
- const delegate: PrismaDelegate = getDelegate(extended, targetModel.delegateKey)
304
- const method: 'findMany' | 'findFirst' = stage.relationField.isList ? 'findMany' : 'findFirst'
320
+ const delegate: PrismaDelegate = getDelegate(
321
+ extended,
322
+ targetModel.delegateKey,
323
+ )
324
+ const method: 'findMany' | 'findFirst' = stage.relationField.isList
325
+ ? 'findMany'
326
+ : 'findFirst'
305
327
  const result = await delegate[method](finalArgs)
306
328
 
307
329
  if (isAborted()) return
308
330
 
309
331
  const appliedInternal = setByPath(internal, stage.relationPath, result)
310
332
  if (!appliedInternal) {
311
- throw new HttpError(500, 'Failed to apply internal patch for ' + stage.relationPath)
333
+ throw new HttpError(
334
+ 500,
335
+ 'Failed to apply internal patch for ' + stage.relationPath,
336
+ )
312
337
  }
313
338
 
314
- const publicResult = buildPublicForStage(result, internalFieldPaths, stage.relationPath)
339
+ const publicResult = buildPublicForStage(
340
+ result,
341
+ internalFieldPaths,
342
+ stage.relationPath,
343
+ )
315
344
 
316
345
  const appliedPublic = setByPath(publicState, stage.relationPath, publicResult)
317
346
  if (!appliedPublic) {
318
- throw new HttpError(500, 'Failed to apply public patch for ' + stage.relationPath)
347
+ throw new HttpError(
348
+ 500,
349
+ 'Failed to apply public patch for ' + stage.relationPath,
350
+ )
319
351
  }
320
352
 
321
353
  sendSSEField(res, stage.relationPath, publicResult)
@@ -336,7 +368,9 @@ async function runAutoIncludeSingle(
336
368
 
337
369
  let rootResult: unknown
338
370
  try {
339
- rootResult = await rootDelegate[baseOp as Exclude<AutoIncludeBaseOp, 'findMany' | 'findManyPaginated'>](plan.rootArgs)
371
+ rootResult = await rootDelegate[
372
+ baseOp as Exclude<AutoIncludeBaseOp, 'findMany' | 'findManyPaginated'>
373
+ ](plan.rootArgs)
340
374
  } catch (err) {
341
375
  if (isClientGone()) return
342
376
  console.error(LOG_PREFIX, 'root query failed:', err)
@@ -400,7 +434,12 @@ async function runAutoIncludeSingle(
400
434
  }
401
435
  if (isAborted()) return
402
436
  completed++
403
- const ok = sendSSEProgress(res, stage.relationPath, completed, plan.stages.length)
437
+ const ok = sendSSEProgress(
438
+ res,
439
+ stage.relationPath,
440
+ completed,
441
+ plan.stages.length,
442
+ )
404
443
  if (!ok) return
405
444
  })
406
445
  }
@@ -430,7 +469,9 @@ function buildStageQueryArgs(
430
469
  : null
431
470
 
432
471
  const finalArgs: Record<string, unknown> = { ...stage.stageArgs }
433
- finalArgs.where = mergeWhere(stage.stageArgs.where, { [childKey]: { in: inChunk } })
472
+ finalArgs.where = mergeWhere(stage.stageArgs.where, {
473
+ [childKey]: { in: inChunk },
474
+ })
434
475
 
435
476
  let injectedChildPath: string | null = null
436
477
 
@@ -500,7 +541,15 @@ async function runOneStageMany(options: {
500
541
  res: Response
501
542
  isAborted: () => boolean
502
543
  }): Promise<void> {
503
- const { extended, models, stage, parentEntries, internalFieldPaths, res, isAborted } = options
544
+ const {
545
+ extended,
546
+ models,
547
+ stage,
548
+ parentEntries,
549
+ internalFieldPaths,
550
+ res,
551
+ isAborted,
552
+ } = options
504
553
 
505
554
  if (isAborted()) return
506
555
 
@@ -510,7 +559,10 @@ async function runOneStageMany(options: {
510
559
 
511
560
  const targetModel = models[rel.type]
512
561
  if (!targetModel) {
513
- throw new HttpError(500, 'Target model not in relation metadata: ' + rel.type)
562
+ throw new HttpError(
563
+ 500,
564
+ 'Target model not in relation metadata: ' + rel.type,
565
+ )
514
566
  }
515
567
 
516
568
  if (parentEntries.length === 0) {
@@ -524,7 +576,10 @@ async function runOneStageMany(options: {
524
576
 
525
577
  const internalParents = parentEntries.map((p) => p.internal)
526
578
  const distinctValues = collectDistinctParentValues(internalParents, parentKey)
527
- const delegate: PrismaDelegate = getDelegate(extended, targetModel.delegateKey)
579
+ const delegate: PrismaDelegate = getDelegate(
580
+ extended,
581
+ targetModel.delegateKey,
582
+ )
528
583
 
529
584
  const children: unknown[] = []
530
585
  let injectedChildPath: string | null = null
@@ -532,7 +587,11 @@ async function runOneStageMany(options: {
532
587
  for (let i = 0; i < distinctValues.length; i += MAX_IN_CHUNK) {
533
588
  if (isAborted()) return
534
589
  const chunk = distinctValues.slice(i, i + MAX_IN_CHUNK)
535
- const { args, injectedChildPath: ip } = buildStageQueryArgs(stage, childKey, chunk)
590
+ const { args, injectedChildPath: ip } = buildStageQueryArgs(
591
+ stage,
592
+ childKey,
593
+ chunk,
594
+ )
536
595
  if (ip) injectedChildPath = ip
537
596
  const partial = await delegate.findMany(args)
538
597
  if (isAborted()) return
@@ -564,7 +623,11 @@ async function runOneStageMany(options: {
564
623
  }
565
624
  }
566
625
 
567
- const publicVal = buildPublicForStage(internalVal, effectivePaths, stage.relationPath)
626
+ const publicVal = buildPublicForStage(
627
+ internalVal,
628
+ effectivePaths,
629
+ stage.relationPath,
630
+ )
568
631
 
569
632
  entry.internal[stage.relationName] = internalVal
570
633
  entry.public[stage.relationName] = publicVal
@@ -629,7 +692,8 @@ async function processFindManyStages(args: {
629
692
  res.destroyed
630
693
 
631
694
  for (const group of groups) {
632
- if (signal?.aborted === true || res.writableEnded || res.destroyed) return stageErrorMessage
695
+ if (signal?.aborted === true || res.writableEnded || res.destroyed)
696
+ return stageErrorMessage
633
697
  if (stageErrorMessage) break
634
698
 
635
699
  await mapLimited(group, STAGE_CONCURRENCY, async (stage) => {
@@ -653,7 +717,12 @@ async function processFindManyStages(args: {
653
717
  }
654
718
  if (isAborted()) return
655
719
  completed++
656
- const ok = sendSSEProgress(res, stage.relationPath, completed, plan.stages.length)
720
+ const ok = sendSSEProgress(
721
+ res,
722
+ stage.relationPath,
723
+ completed,
724
+ plan.stages.length,
725
+ )
657
726
  if (!ok) return
658
727
  })
659
728
  }
@@ -665,9 +734,12 @@ async function fetchRootAndCount(args: {
665
734
  rawClient: unknown
666
735
  rootArgs: Record<string, unknown>
667
736
  distinctCountLimit: number | undefined
668
- countSource: NonNullable<OperationContext['paginationConfig']>['countSource'] | undefined
737
+ countSource:
738
+ | NonNullable<OperationContext['paginationConfig']>['countSource']
739
+ | undefined
669
740
  }): Promise<{ data: unknown[]; count: number }> {
670
- const { delegate, rawClient, rootArgs, distinctCountLimit, countSource } = args
741
+ const { delegate, rawClient, rootArgs, distinctCountLimit, countSource } =
742
+ args
671
743
  const [data, count] = await Promise.all([
672
744
  delegate.findMany(rootArgs),
673
745
  countForPagination(
@@ -732,83 +804,130 @@ async function runAutoIncludeManyOrPaginated(
732
804
  const { res, ctx, delegateKey, models, signal } = options
733
805
  const isClientGone = createClientGoneChecker(res, signal)
734
806
 
735
- await withSSE({ res, signal, label: isPaginated ? 'paginated' : 'many' }, async () => {
736
- const extended = await getExtendedClient(ctx)
737
- if (isClientGone()) return
807
+ await withSSE(
808
+ { res, signal, label: isPaginated ? 'paginated' : 'many' },
809
+ async () => {
810
+ const extended = await getExtendedClient(ctx)
811
+ if (isClientGone()) return
738
812
 
739
- const rootArgs = applyPaginationLimits(plan.rootArgs, ctx.paginationConfig, !!ctx.guardShape)
813
+ const rootArgs = applyPaginationLimits(
814
+ plan.rootArgs,
815
+ ctx.paginationConfig,
816
+ !!ctx.guardShape,
817
+ )
740
818
 
741
- let rootRows: unknown[]
742
- let total = 0
743
- let hasMore = false
819
+ let rootRows: unknown[]
820
+ let total = 0
821
+ let hasMore = false
744
822
 
745
- try {
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
823
+ try {
824
+ if (isPaginated) {
825
+ const mode: FindManyPaginatedMode =
826
+ ctx.findManyPaginatedMode ?? 'promiseAll'
827
+ const r = await runPaginatedRoot({
828
+ extended,
829
+ delegateKey,
830
+ rootArgs,
831
+ ctx,
832
+ mode,
833
+ })
834
+ rootRows = r.data
835
+ total = r.count
836
+ const skip = typeof rootArgs.skip === 'number' ? rootArgs.skip : 0
837
+ const takeRaw =
838
+ typeof rootArgs.take === 'number' ? rootArgs.take : rootRows.length
839
+ const absTake = Math.abs(takeRaw)
840
+ hasMore =
841
+ absTake > 0 &&
842
+ rootRows.length >= absTake &&
843
+ skip + rootRows.length < total
844
+ } else {
845
+ const rootDelegate = getDelegate(extended, delegateKey)
846
+ const result = await rootDelegate.findMany(rootArgs)
847
+ if (!Array.isArray(result)) {
848
+ safeSendError(
849
+ res,
850
+ 'auto-progressive: unexpected non-array root result for findMany',
851
+ )
852
+ return
853
+ }
854
+ rootRows = result
761
855
  }
762
- rootRows = result
856
+ } catch (err) {
857
+ if (isClientGone()) return
858
+ console.error(
859
+ LOG_PREFIX,
860
+ isPaginated
861
+ ? 'root findManyPaginated failed:'
862
+ : 'root findMany failed:',
863
+ err,
864
+ )
865
+ sendSSEError(res, mapError(err).message)
866
+ return
763
867
  }
764
- } catch (err) {
765
- if (isClientGone()) return
766
- console.error(
767
- LOG_PREFIX,
768
- isPaginated ? 'root findManyPaginated failed:' : 'root findMany failed:',
769
- err,
770
- )
771
- sendSSEError(res, mapError(err).message)
772
- return
773
- }
774
868
 
775
- if (isClientGone()) return
776
-
777
- const { publicRows, rootPairs } = buildRootPairs(rootRows, plan.internalFieldPaths)
869
+ if (isClientGone()) return
778
870
 
779
- if (isPaginated) {
780
- sendSSEPageMeta(res, total, hasMore)
781
- }
782
- sendSSERootArray(res, publicRows)
783
- sendSSEProgress(res, 'root', 0, plan.stages.length)
871
+ const { publicRows, rootPairs } = buildRootPairs(
872
+ rootRows,
873
+ plan.internalFieldPaths,
874
+ )
784
875
 
785
- const stageError = await processFindManyStages({
786
- extended, models, plan, rootPairs, res, signal,
787
- })
876
+ if (isPaginated) {
877
+ sendSSEPageMeta(res, total, hasMore)
878
+ }
879
+ sendSSERootArray(res, publicRows)
880
+ sendSSEProgress(res, 'root', 0, plan.stages.length)
881
+
882
+ const stageError = await processFindManyStages({
883
+ extended,
884
+ models,
885
+ plan,
886
+ rootPairs,
887
+ res,
888
+ signal,
889
+ })
788
890
 
789
- if (isClientGone()) return
891
+ if (isClientGone()) return
790
892
 
791
- if (stageError) {
792
- safeSendError(res, stageError)
793
- return
794
- }
893
+ if (stageError) {
894
+ safeSendError(res, stageError)
895
+ return
896
+ }
795
897
 
796
- if (res.writableEnded || res.destroyed) return
797
- if (isPaginated) {
798
- sendSSEResult(res, { data: publicRows, total, hasMore })
799
- } else {
800
- sendSSEResult(res, publicRows)
801
- }
802
- })
898
+ if (res.writableEnded || res.destroyed) return
899
+ if (isPaginated) {
900
+ sendSSEResult(res, { data: publicRows, total, hasMore })
901
+ } else {
902
+ sendSSEResult(res, publicRows)
903
+ }
904
+ },
905
+ )
803
906
  }
804
907
 
805
908
  export async function runAutoIncludeProgressive(
806
909
  options: RunAutoIncludeOptions,
807
910
  ): Promise<void> {
808
911
  if (options.ctx.guardShape) {
912
+ if (isGuardedAutoIncludeBaseOp(options.baseOp)) {
913
+ return runGuardedAutoIncludeProgressive({
914
+ req: options.req,
915
+ res: options.res,
916
+ ctx: options.ctx,
917
+ args: options.args,
918
+ baseOp: options.baseOp,
919
+ modelName: options.modelName,
920
+ delegateKey: options.delegateKey,
921
+ models: options.models,
922
+ variantConfig: options.variantConfig,
923
+ coreQueryFn: options.coreQueryFn,
924
+ signal: options.signal,
925
+ })
926
+ }
809
927
  return handleAutoIncludeFallback(
810
928
  options,
811
- 'auto-progressive fallback: guard shape disables auto-include',
929
+ 'auto-progressive fallback: guard shape disables auto-include for baseOp=' +
930
+ options.baseOp,
812
931
  )
813
932
  }
814
933
 
@@ -845,4 +964,4 @@ export async function runAutoIncludeProgressive(
845
964
  return runAutoIncludeManyOrPaginated(options, plan, true)
846
965
  }
847
966
  return runAutoIncludeSingle(options, plan)
848
- }
967
+ }