Skip to content

Commit 9dd5f08

Browse files
WaVEVtimgraham
authored andcommitted
fix collisions with projected columns and order by columns
1 parent 892f429 commit 9dd5f08

File tree

2 files changed

+12
-17
lines changed

2 files changed

+12
-17
lines changed

django_mongodb/compiler.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -358,9 +358,7 @@ def build_query(self, columns=None):
358358
if columns is None:
359359
extra_fields += ordering_fields
360360
if extra_fields:
361-
query.extra_fields = {
362-
field_name: expr.as_mql(self, self.connection) for field_name, expr in extra_fields
363-
}
361+
query.extra_fields = self.get_project_fields(extra_fields, force_expression=True)
364362
where = self.get_where()
365363
try:
366364
expr = where.as_mql(self, self.connection) if where else {}
@@ -431,16 +429,18 @@ def _get_aggregate_expressions(self, expr):
431429
elif hasattr(expr, "get_source_expressions"):
432430
stack.extend(expr.get_source_expressions())
433431

434-
def get_project_fields(self, columns=None, ordering=None):
432+
def get_project_fields(self, columns=None, ordering=None, force_expression=False):
433+
if not columns:
434+
return {}
435435
fields = defaultdict(dict)
436-
for name, expr in columns or []:
436+
for name, expr in columns + (ordering or ()):
437437
collection = expr.alias if isinstance(expr, Col) else None
438438
try:
439439
fields[collection][name] = (
440440
1
441441
# For brevity/simplicity, project {"field_name": 1}
442442
# instead of {"field_name": "$field_name"}.
443-
if isinstance(expr, Col) and name == expr.target.column
443+
if isinstance(expr, Col) and name == expr.target.column and not force_expression
444444
else expr.as_mql(self, self.connection)
445445
)
446446
except EmptyResultSet:
@@ -451,9 +451,6 @@ def get_project_fields(self, columns=None, ordering=None):
451451
# should appear in the top-level of the fields dict.
452452
fields.update(fields.pop(None, {}))
453453
fields.update(fields.pop(self.collection_name, {}))
454-
# Add order_by() fields.
455-
if fields and ordering:
456-
fields.update({alias: expr.as_mql(self, self.connection) for alias, expr in ordering})
457454
# Convert defaultdict to dict so it doesn't appear as
458455
# "defaultdict(<CLASS 'dict'>, ..." in query logging.
459456
return dict(fields)
@@ -466,28 +463,28 @@ def _get_ordering(self):
466463
- A tuple of ('field_name': Expression, ...) for expressions that need
467464
to be added to extra_fields.
468465
"""
469-
fields = {}
466+
fields = []
470467
sort_ordering = SON()
471-
extra_fields = {}
468+
extra_fields = []
472469
idx = itertools.count(start=1)
473470
for order in self.order_by_objs or []:
474471
if isinstance(order.expression, Col):
475472
field_name = order.expression.as_mql(self, self.connection).removeprefix("$")
476-
fields[field_name] = order.expression
473+
fields.append((order.expression.target.column, order.expression))
477474
elif isinstance(order.expression, Ref):
478475
field_name = order.expression.as_mql(self, self.connection).removeprefix("$")
479476
else:
480477
field_name = f"__order{next(idx)}"
481-
fields[field_name] = order.expression
478+
fields.append((field_name, order.expression))
482479
# If the expression is ordered by NULLS FIRST or NULLS LAST,
483480
# add a field for sorting that's 1 if null or 0 if not.
484481
if order.nulls_first or order.nulls_last:
485482
null_fieldname = f"__order{next(idx)}"
486483
condition = When(IsNull(order.expression, True), then=Value(1))
487-
extra_fields[null_fieldname] = Case(condition, default=Value(0))
484+
extra_fields.append((null_fieldname, Case(condition, default=Value(0))))
488485
sort_ordering[null_fieldname] = DESCENDING if order.nulls_first else ASCENDING
489486
sort_ordering[field_name] = DESCENDING if order.descending else ASCENDING
490-
return tuple(fields.items()), sort_ordering, tuple(extra_fields.items())
487+
return tuple(fields), sort_ordering, tuple(extra_fields)
491488

492489
def get_where(self):
493490
return self.where

django_mongodb/features.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
6161
"aggregation.tests.AggregateTestCase.test_reverse_fkey_annotate",
6262
"aggregation_regress.tests.AggregationTests.test_annotation_disjunction",
6363
"aggregation_regress.tests.AggregationTests.test_decimal_aggregate_annotation_filter",
64-
# Invalid $project :: caused by :: Path collision at aggregation_regress_publisher.name
65-
"aggregation_regress.tests.AggregationTests.test_values_list_annotation_args_ordering",
6664
# QuerySet.extra(select=...) should raise NotSupportedError instead of:
6765
# 'RawSQL' object has no attribute 'as_mql'.
6866
"aggregation_regress.tests.AggregationTests.test_annotate_with_extra",

0 commit comments

Comments
 (0)