Skip to content

Commit 7e6f435

Browse files
committed
edits
1 parent 560e596 commit 7e6f435

File tree

5 files changed

+40
-37
lines changed

5 files changed

+40
-37
lines changed

django_mongodb/compiler.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ class SQLCompiler(compiler.SQLCompiler):
3131
def __init__(self, *args, **kwargs):
3232
super().__init__(*args, **kwargs)
3333
self.aggregation_pipeline = None
34-
# Dictionary mapping parent variable names to their corresponding indices.
35-
self.column_mapping = {}
34+
# Map columns to their subquery indices.
35+
self.column_indices = {}
3636
# A list of OrderBy objects for this query.
3737
self.order_by_objs = None
3838
self.subqueries = []
@@ -160,14 +160,12 @@ def _prepare_annotations_for_aggregation_pipeline(self, order_by):
160160
return group, replacements
161161

162162
def _get_group_expressions(self, order_by):
163-
# The query.group_by is either None (no GROUP BY at all), True
164-
# (group by select fields), or a list of expressions to be added
165-
# to the group by.
166163
if self.query.group_by is None:
167164
return []
168165
seen = set()
169166
expressions = set()
170167
if self.query.group_by is not True:
168+
# If group_by isn't True, then it's a list of expressions.
171169
for expr in self.query.group_by:
172170
if not hasattr(expr, "as_sql"):
173171
expr = self.query.resolve_ref(expr)
@@ -257,10 +255,10 @@ def pre_sql_setup(self, with_col_aliases=False):
257255
having = self.having.replace_expressions(all_replacements).as_mql(
258256
self, self.connection
259257
)
260-
# Add having subqueries.
258+
# Add HAVING subqueries.
261259
for query in self.subqueries or ():
262260
pipeline.extend(query.get_pipeline())
263-
# Clean added subqueries.
261+
# Remove the added subqueries.
264262
self.subqueries = []
265263
pipeline.append({"$match": {"$expr": having}})
266264
self.aggregation_pipeline = pipeline
@@ -685,7 +683,9 @@ def execute_sql(self, result_type=MULTI):
685683
def check_query(self):
686684
super().check_query()
687685
if not self.single_alias:
688-
raise NotSupportedError("Cannot use QuerySet.delete() when a subquery is required.")
686+
raise NotSupportedError(
687+
"Cannot use QuerySet.delete() when querying across multiple collections on MongoDB."
688+
)
689689

690690
def get_where(self):
691691
return self.query.where

django_mongodb/expressions.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,17 @@ def case(self, compiler, connection):
5151

5252

5353
def col(self, compiler, connection): # noqa: ARG001
54-
# If the column is part of a subquery and belongs to one of the parent queries,
55-
# it will be stored for reference using $let in a $lookup stage.
54+
# If the column is part of a subquery and belongs to one of the parent
55+
# queries, it will be stored for reference using $let in a $lookup stage.
5656
if (
5757
self.alias not in compiler.query.alias_refcount
5858
or compiler.query.alias_refcount[self.alias] == 0
5959
):
6060
try:
61-
index = compiler.column_mapping[self]
61+
index = compiler.column_indices[self]
6262
except KeyError:
63-
index = len(compiler.column_mapping)
64-
compiler.column_mapping[self] = index
63+
index = len(compiler.column_indices)
64+
compiler.column_indices[self] = index
6565
return f"$${compiler.PARENT_FIELD_TEMPLATE.format(index)}"
6666
# Add the column's collection's alias for columns in joined collections.
6767
prefix = f"{self.alias}." if self.alias != compiler.collection_name else ""
@@ -106,18 +106,19 @@ def query(self, compiler, connection, lookup_name=None):
106106
from_table = next(
107107
e.table_name for alias, e in self.alias_map.items() if self.alias_refcount[alias]
108108
)
109-
# To perform a subquery, a $lookup stage is added.
110-
# This stage encapsulates the entire subquery pipeline within a $lookup operation.
111-
# The "let" clause defines the variables needed to bridge the main collection with the subquery.
109+
# To perform a subquery, a $lookup stage that escapsulates the entire
110+
# subquery pipeline is added. The "let" clause defines the variables
111+
# needed to bridge the main collection with the subquery.
112112
subquery.subquery_lookup = {
113113
"as": table_output,
114114
"from": from_table,
115115
"let": {
116116
compiler.PARENT_FIELD_TEMPLATE.format(i): col.as_mql(compiler, connection)
117-
for col, i in subquery_compiler.column_mapping.items()
117+
for col, i in subquery_compiler.column_indices.items()
118118
},
119119
}
120-
# The result must be a list of values. The output is compressed with an aggregation pipeline.
120+
# The result must be a list of values. The output is compressed with an
121+
# aggregation pipeline.
121122
if lookup_name in ("in", "range"):
122123
if subquery.aggregation_pipeline is None:
123124
subquery.aggregation_pipeline = []
@@ -154,7 +155,7 @@ def query(self, compiler, connection, lookup_name=None):
154155
},
155156
]
156157
)
157-
# Erase all the projection given that we already project the required value.
158+
# Erase project_fields since the required value is projected above.
158159
subquery.project_fields = None
159160
compiler.subqueries.append(subquery)
160161
return f"${table_output}.{field_name}"

