diff options
author | George Wangensteen <george.wangensteen@10gen.com> | 2019-07-08 13:19:22 -0400 |
---|---|---|
committer | George Wangensteen <george.wangensteen@10gen.com> | 2019-07-24 17:44:23 -0400 |
commit | f4399fceab41c4dfaad6b846b94e1366f67d93cd (patch) | |
tree | 11f0fd253c9fd9cc1670725bb037e160efc47017 /src/mongo/db/pipeline | |
parent | e09a81707daf75e8965cc10d909282db158bc809 (diff) | |
download | mongo-f4399fceab41c4dfaad6b846b94e1366f67d93cd.tar.gz |
SERVER-42017 make stage names in error messages match name used
Diffstat (limited to 'src/mongo/db/pipeline')
-rw-r--r-- | src/mongo/db/pipeline/document_source_add_fields.cpp | 15 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_project.cpp | 28 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_project.h | 4 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_project_test.cpp | 57 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_replace_root.cpp | 33 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_replace_root.h | 8 | ||||
-rw-r--r-- | src/mongo/db/pipeline/parsed_add_fields.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/parsed_aggregation_projection.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/pipeline/parsed_aggregation_projection.h | 7 | ||||
-rw-r--r-- | src/mongo/db/pipeline/pipeline_test.cpp | 12 |
10 files changed, 117 insertions, 65 deletions
diff --git a/src/mongo/db/pipeline/document_source_add_fields.cpp b/src/mongo/db/pipeline/document_source_add_fields.cpp index 319ef9776c6..8784a5ebf16 100644 --- a/src/mongo/db/pipeline/document_source_add_fields.cpp +++ b/src/mongo/db/pipeline/document_source_add_fields.cpp @@ -50,14 +50,23 @@ REGISTER_DOCUMENT_SOURCE(set, DocumentSourceAddFields::createFromBson); intrusive_ptr<DocumentSource> DocumentSourceAddFields::create( - BSONObj addFieldsSpec, const intrusive_ptr<ExpressionContext>& expCtx, StringData stageName) { + BSONObj addFieldsSpec, + const intrusive_ptr<ExpressionContext>& expCtx, + StringData userSpecifiedName) { const bool isIndependentOfAnyCollection = false; intrusive_ptr<DocumentSourceSingleDocumentTransformation> addFields( new DocumentSourceSingleDocumentTransformation( expCtx, - ParsedAddFields::create(expCtx, addFieldsSpec), - stageName.toString(), + [&]() { + try { + return ParsedAddFields::create(expCtx, addFieldsSpec); + } catch (DBException& ex) { + ex.addContext("Invalid " + userSpecifiedName.toString()); + throw; + } + }(), + userSpecifiedName.toString(), isIndependentOfAnyCollection)); return addFields; } diff --git a/src/mongo/db/pipeline/document_source_project.cpp b/src/mongo/db/pipeline/document_source_project.cpp index 50c6f3defb6..419351b20e5 100644 --- a/src/mongo/db/pipeline/document_source_project.cpp +++ b/src/mongo/db/pipeline/document_source_project.cpp @@ -62,15 +62,26 @@ BSONObj buildExclusionProjectionSpecification(const std::vector<BSONElement>& un } // namespace intrusive_ptr<DocumentSource> DocumentSourceProject::create( - BSONObj projectSpec, const intrusive_ptr<ExpressionContext>& expCtx) { + BSONObj projectSpec, const intrusive_ptr<ExpressionContext>& expCtx, StringData specifiedName) { const bool isIndependentOfAnyCollection = false; intrusive_ptr<DocumentSource> project(new DocumentSourceSingleDocumentTransformation( expCtx, - ParsedAggregationProjection::create( - expCtx, - projectSpec, - {ProjectionPolicies::DefaultIdPolicy::kIncludeId, - ProjectionPolicies::ArrayRecursionPolicy::kRecurseNestedArrays}), + [&]() { + // The ParsedAggregationProjection will internally perform a check to see if the + // provided specification is valid, and throw an exception if it was not. The exception + // is caught here so we can add the name that was actually specified by the user, be it + // $project or an alias. + try { + return ParsedAggregationProjection::create( + expCtx, + projectSpec, + {ProjectionPolicies::DefaultIdPolicy::kIncludeId, + ProjectionPolicies::ArrayRecursionPolicy::kRecurseNestedArrays}); + } catch (DBException& ex) { + ex.addContext("Invalid " + specifiedName.toString()); + throw; + } + }(), DocumentSourceProject::kStageName.rawData(), isIndependentOfAnyCollection)); return project; @@ -80,7 +91,7 @@ intrusive_ptr<DocumentSource> DocumentSourceProject::createFromBson( BSONElement elem, const intrusive_ptr<ExpressionContext>& expCtx) { if (elem.fieldNameStringData() == kStageName) { uassert(15969, "$project specification must be an object", elem.type() == BSONType::Object); - return DocumentSourceProject::create(elem.Obj(), expCtx); + return DocumentSourceProject::create(elem.Obj(), expCtx, elem.fieldNameStringData()); } invariant(elem.fieldNameStringData() == kAliasNameUnset); @@ -99,7 +110,8 @@ intrusive_ptr<DocumentSource> DocumentSourceProject::createFromBson( std::all_of(unsetSpec.cbegin(), unsetSpec.cend(), [](BSONElement elem) { return elem.type() == BSONType::String; })); - return DocumentSourceProject::create(buildExclusionProjectionSpecification(unsetSpec), expCtx); + return DocumentSourceProject::create( + buildExclusionProjectionSpecification(unsetSpec), expCtx, elem.fieldNameStringData()); } } // namespace mongo diff --git a/src/mongo/db/pipeline/document_source_project.h b/src/mongo/db/pipeline/document_source_project.h index d1e556e8ccc..43ee90fce0f 100644 --- a/src/mongo/db/pipeline/document_source_project.h +++ b/src/mongo/db/pipeline/document_source_project.h @@ -48,7 +48,9 @@ public: * Convenience method to create a $project stage from 'projectSpec'. */ static boost::intrusive_ptr<DocumentSource> create( - BSONObj projectSpec, const boost::intrusive_ptr<ExpressionContext>& expCtx); + BSONObj projectSpec, + const boost::intrusive_ptr<ExpressionContext>& expCtx, + StringData specifiedName); /** * Parses a $project stage from the user-supplied BSON. diff --git a/src/mongo/db/pipeline/document_source_project_test.cpp b/src/mongo/db/pipeline/document_source_project_test.cpp index 1b7696adad6..4f8f800c79d 100644 --- a/src/mongo/db/pipeline/document_source_project_test.cpp +++ b/src/mongo/db/pipeline/document_source_project_test.cpp @@ -61,8 +61,8 @@ using ProjectStageTest = AggregationContextFixture; using UnsetTest = AggregationContextFixture; TEST_F(ProjectStageTest, InclusionProjectionShouldRemoveUnspecifiedFields) { - auto project = - DocumentSourceProject::create(BSON("a" << true << "c" << BSON("d" << true)), getExpCtx()); + auto project = DocumentSourceProject::create( + BSON("a" << true << "c" << BSON("d" << true)), getExpCtx(), "$project"_sd); auto source = DocumentSourceMock::createForTest("{_id: 0, a: 1, b: 1, c: {d: 1}}"); project->setSource(source.get()); // The first result exists and is as expected. @@ -78,7 +78,9 @@ TEST_F(ProjectStageTest, InclusionProjectionShouldRemoveUnspecifiedFields) { TEST_F(ProjectStageTest, ShouldOptimizeInnerExpressions) { auto project = DocumentSourceProject::create( - BSON("a" << BSON("$and" << BSON_ARRAY(BSON("$const" << true)))), getExpCtx()); + BSON("a" << BSON("$and" << BSON_ARRAY(BSON("$const" << true)))), + getExpCtx(), + "$project"_sd); project->optimize(); // The $and should have been replaced with its only argument. vector<Value> serializedArray; @@ -100,7 +102,7 @@ TEST_F(ProjectStageTest, ShouldErrorOnNonObjectSpec) { * projection. */ TEST_F(ProjectStageTest, InclusionShouldBeAbleToProcessMultipleDocuments) { - auto project = DocumentSourceProject::create(BSON("a" << true), getExpCtx()); + auto project = DocumentSourceProject::create(BSON("a" << true), getExpCtx(), "$project"_sd); auto source = DocumentSourceMock::createForTest({"{a: 1, b: 2}", "{a: 3, b: 4}"}); project->setSource(source.get()); auto next = project->getNext(); @@ -123,7 +125,7 @@ TEST_F(ProjectStageTest, InclusionShouldBeAbleToProcessMultipleDocuments) { * projection. */ TEST_F(ProjectStageTest, ExclusionShouldBeAbleToProcessMultipleDocuments) { - auto project = DocumentSourceProject::create(BSON("a" << false), getExpCtx()); + auto project = DocumentSourceProject::create(BSON("a" << false), getExpCtx(), "$project"_sd); auto source = DocumentSourceMock::createForTest({"{a: 1, b: 2}", "{a: 3, b: 4}"}); project->setSource(source.get()); auto next = project->getNext(); @@ -142,7 +144,7 @@ TEST_F(ProjectStageTest, ExclusionShouldBeAbleToProcessMultipleDocuments) { } TEST_F(ProjectStageTest, ShouldPropagatePauses) { - auto project = DocumentSourceProject::create(BSON("a" << false), getExpCtx()); + auto project = DocumentSourceProject::create(BSON("a" << false), getExpCtx(), "$project"_sd); auto source = DocumentSourceMock::createForTest({Document(), DocumentSource::GetNextResult::makePauseExecution(), @@ -167,7 +169,8 @@ TEST_F(ProjectStageTest, ShouldPropagatePauses) { TEST_F(ProjectStageTest, InclusionShouldAddDependenciesOfIncludedAndComputedFields) { auto project = DocumentSourceProject::create( fromjson("{a: true, x: '$b', y: {$and: ['$c','$d']}, z: {$meta: 'textScore'}}"), - getExpCtx()); + getExpCtx(), + "$project"_sd); DepsTracker dependencies(DepsTracker::MetadataAvailable::kTextScore); ASSERT_EQUALS(DepsTracker::State::EXHAUSTIVE_FIELDS, project->getDependencies(&dependencies)); ASSERT_EQUALS(5U, dependencies.fields.size()); @@ -189,7 +192,8 @@ TEST_F(ProjectStageTest, InclusionShouldAddDependenciesOfIncludedAndComputedFiel } TEST_F(ProjectStageTest, ExclusionShouldNotAddDependencies) { - auto project = DocumentSourceProject::create(fromjson("{a: false, 'b.c': false}"), getExpCtx()); + auto project = DocumentSourceProject::create( + fromjson("{a: false, 'b.c': false}"), getExpCtx(), "$project"_sd); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, project->getDependencies(&dependencies)); @@ -202,7 +206,8 @@ TEST_F(ProjectStageTest, ExclusionShouldNotAddDependencies) { TEST_F(ProjectStageTest, InclusionProjectionReportsIncludedPathsFromGetModifiedPaths) { auto project = DocumentSourceProject::create( fromjson("{a: true, 'b.c': {d: true}, e: {f: {g: true}}, h: {i: {$literal: true}}}"), - getExpCtx()); + getExpCtx(), + "$project"_sd); auto modifiedPaths = project->getModifiedPaths(); ASSERT(modifiedPaths.type == DocumentSource::GetModPathsReturn::Type::kAllExcept); @@ -216,7 +221,8 @@ TEST_F(ProjectStageTest, InclusionProjectionReportsIncludedPathsFromGetModifiedP TEST_F(ProjectStageTest, InclusionProjectionReportsIncludedPathsButExcludesId) { auto project = DocumentSourceProject::create( fromjson("{_id: false, 'b.c': {d: true}, e: {f: {g: true}}, h: {i: {$literal: true}}}"), - getExpCtx()); + getExpCtx(), + "$project"_sd); auto modifiedPaths = project->getModifiedPaths(); ASSERT(modifiedPaths.type == DocumentSource::GetModPathsReturn::Type::kAllExcept); @@ -227,7 +233,7 @@ TEST_F(ProjectStageTest, InclusionProjectionReportsIncludedPathsButExcludesId) { TEST_F(ProjectStageTest, ExclusionProjectionReportsExcludedPathsAsModifiedPaths) { auto project = DocumentSourceProject::create( - fromjson("{a: false, 'b.c': {d: false}, e: {f: {g: false}}}"), getExpCtx()); + fromjson("{a: false, 'b.c': {d: false}, e: {f: {g: false}}}"), getExpCtx(), "$project"_sd); auto modifiedPaths = project->getModifiedPaths(); ASSERT(modifiedPaths.type == DocumentSource::GetModPathsReturn::Type::kFiniteSet); @@ -239,7 +245,9 @@ TEST_F(ProjectStageTest, ExclusionProjectionReportsExcludedPathsAsModifiedPaths) TEST_F(ProjectStageTest, ExclusionProjectionReportsExcludedPathsWithIdExclusion) { auto project = DocumentSourceProject::create( - fromjson("{_id: false, 'b.c': {d: false}, e: {f: {g: false}}}"), getExpCtx()); + fromjson("{_id: false, 'b.c': {d: false}, e: {f: {g: false}}}"), + getExpCtx(), + "$project"_sd); auto modifiedPaths = project->getModifiedPaths(); ASSERT(modifiedPaths.type == DocumentSource::GetModPathsReturn::Type::kFiniteSet); @@ -251,7 +259,9 @@ TEST_F(ProjectStageTest, ExclusionProjectionReportsExcludedPathsWithIdExclusion) TEST_F(ProjectStageTest, CanUseRemoveSystemVariableToConditionallyExcludeProjectedField) { auto project = DocumentSourceProject::create( - fromjson("{a: 1, b: {$cond: [{$eq: ['$b', 4]}, '$$REMOVE', '$b']}}"), getExpCtx()); + fromjson("{a: 1, b: {$cond: [{$eq: ['$b', 4]}, '$$REMOVE', '$b']}}"), + getExpCtx(), + "$project"_sd); auto source = DocumentSourceMock::createForTest({"{a: 2, b: 2}", "{a: 3, b: 4}"}); project->setSource(source.get()); auto next = project->getNext(); @@ -268,7 +278,8 @@ TEST_F(ProjectStageTest, CanUseRemoveSystemVariableToConditionallyExcludeProject } TEST_F(ProjectStageTest, ProjectionCorrectlyReportsRenamesForwards) { - auto project = DocumentSourceProject::create(fromjson("{'renamedB' : '$b'}"), getExpCtx()); + auto project = + DocumentSourceProject::create(fromjson("{'renamedB' : '$b'}"), getExpCtx(), "$project"_sd); auto renames = semantic_analysis::renamedPaths({"b"}, *project, semantic_analysis::Direction::kForward); // renamedPaths should return a mapping of old name->new name for each path in interestingPaths @@ -281,7 +292,8 @@ TEST_F(ProjectStageTest, ProjectionCorrectlyReportsRenamesForwards) { } TEST_F(ProjectStageTest, ProjectionCorrectlyReportsRenamesBackwards) { - auto project = DocumentSourceProject::create(fromjson("{'renamedB' : '$b'}"), getExpCtx()); + auto project = + DocumentSourceProject::create(fromjson("{'renamedB' : '$b'}"), getExpCtx(), "$project"_sd); auto renames = semantic_analysis::renamedPaths( {"renamedB"}, *project, semantic_analysis::Direction::kBackward); auto single_rename = renames->extract("renamedB"); @@ -306,7 +318,9 @@ BSONObj makeProjectForNestedDocument(size_t depth) { TEST_F(ProjectStageTest, CanAddNestedDocumentExactlyAtDepthLimit) { auto project = DocumentSourceProject::create( - makeProjectForNestedDocument(BSONDepth::getMaxAllowableDepth()), getExpCtx()); + makeProjectForNestedDocument(BSONDepth::getMaxAllowableDepth()), + getExpCtx(), + "$project"_sd); auto mock = DocumentSourceMock::createForTest(Document{{"_id", 1}}); project->setSource(mock.get()); @@ -315,11 +329,12 @@ TEST_F(ProjectStageTest, CanAddNestedDocumentExactlyAtDepthLimit) { } TEST_F(ProjectStageTest, CannotAddNestedDocumentExceedingDepthLimit) { - ASSERT_THROWS_CODE( - DocumentSourceProject::create( - makeProjectForNestedDocument(BSONDepth::getMaxAllowableDepth() + 1), getExpCtx()), - AssertionException, - ErrorCodes::Overflow); + ASSERT_THROWS_CODE(DocumentSourceProject::create( + makeProjectForNestedDocument(BSONDepth::getMaxAllowableDepth() + 1), + getExpCtx(), + "$project"_sd), + AssertionException, + ErrorCodes::Overflow); } TEST_F(UnsetTest, AcceptsValidUnsetSpecWithArray) { diff --git a/src/mongo/db/pipeline/document_source_replace_root.cpp b/src/mongo/db/pipeline/document_source_replace_root.cpp index deefe509bb7..e494fe1ea2a 100644 --- a/src/mongo/db/pipeline/document_source_replace_root.cpp +++ b/src/mongo/db/pipeline/document_source_replace_root.cpp @@ -46,15 +46,28 @@ Document ReplaceRootTransformation::applyTransformation(const Document& input) { // Extract subdocument in the form of a Value. Value newRoot = _newRoot->evaluate(input, &_expCtx->variables); + // To ensure an accurate user-facing message, any user-facing syntax that uses this stage + // internally must provide an message opener that complies with its documentation. + StringData msgOpener = [&]() { + switch (_specifiedName) { + case UserSpecifiedName::kReplaceRoot: + return "'newRoot' expression "_sd; + case UserSpecifiedName::kReplaceWith: + return "'replacement document' "_sd; + default: + MONGO_UNREACHABLE; + } + }(); + // The newRoot expression, if it exists, must evaluate to an object. uassert(40228, - str::stream() - << "'newRoot' expression must evaluate to an object, but resulting value was: " - << newRoot.toString() - << ". Type of resulting value: '" - << typeName(newRoot.getType()) - << "'. Input document: " - << input.toString(), + str::stream() << msgOpener.toString() + << "must evaluate to an object, but resulting value was: " + << newRoot.toString() + << ". Type of resulting value: '" + << typeName(newRoot.getType()) + << "'. Input document: " + << input.toString(), newRoot.getType() == BSONType::Object); // Turn the value into a document. @@ -104,7 +117,11 @@ intrusive_ptr<DocumentSource> DocumentSourceReplaceRoot::createFromBson( const bool isIndependentOfAnyCollection = false; return new DocumentSourceSingleDocumentTransformation( expCtx, - std::make_unique<ReplaceRootTransformation>(expCtx, newRootExpression), + std::make_unique<ReplaceRootTransformation>( + expCtx, + newRootExpression, + (stageName == kStageName) ? ReplaceRootTransformation::UserSpecifiedName::kReplaceRoot + : ReplaceRootTransformation::UserSpecifiedName::kReplaceWith), kStageName.toString(), isIndependentOfAnyCollection); } diff --git a/src/mongo/db/pipeline/document_source_replace_root.h b/src/mongo/db/pipeline/document_source_replace_root.h index 290919615bc..917b221e20c 100644 --- a/src/mongo/db/pipeline/document_source_replace_root.h +++ b/src/mongo/db/pipeline/document_source_replace_root.h @@ -40,9 +40,12 @@ namespace mongo { */ class ReplaceRootTransformation final : public TransformerInterface { public: + enum class UserSpecifiedName { kReplaceRoot, kReplaceWith }; + ReplaceRootTransformation(const boost::intrusive_ptr<ExpressionContext>& expCtx, - boost::intrusive_ptr<Expression> newRootExpression) - : _expCtx(expCtx), _newRoot(std::move(newRootExpression)) {} + boost::intrusive_ptr<Expression> newRootExpression, + UserSpecifiedName specifiedName) + : _expCtx(expCtx), _newRoot(std::move(newRootExpression)), _specifiedName(specifiedName) {} TransformerType getType() const final { return TransformerType::kReplaceRoot; @@ -79,6 +82,7 @@ public: private: const boost::intrusive_ptr<ExpressionContext> _expCtx; boost::intrusive_ptr<Expression> _newRoot; + UserSpecifiedName _specifiedName; }; /* diff --git a/src/mongo/db/pipeline/parsed_add_fields.cpp b/src/mongo/db/pipeline/parsed_add_fields.cpp index 2e2a1602414..d756c444fa7 100644 --- a/src/mongo/db/pipeline/parsed_add_fields.cpp +++ b/src/mongo/db/pipeline/parsed_add_fields.cpp @@ -42,7 +42,7 @@ namespace parsed_aggregation_projection { std::unique_ptr<ParsedAddFields> ParsedAddFields::create( const boost::intrusive_ptr<ExpressionContext>& expCtx, const BSONObj& spec) { // Verify that we don't have conflicting field paths, etc. - ProjectionSpecValidator::uassertValid(spec, "$addFields"); + ProjectionSpecValidator::uassertValid(spec); std::unique_ptr<ParsedAddFields> parsedAddFields = std::make_unique<ParsedAddFields>(expCtx); // Actually parse the specification. diff --git a/src/mongo/db/pipeline/parsed_aggregation_projection.cpp b/src/mongo/db/pipeline/parsed_aggregation_projection.cpp index 3f283079ac4..058e20b6d0b 100644 --- a/src/mongo/db/pipeline/parsed_aggregation_projection.cpp +++ b/src/mongo/db/pipeline/parsed_aggregation_projection.cpp @@ -55,13 +55,8 @@ using expression::isPathPrefixOf; // ProjectionSpecValidator // -void ProjectionSpecValidator::uassertValid(const BSONObj& spec, StringData stageName) { - try { - ProjectionSpecValidator(spec).validate(); - } catch (DBException& ex) { - ex.addContext("Invalid " + stageName.toString()); - throw; - } +void ProjectionSpecValidator::uassertValid(const BSONObj& spec) { + ProjectionSpecValidator(spec).validate(); } void ProjectionSpecValidator::ensurePathDoesNotConflictOrThrow(const std::string& path) { @@ -314,11 +309,8 @@ std::unique_ptr<ParsedAggregationProjection> ParsedAggregationProjection::create const boost::intrusive_ptr<ExpressionContext>& expCtx, const BSONObj& spec, ProjectionPolicies policies) { - // Check that the specification was valid. Status returned is unspecific because validate() - // is used by the $addFields stage as well as $project. - // If there was an error, uassert with a $project-specific message. - ProjectionSpecValidator::uassertValid(spec, "$project"); - + // Checks that the specification was valid, and throws if it is not. + ProjectionSpecValidator::uassertValid(spec); // Check for any conflicting specifications, and determine the type of the projection. auto projectionType = ProjectTypeParser::parse(spec, policies); // kComputed is a projection type reserved for $addFields, and should never be detected by the diff --git a/src/mongo/db/pipeline/parsed_aggregation_projection.h b/src/mongo/db/pipeline/parsed_aggregation_projection.h index 0542847e9ba..25a6dc025cb 100644 --- a/src/mongo/db/pipeline/parsed_aggregation_projection.h +++ b/src/mongo/db/pipeline/parsed_aggregation_projection.h @@ -55,10 +55,11 @@ namespace parsed_aggregation_projection { class ProjectionSpecValidator { public: /** - * Throws if the specification is not valid for a projection. The stageName is used to provide a - * more helpful error message. + * Throws if the specification is not valid for a projection. Because this validator is meant to + * be generic, the error thrown is generic. Callers at the DocumentSource level should modify + * the error message if they want to include information specific to the stage name used. */ - static void uassertValid(const BSONObj& spec, StringData stageName); + static void uassertValid(const BSONObj& spec); private: ProjectionSpecValidator(const BSONObj& spec) : _rawObj(spec) {} diff --git a/src/mongo/db/pipeline/pipeline_test.cpp b/src/mongo/db/pipeline/pipeline_test.cpp index 3d59eff1dfa..18e149ab0c1 100644 --- a/src/mongo/db/pipeline/pipeline_test.cpp +++ b/src/mongo/db/pipeline/pipeline_test.cpp @@ -3326,12 +3326,12 @@ TEST(PipelineRenameTracking, CanHandleBackAndForthRename) { TEST(InvolvedNamespacesTest, NoInvolvedNamespacesForMatchSortProject) { boost::intrusive_ptr<ExpressionContext> expCtx(new ExpressionContextForTest()); - auto pipeline = unittest::assertGet( - Pipeline::create({DocumentSourceMock::createForTest(), - DocumentSourceMatch::create(BSON("x" << 1), expCtx), - DocumentSourceSort::create(expCtx, BSON("y" << -1)), - DocumentSourceProject::create(BSON("x" << 1 << "y" << 1), expCtx)}, - expCtx)); + auto pipeline = unittest::assertGet(Pipeline::create( + {DocumentSourceMock::createForTest(), + DocumentSourceMatch::create(BSON("x" << 1), expCtx), + DocumentSourceSort::create(expCtx, BSON("y" << -1)), + DocumentSourceProject::create(BSON("x" << 1 << "y" << 1), expCtx, "$project"_sd)}, + expCtx)); auto involvedNssSet = pipeline->getInvolvedCollections(); ASSERT(involvedNssSet.empty()); } |