Skip to content

Commit 93e2a0a

Browse files
committed
Use query construct code from #4929
1 parent 419e37c commit 93e2a0a

File tree

1 file changed

+31
-38
lines changed

1 file changed

+31
-38
lines changed

Diff for: specifyweb/stored_queries/query_construct.py

+31-38
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ def _safe_filter(query):
1818
return query.first()
1919
raise Exception(f"Got more than one matching: {list(query)}")
2020

21-
class QueryConstruct(namedtuple('QueryConstruct', 'collection objectformatter query join_cache tree_rank_count internal_filters')):
21+
class QueryConstruct(namedtuple('QueryConstruct', 'collection objectformatter query join_cache tree_rank_count param_count internal_filters')):
2222

2323
def __new__(cls, *args, **kwargs):
2424
kwargs['join_cache'] = dict()
25+
kwargs['param_count'] = 0
2526
# TODO: Use tree_rank_count to implement cases where formatter of taxon is defined with fields from the parent.
2627
# In that case, the cycle will end (unlike other cyclical cases).
2728
kwargs['tree_rank_count'] = 0
@@ -71,48 +72,40 @@ def handle_tree_field(self, node, table, tree_rank, next_join_path, current_fiel
7172

7273
assert len(treedefs_with_ranks) >= 1, "Didn't find the tree rank across any tree"
7374

74-
column_name = next_join_path[0].name
75-
76-
# NOTE: Code from #4929
77-
# def make_tree_field_spec(tree_node):
78-
# return current_field_spec._replace(
79-
# root_table=table, # rebasing the query
80-
# root_sql_table=tree_node, # this is needed to preserve SQL aliased going to next part
81-
# join_path=next_join_path, # slicing join path to begin from after the tree
82-
# )
83-
84-
# cases = []
85-
# field = None # just to stop mypy from complaining.
86-
# for ancestor in ancestors:
87-
# field_spec = make_tree_field_spec(ancestor)
88-
# query, orm_field, field, table = field_spec.add_spec_to_query(query)
89-
# #field and table won't matter. rank acts as fork, and these two will be same across siblings
90-
# cases.append((getattr(ancestor, treedefitem_column) == treedefitem_param, orm_field))
91-
92-
# column = sql.case(cases)
93-
94-
# return query, column, field, table
95-
96-
def _predicates_for_node(_node):
97-
return [
98-
# TEST: consider taking the treedef_id comparison just to the first node, if it speeds things up (matching for higher is redundant..)
99-
(sql.and_(getattr(_node, treedef_column)==treedef_id, getattr(_node, treedefitem_column)==treedefitem_id), getattr(_node, column_name))
100-
for (treedef_id, treedefitem_id) in treedefs_with_ranks
101-
]
102-
103-
cases_per_ancestor = [
104-
_predicates_for_node(ancestor)
105-
for ancestor in ancestors
106-
]
107-
108-
column = sql.case([case for per_ancestor in cases_per_ancestor for case in per_ancestor])
75+
treedefitem_params = []
76+
for _, rank_id in treedefs_with_ranks:
77+
treedefitem_param = sql.bindparam(
78+
'tdi_%s' % query.param_count,
79+
value=rank_id
80+
)
81+
treedefitem_params.append(treedefitem_param)
82+
param_count = self.param_count + 1
83+
query = query._replace(param_count=param_count)
84+
85+
def make_tree_field_spec(tree_node):
86+
return current_field_spec._replace(
87+
root_table=table, # rebasing the query
88+
root_sql_table=tree_node, # this is needed to preserve SQL aliased going to next part
89+
join_path=next_join_path, # slicing join path to begin from after the tree
90+
)
91+
92+
cases = []
93+
field = None # just to stop mypy from complaining.
94+
for ancestor in ancestors:
95+
field_spec = make_tree_field_spec(ancestor)
96+
query, orm_field, field, table = field_spec.add_spec_to_query(query)
97+
# Field and table won't matter. Rank acts as fork, and these two will be same across siblings
98+
for treedefitem_param in treedefitem_params:
99+
cases.append((getattr(ancestor, treedefitem_column) == treedefitem_param, orm_field))
100+
101+
column = sql.case(cases)
109102

110103
defs_to_filter_on = [def_id for (def_id, _) in treedefs_with_ranks]
111104
# We don't want to include treedef if the rank is not present.
112105
new_filters = [*query.internal_filters, getattr(node, treedef_column).in_(defs_to_filter_on)]
113106
query = query._replace(internal_filters=new_filters)
114-
115-
return query, column, current_field_spec.get_field(), table
107+
108+
return query, column, field, table
116109

117110
def tables_in_path(self, table, join_path):
118111
path = deque(join_path)

0 commit comments

Comments
 (0)