@@ -18,10 +18,11 @@ def _safe_filter(query):
18
18
return query .first ()
19
19
raise Exception (f"Got more than one matching: { list (query )} " )
20
20
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' )):
22
22
23
23
def __new__ (cls , * args , ** kwargs ):
24
24
kwargs ['join_cache' ] = dict ()
25
+ kwargs ['param_count' ] = 0
25
26
# TODO: Use tree_rank_count to implement cases where formatter of taxon is defined with fields from the parent.
26
27
# In that case, the cycle will end (unlike other cyclical cases).
27
28
kwargs ['tree_rank_count' ] = 0
@@ -71,48 +72,40 @@ def handle_tree_field(self, node, table, tree_rank, next_join_path, current_fiel
71
72
72
73
assert len (treedefs_with_ranks ) >= 1 , "Didn't find the tree rank across any tree"
73
74
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 )
109
102
110
103
defs_to_filter_on = [def_id for (def_id , _ ) in treedefs_with_ranks ]
111
104
# We don't want to include treedef if the rank is not present.
112
105
new_filters = [* query .internal_filters , getattr (node , treedef_column ).in_ (defs_to_filter_on )]
113
106
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
116
109
117
110
def tables_in_path (self , table , join_path ):
118
111
path = deque (join_path )
0 commit comments