Skip to content

fix: Fix nestedOneToOneField to not error when setting to null on non-existent relation#718

Merged
kingston merged 1 commit into
mainfrom
kingston/fix-nested-one-to-one
Dec 26, 2025
Merged

fix: Fix nestedOneToOneField to not error when setting to null on non-existent relation#718
kingston merged 1 commit into
mainfrom
kingston/fix-nested-one-to-one

Conversation

@kingston

@kingston kingston commented Dec 26, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

Bug Fixes

  • Fixed nested one-to-one relationship handling: Setting a nested one-to-one field to null no longer throws an error if the relationship doesn't exist. The operation is now fully idempotent and always succeeds safely, improving application reliability and allowing users to nullify relationships without worrying about missing records.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel

vercel Bot commented Dec 26, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
baseplate-project-builder-web Ready Ready Preview, Comment Dec 26, 2025 9:42pm

@changeset-bot

changeset-bot Bot commented Dec 26, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e7020a4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@baseplate-dev/fastify-generators Patch
@baseplate-dev/project-builder-server Patch
@baseplate-dev/plugin-auth Patch
@baseplate-dev/plugin-queue Patch
@baseplate-dev/plugin-storage Patch
@baseplate-dev/create-project Patch
@baseplate-dev/project-builder-cli Patch
@baseplate-dev/project-builder-common Patch
@baseplate-dev/project-builder-test Patch
@baseplate-dev/project-builder-web Patch
@baseplate-dev/code-morph Patch
@baseplate-dev/core-generators Patch
@baseplate-dev/project-builder-lib Patch
@baseplate-dev/react-generators Patch
@baseplate-dev/sync Patch
@baseplate-dev/tools Patch
@baseplate-dev/ui-components Patch
@baseplate-dev/utils Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Dec 26, 2025

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR fixes nested one-to-one field null-handling by shifting deletion logic from Prisma's delete: true payload to an afterExecute hook using deleteMany, making it idempotent and safe when relations don't exist.

Changes

Cohort / File(s) Summary
Changeset Documentation
\.changeset/fix-nested-one-to-one-null-delete.md``
Adds changelog entry documenting the fix for nested one-to-one null deletion behavior.
Field Definition Implementation (Template & Generated Examples)
packages/fastify-generators/.../field-definitions.ts,
examples/blog-with-auth/.../field-definitions.ts,
examples/todo-with-auth0/.../field-definitions.ts
Updated nestedOneToOneField signature by removing { delete: true } from return type. Refactored null-handling logic to use afterExecute hook with deleteMany instead of returning delete signal in update payload, enabling idempotent deletion regardless of relation existence.
Integration Tests
examples/todo-with-auth0/.../user.data-service.int.test.ts
Added two new test cases: one verifying nested one-to-one relation deletion when set to null, and another confirming no error occurs when setting null on non-existent relation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: changing nestedOneToOneField to handle null values on non-existent relations without throwing errors.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch kingston/fix-nested-one-to-one

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 83e4e7f and e7020a4.

⛔ Files ignored due to path filters (4)
  • examples/blog-with-auth/apps/backend/baseplate/generated/src/utils/data-operations/field-definitions.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-auth0/apps/backend/baseplate/generated/src/utils/data-operations/field-definitions.ts is excluded by !**/generated/**, !**/generated/**
  • tests/simple/apps/backend/baseplate/generated/src/utils/data-operations/field-definitions.ts is excluded by !**/generated/**, !tests/**, !**/generated/**
  • tests/simple/apps/backend/src/utils/data-operations/field-definitions.ts is excluded by !tests/**
📒 Files selected for processing (5)
  • .changeset/fix-nested-one-to-one-null-delete.md
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/code-style.mdc)

**/*.{ts,tsx}: Use TypeScript with strict type checking enabled
Always include return types on top-level functions including React components (React.ReactElement)
Include absolute paths in import statements via tsconfig paths (@src/ is the alias for src/)
If a particular interface or type is not exported, change the file so it is exported
If caught on a typing loop where forcing the any type is necessary, do not iterate too much - leave the typing as broken and let the user fix it

