|
12 | 12 | from django.db.models import lookups |
13 | 13 |
|
14 | 14 | if VERSION >= (3, 1): |
15 | | - from django.db.models.fields.json import KeyTransform, KeyTransformIn, KeyTransformExact |
| 15 | + from django.db.models.fields.json import ( |
| 16 | + KeyTransform, KeyTransformIn, KeyTransformExact, |
| 17 | + HasKeyLookup, compile_json_path) |
16 | 18 |
|
17 | 19 | DJANGO3 = VERSION[0] >= 3 |
18 | 20 |
|
@@ -134,11 +136,42 @@ def json_KeyTransformIn(self, compiler, connection): |
134 | 136 |
|
135 | 137 | return (lhs + ' IN ' + rhs, unquote_json_rhs(rhs_params)) |
136 | 138 |
|
| 139 | +def json_HasKeyLookup(self, compiler, connection): |
| 140 | + # Process JSON path from the left-hand side. |
| 141 | + if isinstance(self.lhs, KeyTransform): |
| 142 | + lhs, _, lhs_key_transforms = self.lhs.preprocess_lhs(compiler, connection) |
| 143 | + lhs_json_path = compile_json_path(lhs_key_transforms) |
| 144 | + else: |
| 145 | + lhs, _ = self.process_lhs(compiler, connection) |
| 146 | + lhs_json_path = '$' |
| 147 | + sql = lhs + ' IN (SELECT ' + lhs + ' FROM ' + self.lhs.output_field.model._meta.db_table + \ |
| 148 | + ' CROSS APPLY OPENJSON(' + lhs + ') WITH ( [json_path_value] char(1) \'%s\') WHERE [json_path_value] IS NOT NULL)' |
| 149 | + # Process JSON path from the right-hand side. |
| 150 | + rhs = self.rhs |
| 151 | + rhs_params = [] |
| 152 | + if not isinstance(rhs, (list, tuple)): |
| 153 | + rhs = [rhs] |
| 154 | + for key in rhs: |
| 155 | + if isinstance(key, KeyTransform): |
| 156 | + *_, rhs_key_transforms = key.preprocess_lhs(compiler, connection) |
| 157 | + else: |
| 158 | + rhs_key_transforms = [key] |
| 159 | + rhs_params.append('%s%s' % ( |
| 160 | + lhs_json_path, |
| 161 | + compile_json_path(rhs_key_transforms, include_root=False), |
| 162 | + )) |
| 163 | + # Add condition for each key. |
| 164 | + if self.logical_operator: |
| 165 | + sql = '(%s)' % self.logical_operator.join([sql] * len(rhs_params)) |
| 166 | + |
| 167 | + return sql % tuple(rhs_params), [] |
| 168 | + |
137 | 169 | ATan2.as_microsoft = sqlserver_atan2 |
138 | 170 | In.split_parameter_list_as_sql = split_parameter_list_as_sql |
139 | 171 | if VERSION >= (3, 1): |
140 | 172 | KeyTransformIn.as_microsoft = json_KeyTransformIn |
141 | 173 | KeyTransformExact.process_rhs = json_KeyTransformExact_process_rhs |
| 174 | + HasKeyLookup.as_microsoft = json_HasKeyLookup |
142 | 175 | Ln.as_microsoft = sqlserver_ln |
143 | 176 | Log.as_microsoft = sqlserver_log |
144 | 177 | Mod.as_microsoft = sqlserver_mod |
|
0 commit comments