Fixed filter bug.
This commit is contained in:
parent
2ad327fcd9
commit
2a73d0ac92
1 changed files with 36 additions and 10 deletions
|
|
@ -76,6 +76,20 @@ def _collect_tables_from_filters(filters) -> set:
|
|||
visit(f)
|
||||
return seen
|
||||
|
||||
def _selectable_keys(sel) -> set[str]:
|
||||
"""
|
||||
Return a set of stable string keys for a selectable/alias and its base,
|
||||
so we can match when when different alias objects are used.
|
||||
"""
|
||||
keys: set[str] = set()
|
||||
cur = sel
|
||||
while cur is not None:
|
||||
k = getattr(cur, "key", None) or getattr(cur, "name", None)
|
||||
if isinstance(k, str) and k:
|
||||
keys.add(k)
|
||||
cur = getattr(cur, "element", None)
|
||||
return keys
|
||||
|
||||
def _unwrap_ob(ob):
|
||||
elem = getattr(ob, "element", None)
|
||||
col = elem if elem is not None else ob
|
||||
|
|
@ -244,6 +258,7 @@ class CRUDService(Generic[T]):
|
|||
collection_field_names: Any
|
||||
join_paths: Any
|
||||
filter_tables: Any
|
||||
filter_table_keys: Any
|
||||
req_fields: Any
|
||||
proj_opts: Any
|
||||
|
||||
|
|
@ -259,12 +274,19 @@ class CRUDService(Generic[T]):
|
|||
join_paths = tuple(spec.get_join_paths())
|
||||
filter_tables = _collect_tables_from_filters(filters)
|
||||
_, proj_opts = compile_projection(self.model, req_fields) if req_fields else ([], [])
|
||||
# Precompute a string-key set for quick/stable membership tests
|
||||
fkeys: set[str] = set()
|
||||
for t in filter_tables:
|
||||
try:
|
||||
fkeys |= _selectable_keys(t)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return self._Plan(
|
||||
spec=spec, filters=filters, order_by=order_by, limit=limit, offset=offset,
|
||||
root_fields=root_fields, rel_field_names=rel_field_names,
|
||||
root_field_names=root_field_names, collection_field_names=collection_field_names,
|
||||
join_paths=join_paths, filter_tables=filter_tables,
|
||||
join_paths=join_paths, filter_tables=filter_tables, filter_table_keys=fkeys,
|
||||
req_fields=req_fields, proj_opts=proj_opts
|
||||
)
|
||||
|
||||
|
|
@ -278,16 +300,20 @@ class CRUDService(Generic[T]):
|
|||
if base_alias is not root_alias:
|
||||
continue
|
||||
prop = getattr(rel_attr, "property", None)
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
try:
|
||||
sel = getattr(target_alias, "selectable", None)
|
||||
sel_key = getattr(sel, "key", None) or getattr(sel, "name", None)
|
||||
log.debug(
|
||||
"FIRST-HOP plan: rel=%s collection=%s selectable=%s filter_keys=%s",
|
||||
rel_attr.key, getattr(prop, "uselist", False), sel_key, getattr(plan, "filter_table_keys", set())
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
is_collection = bool(getattr(prop, "uselist", False))
|
||||
|
||||
sel = getattr(target_alias, "selectable", None)
|
||||
sel_elem = getattr(sel, "element", None)
|
||||
base_sel = sel_elem if sel_elem is not None else sel
|
||||
|
||||
needed_for_filter = (sel in plan.filter_tables) or (base_sel in plan.filter_tables)
|
||||
|
||||
if needed_for_filter and not is_collection:
|
||||
query = query.join(rel_attr, isouter=True)
|
||||
if not is_collection:
|
||||
query = query.join(target_alias, rel_attr.of_type(target_alias), isouter=True)
|
||||
else:
|
||||
opt = selectinload(rel_attr)
|
||||
if is_collection:
|
||||
|
|
@ -407,7 +433,7 @@ class CRUDService(Generic[T]):
|
|||
base = self._apply_not_deleted(base, root_alias, params)
|
||||
for _b, rel_attr, target_alias in plan.join_paths:
|
||||
if not bool(getattr(getattr(rel_attr, "property", None), "uselist", False)):
|
||||
base = base.join(rel_attr, isouter=True)
|
||||
base = base.join(target_alias, rel_attr.of_type(target_alias), isouter=True)
|
||||
if plan.filters:
|
||||
base = base.filter(*plan.filters)
|
||||
total = session.query(func.count()).select_from(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue