Skip to content

Add SET DEFAULT and NO ACTION to OnDeleteType#2034

Open
anxkhn wants to merge 1 commit into
fastapi:mainfrom
anxkhn:patch-4
Open

Add SET DEFAULT and NO ACTION to OnDeleteType#2034
anxkhn wants to merge 1 commit into
fastapi:mainfrom
anxkhn:patch-4

Conversation

@anxkhn

@anxkhn anxkhn commented Jul 6, 2026

Copy link
Copy Markdown
`OnDeleteType`, the `Literal` that types the public `Field(ondelete=...)`
parameter, only listed three of the five standard SQL referential actions:
`CASCADE`, `SET NULL` and `RESTRICT`. The remaining two, `SET DEFAULT` and
`NO ACTION`, are valid everywhere else in the stack: `ondelete` is passed
straight through to SQLAlchemy's `ForeignKey(ondelete=...)`, which emits
`ON DELETE <value>` for any of them, and SQL defines exactly these five actions.

Because the literal omitted them, a type checker (mypy/pyright/ty) rejected a
perfectly valid schema, for example:

```python
class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    team_id: int | None = Field(
        default=None, foreign_key="team.id", ondelete="NO ACTION"
    )

The only workarounds were casting to Any or dropping down to sa_column.
NO ACTION is the default referential action in PostgreSQL and most databases,
and SET DEFAULT pairs naturally with a column server_default, so both are
things people legitimately want to spell out.

This adds the two missing actions to OnDeleteType. There is no runtime change
(the value was always passed through unchanged); this only corrects the static
type. Reported in #1839.

Tests

Added a parametrized regression test over the two newly typed actions that
asserts both the resulting foreign key's ondelete and the generated
ON DELETE <action> DDL, mirroring the existing
test_foreign_key_ondelete_with_annotated.

AI Disclaimer

AI used for diagnostics and drafting; the change and test were reviewed by hand.


---

## Notes for the human reviewer (Anas)

- Head branch is a placeholder name (`patch-4`) from the loop scaffold. Before you
  open the PR, consider renaming it to something conventional, e.g.
  `fix/ondelete-referential-actions`. (Branch names never reach code, only the PR.)
- No CONTRIBUTING.md, no PR template, no DCO/CLA in this repo. The commit is a
  plain Conventional Commit (`fix: ...`), no sign-off needed.
- I included an `## AI Disclaimer` section because the maintainer's own recent
  type-fix PR (#1996) uses exactly that section; keeping it is honest and matches
  house style. Drop it if you'd rather not.
- The repo's CI enforces "Coverage stays at 100%." The new test exercises the new
  literal values end to end, so coverage should hold; the maintainer's checklist
  item is `- [x] Coverage stays at 100%.` if you want to add it.

The OnDeleteType literal that types Field(ondelete=...) only listed
CASCADE, SET NULL and RESTRICT, so type checkers rejected the other two
standard SQL referential actions, SET DEFAULT and NO ACTION, even though
both are valid at runtime and emit correct ON DELETE DDL via SQLAlchemy.

Add the two missing actions to the literal and cover them with a
parametrized regression test asserting the generated foreign key and
DDL.
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.

2 participants