|
17 | 17 | from django.utils.functional import cached_property |
18 | 18 | from pymongo import ASCENDING, DESCENDING |
19 | 19 |
|
20 | | -from .expressions.builtins import SearchExpression |
| 20 | +from .expressions.builtins import SearchExpression, SearchVector |
21 | 21 | from .query import MongoQuery, wrap_database_errors |
22 | 22 |
|
23 | 23 |
|
@@ -117,29 +117,24 @@ def _prepare_search_expressions_for_pipeline( |
117 | 117 | if sub_expr not in replacements: |
118 | 118 | alias = f"__search_expr.search{next(search_idx)}" |
119 | 119 | replacements[sub_expr] = self._get_replace_expr(sub_expr, searches, alias) |
120 | | - return list(searches.values()) |
121 | 120 |
|
122 | 121 | def _prepare_search_query_for_aggregation_pipeline(self, order_by): |
123 | 122 | replacements = {} |
124 | | - searches = [] |
125 | 123 | annotation_group_idx = itertools.count(start=1) |
126 | 124 | for target, expr in self.query.annotation_select.items(): |
127 | | - expr_searches = self._prepare_search_expressions_for_pipeline( |
| 125 | + self._prepare_search_expressions_for_pipeline( |
128 | 126 | expr, target, annotation_group_idx, replacements |
129 | 127 | ) |
130 | | - searches += expr_searches |
131 | 128 |
|
132 | 129 | for expr, _ in order_by: |
133 | | - expr_searches = self._prepare_search_expressions_for_pipeline( |
| 130 | + self._prepare_search_expressions_for_pipeline( |
134 | 131 | expr, None, annotation_group_idx, replacements |
135 | 132 | ) |
136 | | - searches += expr_searches |
137 | 133 |
|
138 | | - having_group = self._prepare_search_expressions_for_pipeline( |
| 134 | + self._prepare_search_expressions_for_pipeline( |
139 | 135 | self.having, None, annotation_group_idx, replacements |
140 | 136 | ) |
141 | | - searches += having_group |
142 | | - return searches, replacements |
| 137 | + return replacements |
143 | 138 |
|
144 | 139 | def _prepare_annotations_for_aggregation_pipeline(self, order_by): |
145 | 140 | """Prepare annotations for the aggregation pipeline.""" |
@@ -248,22 +243,36 @@ def _build_aggregation_pipeline(self, ids, group): |
248 | 243 | pipeline.append({"$unset": "_id"}) |
249 | 244 | return pipeline |
250 | 245 |
|
251 | | - def _compound_searches_queries(self, searches, search_replacements): |
252 | | - if not searches: |
| 246 | + def _compound_searches_queries(self, search_replacements): |
| 247 | + if not search_replacements: |
253 | 248 | return [] |
254 | | - if len(searches) > 1: |
| 249 | + if len(search_replacements) > 1: |
255 | 250 | raise ValueError("Cannot perform more than one search operation.") |
256 | | - score_function = "searchScore" if "$search" in searches[0] else "vectorSearchScore" |
257 | | - return [searches[0], {"$addFields": {"__search_expr.search1": {"$meta": score_function}}}] |
| 251 | + pipeline = [] |
| 252 | + for search, result_col in search_replacements.items(): |
| 253 | + score_function = ( |
| 254 | + "vectorSearchScore" if isinstance(search, SearchVector) else "searchScore" |
| 255 | + ) |
| 256 | + pipeline.extend( |
| 257 | + [ |
| 258 | + search.as_mql(self, self.connection), |
| 259 | + { |
| 260 | + "$addFields": { |
| 261 | + result_col.as_mql(self, self.connection).removeprefix("$"): { |
| 262 | + "$meta": score_function |
| 263 | + } |
| 264 | + } |
| 265 | + }, |
| 266 | + ] |
| 267 | + ) |
| 268 | + return pipeline |
258 | 269 |
|
259 | 270 | def pre_sql_setup(self, with_col_aliases=False): |
260 | 271 | extra_select, order_by, group_by = super().pre_sql_setup(with_col_aliases=with_col_aliases) |
261 | | - searches, search_replacements = self._prepare_search_query_for_aggregation_pipeline( |
262 | | - order_by |
263 | | - ) |
| 272 | + search_replacements = self._prepare_search_query_for_aggregation_pipeline(order_by) |
264 | 273 | group, group_replacements = self._prepare_annotations_for_aggregation_pipeline(order_by) |
265 | 274 | all_replacements = {**search_replacements, **group_replacements} |
266 | | - self.search_pipeline = self._compound_searches_queries(searches, search_replacements) |
| 275 | + self.search_pipeline = self._compound_searches_queries(search_replacements) |
267 | 276 | # query.group_by is either: |
268 | 277 | # - None: no GROUP BY |
269 | 278 | # - True: group by select fields |
|
0 commit comments