Skip to content

Commit 9b502f9

Browse files
committed
🐛 Fix composite primary with AfterValidator/Annotated
1 parent a85de91 commit 9b502f9

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

tests/test_main.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
from typing import List, Optional
22

33
import pytest
4+
from sqlalchemy import inspect
5+
from sqlalchemy.engine.reflection import Inspector
46
from sqlalchemy.exc import IntegrityError
57
from sqlalchemy.orm import RelationshipProperty
68
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select
9+
from typing_extensions import Annotated
710

811

912
def test_should_allow_duplicate_row_if_unique_constraint_is_not_passed(clear_sqlmodel):
@@ -125,3 +128,72 @@ class Hero(SQLModel, table=True):
125128
# The next statement should not raise an AttributeError
126129
assert hero_rusty_man.team
127130
assert hero_rusty_man.team.name == "Preventers"
131+
132+
133+
def test_composite_primary_key(clear_sqlmodel):
134+
class UserPermission(SQLModel, table=True):
135+
user_id: int = Field(primary_key=True)
136+
resource_id: int = Field(primary_key=True)
137+
permission: str
138+
139+
engine = create_engine("sqlite://")
140+
SQLModel.metadata.create_all(engine)
141+
142+
insp: Inspector = inspect(engine)
143+
pk_constraint = insp.get_pk_constraint(str(UserPermission.__tablename__))
144+
145+
assert len(pk_constraint["constrained_columns"]) == 2
146+
assert "user_id" in pk_constraint["constrained_columns"]
147+
assert "resource_id" in pk_constraint["constrained_columns"]
148+
149+
with Session(engine) as session:
150+
perm1 = UserPermission(user_id=1, resource_id=1, permission="read")
151+
perm2 = UserPermission(user_id=1, resource_id=2, permission="write")
152+
session.add(perm1)
153+
session.add(perm2)
154+
session.commit()
155+
156+
with pytest.raises(IntegrityError):
157+
with Session(engine) as session:
158+
perm3 = UserPermission(user_id=1, resource_id=1, permission="admin")
159+
session.add(perm3)
160+
session.commit()
161+
162+
163+
def test_composite_primary_key_and_validator(clear_sqlmodel):
164+
from pydantic import AfterValidator
165+
166+
def validate_resource_id(value: int) -> int:
167+
if value < 1:
168+
raise ValueError("Resource ID must be positive")
169+
return value
170+
171+
class UserPermission(SQLModel, table=True):
172+
user_id: int = Field(primary_key=True)
173+
resource_id: Annotated[int, AfterValidator(validate_resource_id)] = Field(
174+
primary_key=True
175+
)
176+
permission: str
177+
178+
engine = create_engine("sqlite://")
179+
SQLModel.metadata.create_all(engine)
180+
181+
insp: Inspector = inspect(engine)
182+
pk_constraint = insp.get_pk_constraint(str(UserPermission.__tablename__))
183+
184+
assert len(pk_constraint["constrained_columns"]) == 2
185+
assert "user_id" in pk_constraint["constrained_columns"]
186+
assert "resource_id" in pk_constraint["constrained_columns"]
187+
188+
with Session(engine) as session:
189+
perm1 = UserPermission(user_id=1, resource_id=1, permission="read")
190+
perm2 = UserPermission(user_id=1, resource_id=2, permission="write")
191+
session.add(perm1)
192+
session.add(perm2)
193+
session.commit()
194+
195+
with pytest.raises(IntegrityError):
196+
with Session(engine) as session:
197+
perm3 = UserPermission(user_id=1, resource_id=1, permission="admin")
198+
session.add(perm3)
199+
session.commit()

0 commit comments

Comments
 (0)