summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Zolnierz <nicholas.zolnierz@mongodb.com>2019-05-13 13:42:10 -0400
committerNick Zolnierz <nicholas.zolnierz@mongodb.com>2019-05-14 11:18:30 -0400
commitcb8fc5340298bb451f23b1bb8a0b2b1fcfa95c2f (patch)
treec662bc71fc1f9fccdb305205f13a564cebc176e9 /src
parent1ca8e6db734a51a453e50768f88b81a98615ae0b (diff)
downloadmongo-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.h8
-rw-r--r--src/mongo/db/pipeline/pipeline_metadata_tree_test.cpp38
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