@@ -216,20 +216,18 @@ def compile_json_path_final_key(self, key_transform):
216216# Compile the final key without interpreting ints as array elements.
217217return ".%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.
221221if 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 (
223223compiler ,connection
224224 )
225225lhs_json_path = compile_json_path (lhs_key_transforms )
226226else :
227- lhs ,lhs_params = self .process_lhs (compiler ,connection )
227+ lhs_sql ,lhs_params = self .process_lhs (compiler ,connection )
228228lhs_json_path = "$"
229- sql = template % lhs
230229# Process JSON path from the right-hand side.
231230rhs = self .rhs
232- rhs_params = []
233231if not isinstance (rhs , (list ,tuple )):
234232rhs = [rhs ]
235233for key in rhs :
@@ -240,24 +238,43 @@ def as_sql(self, compiler, connection, template=None):
240238* rhs_key_transforms ,final_key = rhs_key_transforms
241239rhs_json_path = compile_json_path (rhs_key_transforms ,include_root = False )
242240rhs_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.
245245if 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
249259def as_mysql (self ,compiler ,connection ):
250260return 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
254264def 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
262279def as_postgresql (self ,compiler ,connection ):
263280if isinstance (self .rhs ,KeyTransform ):
@@ -269,7 +286,7 @@ def as_postgresql(self, compiler, connection):
269286
270287def as_sqlite (self ,compiler ,connection ):
271288return 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):
467484return "(NOT %s OR %s IS NULL)" % (sql ,lhs ),tuple (params )+ tuple (lhs_params )
468485
469486def as_sqlite (self ,compiler ,connection ):
470- template = "JSON_TYPE(%s, %% s) IS NULL"
487+ template = "JSON_TYPE(%s, %s) IS NULL"
471488if not self .rhs :
472- template = "JSON_TYPE(%s, %% s) IS NOT NULL"
489+ template = "JSON_TYPE(%s, %s) IS NOT NULL"
473490return HasKeyOrArrayIndex (self .lhs .lhs ,self .lhs .key_name ).as_sql (
474491compiler ,
475492connection ,