Skip to content

Commit 7880bad

Browse files
authored
feat: non-strict mode for zod plugin (#1697)
1 parent 1ea8e55 commit 7880bad

File tree

3 files changed

+244
-25
lines changed

3 files changed

+244
-25
lines changed

packages/schema/src/plugins/zod/generator.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
PluginError,
23
PluginGlobalOptions,
34
PluginOptions,
45
RUNTIME_PACKAGE,
@@ -54,6 +55,17 @@ export class ZodSchemaGenerator {
5455
ensureEmptyDir(output);
5556
Transformer.setOutputPath(output);
5657

58+
// options validation
59+
if (
60+
this.options.mode &&
61+
(typeof this.options.mode !== 'string' || !['strip', 'strict', 'passthrough'].includes(this.options.mode))
62+
) {
63+
throw new PluginError(
64+
name,
65+
`Invalid mode option: "${this.options.mode}". Must be one of 'strip', 'strict', or 'passthrough'.`
66+
);
67+
}
68+
5769
// calculate the models to be excluded
5870
const excludeModels = this.getExcludedModels();
5971

@@ -322,7 +334,19 @@ export class ZodSchemaGenerator {
322334
writer.writeLine(`${field.name}: ${makeFieldSchema(field)},`);
323335
});
324336
});
325-
writer.writeLine(');');
337+
338+
switch (this.options.mode) {
339+
case 'strip':
340+
// zod strips by default
341+
writer.writeLine(')');
342+
break;
343+
case 'passthrough':
344+
writer.writeLine(').passthrough();');
345+
break;
346+
default:
347+
writer.writeLine(').strict();');
348+
break;
349+
}
326350

327351
// relation fields
328352

