From ae97353d07a0cf2f8da35ee0cc7be4cace3d3599 Mon Sep 17 00:00:00 2001 From: Lynne Wang Date: Mon, 15 Dec 2025 14:11:15 -0500 Subject: [PATCH] SERVER-115431 Return a vector of LiteParsedDocumentSource from getExpandedPipeline() (#45220) GitOrigin-RevId: 89b63f098ff759bcdff0172819ea8c6620210f30 --- .../host/document_source_extension.h | 12 ++-- .../host/document_source_extension_test.cpp | 58 +++++++++---------- .../db/extension/host/load_extension_test.cpp | 10 +--- .../host/load_native_vector_search_test.cpp | 6 +- src/mongo/db/pipeline/lite_parsed_pipeline.h | 6 +- 5 files changed, 43 insertions(+), 49 deletions(-) diff --git a/src/mongo/db/extension/host/document_source_extension.h b/src/mongo/db/extension/host/document_source_extension.h index c572a66e0ca..72ac1bd798c 100644 --- a/src/mongo/db/extension/host/document_source_extension.h +++ b/src/mongo/db/extension/host/document_source_extension.h @@ -83,11 +83,13 @@ public: _nss(nss), _options(options), _expanded([&] { - auto expanded = expand(); + auto expandedList = expand(); tassert(10905600, "LiteParsedExpandable must not have an empty expanded pipeline", - !expanded.empty()); - return expanded; + !expandedList.empty()); + + return StageSpecs(std::make_move_iterator(expandedList.begin()), + std::make_move_iterator(expandedList.end())); }()) {} std::unique_ptr getStageParams() const override { @@ -97,7 +99,7 @@ public: /** * Return the pre-computed expanded pipeline. */ - const LiteParsedList& getExpandedPipeline() const { + const StageSpecs& getExpandedPipeline() const { return _expanded; } @@ -161,7 +163,7 @@ public: const AggStageParseNodeHandle _parseNode; const NamespaceString _nss; const LiteParserOptions _options; - const LiteParsedList _expanded; + const StageSpecs _expanded; }; /** diff --git a/src/mongo/db/extension/host/document_source_extension_test.cpp b/src/mongo/db/extension/host/document_source_extension_test.cpp index ccb61203c3b..16c1a527a73 100644 --- a/src/mongo/db/extension/host/document_source_extension_test.cpp +++ b/src/mongo/db/extension/host/document_source_extension_test.cpp @@ -145,7 +145,7 @@ TEST_F(DocumentSourceExtensionTest, ExpandToExtAst) { // Expanded pipeline contains LiteParsedExpanded. auto* first = - dynamic_cast(expanded.front().get()); + dynamic_cast(expanded[0].get()); ASSERT_TRUE(first != nullptr); ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kTransformName)); } @@ -164,7 +164,7 @@ TEST_F(DocumentSourceExtensionTest, ExpandToExtParse) { // Expanded pipeline contains LiteParsedExpanded. auto* first = - dynamic_cast(expanded.front().get()); + dynamic_cast(expanded[0].get()); ASSERT_TRUE(first != nullptr); ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kTransformName)); } @@ -183,13 +183,13 @@ TEST_F(DocumentSourceExtensionTest, ExpandToHostParse) { ASSERT_EQUALS(expanded.size(), 1); // Expanded pipeline contains LiteParsedDocumentSource. - auto* lpds = dynamic_cast(expanded.front().get()); + auto* lpds = dynamic_cast(expanded[0].get()); ASSERT_TRUE(lpds != nullptr); ASSERT_EQ(lpds->getParseTimeName(), std::string(DocumentSourceMatch::kStageName)); // It is not an instance of LiteParsedExpanded. auto* notExpanded = - dynamic_cast(expanded.front().get()); + dynamic_cast(expanded[0].get()); ASSERT_TRUE(notExpanded == nullptr); } @@ -204,24 +204,20 @@ TEST_F(DocumentSourceExtensionTest, ExpandToMixed) { const auto& expanded = lp.getExpandedPipeline(); ASSERT_EQUALS(expanded.size(), 4); - const auto it0 = expanded.begin(); - const auto it1 = std::next(expanded.begin(), 1); - const auto it2 = std::next(expanded.begin(), 2); - const auto it3 = std::next(expanded.begin(), 3); - - auto* first = dynamic_cast(it0->get()); + auto* first = + dynamic_cast(expanded[0].get()); ASSERT_TRUE(first != nullptr); - auto* second = dynamic_cast(it1->get()); + auto* second = + dynamic_cast(expanded[1].get()); ASSERT_TRUE(second != nullptr); - auto* third = dynamic_cast(it2->get()); + // This one is NOT LiteParsedExpanded. + auto* third = expanded[2].get(); ASSERT_TRUE(third != nullptr); - auto* notExpanded = - dynamic_cast(it2->get()); - ASSERT_TRUE(notExpanded == nullptr); + ASSERT_TRUE(dynamic_cast(third) == nullptr); - auto* fourth = dynamic_cast(it3->get()); + auto* fourth = expanded[3].get(); ASSERT_TRUE(fourth != nullptr); ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kTransformName)); @@ -296,7 +292,7 @@ TEST_F(DocumentSourceExtensionTest, ExpandToHostAst) { ASSERT_EQUALS(expanded.size(), 1); // Expanded pipeline contains LiteParsedDocumentSource. - auto* lpds = dynamic_cast(expanded.front().get()); + auto* lpds = dynamic_cast(expanded[0].get()); ASSERT_TRUE(lpds != nullptr); ASSERT_EQ(lpds->getParseTimeName(), std::string(DocumentSourceInternalSearchIdLookUp::kStageName)); @@ -328,24 +324,23 @@ TEST_F(DocumentSourceExtensionTest, ExpandRecursesMultipleLevels) { const auto& expanded = lp.getExpandedPipeline(); ASSERT_EQUALS(expanded.size(), 4); - const auto it0 = expanded.begin(); - const auto it1 = std::next(expanded.begin(), 1); - const auto it2 = std::next(expanded.begin(), 2); - const auto it3 = std::next(expanded.begin(), 3); - - auto* first = dynamic_cast(it0->get()); + auto* first = + dynamic_cast(expanded[0].get()); ASSERT_TRUE(first != nullptr); ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafAName)); - auto* second = dynamic_cast(it1->get()); + auto* second = + dynamic_cast(expanded[1].get()); ASSERT_TRUE(second != nullptr); ASSERT_EQ(second->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafBName)); - auto* third = dynamic_cast(it2->get()); + auto* third = + dynamic_cast(expanded[2].get()); ASSERT_TRUE(third != nullptr); ASSERT_EQ(third->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafCName)); - auto* fourth = dynamic_cast(it3->get()); + auto* fourth = + dynamic_cast(expanded[3].get()); ASSERT_TRUE(fourth != nullptr); ASSERT_EQ(fourth->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafDName)); } @@ -514,7 +509,7 @@ TEST_F(DocumentSourceExtensionTest, ExpandToMaxDepthSucceeds) { // Final expansion produces exactly one AST leaf. ASSERT_EQUALS(expanded.size(), 1); auto* leaf = - dynamic_cast(expanded.front().get()); + dynamic_cast(expanded[0].get()); ASSERT_TRUE(leaf != nullptr); ASSERT_EQ(leaf->getParseTimeName(), std::string(kDepthLeafName)); } @@ -588,11 +583,10 @@ TEST_F(DocumentSourceExtensionTest, ExpandSameStageOnDifferentBranchesSucceeds) const auto& expanded = lp.getExpandedPipeline(); ASSERT_EQUALS(expanded.size(), 2); - auto it0 = expanded.begin(); - auto it1 = std::next(expanded.begin(), 1); - - auto* first = dynamic_cast(it0->get()); - auto* second = dynamic_cast(it1->get()); + auto* first = + dynamic_cast(expanded[0].get()); + auto* second = + dynamic_cast(expanded[1].get()); ASSERT_TRUE(first != nullptr); ASSERT_TRUE(second != nullptr); diff --git a/src/mongo/db/extension/host/load_extension_test.cpp b/src/mongo/db/extension/host/load_extension_test.cpp index 79fcb11bb1d..30371ce23ae 100644 --- a/src/mongo/db/extension/host/load_extension_test.cpp +++ b/src/mongo/db/extension/host/load_extension_test.cpp @@ -237,19 +237,15 @@ TEST_F(LoadExtensionsTest, LoadMatchTopNDesugarExtensionSucceeds) { const auto& expanded = liteParsedExpandable->getExpandedPipeline(); ASSERT_EQ(expanded.size(), 3U); - const auto it0 = expanded.begin(); - const auto it1 = std::next(expanded.begin(), 1); - const auto it2 = std::next(expanded.begin(), 2); - - auto* first = dynamic_cast(it0->get()); + auto* first = expanded[0].get(); ASSERT(first); ASSERT_EQ(first->getParseTimeName(), DocumentSourceMatch::kStageName); - auto* second = dynamic_cast(it1->get()); + auto* second = expanded[1].get(); ASSERT(second); ASSERT_EQ(second->getParseTimeName(), DocumentSourceSort::kStageName); - auto* third = dynamic_cast(it2->get()); + auto* third = expanded[2].get(); ASSERT(third); ASSERT_EQ(third->getParseTimeName(), DocumentSourceLimit::kStageName); } diff --git a/src/mongo/db/extension/host/load_native_vector_search_test.cpp b/src/mongo/db/extension/host/load_native_vector_search_test.cpp index 5113a66e3d5..e6bce8541bb 100644 --- a/src/mongo/db/extension/host/load_native_vector_search_test.cpp +++ b/src/mongo/db/extension/host/load_native_vector_search_test.cpp @@ -130,12 +130,12 @@ protected: const auto& expanded = lpExpanded->getExpandedPipeline(); ASSERT_EQ(expanded.size(), names.size()); - auto it = expanded.begin(); + size_t i = 0; for (const auto& expected : names) { - auto* lp = dynamic_cast(it->get()); + auto* lp = expanded[i].get(); ASSERT_TRUE(lp); ASSERT_EQ(lp->getParseTimeName(), expected); - ++it; + ++i; } } diff --git a/src/mongo/db/pipeline/lite_parsed_pipeline.h b/src/mongo/db/pipeline/lite_parsed_pipeline.h index f315894af5d..fa3909c63e9 100644 --- a/src/mongo/db/pipeline/lite_parsed_pipeline.h +++ b/src/mongo/db/pipeline/lite_parsed_pipeline.h @@ -52,6 +52,8 @@ namespace mongo { +using StageSpecs = std::vector>; + /** * A semi-parsed version of a Pipeline, parsed just enough to determine information like what * foreign collections are involved. @@ -295,14 +297,14 @@ public: return _isRunningAgainstView_ForHybridSearch; } - const std::vector>& getStages() const { + const StageSpecs& getStages() const { return _stageSpecs; } private: // This is logically const - any changes to _stageSpecs will invalidate cached copies of // "_hasChangeStream" and "_involvedNamespaces" below. - std::vector> _stageSpecs; + StageSpecs _stageSpecs; // This variable specifies whether the pipeline is running on a view's namespace. This is // currently needed for $rankFusion/$scoreFusion positional validation.