| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -61,6 +61,7 @@ def __init__(self, default: Any = Undefined, **kwargs: Any) -> None: | |||
| 61 | 61 | primary_key = kwargs.pop("primary_key", False) | |
| 62 | 62 | nullable = kwargs.pop("nullable", Undefined) | |
| 63 | 63 | foreign_key = kwargs.pop("foreign_key", Undefined) | |
| 64 | + unique = kwargs.pop("unique", False) | ||
| 64 | 65 | index = kwargs.pop("index", Undefined) | |
| 65 | 66 | sa_column = kwargs.pop("sa_column", Undefined) | |
| 66 | 67 | sa_column_args = kwargs.pop("sa_column_args", Undefined) | |
@@ -80,6 +81,7 @@ def __init__(self, default: Any = Undefined, **kwargs: Any) -> None: | |||
| 80 | 81 | self.primary_key = primary_key | |
| 81 | 82 | self.nullable = nullable | |
| 82 | 83 | self.foreign_key = foreign_key | |
| 84 | + self.unique = unique | ||
| 83 | 85 | self.index = index | |
| 84 | 86 | self.sa_column = sa_column | |
| 85 | 87 | self.sa_column_args = sa_column_args | |
@@ -141,6 +143,7 @@ def Field( | |||
| 141 | 143 | regex: Optional[str] = None, | |
| 142 | 144 | primary_key: bool = False, | |
| 143 | 145 | foreign_key: Optional[Any] = None, | |
| 146 | + unique: bool = False, | ||
| 144 | 147 | nullable: Union[bool, UndefinedType] = Undefined, | |
| 145 | 148 | index: Union[bool, UndefinedType] = Undefined, | |
| 146 | 149 | sa_column: Union[Column, UndefinedType] = Undefined, # type: ignore | |
@@ -171,6 +174,7 @@ def Field( | |||
| 171 | 174 | regex=regex, | |
| 172 | 175 | primary_key=primary_key, | |
| 173 | 176 | foreign_key=foreign_key, | |
| 177 | + unique=unique, | ||
| 174 | 178 | nullable=nullable, | |
| 175 | 179 | index=index, | |
| 176 | 180 | sa_column=sa_column, | |
@@ -425,12 +429,14 @@ def get_column_from_field(field: ModelField) -> Column: # type: ignore | |||
| 425 | 429 | nullable = field_nullable | |
| 426 | 430 | args = [] | |
| 427 | 431 | foreign_key = getattr(field.field_info, "foreign_key", None) | |
| 432 | + unique = getattr(field.field_info, "unique", False) | ||
| 428 | 433 | if foreign_key: | |
| 429 | 434 | args.append(ForeignKey(foreign_key)) | |
| 430 | 435 | kwargs = { | |
| 431 | 436 | "primary_key": primary_key, | |
| 432 | 437 | "nullable": nullable, | |
| 433 | 438 | "index": index, | |
| 439 | + "unique": unique, | ||
| 434 | 440 | } | |
| 435 | 441 | sa_default = Undefined | |
| 436 | 442 | if field.field_info.default_factory: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,97 @@ | |||
| 1 | + from typing import Optional | ||
| 2 | + | ||
| 3 | + import pytest | ||
| 4 | + from sqlalchemy.exc import IntegrityError | ||
| 5 | + from sqlmodel import Field, Session, SQLModel, create_engine | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + def test_should_allow_duplicate_row_if_unique_constraint_is_not_passed( | ||
| 9 | + clear_sqlmodel, | ||
| 10 | + ): | ||
| 11 | + class Hero(SQLModel, table=True): | ||
| 12 | + id: Optional[int] = Field(default=None, primary_key=True) | ||
| 13 | + name: str | ||
| 14 | + secret_name: str | ||
| 15 | + age: Optional[int] = None | ||
| 16 | + | ||
| 17 | + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") | ||
| 18 | + hero_2 = Hero(name="Deadpond", secret_name="Dive Wilson") | ||
| 19 | + | ||
| 20 | + engine = create_engine("sqlite://") | ||
| 21 | + | ||
| 22 | + SQLModel.metadata.create_all(engine) | ||
| 23 | + | ||
| 24 | + with Session(engine) as session: | ||
| 25 | + session.add(hero_1) | ||
| 26 | + session.commit() | ||
| 27 | + session.refresh(hero_1) | ||
| 28 | + | ||
| 29 | + with Session(engine) as session: | ||
| 30 | + session.add(hero_2) | ||
| 31 | + session.commit() | ||
| 32 | + session.refresh(hero_2) | ||
| 33 | + | ||
| 34 | + with Session(engine) as session: | ||
| 35 | + heroes = session.query(Hero).all() | ||
| 36 | + assert len(heroes) == 2 | ||
| 37 | + assert heroes[0].name == heroes[1].name | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + def test_should_allow_duplicate_row_if_unique_constraint_is_false( | ||
| 41 | + clear_sqlmodel, | ||
| 42 | + ): | ||
| 43 | + class Hero(SQLModel, table=True): | ||
| 44 | + id: Optional[int] = Field(default=None, primary_key=True) | ||
| 45 | + name: str | ||
| 46 | + secret_name: str = Field(unique=False) | ||
| 47 | + age: Optional[int] = None | ||
| 48 | + | ||
| 49 | + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") | ||
| 50 | + hero_2 = Hero(name="Deadpond", secret_name="Dive Wilson") | ||
| 51 | + | ||
| 52 | + engine = create_engine("sqlite://") | ||
| 53 | + | ||
| 54 | + SQLModel.metadata.create_all(engine) | ||
| 55 | + | ||
| 56 | + with Session(engine) as session: | ||
| 57 | + session.add(hero_1) | ||
| 58 | + session.commit() | ||
| 59 | + session.refresh(hero_1) | ||
| 60 | + | ||
| 61 | + with Session(engine) as session: | ||
| 62 | + session.add(hero_2) | ||
| 63 | + session.commit() | ||
| 64 | + session.refresh(hero_2) | ||
| 65 | + | ||
| 66 | + with Session(engine) as session: | ||
| 67 | + heroes = session.query(Hero).all() | ||
| 68 | + assert len(heroes) == 2 | ||
| 69 | + assert heroes[0].name == heroes[1].name | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + def test_should_raise_exception_when_try_to_duplicate_row_if_unique_constraint_is_true( | ||
| 73 | + clear_sqlmodel, | ||
| 74 | + ): | ||
| 75 | + class Hero(SQLModel, table=True): | ||
| 76 | + id: Optional[int] = Field(default=None, primary_key=True) | ||
| 77 | + name: str | ||
| 78 | + secret_name: str = Field(unique=True) | ||
| 79 | + age: Optional[int] = None | ||
| 80 | + | ||
| 81 | + hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson") | ||
| 82 | + hero_2 = Hero(name="Deadpond", secret_name="Dive Wilson") | ||
| 83 | + | ||
| 84 | + engine = create_engine("sqlite://") | ||
| 85 | + | ||
| 86 | + SQLModel.metadata.create_all(engine) | ||
| 87 | + | ||
| 88 | + with Session(engine) as session: | ||
| 89 | + session.add(hero_1) | ||
| 90 | + session.commit() | ||
| 91 | + session.refresh(hero_1) | ||
| 92 | + | ||
| 93 | + with pytest.raises(IntegrityError): | ||
| 94 | + with Session(engine) as session: | ||
| 95 | + session.add(hero_2) | ||
| 96 | + session.commit() | ||
| 97 | + session.refresh(hero_2) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments