Fix/add class-validator and swagger decorator into combined model class#25
Fix/add class-validator and swagger decorator into combined model class#25JackCme wants to merge 2 commits into
Conversation
…eRelationFields When using separateRelationFields=true with swagger=true, the combined class was missing class-validator and Swagger decorators for relation fields. Changes: - Add class-validator imports (IsDefined, IsOptional) for relation fields - Add Swagger imports (ApiProperty) when swagger option is enabled - Add decorators to relation field properties in combined class - Add comprehensive tests to verify decorator generation This ensures the combined class properly decorates relation fields, matching the behavior of RelationClass and single class generation modes. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
WalkthroughThe generator now conditionally emits relation imports, adds validator and Swagger imports for relation fields in combined classes, and applies decorators to relation properties. Tests were added to verify generated base, relation, and combined classes, including imports, inheritance, relation field decorators, and separation of scalar vs. relation fields. Changes
Sequence Diagram(s)sequenceDiagram
actor Dev as Developer
participant Gen as generateCombinedClass
participant Rel as Relation Fields
participant Imp as Import Generators
participant Dec as Decorator Resolver
participant Out as Emitter
Dev->>Gen: Invoke for model
Gen->>Rel: Collect relation fields
alt any relations
Gen->>Dec: getDecoratorsByFieldType(field, config.swagger)
Dec-->>Gen: Decorator list per relation field
Gen->>Imp: compute validatorImports from relation fields
Imp-->>Gen: validatorImports (maybe empty)
Gen->>Imp: compute swaggerImports if swagger enabled and needed
Imp-->>Gen: swaggerImports (maybe empty)
Gen->>Out: Emit validatorImports if non-empty
Gen->>Out: Emit swaggerImports if non-empty
Gen->>Out: Emit relation-type imports if needed
Gen->>Out: Emit class with decorated relation properties
else no relations
Gen->>Out: Emit class without relation imports/decorators
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (6)
src/generate-class.ts (3)
224-228: Guarded relation imports: good; also fix self-relations and mirror this guard in single-class.
- Nice: avoids emitting
import { } from "./".- Edge case: in Relations files, self-relations (e.g.,
UserRelationsfield typedUser) currently skip importingUser, causing an unresolved type in that file. Importing the model type is safe here and required.Apply in Relations file (safe for self-relations):
- relationFields.forEach((field) => { - if (field.relationName && model.name !== field.type) { - relationImports.add(field.type); - } - }); + relationFields.forEach((field) => { + if (field.relationName) { + relationImports.add(field.type); // include self type (e.g., "User") for Relations file + } + });Mirror the same empty-import guard in generateSingleClass to keep behavior consistent:
- generateRelationImportsImport(sourceFile, [ - ...relationImports, - ] as Array<string>); + if (relationImports.size > 0) { + generateRelationImportsImport(sourceFile, [ + ...relationImports, + ] as Array<string>); + }
269-276: Deterministic import order for relation validator imports.Sort to reduce diff churn across runs.
- const validatorImports = [ - ...new Set( - relationFields - .map((field) => getDecoratorsImportsByType(field)) - .flatMap((item) => item), - ), - ]; + const validatorImports = Array.from( + new Set(relationFields.flatMap((f) => getDecoratorsImportsByType(f))), + ).sort();Also applies to: 278-281
283-292: Swagger import condition is correct; drop redundant length check.
shouldImportSwagger(relationFields)already implies non-empty.- if ( - config.swagger && - relationFields.length > 0 && - shouldImportSwagger(relationFields as PrismaDMMF.Field[]) - ) { + if (config.swagger && shouldImportSwagger(relationFields as PrismaDMMF.Field[])) {tests/swagger-generation.test.ts (3)
74-83: Avoid rebuilding twice and run sequentially to reduce flakiness.Build once or run suites sequentially; remove duplicate
npm run build.-describe('Combined Class with separateRelationFields', () => { +describe.sequential('Combined Class with separateRelationFields', () => { beforeAll(async () => { - // Build the generator first - await execAsync('npm run build'); - // Generate models for full-features schema (has both swagger and separateRelationFields) const schemaPath = path.resolve(__dirname, 'schemas/full-features.prisma'); await execAsync(`npx prisma generate --schema="${schemaPath}"`); }, 60000);
95-101: Make import assertions resilient to quote/style changes.Use regex to tolerate single/double quotes and spacing.
- // Check for Swagger imports - expect(userModel).toContain('import { ApiProperty } from "@nestjs/swagger"'); + // Check for Swagger imports + expect(userModel).toMatch(/import\s+\{\s*ApiProperty\s*\}\s+from\s+["']@nestjs\/swagger["']/);
127-133: Same resilience for class-validator/Swagger imports in Post model.- // Check for class-validator imports for optional relation - expect(postModel).toContain('import { IsOptional } from "class-validator"'); + // Check for class-validator imports for optional relation + expect(postModel).toMatch(/import\s+\{\s*IsOptional\s*\}\s+from\s+["']class-validator["']/); - // Check for Swagger imports - expect(postModel).toContain('import { ApiProperty } from "@nestjs/swagger"'); + // Check for Swagger imports + expect(postModel).toMatch(/import\s+\{\s*ApiProperty\s*\}\s+from\s+["']@nestjs\/swagger["']/);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/generate-class.ts(3 hunks)tests/swagger-generation.test.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/generate-class.ts (1)
src/helpers.ts (7)
generateRelationImportsImport(260-268)getDecoratorsImportsByType(213-241)generateClassValidatorImport(243-251)shouldImportSwagger(295-297)getSwaggerImportsByType(299-303)generateSwaggerImport(305-313)getDecoratorsByFieldType(80-145)
🔇 Additional comments (1)
src/generate-class.ts (1)
323-323: Decorators now applied to combined relation fields.Fix addresses the missing validators/Swagger on relations in combined classes.
When using separateRelationFields=true with swagger=true, the combined class was missing class-validator and Swagger decorators for relation fields.
Changes:
This ensures the combined class properly decorates relation fields, matching the behavior of RelationClass and single class generation modes.
Summary by CodeRabbit
New Features
Tests