SERVER-115431 Return a vector of LiteParsedDocumentSource from getExpandedPipeline() (#45220)

GitOrigin-RevId: 89b63f098ff759bcdff0172819ea8c6620210f30
This commit is contained in:
Lynne Wang 2025-12-15 14:11:15 -05:00 committed by MongoDB Bot
parent 44288f13ed
commit ae97353d07
5 changed files with 43 additions and 49 deletions

View File

@ -83,11 +83,13 @@ public:
_nss(nss), _nss(nss),
_options(options), _options(options),
_expanded([&] { _expanded([&] {
auto expanded = expand(); auto expandedList = expand();
tassert(10905600, tassert(10905600,
"LiteParsedExpandable must not have an empty expanded pipeline", "LiteParsedExpandable must not have an empty expanded pipeline",
!expanded.empty()); !expandedList.empty());
return expanded;
return StageSpecs(std::make_move_iterator(expandedList.begin()),
std::make_move_iterator(expandedList.end()));
}()) {} }()) {}
std::unique_ptr<StageParams> getStageParams() const override { std::unique_ptr<StageParams> getStageParams() const override {
@ -97,7 +99,7 @@ public:
/** /**
* Return the pre-computed expanded pipeline. * Return the pre-computed expanded pipeline.
*/ */
const LiteParsedList& getExpandedPipeline() const { const StageSpecs& getExpandedPipeline() const {
return _expanded; return _expanded;
} }
@ -161,7 +163,7 @@ public:
const AggStageParseNodeHandle _parseNode; const AggStageParseNodeHandle _parseNode;
const NamespaceString _nss; const NamespaceString _nss;
const LiteParserOptions _options; const LiteParserOptions _options;
const LiteParsedList _expanded; const StageSpecs _expanded;
}; };
/** /**

View File

@ -145,7 +145,7 @@ TEST_F(DocumentSourceExtensionTest, ExpandToExtAst) {
// Expanded pipeline contains LiteParsedExpanded. // Expanded pipeline contains LiteParsedExpanded.
auto* first = auto* first =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded.front().get()); dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[0].get());
ASSERT_TRUE(first != nullptr); ASSERT_TRUE(first != nullptr);
ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kTransformName)); ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kTransformName));
} }
@ -164,7 +164,7 @@ TEST_F(DocumentSourceExtensionTest, ExpandToExtParse) {
// Expanded pipeline contains LiteParsedExpanded. // Expanded pipeline contains LiteParsedExpanded.
auto* first = auto* first =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded.front().get()); dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[0].get());
ASSERT_TRUE(first != nullptr); ASSERT_TRUE(first != nullptr);
ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kTransformName)); ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kTransformName));
} }
@ -183,13 +183,13 @@ TEST_F(DocumentSourceExtensionTest, ExpandToHostParse) {
ASSERT_EQUALS(expanded.size(), 1); ASSERT_EQUALS(expanded.size(), 1);
// Expanded pipeline contains LiteParsedDocumentSource. // Expanded pipeline contains LiteParsedDocumentSource.
auto* lpds = dynamic_cast<LiteParsedDocumentSource*>(expanded.front().get()); auto* lpds = dynamic_cast<LiteParsedDocumentSource*>(expanded[0].get());
ASSERT_TRUE(lpds != nullptr); ASSERT_TRUE(lpds != nullptr);
ASSERT_EQ(lpds->getParseTimeName(), std::string(DocumentSourceMatch::kStageName)); ASSERT_EQ(lpds->getParseTimeName(), std::string(DocumentSourceMatch::kStageName));
// It is not an instance of LiteParsedExpanded. // It is not an instance of LiteParsedExpanded.
auto* notExpanded = auto* notExpanded =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded.front().get()); dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[0].get());
ASSERT_TRUE(notExpanded == nullptr); ASSERT_TRUE(notExpanded == nullptr);
} }
@ -204,24 +204,20 @@ TEST_F(DocumentSourceExtensionTest, ExpandToMixed) {
const auto& expanded = lp.getExpandedPipeline(); const auto& expanded = lp.getExpandedPipeline();
ASSERT_EQUALS(expanded.size(), 4); ASSERT_EQUALS(expanded.size(), 4);
const auto it0 = expanded.begin(); auto* first =
const auto it1 = std::next(expanded.begin(), 1); dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[0].get());
const auto it2 = std::next(expanded.begin(), 2);
const auto it3 = std::next(expanded.begin(), 3);
auto* first = dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it0->get());
ASSERT_TRUE(first != nullptr); ASSERT_TRUE(first != nullptr);
auto* second = dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it1->get()); auto* second =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[1].get());
ASSERT_TRUE(second != nullptr); ASSERT_TRUE(second != nullptr);
auto* third = dynamic_cast<LiteParsedDocumentSource*>(it2->get()); // This one is NOT LiteParsedExpanded.
auto* third = expanded[2].get();
ASSERT_TRUE(third != nullptr); ASSERT_TRUE(third != nullptr);
auto* notExpanded = ASSERT_TRUE(dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(third) == nullptr);
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it2->get());
ASSERT_TRUE(notExpanded == nullptr);
auto* fourth = dynamic_cast<LiteParsedDocumentSource*>(it3->get()); auto* fourth = expanded[3].get();
ASSERT_TRUE(fourth != nullptr); ASSERT_TRUE(fourth != nullptr);
ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kTransformName)); ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kTransformName));
@ -296,7 +292,7 @@ TEST_F(DocumentSourceExtensionTest, ExpandToHostAst) {
ASSERT_EQUALS(expanded.size(), 1); ASSERT_EQUALS(expanded.size(), 1);
// Expanded pipeline contains LiteParsedDocumentSource. // Expanded pipeline contains LiteParsedDocumentSource.
auto* lpds = dynamic_cast<LiteParsedDocumentSource*>(expanded.front().get()); auto* lpds = dynamic_cast<LiteParsedDocumentSource*>(expanded[0].get());
ASSERT_TRUE(lpds != nullptr); ASSERT_TRUE(lpds != nullptr);
ASSERT_EQ(lpds->getParseTimeName(), ASSERT_EQ(lpds->getParseTimeName(),
std::string(DocumentSourceInternalSearchIdLookUp::kStageName)); std::string(DocumentSourceInternalSearchIdLookUp::kStageName));
@ -328,24 +324,23 @@ TEST_F(DocumentSourceExtensionTest, ExpandRecursesMultipleLevels) {
const auto& expanded = lp.getExpandedPipeline(); const auto& expanded = lp.getExpandedPipeline();
ASSERT_EQUALS(expanded.size(), 4); ASSERT_EQUALS(expanded.size(), 4);
const auto it0 = expanded.begin(); auto* first =
const auto it1 = std::next(expanded.begin(), 1); dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[0].get());
const auto it2 = std::next(expanded.begin(), 2);
const auto it3 = std::next(expanded.begin(), 3);
auto* first = dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it0->get());
ASSERT_TRUE(first != nullptr); ASSERT_TRUE(first != nullptr);
ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafAName)); ASSERT_EQ(first->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafAName));
auto* second = dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it1->get()); auto* second =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[1].get());
ASSERT_TRUE(second != nullptr); ASSERT_TRUE(second != nullptr);
ASSERT_EQ(second->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafBName)); ASSERT_EQ(second->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafBName));
auto* third = dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it2->get()); auto* third =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[2].get());
ASSERT_TRUE(third != nullptr); ASSERT_TRUE(third != nullptr);
ASSERT_EQ(third->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafCName)); ASSERT_EQ(third->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafCName));
auto* fourth = dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it3->get()); auto* fourth =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[3].get());
ASSERT_TRUE(fourth != nullptr); ASSERT_TRUE(fourth != nullptr);
ASSERT_EQ(fourth->getParseTimeName(), std::string(sdk::shared_test_stages::kLeafDName)); 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. // Final expansion produces exactly one AST leaf.
ASSERT_EQUALS(expanded.size(), 1); ASSERT_EQUALS(expanded.size(), 1);
auto* leaf = auto* leaf =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded.front().get()); dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[0].get());
ASSERT_TRUE(leaf != nullptr); ASSERT_TRUE(leaf != nullptr);
ASSERT_EQ(leaf->getParseTimeName(), std::string(kDepthLeafName)); ASSERT_EQ(leaf->getParseTimeName(), std::string(kDepthLeafName));
} }
@ -588,11 +583,10 @@ TEST_F(DocumentSourceExtensionTest, ExpandSameStageOnDifferentBranchesSucceeds)
const auto& expanded = lp.getExpandedPipeline(); const auto& expanded = lp.getExpandedPipeline();
ASSERT_EQUALS(expanded.size(), 2); ASSERT_EQUALS(expanded.size(), 2);
auto it0 = expanded.begin(); auto* first =
auto it1 = std::next(expanded.begin(), 1); dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[0].get());
auto* second =
auto* first = dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it0->get()); dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[1].get());
auto* second = dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it1->get());
ASSERT_TRUE(first != nullptr); ASSERT_TRUE(first != nullptr);
ASSERT_TRUE(second != nullptr); ASSERT_TRUE(second != nullptr);

View File

@ -237,19 +237,15 @@ TEST_F(LoadExtensionsTest, LoadMatchTopNDesugarExtensionSucceeds) {
const auto& expanded = liteParsedExpandable->getExpandedPipeline(); const auto& expanded = liteParsedExpandable->getExpandedPipeline();
ASSERT_EQ(expanded.size(), 3U); ASSERT_EQ(expanded.size(), 3U);
const auto it0 = expanded.begin(); auto* first = expanded[0].get();
const auto it1 = std::next(expanded.begin(), 1);
const auto it2 = std::next(expanded.begin(), 2);
auto* first = dynamic_cast<LiteParsedDocumentSource*>(it0->get());
ASSERT(first); ASSERT(first);
ASSERT_EQ(first->getParseTimeName(), DocumentSourceMatch::kStageName); ASSERT_EQ(first->getParseTimeName(), DocumentSourceMatch::kStageName);
auto* second = dynamic_cast<LiteParsedDocumentSource*>(it1->get()); auto* second = expanded[1].get();
ASSERT(second); ASSERT(second);
ASSERT_EQ(second->getParseTimeName(), DocumentSourceSort::kStageName); ASSERT_EQ(second->getParseTimeName(), DocumentSourceSort::kStageName);
auto* third = dynamic_cast<LiteParsedDocumentSource*>(it2->get()); auto* third = expanded[2].get();
ASSERT(third); ASSERT(third);
ASSERT_EQ(third->getParseTimeName(), DocumentSourceLimit::kStageName); ASSERT_EQ(third->getParseTimeName(), DocumentSourceLimit::kStageName);
} }

View File

@ -130,12 +130,12 @@ protected:
const auto& expanded = lpExpanded->getExpandedPipeline(); const auto& expanded = lpExpanded->getExpandedPipeline();
ASSERT_EQ(expanded.size(), names.size()); ASSERT_EQ(expanded.size(), names.size());
auto it = expanded.begin(); size_t i = 0;
for (const auto& expected : names) { for (const auto& expected : names) {
auto* lp = dynamic_cast<LiteParsedDocumentSource*>(it->get()); auto* lp = expanded[i].get();
ASSERT_TRUE(lp); ASSERT_TRUE(lp);
ASSERT_EQ(lp->getParseTimeName(), expected); ASSERT_EQ(lp->getParseTimeName(), expected);
++it; ++i;
} }
} }

View File

@ -52,6 +52,8 @@
namespace mongo { namespace mongo {
using StageSpecs = std::vector<std::unique_ptr<LiteParsedDocumentSource>>;
/** /**
* A semi-parsed version of a Pipeline, parsed just enough to determine information like what * A semi-parsed version of a Pipeline, parsed just enough to determine information like what
* foreign collections are involved. * foreign collections are involved.
@ -295,14 +297,14 @@ public:
return _isRunningAgainstView_ForHybridSearch; return _isRunningAgainstView_ForHybridSearch;
} }
const std::vector<std::unique_ptr<LiteParsedDocumentSource>>& getStages() const { const StageSpecs& getStages() const {
return _stageSpecs; return _stageSpecs;
} }
private: private:
// This is logically const - any changes to _stageSpecs will invalidate cached copies of // This is logically const - any changes to _stageSpecs will invalidate cached copies of
// "_hasChangeStream" and "_involvedNamespaces" below. // "_hasChangeStream" and "_involvedNamespaces" below.
std::vector<std::unique_ptr<LiteParsedDocumentSource>> _stageSpecs; StageSpecs _stageSpecs;
// This variable specifies whether the pipeline is running on a view's namespace. This is // This variable specifies whether the pipeline is running on a view's namespace. This is
// currently needed for $rankFusion/$scoreFusion positional validation. // currently needed for $rankFusion/$scoreFusion positional validation.