From 17b59e58d6048f4deba40ae84cce80cb6b94abd7 Mon Sep 17 00:00:00 2001 From: Julien Date: Sat, 11 Jan 2025 21:36:38 +0100 Subject: [PATCH 1/2] feat: add softdelete mixin --- advanced_alchemy/mixins/softdelete.py | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 advanced_alchemy/mixins/softdelete.py diff --git a/advanced_alchemy/mixins/softdelete.py b/advanced_alchemy/mixins/softdelete.py new file mode 100644 index 000000000..52e60eecf --- /dev/null +++ b/advanced_alchemy/mixins/softdelete.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from datetime import datetime, timezone + +from sqlalchemy import mapped_column +from sqlalchemy.orm import Mapped, declarative_mixin, declared_attr +from sqlalchemy.types import DateTime + + +@declarative_mixin +class SoftDeleteMixin: + """Mixin class that adds soft delete functionality to SQLAlchemy models. + + Adds two columns: + - deleted_at: Timestamp when the record was deleted + """ + + @declared_attr + def deleted_at(cls) -> Mapped[datetime | None]: + """Timestamp when the record was soft deleted""" + return mapped_column( + DateTime(timezone=True), + default=None, + nullable=True, + index=True, + ) + + def set_deleted_at(self, timestamp: datetime | None = None) -> None: + """Mark the record as soft deleted. + + Args: + timestamp: Optional timestamp to use for the deletion. If not provided, + the current UTC timestamp will be used. + """ + self.deleted_at = timestamp or datetime.now(timezone.utc) + + def restore(self) -> None: + self.deleted_at = None From a2b360021f7071c1f4559ad70d57e0658dddc0dd Mon Sep 17 00:00:00 2001 From: Julien Date: Sat, 11 Jan 2025 21:42:32 +0100 Subject: [PATCH 2/2] add docstring to the restore method --- advanced_alchemy/mixins/softdelete.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/advanced_alchemy/mixins/softdelete.py b/advanced_alchemy/mixins/softdelete.py index 52e60eecf..e0b888297 100644 --- a/advanced_alchemy/mixins/softdelete.py +++ b/advanced_alchemy/mixins/softdelete.py @@ -35,4 +35,9 @@ def set_deleted_at(self, timestamp: datetime | None = None) -> None: self.deleted_at = timestamp or datetime.now(timezone.utc) def restore(self) -> None: + """Restore a soft-deleted record by clearing the deleted_at timestamp. + + This method undeletes a previously soft-deleted record by setting the deleted_at + field to None, making it visible in normal queries again. + """ self.deleted_at = None