fix: zod4 compatibility regarding fields with default values#2233
Conversation
📝 WalkthroughWalkthroughRefactors Zod schema generation by introducing a centralized createModelBaseSchema that controls default inclusion via makeFieldSchema(field, addDefaults). Updates generator paths to use baseSchemaWithoutDefaults for create/update. Adjusts makeFieldSchema signature to accept addDefaults. Loosens typings in getZodErrorMessage by casting to any instead of Zod-specific error types. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as Generator
participant G as generator.ts
participant B as createModelBaseSchema
participant F as makeFieldSchema(addDefaults)
participant Z as z.object(...)
Dev->>G: generateModelSchema / generateTypeDefSchema
G->>B: createModelBaseSchema(fields, mode=strip|passthrough|strict, addDefaults=true)
loop For each field
B->>F: makeFieldSchema(field, addDefaults=true)
F-->>B: field Zod schema (with defaults)
end
B->>Z: z.object({ ...fields }).mode(...)
Z-->>G: baseSchema
note over G,B: Create/Update paths
G->>B: createModelBaseSchema(fields, mode=..., addDefaults=false)
loop For each field
B->>F: makeFieldSchema(field, addDefaults=false)
F-->>B: field Zod schema (no defaults)
end
B->>Z: z.object({ ...fields }).mode(...)
Z-->>G: baseSchemaWithoutDefaults
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/schema/src/plugins/zod/utils/schema-gen.ts (1)
37-44: Bug: min/max checks drop 0 due to truthy test
@length(min: 0)or@length(max: 0)are ignored. Use explicit undefined checks.- const min = getAttrLiteralArg<number>(attr, 'min'); - if (min) { + const min = getAttrLiteralArg<number>(attr, 'min'); + if (min !== undefined) { schema += `.min(${min}${messageArg})`; } - const max = getAttrLiteralArg<number>(attr, 'max'); - if (max) { + const max = getAttrLiteralArg<number>(attr, 'max'); + if (max !== undefined) { schema += `.max(${max}${messageArg})`; }packages/schema/src/plugins/zod/generator.ts (1)
551-559: Support atomic operations for BigInt and Decimal tooPrisma exposes atomic update inputs for BigInt/Decimal; currently only Int/Float are handled.
- if (field.type.type === 'Int' || field.type.type === 'Float') { + if ( + field.type.type === 'Int' || + field.type.type === 'Float' || + field.type.type === 'BigInt' || + field.type.type === 'Decimal' + ) { fieldSchema = `z.union([${fieldSchema}, z.record(z.unknown())])`; }
🧹 Nitpick comments (3)
packages/runtime/src/local-helpers/zod-utils.ts (2)
1-1: Scope down the ESLint any-disable to the casts instead of the whole fileAvoid blanket disables; keep the file type-safe and silence only the necessary lines.
Apply:
-/* eslint-disable @typescript-eslint/no-explicit-any */
9-21: Handle string errors and localize the any-castsSmall robustness win and narrower lint suppression.
export function getZodErrorMessage(err: unknown): string { - if (!(err instanceof Error)) { + if (typeof err === 'string') { + return err; + } + if (!(err instanceof Error)) { return 'Unknown error'; } try { if ('_zod' in err) { - return fromZodErrorV4(err as any).message; + return fromZodErrorV4(err as any).message; // eslint-disable-line @typescript-eslint/no-explicit-any } else { - return fromZodErrorV3(err as any).message; + return fromZodErrorV3(err as any).message; // eslint-disable-line @typescript-eslint/no-explicit-any } } catch { return err.message; } }packages/schema/src/plugins/zod/generator.ts (1)
673-698: Add a brief JSDoc for createModelBaseSchema to document addDefaults semanticsHelps future contributors understand when defaults are injected.
- private createModelBaseSchema( + /** + * Emits `const <name> = z.object({...})` for scalar fields. + * When `addDefaults` is true, per-field `.default(...)` is appended; otherwise omitted. + */ + private createModelBaseSchema( name: string, writer: CodeBlockWriter, scalarFields: DataModelField[], addDefaults: boolean ) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/runtime/src/local-helpers/zod-utils.ts(2 hunks)packages/schema/src/plugins/zod/generator.ts(8 hunks)packages/schema/src/plugins/zod/utils/schema-gen.ts(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/schema/src/plugins/zod/generator.ts (1)
packages/schema/src/plugins/zod/utils/schema-gen.ts (1)
makeFieldSchema(17-163)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: dependency-review
- GitHub Check: build-test (20.x)
- GitHub Check: build-test (20.x)
- GitHub Check: build-test (20.x)
- GitHub Check: OSSAR-Scan
🔇 Additional comments (5)
packages/schema/src/plugins/zod/utils/schema-gen.ts (2)
144-156: Correct gating of .default(...) applicationSkipping
.default(...)whenaddDefaultsis false solves the Zod v4 compatibility concern for create/update paths.
17-17: No remaining call sites needaddDefaults: false
All three calls in packages/schema/src/plugins/zod/generator.ts (lines 325, 446, 457) intentionally rely on the defaultaddDefaults: true.packages/schema/src/plugins/zod/generator.ts (3)
431-435: Nice centralization via createModelBaseSchemaReducing duplication and threading
addDefaultsimproves maintainability.
533-537: Prisma create now based on baseSchemaWithoutDefaults — correctThis prevents generator-inserted defaults from masking DB defaults.
577-586: Create schema correctly derives from baseSchemaWithoutDefaults and marks defaulted fields optionalMatches Prisma behavior for
@default,@updatedAt, and list fields.
No description provided.