Skip to content

Commit ce8eac9

Browse files
committed
fix: add SET DEFAULT and NO ACTION to OnDeleteType
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.
1 parent 07b69be commit ce8eac9

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

sqlmodel/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
| Mapping[int, Union["IncEx", bool]]
8888
| Mapping[str, Union["IncEx", bool]]
8989
)
90-
OnDeleteType = Literal["CASCADE", "SET NULL", "RESTRICT"]
90+
OnDeleteType = Literal["CASCADE", "SET NULL", "SET DEFAULT", "RESTRICT", "NO ACTION"]
9191

9292

9393
def __dataclass_transform__(

tests/test_main.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import pytest
44
from sqlalchemy.exc import IntegrityError
55
from sqlalchemy.orm import RelationshipProperty
6+
from sqlalchemy.schema import CreateTable
67
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select
78

89

@@ -216,3 +217,26 @@ class Hero(SQLModel, table=True):
216217
assert len(foreign_keys) == 1
217218
assert foreign_keys[0].ondelete == "CASCADE"
218219
assert team_id_column.nullable is False
220+
221+
222+
@pytest.mark.parametrize("ondelete", ["SET DEFAULT", "NO ACTION"])
223+
def test_foreign_key_ondelete_referential_actions(clear_sqlmodel, ondelete):
224+
class Team(SQLModel, table=True):
225+
id: int | None = Field(default=None, primary_key=True)
226+
227+
class Hero(SQLModel, table=True):
228+
id: int | None = Field(default=None, primary_key=True)
229+
team_id: int | None = Field(
230+
default=None, foreign_key="team.id", ondelete=ondelete
231+
)
232+
233+
engine = create_engine("sqlite://")
234+
SQLModel.metadata.create_all(engine)
235+
236+
hero_table = Hero.__table__ # type: ignore[attr-defined]
237+
foreign_keys = list(hero_table.c.team_id.foreign_keys)
238+
assert len(foreign_keys) == 1
239+
assert foreign_keys[0].ondelete == ondelete
240+
241+
ddl = str(CreateTable(hero_table).compile(engine))
242+
assert f"ON DELETE {ondelete}" in ddl

0 commit comments

Comments
 (0)