@@ -193,20 +193,18 @@ def compile_json_path_final_key(self, key_transform):
193193 # Compile the final key without interpreting ints as array elements.
194194 return ".%s" % json .dumps (key_transform )
195195
196- def as_sql (self , compiler , connection , template = None ):
196+ def _as_sql_parts (self , compiler , connection ):
197197 # Process JSON path from the left-hand side.
198198 if isinstance (self .lhs , KeyTransform ):
199- lhs , lhs_params , lhs_key_transforms = self .lhs .preprocess_lhs (
199+ lhs_sql , lhs_params , lhs_key_transforms = self .lhs .preprocess_lhs (
200200 compiler , connection
201201 )
202202 lhs_json_path = compile_json_path (lhs_key_transforms )
203203 else :
204- lhs , lhs_params = self .process_lhs (compiler , connection )
204+ lhs_sql , lhs_params = self .process_lhs (compiler , connection )
205205 lhs_json_path = "$"
206- sql = template % lhs
207206 # Process JSON path from the right-hand side.
208207 rhs = self .rhs
209- rhs_params = []
210208 if not isinstance (rhs , (list , tuple )):
211209 rhs = [rhs ]
212210 for key in rhs :
@@ -217,24 +215,43 @@ def as_sql(self, compiler, connection, template=None):
217215 * rhs_key_transforms , final_key = rhs_key_transforms
218216 rhs_json_path = compile_json_path (rhs_key_transforms , include_root = False )
219217 rhs_json_path += self .compile_json_path_final_key (final_key )
220- rhs_params .append (lhs_json_path + rhs_json_path )
218+ yield lhs_sql , lhs_params , lhs_json_path + rhs_json_path
219+
220+ def _combine_sql_parts (self , parts ):
221221 # Add condition for each key.
222222 if self .logical_operator :
223- sql = "(%s)" % self .logical_operator .join ([sql ] * len (rhs_params ))
224- return sql , tuple (lhs_params ) + tuple (rhs_params )
223+ return "(%s)" % self .logical_operator .join (parts )
224+ return "" .join (parts )
225+
226+ def as_sql (self , compiler , connection , template = None ):
227+ sql_parts = []
228+ params = []
229+ for lhs_sql , lhs_params , rhs_json_path in self ._as_sql_parts (
230+ compiler , connection
231+ ):
232+ sql_parts .append (template % (lhs_sql , "%s" ))
233+ params .extend (lhs_params + [rhs_json_path ])
234+ return self ._combine_sql_parts (sql_parts ), tuple (params )
225235
226236 def as_mysql (self , compiler , connection ):
227237 return self .as_sql (
228- compiler , connection , template = "JSON_CONTAINS_PATH(%s, 'one', %% s)"
238+ compiler , connection , template = "JSON_CONTAINS_PATH(%s, 'one', %s)"
229239 )
230240
231241 def as_oracle (self , compiler , connection ):
232- sql , params = self .as_sql (
233- compiler , connection , template = "JSON_EXISTS(%s, '%%s')"
234- )
235- # Add paths directly into SQL because path expressions cannot be passed
236- # as bind variables on Oracle.
237- return sql % tuple (params ), []
242+ template = "JSON_EXISTS(%s, '%s')"
243+ sql_parts = []
244+ params = []
245+ for lhs_sql , lhs_params , rhs_json_path in self ._as_sql_parts (
246+ compiler , connection
247+ ):
248+ # Add right-hand-side directly into SQL because it cannot be passed
249+ # as bind variables to JSON_EXISTS. It might result in invalid
250+ # queries but it is assumed that it cannot be evaded because the
251+ # path is JSON serialized.
252+ sql_parts .append (template % (lhs_sql , rhs_json_path ))
253+ params .extend (lhs_params )
254+ return self ._combine_sql_parts (sql_parts ), tuple (params )
238255
239256 def as_postgresql (self , compiler , connection ):
240257 if isinstance (self .rhs , KeyTransform ):
@@ -246,7 +263,7 @@ def as_postgresql(self, compiler, connection):
246263
247264 def as_sqlite (self , compiler , connection ):
248265 return self .as_sql (
249- compiler , connection , template = "JSON_TYPE(%s, %% s) IS NOT NULL"
266+ compiler , connection , template = "JSON_TYPE(%s, %s) IS NOT NULL"
250267 )
251268
252269
@@ -455,9 +472,9 @@ def as_oracle(self, compiler, connection):
455472 return "(NOT %s OR %s IS NULL)" % (sql , lhs ), tuple (params ) + tuple (lhs_params )
456473
457474 def as_sqlite (self , compiler , connection ):
458- template = "JSON_TYPE(%s, %% s) IS NULL"
475+ template = "JSON_TYPE(%s, %s) IS NULL"
459476 if not self .rhs :
460- template = "JSON_TYPE(%s, %% s) IS NOT NULL"
477+ template = "JSON_TYPE(%s, %s) IS NOT NULL"
461478 return HasKeyOrArrayIndex (self .lhs .lhs , self .lhs .key_name ).as_sql (
462479 compiler ,
463480 connection ,
0 commit comments