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),
_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<StageParams> 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;
};
/**

View File

@ -145,7 +145,7 @@ TEST_F(DocumentSourceExtensionTest, ExpandToExtAst) {
// Expanded pipeline contains LiteParsedExpanded.
auto* first =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded.front().get());
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(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<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded.front().get());
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(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<LiteParsedDocumentSource*>(expanded.front().get());
auto* lpds = dynamic_cast<LiteParsedDocumentSource*>(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<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded.front().get());
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(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<host::DocumentSourceExtension::LiteParsedExpanded*>(it0->get());
auto* first =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[0].get());
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);
auto* third = dynamic_cast<LiteParsedDocumentSource*>(it2->get());
// This one is NOT LiteParsedExpanded.
auto* third = expanded[2].get();
ASSERT_TRUE(third != nullptr);
auto* notExpanded =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it2->get());
ASSERT_TRUE(notExpanded == nullptr);
ASSERT_TRUE(dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(third) == nullptr);
auto* fourth = dynamic_cast<LiteParsedDocumentSource*>(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<LiteParsedDocumentSource*>(expanded.front().get());
auto* lpds = dynamic_cast<LiteParsedDocumentSource*>(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<host::DocumentSourceExtension::LiteParsedExpanded*>(it0->get());
auto* first =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[0].get());
ASSERT_TRUE(first != nullptr);
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_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_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_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<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded.front().get());
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(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<host::DocumentSourceExtension::LiteParsedExpanded*>(it0->get());
auto* second = dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(it1->get());
auto* first =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[0].get());
auto* second =
dynamic_cast<host::DocumentSourceExtension::LiteParsedExpanded*>(expanded[1].get());
ASSERT_TRUE(first != nullptr);
ASSERT_TRUE(second != nullptr);

View File

@ -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<LiteParsedDocumentSource*>(it0->get());
auto* first = expanded[0].get();
ASSERT(first);
ASSERT_EQ(first->getParseTimeName(), DocumentSourceMatch::kStageName);
auto* second = dynamic_cast<LiteParsedDocumentSource*>(it1->get());
auto* second = expanded[1].get();
ASSERT(second);
ASSERT_EQ(second->getParseTimeName(), DocumentSourceSort::kStageName);
auto* third = dynamic_cast<LiteParsedDocumentSource*>(it2->get());
auto* third = expanded[2].get();
ASSERT(third);
ASSERT_EQ(third->getParseTimeName(), DocumentSourceLimit::kStageName);
}

View File

@ -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<LiteParsedDocumentSource*>(it->get());
auto* lp = expanded[i].get();
ASSERT_TRUE(lp);
ASSERT_EQ(lp->getParseTimeName(), expected);
++it;
++i;
}
}

View File

@ -52,6 +52,8 @@
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
* foreign collections are involved.
@ -295,14 +297,14 @@ public:
return _isRunningAgainstView_ForHybridSearch;
}
const std::vector<std::unique_ptr<LiteParsedDocumentSource>>& 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<std::unique_ptr<LiteParsedDocumentSource>> _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.