Skip to content

Commit 1abc33a

Browse files
committed
add encryption-compatible aggregation wrap
1 parent b012f3b commit 1abc33a

File tree

2 files changed

+42
-24
lines changed

2 files changed

+42
-24
lines changed

django_mongodb_backend/base.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,14 @@ def get_database(self):
244244

245245
@cached_property
246246
def client_encryption(self):
247-
auto_encryption_opts = self.connection._options.auto_encryption_opts
248-
return ClientEncryption(
249-
auto_encryption_opts._kms_providers,
250-
auto_encryption_opts._key_vault_namespace,
251-
self.connection,
252-
self.connection.codec_options,
253-
)
247+
if auto_encryption_opts := self.connection._options.auto_encryption_opts:
248+
return ClientEncryption(
249+
auto_encryption_opts._kms_providers,
250+
auto_encryption_opts._key_vault_namespace,
251+
self.connection,
252+
self.connection.codec_options,
253+
)
254+
return None
254255

255256
@cached_property
256257
def database(self):

django_mongodb_backend/query.py

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,24 +93,41 @@ def get_pipeline(self):
9393
if self.aggregation_pipeline:
9494
pipeline.extend(self.aggregation_pipeline)
9595
if self.needs_wrap_aggregation:
96-
# Add the aggregation stage for queries without a GROUP BY.
97-
# e.g. SQL equivalent of SELECT avg(col) FROM table
98-
pipeline.extend(
99-
[
100-
# Workaround for https://jira.mongodb.org/browse/SERVER-114196:
101-
# $$NOW becomes unavailable after $unionWith, so it must be
102-
# stored beforehand to ensure it remains accessible later
103-
# in the pipeline.
104-
{"$addFields": {"__now": "$$NOW"}},
105-
# Add an empty extra document to handle default values on
106-
# empty results.
107-
{"$unionWith": {"pipeline": [{"$documents": [{}]}]}},
108-
# Limiting to one document ensures the original result
109-
# takes precedence when present, otherwise the injected
110-
# empty document is used.
111-
{"$limit": 1},
96+
if self.compiler.connection.client_encryption:
97+
pipeline = [
98+
{"$collStats": {}},
99+
{
100+
"$lookup": {
101+
"from": self.compiler.collection_name,
102+
"as": "wrapped",
103+
"pipeline": pipeline,
104+
}
105+
},
106+
{
107+
"$replaceWith": {
108+
"$cond": [{"$eq": ["$wrapped", []]}, {}, {"$first": "$wrapped"}]
109+
}
110+
},
112111
]
113-
)
112+
else:
113+
# Add the aggregation stage for queries without a GROUP BY.
114+
# e.g. SQL equivalent of SELECT avg(col) FROM table
115+
pipeline.extend(
116+
[
117+
# Workaround for https://jira.mongodb.org/browse/SERVER-114196:
118+
# $$NOW becomes unavailable after $unionWith, so it
119+
# must be stored beforehand to ensure it remains
120+
# accessible later in the pipeline.
121+
{"$addFields": {"__now": "$$NOW"}},
122+
# Add an empty extra document to handle default values
123+
# on empty results.
124+
{"$unionWith": {"pipeline": [{"$documents": [{}]}]}},
125+
# Limiting to one document ensures the original result
126+
# takes precedence when present, otherwise the injected
127+
# empty document is used.
128+
{"$limit": 1},
129+
]
130+
)
114131
if self.project_fields:
115132
pipeline.append({"$project": self.project_fields})
116133
if self.combinator_pipeline:

0 commit comments

Comments
 (0)