Skip to content

Commit 07e6ffb

Browse files
committed
fixed match and op conversion tests
1 parent 7ab6b37 commit 07e6ffb

File tree

3 files changed

+33
-47
lines changed

3 files changed

+33
-47
lines changed

django_mongodb_backend/query_conversion/expression_converters.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class BinaryConverter(BaseConverter):
6565
{"$gt": ["$price", 100]}
6666
}
6767
is converted to:
68-
{"$gt": ["price", 100]}
68+
{"price": {"$gt": 100}}
6969
"""
7070

7171
operator: str
@@ -79,6 +79,10 @@ def convert(cls, args):
7979
if cls.operator == "$eq":
8080
return {field_name: value}
8181
return {field_name: {cls.operator: value}}
82+
# If simple getFields are found, still mutate the original args list
83+
for i, arg in enumerate(args):
84+
if cls.is_simple_get_field(arg):
85+
args[i] = "$" + cls.convert_field_name(arg)
8286
return None
8387

8488

@@ -136,6 +140,15 @@ def convert(cls, in_args):
136140
and all(cls.is_simple_value(v) for v in values)
137141
):
138142
return {field_name: {"$in": values}}
143+
# Mutate the original list
144+
for i, arg in enumerate(in_args):
145+
if cls.is_simple_get_field(arg):
146+
in_args[i] = "$" + cls.convert_field_name(arg)
147+
if isinstance(arg, list | tuple | set):
148+
arg[i] = [
149+
"$" + cls.convert_field_name(v) if cls.is_simple_get_field(v) else v
150+
for v in arg
151+
]
139152
return None
140153

141154

tests/expression_converter_/test_match_conversion.py

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -223,24 +223,13 @@ def test_getfield_usage_on_dual_binary_operator(self):
223223
]
224224
}
225225
}
226-
expected = [
227-
{
228-
"$match": {
229-
"$expr": {
230-
"$gt": [
231-
{"$getField": {"input": "$price", "field": "value"}},
232-
{"$getField": {"input": "$discounted_price", "field": "value"}},
233-
]
234-
}
235-
}
236-
}
237-
]
226+
expected = [{"$match": {"$expr": {"$gt": ["$price.value", "$discounted_price.value"]}}}]
238227
self.assertOptimizerEqual(expr, expected)
239228

240229
def test_getfield_usage_on_onesided_binary_operator(self):
241230
expr = {"$expr": {"$gt": [{"$getField": {"input": "$price", "field": "value"}}, 100]}}
242231
# This should create a proper match condition with no $expr
243-
expected = {"price.value": {"$gt": 100}}
232+
expected = [{"$match": {"price.value": {"$gt": 100}}}]
244233
self.assertOptimizerEqual(expr, expected)
245234

246235
def test_nested_getfield_usage_on_onesided_binary(self):
@@ -257,25 +246,5 @@ def test_nested_getfield_usage_on_onesided_binary(self):
257246
]
258247
}
259248
}
260-
expected = {"item.price.value": {"$gt": 100}}
249+
expected = [{"$match": {"item.price.value": {"$gt": 100}}}]
261250
self.assertOptimizerEqual(expr, expected)
262-
263-
def test_getfield_with_non_constant_field(self):
264-
expr = {"$expr": {"$gt": [{"$getField": {"input": "$price", "field": "$field_name"}}, 100]}}
265-
self.assertOptimizerEqual(expr, expr)
266-
267-
def test_getfield_with_object_non_simple_input(self):
268-
expr = {
269-
"$expr": {
270-
"$gt": [
271-
{
272-
"$getField": {
273-
"input": {"$literal": "$item"},
274-
"field": "price",
275-
}
276-
},
277-
100,
278-
]
279-
}
280-
}
281-
self.assertOptimizerEqual(expr, expr)

tests/expression_converter_/test_op_expressions.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ def _test_conversion_various_types(self, conversion_test):
3333
with self.subTest(_type=_type, val=val):
3434
conversion_test(val)
3535

36-
def _test_conversion_getfield(self, logical_op):
37-
expr = {logical_op: [{"$getField": {"input": "$item", "field": "age"}}, 10]}
36+
def _test_conversion_getfield(self, logical_op, value=10):
37+
expr = {logical_op: [{"$getField": {"input": "$item", "field": "age"}}, value]}
3838
self.assertConversionEqual(
39-
expr, {"item.age": 10} if logical_op == "eq" else {"item.age": {logical_op: 10}}
39+
expr, {"item.age": value} if logical_op == "$eq" else {"item.age": {logical_op: value}}
4040
)
4141

42-
def _test_conversion_nested_getfield(self, logical_op):
42+
def _test_conversion_nested_getfield(self, logical_op, value=10):
4343
expr = {
4444
logical_op: [
4545
{
@@ -48,14 +48,14 @@ def _test_conversion_nested_getfield(self, logical_op):
4848
"field": "age",
4949
}
5050
},
51-
10,
51+
value,
5252
]
5353
}
5454
self.assertConversionEqual(
5555
expr,
56-
{"item.shel_life.age": 10}
57-
if logical_op == "eq"
58-
else {"item.shelf_life.age": {logical_op: 10}},
56+
{"item.shelf_life.age": value}
57+
if logical_op == "$eq"
58+
else {"item.shelf_life.age": {logical_op: value}},
5959
)
6060

6161
def _test_conversion_dual_getfield_ineligible(self, logical_op):
@@ -75,7 +75,9 @@ def _test_conversion_dual_getfield_ineligible(self, logical_op):
7575
},
7676
]
7777
}
78-
self.assertNotOptimizable(expr)
78+
# Not optimized but should still convert getFields
79+
expected = {logical_op: ["$root.age", "$value.age"]}
80+
self.assertConversionEqual(expr, expected)
7981

8082

8183
class ExpressionTests(ConversionTestCase):
@@ -139,10 +141,10 @@ def test_conversion_various_types(self):
139141
self._test_conversion_valid_type(val)
140142

141143
def test_conversion_getfield(self):
142-
self._test_conversion_getfield("$in")
144+
self._test_conversion_getfield("$in", [10])
143145

144146
def test_conversion_nested_getfield(self):
145-
self._test_conversion_nested_getfield("$in")
147+
self._test_conversion_nested_getfield("$in", [10])
146148

147149
def test_conversion_dual_getfield_ineligible(self):
148150
expr = {
@@ -163,7 +165,9 @@ def test_conversion_dual_getfield_ineligible(self):
163165
],
164166
]
165167
}
166-
self.assertNotOptimizable(expr)
168+
# Not optimized but should still convert getFields
169+
expected = {"$in": ["$root.age", ["$value.age"]]}
170+
self.assertConversionEqual(expr, expected)
167171

168172

169173
class LogicalTests(ConversionTestCase):

0 commit comments

Comments
 (0)