@@ -42,6 +42,10 @@ def _extract_comparison(cls, args):
4242 def _get_value (obj ):
4343 while isinstance (obj , Tree ):
4444 obj = obj .children [0 ]
45+
46+ if isinstance (obj , Q ):
47+ return obj
48+
4549 return obj .value
4650
4751 def sign_prop (self , args ):
@@ -72,13 +76,47 @@ class RQLToDjangoORMTransformer(BaseRQLTransformer):
7276 They are applied later in FilterCls. This is done on purpose, because transformer knows
7377 nothing about the mappings between filter names and orm fields.
7478 """
79+ NAMESPACE_PROVIDERS = ('comp' , 'listing' )
80+ NAMESPACE_FILLERS = ('prop' ,)
81+ NAMESPACE_ACTIVATORS = ('tuple' ,)
82+
7583 def __init__ (self , filter_cls_instance ):
7684 self ._filter_cls_instance = filter_cls_instance
7785
7886 self ._ordering = []
7987 self ._select = []
8088 self ._filtered_props = set ()
8189
90+ self ._namespace = []
91+ self ._active_namespace = 0
92+
93+ self .__visit_tokens__ = False
94+
95+ def _push_namespace (self , tree ):
96+ if tree .data in self .NAMESPACE_PROVIDERS :
97+ self ._namespace .append (None )
98+ elif tree .data in self .NAMESPACE_ACTIVATORS :
99+ self ._active_namespace = len (self ._namespace )
100+ elif (tree .data in self .NAMESPACE_FILLERS
101+ and self ._namespace
102+ and self ._namespace [- 1 ] is None ):
103+ self ._namespace [- 1 ] = self ._get_value (tree )
104+
105+ def _pop_namespace (self , tree ):
106+ if tree .data in self .NAMESPACE_PROVIDERS :
107+ self ._namespace .pop ()
108+ elif tree .data in self .NAMESPACE_ACTIVATORS :
109+ self ._active_namespace -= 1
110+
111+ def _get_current_namespace (self ):
112+ return self ._namespace [:self ._active_namespace ]
113+
114+ def _transform_tree (self , tree ):
115+ self ._push_namespace (tree )
116+ ret_value = super ()._transform_tree (tree )
117+ self ._pop_namespace (tree )
118+ return ret_value
119+
82120 @property
83121 def ordering_filters (self ):
84122 return self ._ordering
@@ -94,9 +132,19 @@ def start(self, args):
94132
95133 def comp (self , args ):
96134 prop , operation , value = self ._extract_comparison (args )
97- self ._filtered_props .add (prop )
98135
99- return self ._filter_cls_instance .build_q_for_filter (FilterArgs (prop , operation , value ))
136+ if isinstance (value , Q ):
137+ if operation == ComparisonOperators .EQ :
138+ return value
139+ else :
140+ return ~ value
141+
142+ filter_args = FilterArgs (prop , operation , value , namespace = self ._get_current_namespace ())
143+ self ._filtered_props .add (filter_args .filter_name )
144+ return self ._filter_cls_instance .build_q_for_filter (filter_args )
145+
146+ def tuple (self , args ):
147+ return Q (* args )
100148
101149 def logical (self , args ):
102150 operation = args [0 ].data
@@ -119,10 +167,17 @@ def listing(self, args):
119167
120168 q = Q ()
121169 for value_tree in args [2 :]:
122- field_q = self ._filter_cls_instance .build_q_for_filter (FilterArgs (
123- prop , f_op , self ._get_value (value_tree ),
124- list_operator = operation ,
125- ))
170+ value = self ._get_value (value_tree )
171+ if isinstance (value , Q ):
172+ if f_op == ComparisonOperators .EQ :
173+ field_q = value
174+ else :
175+ field_q = ~ value
176+ else :
177+ field_q = self ._filter_cls_instance .build_q_for_filter (FilterArgs (
178+ prop , f_op , value ,
179+ list_operator = operation ,
180+ ))
126181 if operation == ListOperators .IN :
127182 q |= field_q
128183 else :
@@ -135,9 +190,9 @@ def listing(self, args):
135190 def searching (self , args ):
136191 # like, ilike
137192 operation , prop , val = tuple (self ._get_value (args [index ]) for index in range (3 ))
138- self ._filtered_props . add ( prop )
139-
140- return self ._filter_cls_instance .build_q_for_filter (FilterArgs ( prop , operation , val ) )
193+ filter_args = FilterArgs ( prop , operation , val , namespace = self ._get_current_namespace () )
194+ self . _filtered_props . add ( filter_args . filter_name )
195+ return self ._filter_cls_instance .build_q_for_filter (filter_args )
141196
142197 def ordering (self , args ):
143198 props = args [1 :]
0 commit comments