Skip to content

Commit b9bfcd8

Browse files
committed
add support for CombinedExpression
1 parent 0ad109a commit b9bfcd8

File tree

4 files changed

+40
-10
lines changed

4 files changed

+40
-10
lines changed

.github/workflows/test-python.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ jobs:
7676
datetimes
7777
db_functions
7878
empty
79+
expressions.tests.ExpressionOperatorTests
7980
expressions.tests.NegatedExpressionTests
8081
defer
8182
defer_regress

django_mongodb/expressions.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
1-
from django.db.models.expressions import Col, ExpressionWrapper, NegatedExpression, Value
1+
from django.db.models.expressions import (
2+
Col,
3+
CombinedExpression,
4+
ExpressionWrapper,
5+
NegatedExpression,
6+
Value,
7+
)
28

39

410
def col(self, compiler, connection): # noqa: ARG001
511
return f"${self.target.column}"
612

713

14+
def combined_expression(self, compiler, connection):
15+
expressions = [
16+
self.lhs.as_mql(compiler, connection),
17+
self.rhs.as_mql(compiler, connection),
18+
]
19+
return connection.ops.combine_expression(self.connector, expressions)
20+
21+
822
def expression_wrapper(self, compiler, connection):
923
return self.expression.as_mql(compiler, connection)
1024

@@ -19,6 +33,7 @@ def value(self, compiler, connection): # noqa: ARG001
1933

2034
def register_expressions():
2135
Col.as_mql = col
36+
CombinedExpression.as_mql = combined_expression
2237
ExpressionWrapper.as_mql = expression_wrapper
2338
NegatedExpression.as_mql = negated_expression
2439
Value.as_mql = value

django_mongodb/features.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,18 +176,11 @@ class DatabaseFeatures(BaseDatabaseFeatures):
176176
"db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_subquery_with_parameters",
177177
"lookup.tests.LookupQueryingTests.test_filter_subquery_lhs",
178178
# Invalid $project :: caused by :: Unknown expression $count,
179+
"annotations.tests.NonAggregateAnnotationTestCase.test_combined_expression_annotation_with_aggregation",
180+
"annotations.tests.NonAggregateAnnotationTestCase.test_combined_f_expression_annotation_with_aggregation",
179181
"annotations.tests.NonAggregateAnnotationTestCase.test_full_expression_annotation_with_aggregation",
180182
"annotations.tests.NonAggregateAnnotationTestCase.test_grouping_by_q_expression_annotation",
181183
"annotations.tests.NonAggregateAnnotationTestCase.test_q_expression_annotation_with_aggregation",
182-
# CombinedExpression not implemented.
183-
"annotations.tests.NonAggregateAnnotationTestCase.test_combined_annotation_commutative",
184-
"annotations.tests.NonAggregateAnnotationTestCase.test_combined_expression_annotation_with_aggregation",
185-
"annotations.tests.NonAggregateAnnotationTestCase.test_combined_f_expression_annotation_with_aggregation",
186-
"annotations.tests.NonAggregateAnnotationTestCase.test_decimal_annotation",
187-
"annotations.tests.NonAggregateAnnotationTestCase.test_defer_annotation",
188-
"annotations.tests.NonAggregateAnnotationTestCase.test_filter_decimal_annotation",
189-
"annotations.tests.NonAggregateAnnotationTestCase.test_mixed_type_annotation_numbers",
190-
"annotations.tests.NonAggregateAnnotationTestCase.test_values_annotation",
191184
# Func not implemented.
192185
"annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions",
193186
"annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions_can_ref_other_functions",

django_mongodb/operations.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,24 @@
44
from bson.decimal128 import Decimal128
55
from django.conf import settings
66
from django.db.backends.base.operations import BaseDatabaseOperations
7+
from django.db.models.expressions import Combinable
78
from django.utils import timezone
89
from django.utils.regex_helper import _lazy_re_compile
910

1011

1112
class DatabaseOperations(BaseDatabaseOperations):
1213
compiler_module = "django_mongodb.compiler"
14+
combine_operators = {
15+
Combinable.ADD: "add",
16+
Combinable.SUB: "subtract",
17+
Combinable.MUL: "multiply",
18+
Combinable.DIV: "divide",
19+
Combinable.POW: "pow",
20+
Combinable.MOD: "mod",
21+
Combinable.BITAND: "bitAnd",
22+
Combinable.BITOR: "bitOr",
23+
Combinable.BITXOR: "bitXor",
24+
}
1325

1426
def adapt_datefield_value(self, value):
1527
"""Store DateField as datetime."""
@@ -86,6 +98,15 @@ def convert_uuidfield_value(self, value, expression, connection):
8698
value = uuid.UUID(value)
8799
return value
88100

101+
def combine_expression(self, connector, sub_expressions):
102+
lhs, rhs = sub_expressions
103+
if connector == Combinable.BITLEFTSHIFT:
104+
return {"$multiply": [lhs, {"$pow": [2, rhs]}]}
105+
if connector == Combinable.BITRIGHTSHIFT:
106+
return {"$floor": {"$divide": [lhs, {"$pow": [2, rhs]}]}}
107+
operator = self.combine_operators[connector]
108+
return {f"${operator}": sub_expressions}
109+
89110
def prep_for_like_query(self, x):
90111
# Override value escaping for LIKE queries.
91112
return str(x)

0 commit comments

Comments
 (0)