@@ -216,20 +216,18 @@ def compile_json_path_final_key(self, key_transform):
216
216
# Compile the final key without interpreting ints as array elements.
217
217
return ".%s" % json .dumps (key_transform )
218
218
219
- def as_sql (self , compiler , connection , template = None ):
219
+ def _as_sql_parts (self , compiler , connection ):
220
220
# Process JSON path from the left-hand side.
221
221
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 (
223
223
compiler , connection
224
224
)
225
225
lhs_json_path = compile_json_path (lhs_key_transforms )
226
226
else :
227
- lhs , lhs_params = self .process_lhs (compiler , connection )
227
+ lhs_sql , lhs_params = self .process_lhs (compiler , connection )
228
228
lhs_json_path = "$"
229
- sql = template % lhs
230
229
# Process JSON path from the right-hand side.
231
230
rhs = self .rhs
232
- rhs_params = []
233
231
if not isinstance (rhs , (list , tuple )):
234
232
rhs = [rhs ]
235
233
for key in rhs :
@@ -240,24 +238,43 @@ def as_sql(self, compiler, connection, template=None):
240
238
* rhs_key_transforms , final_key = rhs_key_transforms
241
239
rhs_json_path = compile_json_path (rhs_key_transforms , include_root = False )
242
240
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 ):
244
244
# Add condition for each key.
245
245
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 )
248
258
249
259
def as_mysql (self , compiler , connection ):
250
260
return self .as_sql (
251
- compiler , connection , template = "JSON_CONTAINS_PATH(%s, 'one', %% s)"
261
+ compiler , connection , template = "JSON_CONTAINS_PATH(%s, 'one', %s)"
252
262
)
253
263
254
264
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 )
261
278
262
279
def as_postgresql (self , compiler , connection ):
263
280
if isinstance (self .rhs , KeyTransform ):
@@ -269,7 +286,7 @@ def as_postgresql(self, compiler, connection):
269
286
270
287
def as_sqlite (self , compiler , connection ):
271
288
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"
273
290
)
274
291
275
292
@@ -467,9 +484,9 @@ def as_oracle(self, compiler, connection):
467
484
return "(NOT %s OR %s IS NULL)" % (sql , lhs ), tuple (params ) + tuple (lhs_params )
468
485
469
486
def as_sqlite (self , compiler , connection ):
470
- template = "JSON_TYPE(%s, %% s) IS NULL"
487
+ template = "JSON_TYPE(%s, %s) IS NULL"
471
488
if not self .rhs :
472
- template = "JSON_TYPE(%s, %% s) IS NOT NULL"
489
+ template = "JSON_TYPE(%s, %s) IS NOT NULL"
473
490
return HasKeyOrArrayIndex (self .lhs .lhs , self .lhs .key_name ).as_sql (
474
491
compiler ,
475
492
connection ,
0 commit comments