If target code is not easily testable, refactor it to be more testable (e.g., export types or functions)

**/*.{ts,tsx}: Import components from '@baseplate-dev/ui-components' package for UI development (e.g., Button, Input, Card, Dialog, etc.)
Use form components with React Hook Form controller variants (InputField, TextareaField, SelectField, CheckboxField, SwitchField, ComboboxField, MultiComboboxField, ColorPickerField, DatePickerField, DateTimePickerField)
Use SidebarLayout, Card, Breadcrumb, NavigationMenu, and NavigationTabs components for consistent layout structure from @baseplate-dev/ui-components
Use Dialog, ConfirmDialog, and useConfirmDialog from @baseplate-dev/ui-components for modal dialogs and confirmation interactions
Always use compareStrings from @baseplate-dev/utils instead of String.prototype.localeCompare() for code generation, file sorting, and internal data structures
If a particular interface or type is not exported, modify the file to export it
Use TsCodeFragment for composable code pieces and TsCodeUtils for manipulating fragments when generating TypeScript code
Create generators using createGenerator with configuration via descriptor schema (Zod), organizing into one or more tasks created with createGeneratorTask
Tasks should have run (initialization) and build (code generation) phases, export and consume providers, and may be organized into phases for ordered execution
Use provider scopes to control visibility and prevent collisions be...

Files:

  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/code-style.mdc)

**/*.{ts,tsx,js}: Node 16 module resolution - include file extensions in imports (.js)
Sort imports by group: external libs first, then local imports
Use camelCase for variables/functions, PascalCase for types/classes
Order functions such that functions are placed below the variables/functions they use
Prefer using nullish coalescing operator (??) instead of logical or (||), enforced via ESLint rule
Prefer barrel exports e.g. export * from './foo.js' instead of individual named exports
Use console.info/warn/error instead of console.log

Files:

  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts
examples/todo-with-auth0/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (examples/todo-with-auth0/CLAUDE.md)

Always use .js extensions in import statements, even for TypeScript files. Example: import { getSystemInfo } from '@src/system-info.js';

Files:

  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts
examples/todo-with-auth0/**/*.{ts,tsx}

📄 CodeRabbit inference engine (examples/todo-with-auth0/CLAUDE.md)

examples/todo-with-auth0/**/*.{ts,tsx}: Use import type for type-only imports
Always specify explicit return types for functions
Add JSDocs to all exported functions, interfaces, and classes with documentation of the function, its parameters, return value, and all fields

Files:

  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts
examples/todo-with-auth0/**/*.{unit,int}.test.ts

📄 CodeRabbit inference engine (examples/todo-with-auth0/CLAUDE.md)

examples/todo-with-auth0/**/*.{unit,int}.test.ts: Use .unit.test.ts or .int.test.ts suffixes for test files in TypeScript
Import test functions explicitly from 'vitest' instead of using globals. Example: import { describe, expect, it } from 'vitest';

Files:

  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts
**/*.{unit.test.ts,int.test.ts}

📄 CodeRabbit inference engine (.cursor/rules/code-style.mdc)

**/*.{unit.test.ts,int.test.ts}: Unit tests must use .unit.test.ts suffix, integration tests must use .int.test.ts suffix
Always import vitest globals explicitly (describe, it, expect)

Files:

  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts
**/*.{unit,int}.test.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)

**/*.{unit,int}.test.{ts,tsx}: Use descriptive test names that explain what is being tested
Structure tests with Arrange-Act-Assert: clear setup, execution, and verification phases
Always mock external API calls and file system operations
Each test should be independent and not rely on other tests
Leverage TypeScript for type-safe mocking in tests
Focus on testing public methods and behaviors, not implementation details
Each test should verify one specific behavior
Extract repeated logic into helper functions to reduce duplication
Test broad behavior and common edge cases intelligently to avoid slowing down CI with excessive tests
For file system operations in tests, use memfs and mock node:fs and node:fs/promises
When using globby with mocked fs, pass the mocked fs adapter to the globby call

