"""Soft-delete query predicates shared across soft-deletable models.""" from sqlalchemy import or_ def predicates(model: type, is_deleted: bool | None) -> list: """Return the deleted-column predicates for an is_deleted filter. False: active rows (both markers null). True: deleted rows (either marker set). None: no predicate (all rows). active and deleted are exact complements so no row falls into neither. Applied identically to the parent query and the detail subquery so the two never diverge. Raises ValueError on a non-bool, non-None value to guard callers. """ if is_deleted is None: return [] if is_deleted is True: return [or_(model.deleted_at.isnot(None), model.deleted_by.isnot(None))] if is_deleted is False: return [model.deleted_at.is_(None), model.deleted_by.is_(None)] raise ValueError(f'Expected bool or None for is_deleted, got {is_deleted!r}')