Update: Sheet 8 & 11 compliance + changing api router due to error unauthorized when access some pages
parent
2a57ac8bec
commit
2615ff9a6e
@ -0,0 +1,77 @@
|
||||
"""
|
||||
Soft delete utilities.
|
||||
|
||||
Provides reusable functions to convert hard-delete operations into soft-deletes.
|
||||
The `soft_delete_record` function works with any model that inherits `SoftDeleteMixin`
|
||||
(which is included in `DefaultMixin`).
|
||||
|
||||
Usage in service files:
|
||||
from src.soft_delete import soft_delete_record, apply_not_deleted_filter
|
||||
|
||||
async def delete(*, db_session, record_id: str):
|
||||
await soft_delete_record(db_session=db_session, model=MyModel, record_id=record_id)
|
||||
|
||||
async def get_all(*, db_session, ...):
|
||||
query = Select(MyModel)
|
||||
query = apply_not_deleted_filter(query, MyModel)
|
||||
...
|
||||
"""
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import TypeVar, Type
|
||||
|
||||
from sqlalchemy import Select, Update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
import pytz
|
||||
from src.config import TIMEZONE
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def apply_not_deleted_filter(query: Select, model) -> Select:
|
||||
"""
|
||||
Appends a WHERE clause to exclude soft-deleted records.
|
||||
Use this on all "get" queries to hide deleted data.
|
||||
|
||||
Example:
|
||||
query = Select(OverhaulScope)
|
||||
query = apply_not_deleted_filter(query, OverhaulScope)
|
||||
"""
|
||||
if hasattr(model, "deleted_at"):
|
||||
return query.filter(model.deleted_at.is_(None))
|
||||
return query
|
||||
|
||||
|
||||
async def soft_delete_record(
|
||||
*,
|
||||
db_session: AsyncSession,
|
||||
model: Type[T],
|
||||
record_id: str,
|
||||
id_column: str = "id",
|
||||
) -> None:
|
||||
"""
|
||||
Soft-delete a record by setting its `deleted_at` timestamp.
|
||||
Instead of DELETE, this performs an UPDATE.
|
||||
|
||||
Args:
|
||||
db_session: The async database session.
|
||||
model: The SQLAlchemy model class.
|
||||
record_id: The value of the ID to match.
|
||||
id_column: The name of the ID column (default: "id").
|
||||
"""
|
||||
now = datetime.now(pytz.timezone(TIMEZONE))
|
||||
id_col = getattr(model, id_column)
|
||||
|
||||
stmt = (
|
||||
Update(model)
|
||||
.where(id_col == record_id)
|
||||
.values(deleted_at=now)
|
||||
)
|
||||
await db_session.execute(stmt)
|
||||
await db_session.commit()
|
||||
|
||||
log.info(f"Soft-deleted {model.__tablename__} record: {record_id}")
|
||||
Loading…
Reference in New Issue