@@ -463,7 +487,7 @@ export const ${upperCaseFirst(model.name)}PrismaCreateSchema = ${prismaCreateSch
463487
})
464488
.join(',\n')}
465489
})`;
466-
prismaUpdateSchema = this.makePartial(prismaUpdateSchema);
490+
prismaUpdateSchema = this.makePassthrough(this.makePartial(prismaUpdateSchema));
467491
writer.writeLine(
468492
`
469493
/**

packages/schema/src/plugins/zod/transformer.ts

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ export default class Transformer {
291291

292292
prepareObjectSchema(zodObjectSchemaFields: string[], options: PluginOptions) {
293293
const objectSchema = `${this.generateExportObjectSchemaStatement(
294-
this.addFinalWrappers({ zodStringFields: zodObjectSchemaFields })
294+
this.wrapWithZodObject(zodObjectSchemaFields, options.mode as string)
295295
)}\n`;
296296

297297
const prismaImportStatement = this.generateImportPrismaStatement(options);
@@ -314,12 +314,6 @@ export default class Transformer {
314314
export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
315315
}
316316

317-
addFinalWrappers({ zodStringFields }: { zodStringFields: string[] }) {
318-
const fields = [...zodStringFields];
319-
320-
return this.wrapWithZodObject(fields) + '.strict()';
321-
}
322-
323317
generateImportPrismaStatement(options: PluginOptions) {
324318
const prismaClientImportPath = computePrismaClientImport(
325319
path.resolve(Transformer.outputPath, './objects'),
@@ -408,14 +402,26 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
408402
return wrapped;
409403
}
410404

411-
wrapWithZodObject(zodStringFields: string | string[]) {
405+
wrapWithZodObject(zodStringFields: string | string[], mode = 'strict') {
412406
let wrapped = '';
413407

414408
wrapped += 'z.object({';
415409
wrapped += '\n';
416410
wrapped += ' ' + zodStringFields;
417411
wrapped += '\n';
418412
wrapped += '})';
413+
414+
switch (mode) {
415+
case 'strip':
416+
// zod strips by default
417+
break;
418+
case 'passthrough':
419+
wrapped += '.passthrough()';
420+
break;
421+
default:
422+
wrapped += '.strict()';
423+
break;
424+
}
419425
return wrapped;
420426
}
421427

@@ -465,6 +471,7 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
465471
];
466472
let codeBody = '';
467473
const operations: [string, string][] = [];
474+
const mode = (options.mode as string) ?? 'strict';
468475

469476
// OrderByWithRelationInput's name is different when "fullTextSearch" is enabled
470477
const orderByWithRelationInput = this.inputObjectTypes
@@ -477,7 +484,8 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
477484
imports.push(
478485
`import { ${modelName}WhereUniqueInputObjectSchema } from '../objects/${modelName}WhereUniqueInput.schema'`
479486
);
480-
codeBody += `findUnique: z.object({ ${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} where: ${modelName}WhereUniqueInputObjectSchema }),`;
487+
const fields = `${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} where: ${modelName}WhereUniqueInputObjectSchema`;
488+
codeBody += `findUnique: ${this.wrapWithZodObject(fields, mode)},`;
481489
operations.push(['findUnique', origModelName]);
482490
}
483491

@@ -488,7 +496,8 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
488496
`import { ${modelName}WhereUniqueInputObjectSchema } from '../objects/${modelName}WhereUniqueInput.schema'`,
489497
`import { ${modelName}ScalarFieldEnumSchema } from '../enums/${modelName}ScalarFieldEnum.schema'`
490498
);
491-
codeBody += `findFirst: z.object({ ${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${orderByWithRelationInput}ObjectSchema, ${orderByWithRelationInput}ObjectSchema.array()]).optional(), cursor: ${modelName}WhereUniqueInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), distinct: z.array(${modelName}ScalarFieldEnumSchema).optional() }),`;
499+
const fields = `${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${orderByWithRelationInput}ObjectSchema, ${orderByWithRelationInput}ObjectSchema.array()]).optional(), cursor: ${modelName}WhereUniqueInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), distinct: z.array(${modelName}ScalarFieldEnumSchema).optional()`;
500+
codeBody += `findFirst: ${this.wrapWithZodObject(fields, mode)},`;
492501
operations.push(['findFirst', origModelName]);
493502
}
494503

@@ -499,7 +508,8 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
499508
`import { ${modelName}WhereUniqueInputObjectSchema } from '../objects/${modelName}WhereUniqueInput.schema'`,
500509
`import { ${modelName}ScalarFieldEnumSchema } from '../enums/${modelName}ScalarFieldEnum.schema'`
501510
);
502-
codeBody += `findMany: z.object({ ${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${orderByWithRelationInput}ObjectSchema, ${orderByWithRelationInput}ObjectSchema.array()]).optional(), cursor: ${modelName}WhereUniqueInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), distinct: z.array(${modelName}ScalarFieldEnumSchema).optional() }),`;
511+
const fields = `${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${orderByWithRelationInput}ObjectSchema, ${orderByWithRelationInput}ObjectSchema.array()]).optional(), cursor: ${modelName}WhereUniqueInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), distinct: z.array(${modelName}ScalarFieldEnumSchema).optional()`;
512+
codeBody += `findMany: ${this.wrapWithZodObject(fields, mode)},`;
503513
operations.push(['findMany', origModelName]);
504514
}
505515

@@ -515,31 +525,35 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
515525
const dataSchema = generateUnchecked
516526
? `z.union([${modelName}CreateInputObjectSchema, ${modelName}UncheckedCreateInputObjectSchema])`
517527
: `${modelName}CreateInputObjectSchema`;
518-
codeBody += `create: z.object({ ${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} data: ${dataSchema} }),`;
528+
const fields = `${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} data: ${dataSchema}`;
529+
codeBody += `create: ${this.wrapWithZodObject(fields, mode)},`;
519530
operations.push(['create', origModelName]);
520531
}
521532

522533
if (createMany && supportCreateMany(zmodel)) {
523534
imports.push(
524535
`import { ${modelName}CreateManyInputObjectSchema } from '../objects/${modelName}CreateManyInput.schema'`
525536
);
526-
codeBody += `createMany: z.object({ data: z.union([${modelName}CreateManyInputObjectSchema, z.array(${modelName}CreateManyInputObjectSchema)]), skipDuplicates: z.boolean().optional() }),`;
537+
const fields = `data: z.union([${modelName}CreateManyInputObjectSchema, z.array(${modelName}CreateManyInputObjectSchema)]), skipDuplicates: z.boolean().optional()`;
538+
codeBody += `createMany: ${this.wrapWithZodObject(fields, mode)},`;
527539
operations.push(['createMany', origModelName]);
528540
}
529541

530542
if (deleteOne) {
531543
imports.push(
532544
`import { ${modelName}WhereUniqueInputObjectSchema } from '../objects/${modelName}WhereUniqueInput.schema'`
533545
);
534-
codeBody += `'delete': z.object({ ${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} where: ${modelName}WhereUniqueInputObjectSchema }),`;
546+
const fields = `${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} where: ${modelName}WhereUniqueInputObjectSchema`;
547+
codeBody += `'delete': ${this.wrapWithZodObject(fields, mode)},`;
535548
operations.push(['delete', origModelName]);
536549
}
537550

538551
if (deleteMany) {
539552
imports.push(
540553
`import { ${modelName}WhereInputObjectSchema } from '../objects/${modelName}WhereInput.schema'`
541554
);
542-
codeBody += `deleteMany: z.object({ where: ${modelName}WhereInputObjectSchema.optional() }),`;
555+
const fields = `where: ${modelName}WhereInputObjectSchema.optional()`;
556+
codeBody += `deleteMany: ${this.wrapWithZodObject(fields, mode)},`;
543557
operations.push(['deleteMany', origModelName]);
544558
}
545559

@@ -556,7 +570,8 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
556570
const dataSchema = generateUnchecked
557571
? `z.union([${modelName}UpdateInputObjectSchema, ${modelName}UncheckedUpdateInputObjectSchema])`
558572
: `${modelName}UpdateInputObjectSchema`;
559-
codeBody += `update: z.object({ ${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} data: ${dataSchema}, where: ${modelName}WhereUniqueInputObjectSchema }),`;
573+
const fields = `${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} data: ${dataSchema}, where: ${modelName}WhereUniqueInputObjectSchema`;
574+
codeBody += `update: ${this.wrapWithZodObject(fields, mode)},`;
560575
operations.push(['update', origModelName]);
561576
}
562577

@@ -573,7 +588,8 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
573588
const dataSchema = generateUnchecked
574589
? `z.union([${modelName}UpdateManyMutationInputObjectSchema, ${modelName}UncheckedUpdateManyInputObjectSchema])`
575590
: `${modelName}UpdateManyMutationInputObjectSchema`;
576-
codeBody += `updateMany: z.object({ data: ${dataSchema}, where: ${modelName}WhereInputObjectSchema.optional() }),`;
591+
const fields = `data: ${dataSchema}, where: ${modelName}WhereInputObjectSchema.optional()`;
592+
codeBody += `updateMany: ${this.wrapWithZodObject(fields, mode)},`;
577593
operations.push(['updateMany', origModelName]);
578594
}
579595

@@ -595,7 +611,8 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
595611
const updateSchema = generateUnchecked
596612
? `z.union([${modelName}UpdateInputObjectSchema, ${modelName}UncheckedUpdateInputObjectSchema])`
597613
: `${modelName}UpdateInputObjectSchema`;
598-
codeBody += `upsert: z.object({ ${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} where: ${modelName}WhereUniqueInputObjectSchema, create: ${createSchema}, update: ${updateSchema} }),`;
614+
const fields = `${selectZodSchemaLineLazy} ${includeZodSchemaLineLazy} where: ${modelName}WhereUniqueInputObjectSchema, create: ${createSchema}, update: ${updateSchema}`;
615+
codeBody += `upsert: ${this.wrapWithZodObject(fields, mode)},`;
599616
operations.push(['upsert', origModelName]);
600617
}
601618

@@ -641,9 +658,10 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
641658
`import { ${modelName}WhereUniqueInputObjectSchema } from '../objects/${modelName}WhereUniqueInput.schema'`
642659
);
643660

644-
codeBody += `aggregate: z.object({ where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${orderByWithRelationInput}ObjectSchema, ${orderByWithRelationInput}ObjectSchema.array()]).optional(), cursor: ${modelName}WhereUniqueInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), ${aggregateOperations.join(
661+
const fields = `where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${orderByWithRelationInput}ObjectSchema, ${orderByWithRelationInput}ObjectSchema.array()]).optional(), cursor: ${modelName}WhereUniqueInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), ${aggregateOperations.join(
645662
', '
646-
)} }),`;
663+
)}`;
664+
codeBody += `aggregate: ${this.wrapWithZodObject(fields, mode)},`;
647665
operations.push(['aggregate', modelName]);
648666
}
649667

@@ -654,9 +672,10 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
654672
`import { ${modelName}ScalarWhereWithAggregatesInputObjectSchema } from '../objects/${modelName}ScalarWhereWithAggregatesInput.schema'`,
655673
`import { ${modelName}ScalarFieldEnumSchema } from '../enums/${modelName}ScalarFieldEnum.schema'`
656674
);
657-
codeBody += `groupBy: z.object({ where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${modelName}OrderByWithAggregationInputObjectSchema, ${modelName}OrderByWithAggregationInputObjectSchema.array()]).optional(), having: ${modelName}ScalarWhereWithAggregatesInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), by: z.array(${modelName}ScalarFieldEnumSchema), ${aggregateOperations.join(
675+
const fields = `where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${modelName}OrderByWithAggregationInputObjectSchema, ${modelName}OrderByWithAggregationInputObjectSchema.array()]).optional(), having: ${modelName}ScalarWhereWithAggregatesInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), by: z.array(${modelName}ScalarFieldEnumSchema), ${aggregateOperations.join(
658676
', '
659-
)} }),`;
677+
)}`;
678+
codeBody += `groupBy: ${this.wrapWithZodObject(fields, mode)},`;
660679

661680
operations.push(['groupBy', origModelName]);
662681
}
@@ -671,7 +690,8 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`;
671690
`import { ${modelName}CountAggregateInputObjectSchema } from '../objects/${modelName}CountAggregateInput.schema'`
672691
);
673692

674-
codeBody += `count: z.object({ where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${orderByWithRelationInput}ObjectSchema, ${orderByWithRelationInput}ObjectSchema.array()]).optional(), cursor: ${modelName}WhereUniqueInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), distinct: z.array(${modelName}ScalarFieldEnumSchema).optional(), select: z.union([ z.literal(true), ${modelName}CountAggregateInputObjectSchema ]).optional() })`;
693+
const fields = `where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${orderByWithRelationInput}ObjectSchema, ${orderByWithRelationInput}ObjectSchema.array()]).optional(), cursor: ${modelName}WhereUniqueInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), distinct: z.array(${modelName}ScalarFieldEnumSchema).optional(), select: z.union([ z.literal(true), ${modelName}CountAggregateInputObjectSchema ]).optional()`;
694+
codeBody += `count: ${this.wrapWithZodObject(fields, mode)},`;
675695
operations.push(['count', origModelName]);
676696
}
677697

0 commit comments

Comments
 (0)