django_mongodb/features.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,17 @@ class DatabaseFeatures(BaseDatabaseFeatures):
9292
"schema.tests.SchemaTests.test_composed_constraint_with_fk",
9393
"schema.tests.SchemaTests.test_remove_ignored_unique_constraint_not_create_fk_index",
9494
"schema.tests.SchemaTests.test_unique_constraint",
95-
# Handle column default value.
96-
# https://github.com/mongodb-labs/django-mongodb/issues/155
95+
# Column default values aren't handled when a field raises
96+
# EmptyResultSet: https://github.com/mongodb-labs/django-mongodb/issues/155
9797
"annotations.tests.NonAggregateAnnotationTestCase.test_empty_queryset_annotation",
9898
"db_functions.comparison.test_coalesce.CoalesceTests.test_empty_queryset",
99-
# Union as subquery is not mapping the parent parameter and collections.
99+
# Union as subquery is not mapping the parent parameter and collections:
100100
# https://github.com/mongodb-labs/django-mongodb/issues/156
101101
"queries.test_qs_combinators.QuerySetSetOperationTests.test_union_in_subquery_related_outerref",
102102
"queries.test_qs_combinators.QuerySetSetOperationTests.test_union_in_subquery",
103103
"queries.test_qs_combinators.QuerySetSetOperationTests.test_union_in_with_ordering",
104-
# ObjectId type mismatch in a subquery (casted as string).
105-
# TODO: Create a ticket.
104+
# ObjectId type mismatch in a subquery:
105+
# https://github.com/mongodb-labs/django-mongodb/issues/161
106106
"queries.tests.RelatedLookupTypeTests.test_values_queryset_lookup",
107107
"queries.tests.ValuesSubqueryTests.test_values_in_subquery",
108108
}
@@ -218,9 +218,9 @@ def django_test_expected_failures(self):
218218
},
219219
"Test assumes integer primary key.": {
220220
"db_functions.comparison.test_cast.CastTests.test_cast_to_integer_foreign_key",
221+
"expressions.tests.BasicExpressionsTests.test_nested_subquery_outer_ref_with_autofield",
221222
"model_fields.test_foreignkey.ForeignKeyTests.test_to_python",
222223
"queries.test_qs_combinators.QuerySetSetOperationTests.test_order_raises_on_non_selected_column",
223-
"expressions.tests.BasicExpressionsTests.test_nested_subquery_outer_ref_with_autofield",
224224
},
225225
"Cannot use QuerySet.delete() when querying across multiple collections on MongoDB.": {
226226
"delete.tests.FastDeleteTests.test_fast_delete_aggregation",
@@ -233,6 +233,16 @@ def django_test_expected_failures(self):
233233
"delete_regress.tests.Ticket19102Tests.test_ticket_19102_select_related",
234234
"one_to_one.tests.OneToOneTests.test_o2o_primary_key_delete",
235235
},
236+
"Cannot use QuerySet.delete() when a subquery is required.": {
237+
"delete_regress.tests.DeleteTests.test_self_reference_with_through_m2m_at_second_level",
238+
"many_to_many.tests.ManyToManyTests.test_assign",
239+
"many_to_many.tests.ManyToManyTests.test_assign_ids",
240+
"many_to_many.tests.ManyToManyTests.test_clear",
241+
"many_to_many.tests.ManyToManyTests.test_remove",
242+
"many_to_many.tests.ManyToManyTests.test_reverse_assign_with_queryset",
243+
"many_to_many.tests.ManyToManyTests.test_set",
244+
"many_to_many.tests.ManyToManyTests.test_set_existing_different_type",
245+
},
236246
"Cannot use QuerySet.update() when querying across multiple collections on MongoDB.": {
237247
"expressions.tests.BasicExpressionsTests.test_filter_with_join",
238248
"queries.tests.Queries4Tests.test_ticket7095",
@@ -337,16 +347,6 @@ def django_test_expected_failures(self):
337347
"schema.tests.SchemaTests.test_rename_column_renames_deferred_sql_references",
338348
"schema.tests.SchemaTests.test_rename_table_renames_deferred_sql_references",
339349
},
340-
"Cannot use QuerySet.delete() when a subquery is required.": {
341-
"delete_regress.tests.DeleteTests.test_self_reference_with_through_m2m_at_second_level",
342-
"many_to_many.tests.ManyToManyTests.test_assign",
343-
"many_to_many.tests.ManyToManyTests.test_assign_ids",
344-
"many_to_many.tests.ManyToManyTests.test_clear",
345-
"many_to_many.tests.ManyToManyTests.test_remove",
346-
"many_to_many.tests.ManyToManyTests.test_reverse_assign_with_queryset",
347-
"many_to_many.tests.ManyToManyTests.test_set",
348-
"many_to_many.tests.ManyToManyTests.test_set_existing_different_type",
349-
},
350350
"Test executes raw SQL.": {
351351
"aggregation.tests.AggregateTestCase.test_coalesced_empty_result_set",
352352
"aggregation_regress.tests.AggregationTests.test_annotate_with_extra",

django_mongodb/query.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ def __init__(self, compiler):
5656
self.aggregation_pipeline = compiler.aggregation_pipeline
5757
self.extra_fields = None
5858
self.combinator_pipeline = None
59-
# Stage that encapsulates the pipeline for performing a nested subquery within a $lookup.
59+
# $lookup stage that encapsulates the pipeline for performing a nested
60+
# subquery.
6061
self.subquery_lookup = None
6162

6263
def __repr__(self):

django_mongodb/query_utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ def process_rhs(node, compiler, connection):
3434
value = rhs.as_mql(compiler, connection)
3535
else:
3636
_, value = node.process_rhs(compiler, connection)
37+
lookup_name = node.lookup_name
3738
# Undo Lookup.get_db_prep_lookup() putting params in a list.
38-
if node.lookup_name not in ("in", "range"):
39+
if lookup_name not in ("in", "range"):
3940
value = value[0]
4041
if hasattr(node, "prep_lookup_value_mongo"):
4142
value = node.prep_lookup_value_mongo(value)

0 commit comments

Comments
 (0)