Skip to content

Commit c43b622

Browse files
committed
Merge branch 'feat/soft-delete' of https://github.com/letsdeepchat/sqlmodel into feat/soft-delete
2 parents 3ef44a5 + b404d0f commit c43b622

6 files changed

Lines changed: 29 additions & 16 deletions

File tree

docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_extra_coverage.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
def test_startup():
1313
app_mod.engine = create_engine("sqlite://")
14-
app_mod.on_startup()
14+
app_mod.create_db_and_tables()
1515
insp: Inspector = inspect(app_mod.engine)
1616
assert insp.has_table(str(app_mod.Hero.__tablename__))
1717

docs_src/tutorial/fastapi/update/tutorial002_py310.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,21 @@ def create_db_and_tables():
4141
SQLModel.metadata.create_all(engine)
4242

4343

44-
@asynccontextmanager
45-
async def lifespan(app: FastAPI):
46-
create_db_and_tables()
47-
yield
44+
def hash_password(password: str) -> str:
45+
return f"not really hashed {password} hehehe"
46+
47+
48+
def get_session():
49+
with Session(engine) as session:
50+
yield session
4851

4952

50-
app = FastAPI(lifespan=lifespan)
53+
app = FastAPI()
54+
55+
56+
@app.on_event("startup")
57+
def on_startup():
58+
create_db_and_tables()
5159

5260

5361
@app.post("/heroes/", response_model=HeroPublic)

sqlmodel/soft_delete.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,10 @@
55

66

77
class SoftDeleteMixin:
8-
deleted_at: Optional[datetime] = Field(default=None, nullable=True)
8+
"""
9+
Mixin that adds a `deleted_at` timestamp column.
10+
11+
Usage:
12+
class MyModel(SQLModel, SoftDeleteMixin, table=True): ...
13+
"""
14+
deleted_at: Optional[datetime] = Field(default=None)

sqlmodel/soft_delete_session.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from typing import Any
22

33
from sqlmodel.orm.session import Session
4-
54
from sqlmodel.soft_delete import SoftDeleteMixin
65

76

@@ -15,4 +14,5 @@ def delete(self, instance: Any, hard_delete: bool = False) -> Any:
1514

1615
def _now(self) -> Any:
1716
from datetime import datetime, timezone
18-
return datetime.now(timezone.utc)
17+
18+
return datetime.now(timezone.utc)

tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def cov_tmp_path(tmp_path: Path) -> Generator[Path, None, None]:
3737

3838
def coverage_run(*, module: str, cwd: str | Path) -> subprocess.CompletedProcess:
3939
import os
40+
4041
env = os.environ.copy()
4142
env["PYTHONPATH"] = str(top_level_path)
4243
# On Windows, coverage causes asyncio issues, so run python directly

tests/test_session_delete.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import pytest
21
from datetime import datetime
3-
from typing import Optional
42

5-
from sqlmodel import SQLModel, create_engine, Field
6-
from sqlmodel.main import default_registry
3+
import pytest
4+
from sqlmodel import Field, SQLModel, create_engine
75
from sqlmodel.soft_delete import SoftDeleteMixin
86
from sqlmodel.soft_delete_session import SoftDeleteSession
97

@@ -17,7 +15,7 @@ def clear_sqlmodel():
1715
def test_soft_delete():
1816
# Define model inside test to avoid registry conflicts
1917
class SoftDeleteHero(SQLModel, SoftDeleteMixin, table=True):
20-
id: Optional[int] = Field(default=None, primary_key=True)
18+
id: int | None = Field(default=None, primary_key=True)
2119
name: str
2220

2321
engine = create_engine("sqlite:///:memory:")
@@ -45,7 +43,7 @@ def test_hard_delete():
4543
# Define model inside test to avoid registry conflicts
4644
class HardDeleteHero(SQLModel, SoftDeleteMixin, table=True):
4745
__tablename__ = "hard_delete_heroes"
48-
id: Optional[int] = Field(default=None, primary_key=True)
46+
id: int | None = Field(default=None, primary_key=True)
4947
name: str
5048

5149
engine = create_engine("sqlite:///:memory:")
@@ -62,4 +60,4 @@ class HardDeleteHero(SQLModel, SoftDeleteMixin, table=True):
6260

6361
# Check hard deleted (would raise if not handled, but since hard delete, it's gone)
6462
# In SQLAlchemy, after hard delete, the object is detached
65-
assert hero.id is None or session.get(HardDeleteHero, hero.id) is None
63+
assert hero.id is None or session.get(HardDeleteHero, hero.id) is None

0 commit comments

Comments
 (0)