@@ -216,20 +216,18 @@ def compile_json_path_final_key(self, key_transform):
216216 # Compile the final key without interpreting ints as array elements.
217217 return ".%s" % json .dumps (key_transform )
218218
219- def as_sql (self , compiler , connection , template = None ):
219+ def _as_sql_parts (self , compiler , connection ):
220220 # Process JSON path from the left-hand side.
221221 if isinstance (self .lhs , KeyTransform ):
222- lhs , lhs_params , lhs_key_transforms = self .lhs .preprocess_lhs (
222+ lhs_sql , lhs_params , lhs_key_transforms = self .lhs .preprocess_lhs (
223223 compiler , connection
224224 )
225225 lhs_json_path = compile_json_path (lhs_key_transforms )
226226 else :
227- lhs , lhs_params = self .process_lhs (compiler , connection )
227+ lhs_sql , lhs_params = self .process_lhs (compiler , connection )
228228 lhs_json_path = "$"
229- sql = template % lhs
230229 # Process JSON path from the right-hand side.
231230 rhs = self .rhs
232- rhs_params = []
233231 if not isinstance (rhs , (list , tuple )):
234232 rhs = [rhs ]
235233 for key in rhs :
@@ -240,24 +238,43 @@ def as_sql(self, compiler, connection, template=None):
240238 * rhs_key_transforms , final_key = rhs_key_transforms
241239 rhs_json_path = compile_json_path (rhs_key_transforms , include_root = False )
242240 rhs_json_path += self .compile_json_path_final_key (final_key )
243- rhs_params .append (lhs_json_path + rhs_json_path )
241+ yield lhs_sql , lhs_params , lhs_json_path + rhs_json_path
242+
243+ def _combine_sql_parts (self , parts ):
244244 # Add condition for each key.
245245 if self .logical_operator :
246- sql = "(%s)" % self .logical_operator .join ([sql ] * len (rhs_params ))
247- return sql , tuple (lhs_params ) + tuple (rhs_params )
246+ return "(%s)" % self .logical_operator .join (parts )
247+ return "" .join (parts )
248+
249+ def as_sql (self , compiler , connection , template = None ):
250+ sql_parts = []
251+ params = []
252+ for lhs_sql , lhs_params , rhs_json_path in self ._as_sql_parts (
253+ compiler , connection
254+ ):
255+ sql_parts .append (template % (lhs_sql , "%s" ))
256+ params .extend (lhs_params + [rhs_json_path ])
257+ return self ._combine_sql_parts (sql_parts ), tuple (params )
248258
249259 def as_mysql (self , compiler , connection ):
250260 return self .as_sql (
251- compiler , connection , template = "JSON_CONTAINS_PATH(%s, 'one', %% s)"
261+ compiler , connection , template = "JSON_CONTAINS_PATH(%s, 'one', %s)"
252262 )
253263
254264 def as_oracle (self , compiler , connection ):
255- sql , params = self .as_sql (
256- compiler , connection , template = "JSON_EXISTS(%s, '%%s')"
257- )
258- # Add paths directly into SQL because path expressions cannot be passed
259- # as bind variables on Oracle.
260- return sql % tuple (params ), []
265+ template = "JSON_EXISTS(%s, '%s')"
266+ sql_parts = []
267+ params = []
268+ for lhs_sql , lhs_params , rhs_json_path in self ._as_sql_parts (
269+ compiler , connection
270+ ):
271+ # Add right-hand-side directly into SQL because it cannot be passed
272+ # as bind variables to JSON_EXISTS. It might result in invalid
273+ # queries but it is assumed that it cannot be evaded because the
274+ # path is JSON serialized.
275+ sql_parts .append (template % (lhs_sql , rhs_json_path ))
276+ params .extend (lhs_params )
277+ return self ._combine_sql_parts (sql_parts ), tuple (params )
261278
262279 def as_postgresql (self , compiler , connection ):
263280 if isinstance (self .rhs , KeyTransform ):
@@ -269,7 +286,7 @@ def as_postgresql(self, compiler, connection):
269286
270287 def as_sqlite (self , compiler , connection ):
271288 return self .as_sql (
272- compiler , connection , template = "JSON_TYPE(%s, %% s) IS NOT NULL"
289+ compiler , connection , template = "JSON_TYPE(%s, %s) IS NOT NULL"
273290 )
274291
275292
@@ -467,9 +484,9 @@ def as_oracle(self, compiler, connection):
467484 return "(NOT %s OR %s IS NULL)" % (sql , lhs ), tuple (params ) + tuple (lhs_params )
468485
469486 def as_sqlite (self , compiler , connection ):
470- template = "JSON_TYPE(%s, %% s) IS NULL"
487+ template = "JSON_TYPE(%s, %s) IS NULL"
471488 if not self .rhs :
472- template = "JSON_TYPE(%s, %% s) IS NOT NULL"
489+ template = "JSON_TYPE(%s, %s) IS NOT NULL"
473490 return HasKeyOrArrayIndex (self .lhs .lhs , self .lhs .key_name ).as_sql (
474491 compiler ,
475492 connection ,
0 commit comments