Files:

  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts
**/*.int.test.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)

Integration tests use .int.test.ts suffix

Files:

  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Add a new Changeset in the .changeset/ directory for new features or changes, with format 'package-name': patch and description of the feature or change

Files:

  • .changeset/fix-nested-one-to-one-null-delete.md
examples/blog-with-auth/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (examples/blog-with-auth/CLAUDE.md)

examples/blog-with-auth/**/*.{ts,tsx,js,jsx}: Always use .js extensions in import statements, even for TypeScript files (e.g., import { getSystemInfo } from '@src/system-info.js';)
Follow ESM module resolution with TypeScript's NodeNext setting
Add JSDocs to all exported functions, interfaces, and classes with documentation of the function, its parameters, return value, and all fields

Files:

  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts
examples/blog-with-auth/**/*.{ts,tsx}

📄 CodeRabbit inference engine (examples/blog-with-auth/CLAUDE.md)

examples/blog-with-auth/**/*.{ts,tsx}: Use import type for type-only imports in TypeScript
Always specify explicit return types for functions in TypeScript

Files:

  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts
🧠 Learnings (2)
📚 Learning: 2025-11-24T19:44:46.506Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:44:46.506Z
Learning: Applies to examples/todo-with-auth0/**/*.{ts,tsx} : Use `import type` for type-only imports

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
📚 Learning: 2025-11-25T22:46:20.505Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T22:46:20.505Z
Learning: Applies to .changeset/*.md : Add a new Changeset in the `.changeset/` directory for new features or changes, with format `'package-name': patch` and description of the feature or change

Applied to files:

  • .changeset/fix-nested-one-to-one-null-delete.md
🧬 Code graph analysis (2)
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts (3)
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/define-operations.ts (1)
  • generateCreateSchema (240-250)
examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts (1)
  • generateCreateSchema (242-252)
examples/todo-with-auth0/apps/backend/src/utils/data-operations/define-operations.ts (1)
  • generateCreateSchema (242-252)
examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts (1)
packages/fastify-generators/src/generators/prisma/prisma/templates/src/services/prisma.ts (1)
  • prisma (8-8)
⏰ 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: Verify Sync (todo-with-auth0)
  • GitHub Check: Verify Sync (blog-with-auth)
  • GitHub Check: test
  • GitHub Check: Lint
  • GitHub Check: Test E2E
🔇 Additional comments (5)
examples/todo-with-auth0/apps/backend/src/modules/accounts/users/services/user.data-service.int.test.ts (1)

261-319: Well-structured tests covering both scenarios.

The new tests properly verify:

  1. Deleting an existing nested relation when set to null
  2. Idempotent behavior when setting a non-existent relation to null

Good use of direct Prisma calls for setup/verification while testing the data service behavior.

.changeset/fix-nested-one-to-one-null-delete.md (1)

1-7: Changeset is clear and well-documented.

The description accurately explains the behavioral change from error-throwing delete: true to idempotent deleteMany via afterExecute hook.

packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts (1)

273-303: Clean fix using idempotent deleteMany.

The change from { delete: true } (which requires the record to exist) to an afterExecute hook with deleteMany is the right approach. The expandWhereUnique utility correctly converts the unique constraint to a where clause suitable for deleteMany.

examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts (1)

273-303: Changes are consistent with the template.

The implementation matches the template file exactly, ensuring the example project demonstrates the correct idempotent deletion behavior.

examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts (1)

273-303: Consistent with template and other examples.

Implementation is identical across all three field-definitions.ts files, maintaining consistency between the generator template and example projects.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant