Finally got that bug!
This commit is contained in:
parent
dc1d4111e2
commit
87cb686c64
2 changed files with 112 additions and 90 deletions
|
|
@ -1,9 +1,17 @@
|
|||
from dataclasses import dataclass
|
||||
from typing import Any, List, Tuple, Set, Dict, Optional, Iterable
|
||||
from sqlalchemy import and_, asc, desc, or_
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.orm import aliased, selectinload
|
||||
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CollPred:
|
||||
table: Any
|
||||
col_key: str
|
||||
op: str
|
||||
value: Any
|
||||
|
||||
OPERATORS = {
|
||||
'eq': lambda col, val: col == val,
|
||||
'lt': lambda col, val: col < val,
|
||||
|
|
@ -68,16 +76,48 @@ class CRUDSpec:
|
|||
|
||||
exprs = []
|
||||
for col, join_path in pairs:
|
||||
# Track eager path for each involved relationship chain
|
||||
if join_path:
|
||||
self.eager_paths.add(join_path)
|
||||
|
||||
try:
|
||||
cur_cls = self.model
|
||||
names = list(join_path)
|
||||
last_name = names[-1]
|
||||
is_collection = False
|
||||
for nm in names:
|
||||
rel_attr = getattr(cur_cls, nm)
|
||||
prop = rel_attr.property
|
||||
cur_cls = prop.mapper.class_
|
||||
is_collection = bool(getattr(getattr(self.model, last_name), "property", None)
|
||||
and getattr(getattr(self.model, last_name).property, "uselist", False))
|
||||
except Exception:
|
||||
is_collection = False
|
||||
|
||||
if is_collection:
|
||||
target_cls = cur_cls
|
||||
key = getattr(col, "key", None) or getattr(col, "name", None)
|
||||
if key and hasattr(target_cls, key):
|
||||
target_tbl = getattr(target_cls, "__table__", None)
|
||||
if target_tbl is not None:
|
||||
exprs.append(CollPred(table=target_tbl, col_key=key, op=op, value=value))
|
||||
continue
|
||||
|
||||
exprs.append(OPERATORS[op](col, value))
|
||||
|
||||
if not exprs:
|
||||
return None
|
||||
if len(exprs) == 1:
|
||||
|
||||
# If any CollPred is in exprs, do NOT or_ them. Keep it single for now.
|
||||
if any(isinstance(x, CollPred) for x in exprs):
|
||||
# If someone used a pipe 'relA.col|relB.col' that produced multiple CollPreds,
|
||||
# keep the first or raise for now (your choice).
|
||||
if len(exprs) > 1:
|
||||
# raise NotImplementedError("OR across collection paths not supported yet")
|
||||
exprs = [next(x for x in exprs if isinstance(x, CollPred))]
|
||||
return exprs[0]
|
||||
return or_(*exprs)
|
||||
|
||||
# Otherwise, standard SQLA clause(s)
|
||||
return exprs[0] if len(exprs) == 1 else or_(*exprs)
|
||||
|
||||
def _collect_filters(self, params: dict) -> list:
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue