prisma-generator-express 1.14.0 → 1.14.1
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 +2 -2
- package/dist/helpers/generateRouteFile.js +1 -1
- package/package.json +1 -1
- package/src/copy/transformZod.spec.ts +155 -106
- package/src/copy/transformZod.ts +21 -21
- package/src/helpers/generateRouteFile.ts +1 -1
package/README.md
CHANGED
|
@@ -164,7 +164,7 @@ const afterFindFirst: RequestHandler = (
|
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
166
|
* For generated route the middleware order will be as follows:
|
|
167
|
-
* 1. Query parser
|
|
167
|
+
* 1. Query parser (kicks in for GET requests)
|
|
168
168
|
* 2. Custom middlewares: config.{method}.before[]
|
|
169
169
|
* 3. Input validator middleware (Optional): config.{method}.input
|
|
170
170
|
* 4. Generated middleware
|
|
@@ -176,7 +176,7 @@ const someRouterConfig: RouteConfig<RequestHandler> = {
|
|
|
176
176
|
before: [beforeFindFirst],
|
|
177
177
|
after: [afterFindFirst],
|
|
178
178
|
input: {
|
|
179
|
-
schema: UserAccountFindFirstSchema,
|
|
179
|
+
schema: UserAccountFindFirstSchema, // make sure you set `isGenerateSelect = true` in prisma-zod-generator
|
|
180
180
|
allow: [
|
|
181
181
|
'select.id',
|
|
182
182
|
'select.full_name',
|
|
@@ -27,7 +27,7 @@ import { ${modelName}GroupBy } from './${modelName}GroupBy';
|
|
|
27
27
|
import { createValidatorMiddleware, ValidatorOptions } from '../createValidatorMiddleware'
|
|
28
28
|
import { createOutputValidatorMiddleware } from '../createOutputValidatorMiddleware'
|
|
29
29
|
import { RouteConfig, ValidatorConfig } from '../routeConfig'
|
|
30
|
-
import { parseQueryParams } from "../
|
|
30
|
+
import { parseQueryParams } from "../parseQueryParams";
|
|
31
31
|
|
|
32
32
|
const defaultBeforeAfter = {
|
|
33
33
|
before: [] as RequestHandler[],
|
package/package.json
CHANGED
|
@@ -553,106 +553,7 @@ describe('Cryptocurrency Schema Validation', () => {
|
|
|
553
553
|
expect(error).toBeInstanceOf(ZodError)
|
|
554
554
|
}
|
|
555
555
|
})
|
|
556
|
-
|
|
557
|
-
it('deep nesting', () => {
|
|
558
|
-
const taskSchema = z.object({
|
|
559
|
-
select: z
|
|
560
|
-
.object({
|
|
561
|
-
id: z.boolean().optional(),
|
|
562
|
-
project_id: z.boolean().optional(),
|
|
563
|
-
list_id: z.boolean().optional(),
|
|
564
|
-
user_assignments: z
|
|
565
|
-
.object({
|
|
566
|
-
select: z.object({
|
|
567
|
-
user: z.boolean().optional(),
|
|
568
|
-
}),
|
|
569
|
-
})
|
|
570
|
-
.optional(),
|
|
571
|
-
tags_mappings: z
|
|
572
|
-
.object({
|
|
573
|
-
select: z.object({
|
|
574
|
-
tag: z.boolean().optional(),
|
|
575
|
-
}),
|
|
576
|
-
})
|
|
577
|
-
.optional(),
|
|
578
|
-
attachments: z
|
|
579
|
-
.object({
|
|
580
|
-
select: z.object({
|
|
581
|
-
attachment: z.boolean().optional(),
|
|
582
|
-
}),
|
|
583
|
-
where: z
|
|
584
|
-
.object({
|
|
585
|
-
is_image: z.boolean().optional(),
|
|
586
|
-
})
|
|
587
|
-
.optional(),
|
|
588
|
-
take: z.number().optional(),
|
|
589
|
-
orderBy: z
|
|
590
|
-
.object({
|
|
591
|
-
created_at: z.enum(['asc', 'desc']).optional(),
|
|
592
|
-
})
|
|
593
|
-
.optional(),
|
|
594
|
-
})
|
|
595
|
-
.optional(),
|
|
596
|
-
rendered_description: z.boolean().optional(),
|
|
597
|
-
description: z.boolean().optional(),
|
|
598
|
-
created_at: z.boolean().optional(),
|
|
599
|
-
start_date: z.boolean().optional(),
|
|
600
|
-
reactions: z.boolean().optional(),
|
|
601
|
-
intervals: z.boolean().optional(),
|
|
602
|
-
column_id: z.boolean().optional(),
|
|
603
|
-
priority: z.boolean().optional(),
|
|
604
|
-
due_date: z.boolean().optional(),
|
|
605
|
-
column: z.boolean().optional(),
|
|
606
|
-
title: z.boolean().optional(),
|
|
607
|
-
order: z.boolean().optional(),
|
|
608
|
-
color: z.boolean().optional(),
|
|
609
|
-
})
|
|
610
|
-
.optional(),
|
|
611
|
-
where: z
|
|
612
|
-
.object({
|
|
613
|
-
id: z.string().optional(),
|
|
614
|
-
AND: z
|
|
615
|
-
.array(
|
|
616
|
-
z.object({
|
|
617
|
-
OR: z
|
|
618
|
-
.array(
|
|
619
|
-
z.object({
|
|
620
|
-
to_delete: z.boolean().nullable().optional(),
|
|
621
|
-
}),
|
|
622
|
-
)
|
|
623
|
-
.optional(),
|
|
624
|
-
}),
|
|
625
|
-
)
|
|
626
|
-
.optional(),
|
|
627
|
-
})
|
|
628
|
-
.optional(),
|
|
629
|
-
})
|
|
630
|
-
|
|
631
|
-
const allowedFields = [
|
|
632
|
-
'select.id',
|
|
633
|
-
'select.project_id',
|
|
634
|
-
'select.list_id',
|
|
635
|
-
'select.user_assignments.select.user',
|
|
636
|
-
'select.tags_mappings.select.tag',
|
|
637
|
-
'select.attachments.select.attachment',
|
|
638
|
-
'select.attachments.where.is_image',
|
|
639
|
-
'select.attachments.take',
|
|
640
|
-
'select.attachments.orderBy.created_at',
|
|
641
|
-
'select.rendered_description',
|
|
642
|
-
'select.description',
|
|
643
|
-
'select.created_at',
|
|
644
|
-
'select.start_date',
|
|
645
|
-
'select.reactions',
|
|
646
|
-
'select.intervals',
|
|
647
|
-
'select.column_id',
|
|
648
|
-
'select.priority',
|
|
649
|
-
'select.due_date',
|
|
650
|
-
'select.column',
|
|
651
|
-
'select.order',
|
|
652
|
-
'select.color',
|
|
653
|
-
'where.id',
|
|
654
|
-
'where.AND[].OR[].to_delete',
|
|
655
|
-
]
|
|
556
|
+
describe('Prisma example', () => {
|
|
656
557
|
const inputData = {
|
|
657
558
|
select: {
|
|
658
559
|
id: true,
|
|
@@ -703,12 +604,160 @@ describe('Cryptocurrency Schema Validation', () => {
|
|
|
703
604
|
],
|
|
704
605
|
},
|
|
705
606
|
}
|
|
607
|
+
it('deep nesting', () => {
|
|
608
|
+
const taskSchema = z.object({
|
|
609
|
+
select: z
|
|
610
|
+
.object({
|
|
611
|
+
id: z.boolean().optional(),
|
|
612
|
+
project_id: z.boolean().optional(),
|
|
613
|
+
list_id: z.boolean().optional(),
|
|
614
|
+
user_assignments: z
|
|
615
|
+
.object({
|
|
616
|
+
select: z.object({
|
|
617
|
+
user: z.boolean().optional(),
|
|
618
|
+
}),
|
|
619
|
+
})
|
|
620
|
+
.optional(),
|
|
621
|
+
tags_mappings: z
|
|
622
|
+
.object({
|
|
623
|
+
select: z.object({
|
|
624
|
+
tag: z.boolean().optional(),
|
|
625
|
+
}),
|
|
626
|
+
})
|
|
627
|
+
.optional(),
|
|
628
|
+
attachments: z
|
|
629
|
+
.object({
|
|
630
|
+
select: z.object({
|
|
631
|
+
attachment: z.boolean().optional(),
|
|
632
|
+
}),
|
|
633
|
+
where: z
|
|
634
|
+
.object({
|
|
635
|
+
is_image: z.boolean().optional(),
|
|
636
|
+
})
|
|
637
|
+
.optional(),
|
|
638
|
+
take: z.number().optional(),
|
|
639
|
+
orderBy: z
|
|
640
|
+
.object({
|
|
641
|
+
created_at: z.enum(['asc', 'desc']).optional(),
|
|
642
|
+
})
|
|
643
|
+
.optional(),
|
|
644
|
+
})
|
|
645
|
+
.optional(),
|
|
646
|
+
rendered_description: z.boolean().optional(),
|
|
647
|
+
description: z.boolean().optional(),
|
|
648
|
+
created_at: z.boolean().optional(),
|
|
649
|
+
start_date: z.boolean().optional(),
|
|
650
|
+
reactions: z.boolean().optional(),
|
|
651
|
+
intervals: z.boolean().optional(),
|
|
652
|
+
column_id: z.boolean().optional(),
|
|
653
|
+
priority: z.boolean().optional(),
|
|
654
|
+
due_date: z.boolean().optional(),
|
|
655
|
+
column: z.boolean().optional(),
|
|
656
|
+
title: z.boolean().optional(),
|
|
657
|
+
order: z.boolean().optional(),
|
|
658
|
+
color: z.boolean().optional(),
|
|
659
|
+
})
|
|
660
|
+
.optional(),
|
|
661
|
+
where: z
|
|
662
|
+
.object({
|
|
663
|
+
id: z.string().optional(),
|
|
664
|
+
AND: z
|
|
665
|
+
.array(
|
|
666
|
+
z.object({
|
|
667
|
+
OR: z
|
|
668
|
+
.array(
|
|
669
|
+
z.object({
|
|
670
|
+
to_delete: z.boolean().nullable().optional(),
|
|
671
|
+
}),
|
|
672
|
+
)
|
|
673
|
+
.optional(),
|
|
674
|
+
}),
|
|
675
|
+
)
|
|
676
|
+
.optional(),
|
|
677
|
+
})
|
|
678
|
+
.optional(),
|
|
679
|
+
})
|
|
706
680
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
681
|
+
const allowedFields = [
|
|
682
|
+
'select.id',
|
|
683
|
+
'select.project_id',
|
|
684
|
+
'select.list_id',
|
|
685
|
+
'select.user_assignments.select.user',
|
|
686
|
+
'select.tags_mappings.select.tag',
|
|
687
|
+
'select.attachments.select.attachment',
|
|
688
|
+
'select.attachments.where.is_image',
|
|
689
|
+
'select.attachments.take',
|
|
690
|
+
'select.attachments.orderBy.created_at',
|
|
691
|
+
'select.rendered_description',
|
|
692
|
+
'select.description',
|
|
693
|
+
'select.created_at',
|
|
694
|
+
'select.start_date',
|
|
695
|
+
'select.reactions',
|
|
696
|
+
'select.intervals',
|
|
697
|
+
'select.column_id',
|
|
698
|
+
'select.priority',
|
|
699
|
+
'select.due_date',
|
|
700
|
+
'select.column',
|
|
701
|
+
'select.order',
|
|
702
|
+
'select.color',
|
|
703
|
+
'where.id',
|
|
704
|
+
'where.AND[].OR[].to_delete',
|
|
705
|
+
]
|
|
706
|
+
|
|
707
|
+
try {
|
|
708
|
+
const result = allow(taskSchema, allowedFields).safeParse(inputData)
|
|
709
|
+
expect(result.success).toBe(false)
|
|
710
|
+
} catch (error) {
|
|
711
|
+
expect(error).toBeInstanceOf(ZodError)
|
|
712
|
+
}
|
|
713
|
+
})
|
|
714
|
+
|
|
715
|
+
it('deep nesting 2', () => {
|
|
716
|
+
const taskSchema = z.object({
|
|
717
|
+
where: z
|
|
718
|
+
.object({
|
|
719
|
+
id: z.string().optional(),
|
|
720
|
+
AND: z
|
|
721
|
+
.array(
|
|
722
|
+
z.object({
|
|
723
|
+
OR: z
|
|
724
|
+
.array(
|
|
725
|
+
z.object({
|
|
726
|
+
to_delete: z.boolean().nullable().optional(),
|
|
727
|
+
}),
|
|
728
|
+
)
|
|
729
|
+
.optional(),
|
|
730
|
+
}),
|
|
731
|
+
)
|
|
732
|
+
.optional(),
|
|
733
|
+
})
|
|
734
|
+
.optional(),
|
|
735
|
+
})
|
|
736
|
+
|
|
737
|
+
const allowedFields = [
|
|
738
|
+
'select.id',
|
|
739
|
+
'select.project_id',
|
|
740
|
+
'select.list_id',
|
|
741
|
+
'select.user_assignments.select.user',
|
|
742
|
+
'select.tags_mappings.select.tag',
|
|
743
|
+
'select.attachments.select.attachment',
|
|
744
|
+
'select.attachments.where.is_image',
|
|
745
|
+
'select.attachments.take',
|
|
746
|
+
'select.attachments.orderBy.created_at',
|
|
747
|
+
'select.rendered_description',
|
|
748
|
+
'select.description',
|
|
749
|
+
'select.created_at',
|
|
750
|
+
'select.start_date',
|
|
751
|
+
'where.id',
|
|
752
|
+
'where.AND[].OR[].to_delete',
|
|
753
|
+
]
|
|
754
|
+
|
|
755
|
+
try {
|
|
756
|
+
const result = allow(taskSchema, allowedFields).safeParse(inputData)
|
|
757
|
+
expect(result.success).toBe(false)
|
|
758
|
+
} catch (error) {
|
|
759
|
+
expect(error).toBeInstanceOf(ZodError)
|
|
760
|
+
}
|
|
761
|
+
})
|
|
713
762
|
})
|
|
714
763
|
})
|
package/src/copy/transformZod.ts
CHANGED
|
@@ -38,10 +38,11 @@ export function allow<T extends ZodTypeAny>(
|
|
|
38
38
|
schema: T,
|
|
39
39
|
allowedPaths: string[],
|
|
40
40
|
): ZodEffects<T, any, any> {
|
|
41
|
-
const rootSchema = schema instanceof z.ZodObject ? schema : undefined
|
|
41
|
+
const rootSchema = schema instanceof z.ZodObject ? schema.strict() : undefined
|
|
42
42
|
|
|
43
|
-
return
|
|
43
|
+
return rootSchema?.transform((data) => {
|
|
44
44
|
const flatData = flattenObject(data, '', rootSchema)
|
|
45
|
+
|
|
45
46
|
const disallowedPaths: string[] = []
|
|
46
47
|
|
|
47
48
|
for (const key of Object.keys(flatData)) {
|
|
@@ -51,19 +52,11 @@ export function allow<T extends ZodTypeAny>(
|
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
if (disallowedPaths.length > 0) {
|
|
54
|
-
|
|
55
|
-
for (const path of disallowedPaths) {
|
|
56
|
-
errors.push({
|
|
57
|
-
code: ZodIssueCode.custom,
|
|
58
|
-
message: `Field '${path}' is not allowed.`,
|
|
59
|
-
path: path.split('.'),
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
throw new ZodError(errors)
|
|
55
|
+
throw createZodErrorFromPaths(disallowedPaths, 'Field is not allowed:')
|
|
63
56
|
}
|
|
64
57
|
|
|
65
58
|
return data
|
|
66
|
-
}) as ZodEffects<T, any, any>
|
|
59
|
+
}) as unknown as ZodEffects<T, any, any>
|
|
67
60
|
}
|
|
68
61
|
|
|
69
62
|
export function forbid<T extends z.ZodTypeAny>(
|
|
@@ -82,15 +75,7 @@ export function forbid<T extends z.ZodTypeAny>(
|
|
|
82
75
|
}
|
|
83
76
|
|
|
84
77
|
if (forbiddenMatches.length > 0) {
|
|
85
|
-
|
|
86
|
-
for (const path of forbiddenMatches) {
|
|
87
|
-
errors.push({
|
|
88
|
-
code: ZodIssueCode.custom,
|
|
89
|
-
message: `Field '${path}' is forbidden.`,
|
|
90
|
-
path: [path],
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
throw new ZodError(errors)
|
|
78
|
+
throw createZodErrorFromPaths(forbiddenMatches, 'Field is forbidden:')
|
|
94
79
|
}
|
|
95
80
|
return data
|
|
96
81
|
}) as ZodEffects<T, any, any>
|
|
@@ -138,3 +123,18 @@ export function flattenObject(
|
|
|
138
123
|
flatten(obj, prefix, schema)
|
|
139
124
|
return result
|
|
140
125
|
}
|
|
126
|
+
|
|
127
|
+
function createZodErrorFromPaths(
|
|
128
|
+
disallowedPaths: string[],
|
|
129
|
+
errorMessage: string,
|
|
130
|
+
): ZodError {
|
|
131
|
+
const errors: ZodIssue[] = []
|
|
132
|
+
for (const path of disallowedPaths) {
|
|
133
|
+
errors.push({
|
|
134
|
+
code: ZodIssueCode.custom,
|
|
135
|
+
message: `${errorMessage} '${path}'`,
|
|
136
|
+
path: path.split('.'),
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
return new ZodError(errors)
|
|
140
|
+
}
|
|
@@ -31,7 +31,7 @@ import { ${modelName}GroupBy } from './${modelName}GroupBy';
|
|
|
31
31
|
import { createValidatorMiddleware, ValidatorOptions } from '../createValidatorMiddleware'
|
|
32
32
|
import { createOutputValidatorMiddleware } from '../createOutputValidatorMiddleware'
|
|
33
33
|
import { RouteConfig, ValidatorConfig } from '../routeConfig'
|
|
34
|
-
import { parseQueryParams } from "../
|
|
34
|
+
import { parseQueryParams } from "../parseQueryParams";
|
|
35
35
|
|
|
36
36
|
const defaultBeforeAfter = {
|
|
37
37
|
before: [] as RequestHandler[],
|