Fix soft delete not being recognized.

This commit is contained in:
Yaro Kasear 2025-10-07 13:15:30 -05:00
parent 598a9f7793
commit eff6da0a3b
3 changed files with 101 additions and 5 deletions

View file

@ -6,7 +6,7 @@ from flask import current_app
from typing import Any, Callable, Type, TypeVar, Generic, Optional, Protocol, runtime_checkable, cast
from sqlalchemy import and_, func, inspect, or_, text
from sqlalchemy.engine import Engine, Connection
from sqlalchemy.orm import Load, Session, with_polymorphic, Mapper, selectinload
from sqlalchemy.orm import Load, Session, with_polymorphic, Mapper, selectinload, with_loader_criteria
from sqlalchemy.orm.attributes import InstrumentedAttribute
from sqlalchemy.sql import operators
from sqlalchemy.sql.elements import UnaryExpression, ColumnElement
@ -186,6 +186,31 @@ class CRUDService(Generic[T]):
# ---- common building blocks
def _apply_soft_delete_criteria_for_children(self, query, plan: "CRUDService._Plan", params):
# Skip if caller explicitly asked for deleted
if _is_truthy((params or {}).get("include_deleted")):
return query
seen = set()
for _base_alias, rel_attr, _target_alias in plan.join_paths:
prop = getattr(rel_attr, "property", None)
if not prop:
continue
target_cls = getattr(prop.mapper, "class_", None)
if not target_cls or target_cls in seen:
continue
seen.add(target_cls)
# Only apply to models that support soft delete
if hasattr(target_cls, "is_deleted"):
query = query.options(
with_loader_criteria(
target_cls,
lambda cls: cls.is_deleted == False,
include_aliases=True
)
)
return query
def _order_clauses(self, order_spec, invert: bool = False):
clauses = []
for c, is_desc in zip(order_spec.cols, order_spec.desc):
@ -442,6 +467,7 @@ class CRUDService(Generic[T]):
plan = self._plan(params, root_alias)
query = self._apply_projection_load_only(query, root_alias, plan)
query = self._apply_firsthop_strategies(query, root_alias, plan)
query = self._apply_soft_delete_criteria_for_children(query, plan, params)
if plan.filters:
query = query.filter(*plan.filters)
@ -528,6 +554,7 @@ class CRUDService(Generic[T]):
plan = self._plan(params, root_alias)
query = self._apply_projection_load_only(query, root_alias, plan)
query = self._apply_firsthop_strategies(query, root_alias, plan)
query = self._apply_soft_delete_criteria_for_children(query, plan, params)
if plan.filters:
query = query.filter(*plan.filters)
query = query.filter(getattr(root_alias, "id") == id)
@ -548,6 +575,7 @@ class CRUDService(Generic[T]):
query = self._apply_not_deleted(query, root_alias, params)
query = self._apply_projection_load_only(query, root_alias, plan)
query = self._apply_firsthop_strategies(query, root_alias, plan)
query = self._apply_soft_delete_criteria_for_children(query, plan, params)
if plan.filters:
query = query.filter(*plan.filters)