diff options
author | Nick Zolnierz <nicholas.zolnierz@mongodb.com> | 2019-05-13 13:42:10 -0400 |
---|---|---|
committer | Nick Zolnierz <nicholas.zolnierz@mongodb.com> | 2019-05-14 11:18:30 -0400 |
commit | cb8fc5340298bb451f23b1bb8a0b2b1fcfa95c2f (patch) | |
tree | c662bc71fc1f9fccdb305205f13a564cebc176e9 /src | |
parent | 1ca8e6db734a51a453e50768f88b81a98615ae0b (diff) | |
download | mongo-cb8fc5340298bb451f23b1bb8a0b2b1fcfa95c2f.tar.gz |
SERVER-40907 Fix pipeline_metadata_tree to handle empty pipelines
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/pipeline/pipeline_metadata_tree.h | 8 | ||||
-rw-r--r-- | src/mongo/db/pipeline/pipeline_metadata_tree_test.cpp | 38 |
2 files changed, 33 insertions, 13 deletions
diff --git a/src/mongo/db/pipeline/pipeline_metadata_tree.h b/src/mongo/db/pipeline/pipeline_metadata_tree.h index 212ff516a52..33c8ea619dc 100644 --- a/src/mongo/db/pipeline/pipeline_metadata_tree.h +++ b/src/mongo/db/pipeline/pipeline_metadata_tree.h @@ -258,10 +258,16 @@ inline void walk(Stage<T>* stage, * calling the 'propagator' function on the last source. */ template <typename T> -inline std::pair<Stage<T>, T> makeTree( +inline std::pair<boost::optional<Stage<T>>, T> makeTree( std::deque<T>&& initialStageContents, const Pipeline& pipeline, const std::function<T(const T&, const std::vector<T>&, const DocumentSource&)>& propagator) { + // For empty pipelines, there's no Stage<T> to return and the output schema is the same as the + // input schema. + if (pipeline.getSources().empty()) { + return std::pair(boost::none, initialStageContents.front()); + } + auto && [ finalStage, reshaper ] = detail::makeTreeWithOffTheEndStage(std::move(initialStageContents), pipeline, propagator); diff --git a/src/mongo/db/pipeline/pipeline_metadata_tree_test.cpp b/src/mongo/db/pipeline/pipeline_metadata_tree_test.cpp index 4c405379c20..a0d85705579 100644 --- a/src/mongo/db/pipeline/pipeline_metadata_tree_test.cpp +++ b/src/mongo/db/pipeline/pipeline_metadata_tree_test.cpp @@ -127,15 +127,15 @@ TEST_F(PipelineMetadataTreeTest, LinearPipelinesConstructProperTrees) { ASSERT([&]() { auto pipePtr = jsonToPipeline("[{$project: {name : 1}}]"); - return makeTree<TestThing>({initial}, *pipePtr, ignoreDocumentSourceAddOne).first; - }() == Stage(TestThing{23}, {}, {})); + return makeTree<TestThing>({initial}, *pipePtr, ignoreDocumentSourceAddOne); + }().first.get() == Stage(TestThing{23}, {}, {})); ASSERT([&]() { auto pipePtr = jsonToPipeline( "[{$project: {name: 1, status: 1}}, " "{$match: {status: \"completed\"}}]"); - return makeTree<TestThing>({initial}, *pipePtr, ignoreDocumentSourceAddOne).first; - }() == Stage(TestThing{24}, makeUniqueStage(TestThing{23}, {}, {}), {})); + return makeTree<TestThing>({initial}, *pipePtr, ignoreDocumentSourceAddOne); + }().first.get() == Stage(TestThing{24}, makeUniqueStage(TestThing{23}, {}, {}), {})); ASSERT([&]() { auto pipePtr = jsonToPipeline( @@ -145,8 +145,9 @@ TEST_F(PipelineMetadataTreeTest, LinearPipelinesConstructProperTrees) { "{$match: {status: \"completed\"}}, " "{$match: {status: \"completed\"}}, " "{$match: {status: \"completed\"}}]"); - return makeTree<TestThing>({initial}, *pipePtr, ignoreDocumentSourceAddOne).first; - }() == Stage(TestThing{28}, + return makeTree<TestThing>({initial}, *pipePtr, ignoreDocumentSourceAddOne); + }().first.get() == + Stage(TestThing{28}, makeUniqueStage( TestThing{27}, makeUniqueStage( @@ -237,8 +238,9 @@ TEST_F(PipelineMetadataTreeTest, BranchingPipelinesConstructProperTrees) { "{$unwind: \"$instr\"}, " "{$group: {_id: {PositionID: \"$trade.mvtident\", \"InstrumentReference\": " "\"$instr.libelle\"}, NumberOfSecurities: {$sum:\"$trade.quantite\"}}}]"); - return makeTree<TestThing>({{"1"}, {"2"}}, *pipePtr, buildRepresentativeString).first; - }() == Stage(TestThing{"1mpxul[2m]ulu"}, + return makeTree<TestThing>({{"1"}, {"2"}}, *pipePtr, buildRepresentativeString); + }().first.get() == + Stage(TestThing{"1mpxul[2m]ulu"}, makeUniqueStage( TestThing{"1mpxul[2m]ul"}, makeUniqueStage( @@ -271,8 +273,9 @@ TEST_F(PipelineMetadataTreeTest, BranchingPipelinesConstructProperTrees) { "{$bucket: {groupBy: \"$year\", boundaries: [ 2000, 2010, 2015, 2020]}}], " "\"categorizedByYears(Auto)\": [{$bucketAuto: {groupBy: \"$year\", buckets: 2}}]}}, " "{$limit: 12}]"); - return makeTree<TestThing>({{""}}, *pipePtr, buildRepresentativeString).first; - }() == Stage(TestThing{"f[tugs, tmgs, tb]"}, + return makeTree<TestThing>({{""}}, *pipePtr, buildRepresentativeString); + }().first.get() == + Stage(TestThing{"f[tugs, tmgs, tb]"}, makeUniqueStage( TestThing{""}, {}, @@ -344,7 +347,7 @@ TEST_F(PipelineMetadataTreeTest, ZipWalksAPipelineAndTreeInTandemAndInOrder) { "{$group: {_id: {PositionID: \"$trade.mvtident\", \"InstrumentReference\": " "\"$instr.libelle\"}, NumberOfSecurities: {$sum:\"$trade.quantite\"}}}]"); auto tree = makeTree<TestThing>({{}, {}}, *pipePtr, takeTypeInfo).first; - zip<TestThing>(&tree, &*pipePtr, tookTypeInfoOrThrow); + zip<TestThing>(&tree.get(), &*pipePtr, tookTypeInfoOrThrow); previousStack.pop(); }()); @@ -358,10 +361,21 @@ TEST_F(PipelineMetadataTreeTest, ZipWalksAPipelineAndTreeInTandemAndInOrder) { "\"categorizedByYears(Auto)\": [{$bucketAuto: {groupBy: \"$year\", buckets: 2}}]}}, " "{$limit: 12}]"); auto tree = makeTree<TestThing>({{}, {}}, *pipePtr, takeTypeInfo).first; - zip<TestThing>(&tree, &*pipePtr, tookTypeInfoOrThrow); + zip<TestThing>(&tree.get(), &*pipePtr, tookTypeInfoOrThrow); previousStack.pop(); }()); } +TEST_F(PipelineMetadataTreeTest, MakeTreeWithEmptyPipeline) { + auto pipeline = uassertStatusOK(Pipeline::parse({}, getExpCtx())); + auto result = makeTree<std::string>({std::string("input")}, + *pipeline, + [](const auto&, const auto&, const DocumentSource& source) { + return std::string("not called"); + }); + ASSERT_FALSE(result.first); + ASSERT_EQ(result.second, "input"_sd); +} + } // namespace } // namespace mongo |