TEST_F(DocumentSourceMatchTest, MultipleMatchStagesShouldCombineIntoOne) { auto match1 = DocumentSourceMatch::create(BSON("a" << 1), getExpCtx()); auto match2 = DocumentSourceMatch::create(BSON("b" << 1), getExpCtx()); auto match3 = DocumentSourceMatch::create(BSON("c" << 1), getExpCtx()); Pipeline::SourceContainer container; // Check initial state ASSERT_BSONOBJ_EQ(match1->getQuery(), BSON("a" << 1)); ASSERT_BSONOBJ_EQ(match2->getQuery(), BSON("b" << 1)); ASSERT_BSONOBJ_EQ(match3->getQuery(), BSON("c" << 1)); container.push_back(match1); container.push_back(match2); match1->optimizeAt(container.begin(), &container); ASSERT_EQUALS(container.size(), 1U); ASSERT_BSONOBJ_EQ(match1->getQuery(), fromjson("{'$and': [{a:1}, {b:1}]}")); container.push_back(match3); match1->optimizeAt(container.begin(), &container); ASSERT_EQUALS(container.size(), 1U); ASSERT_BSONOBJ_EQ(match1->getQuery(), fromjson("{'$and': [{'$and': [{a:1}, {b:1}]}," "{c:1}]}")); }
TEST_F(DocumentSourceFacetTest, MultipleFacetsShouldSeeTheSameDocuments) { auto ctx = getExpCtx(); auto firstDummy = DocumentSourcePassthrough::create(); auto firstPipeline = uassertStatusOK(Pipeline::create({firstDummy}, ctx)); auto secondDummy = DocumentSourcePassthrough::create(); auto secondPipeline = uassertStatusOK(Pipeline::create({secondDummy}, ctx)); auto facetStage = DocumentSourceFacet::create({{"first", firstPipeline}, {"second", secondPipeline}}, ctx); deque<DocumentSource::GetNextResult> inputs = { Document{{"_id", 0}}, Document{{"_id", 1}}, Document{{"_id", 2}}}; auto mock = DocumentSourceMock::create(inputs); facetStage->setSource(mock.get()); auto output = facetStage->getNext(); // The output fields are in no guaranteed order. vector<Value> expectedOutputs; for (auto&& input : inputs) { expectedOutputs.emplace_back(input.releaseDocument()); } ASSERT(output.isAdvanced()); ASSERT_EQ(output.getDocument().size(), 2UL); ASSERT_VALUE_EQ(output.getDocument()["first"], Value(expectedOutputs)); ASSERT_VALUE_EQ(output.getDocument()["second"], Value(expectedOutputs)); // Should be exhausted now. ASSERT(facetStage->getNext().isEOF()); ASSERT(facetStage->getNext().isEOF()); ASSERT(facetStage->getNext().isEOF()); }
TEST_F(DocumentSourceFacetTest, SingleFacetShouldReceiveAllDocuments) { auto ctx = getExpCtx(); auto dummy = DocumentSourcePassthrough::create(); auto statusWithPipeline = Pipeline::create({dummy}, ctx); ASSERT_OK(statusWithPipeline.getStatus()); auto pipeline = std::move(statusWithPipeline.getValue()); auto facetStage = DocumentSourceFacet::create({{"results", pipeline}}, ctx); deque<DocumentSource::GetNextResult> inputs = { Document{{"_id", 0}}, Document{{"_id", 1}}, Document{{"_id", 2}}}; auto mock = DocumentSourceMock::create(inputs); facetStage->setSource(mock.get()); auto output = facetStage->getNext(); ASSERT(output.isAdvanced()); ASSERT_DOCUMENT_EQ(output.getDocument(), Document(fromjson("{results: [{_id: 0}, {_id: 1}, {_id: 2}]}"))); // Should be exhausted now. ASSERT(facetStage->getNext().isEOF()); ASSERT(facetStage->getNext().isEOF()); ASSERT(facetStage->getNext().isEOF()); }
TEST_F(DocumentSourceFacetTest, ShouldAcceptLegalSpecification) { auto ctx = getExpCtx(); auto spec = BSON("$facet" << BSON("a" << BSON_ARRAY(BSON("$skip" << 4)) << "b" << BSON_ARRAY(BSON("$limit" << 3)))); auto facetStage = DocumentSourceFacet::createFromBson(spec.firstElement(), ctx); ASSERT_TRUE(facetStage.get()); }
TEST_F(DocumentSourceMatchTest, CommentShouldNotAddAnyDependencies) { auto match = DocumentSourceMatch::create(fromjson("{$comment: 'misleading?'}"), getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceFacetTest, ShouldRejectNonArrayFacets) { auto ctx = getExpCtx(); auto spec = BSON("$facet" << BSON("a" << 1)); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); spec = BSON("$facet" << BSON("a" << BSON_ARRAY(BSON("$skip" << 4)) << "b" << 2)); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); }
TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithEmptyJSONSchema) { DepsTracker dependencies; auto query = fromjson("{$jsonSchema: {}}"); auto match = DocumentSourceMatch::create(query, getExpCtx()); ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceFacetTest, ShouldRejectFacetsWithStagesThatMustBeTheFirstStage) { auto ctx = getExpCtx(); auto spec = BSON("$facet" << BSON("a" << BSON_ARRAY(BSON("$indexStats" << BSONObj())))); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); spec = BSON("$facet" << BSON( "a" << BSON_ARRAY(BSON("$limit" << 1) << BSON("$indexStats" << BSONObj())))); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); }
TEST_F(DocumentSourceMatchTest, ShouldAddNotClausesFieldAsDependency) { auto match = DocumentSourceMatch::create(fromjson("{b: {$not: {$gte: 4}}}}"), getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.count("b")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithInternalSchemaType) { auto query = fromjson("{a: {$_internalSchemaType: 1}}"); auto match = DocumentSourceMatch::create(query, getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceMatchTest, ShouldAddWholeDocumentAsDependencyOfClausesWithInternalSchemaRootDocEq) { auto query = fromjson("{$_internalSchemaRootDocEq: {a: 1}}"); auto match = DocumentSourceMatch::create(query, getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(true, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceMatchTest, ShouldAddWholeDocumentAsDependencyOfClausesWithinInternalSchemaMaxProperties) { auto query = fromjson("{$_internalSchemaMaxProperties: 1}"); auto match = DocumentSourceMatch::create(query, getExpCtx()); DepsTracker dependencies1; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies1)); ASSERT_EQUALS(0U, dependencies1.fields.size()); ASSERT_EQUALS(true, dependencies1.needWholeDocument); ASSERT_EQUALS(false, dependencies1.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); query = fromjson("{a: {$_internalSchemaObjectMatch: {$_internalSchemaMaxProperties: 1}}}"); match = DocumentSourceMatch::create(query, getExpCtx()); DepsTracker dependencies2; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies2)); ASSERT_EQUALS(1U, dependencies2.fields.size()); ASSERT_EQUALS(1U, dependencies2.fields.count("a")); ASSERT_EQUALS(false, dependencies2.needWholeDocument); ASSERT_EQUALS(false, dependencies2.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceMatchTest, ShouldAddOuterFieldToDependenciesIfElemMatchContainsNoFieldNames) { auto match = DocumentSourceMatch::create(fromjson("{a: {$elemMatch: {$gt: 1, $lt: 5}}}"), getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceMatchTest, ShouldOnlyAddOuterFieldAsDependencyOfClausesWithinElemMatch) { auto match = DocumentSourceMatch::create(fromjson("{a: {$elemMatch: {c: {$gte: 4}}}}"), getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceMatchTest, ClauseAndedWithCommentShouldAddDependencies) { auto match = DocumentSourceMatch::create(fromjson("{a: 4, $comment: 'irrelevant'}"), getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceMatchTest, ShouldAddDependenciesOfClausesWithinElemMatchAsDottedPaths) { auto match = DocumentSourceMatch::create(fromjson("{a: {$elemMatch: {c: {$gte: 4}}}}"), getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DocumentSource::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.count("a.c")); ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(2U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedTextScore()); }
TEST_F(DocumentSourceMatchTest, ShouldAddDependenciesOfEachNorClause) { auto match = DocumentSourceMatch::create( fromjson("{$nor: [{'a.b': {$gte: 4}}, {'b.c': {$in: [1, 2]}}]}"), getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.count("a.b")); ASSERT_EQUALS(1U, dependencies.fields.count("b.c")); ASSERT_EQUALS(2U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceFacetTest, ShouldRejectFacetsContainingAFacetStage) { auto ctx = getExpCtx(); auto spec = fromjson("{$facet: {a: [{$facet: {a: [{$skip: 2}]}}]}}"); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); spec = fromjson("{$facet: {a: [{$skip: 2}, {$facet: {a: [{$skip: 2}]}}]}}"); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); spec = fromjson("{$facet: {a: [{$skip: 2}], b: [{$facet: {a: [{$skip: 2}]}}]}}"); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); }
TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForMultiplePredicatesWithJSONSchema) { DepsTracker dependencies; auto query = fromjson("{$jsonSchema: {properties: {a: {type: 'number'}}}, b: 1}"); auto match = DocumentSourceMatch::create(query, getExpCtx()); ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(2U, dependencies.fields.size()); ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.count("b")); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceFacetTest, ShouldRejectFacetsWithInvalidNames) { auto ctx = getExpCtx(); auto spec = BSON("$facet" << BSON("" << BSON_ARRAY(BSON("$skip" << 4)))); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); spec = BSON("$facet" << BSON("a.b" << BSON_ARRAY(BSON("$skip" << 4)))); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); spec = BSON("$facet" << BSON("$a" << BSON_ARRAY(BSON("$skip" << 4)))); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); }
TEST_F(DocumentSourceMatchTest, ShouldAddWholeDocumentAsDependencyOfClausesWithinInternalSchemaAllowedProperties) { auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: ['a', 'b']," "namePlaceholder: 'i', patternProperties: [], otherwise: {i: 0}}}"); auto match = DocumentSourceMatch::create(query, getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(true, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceMatchTest, ShouldCorrectlyJoinWithSubsequentMatch) { const auto match = DocumentSourceMatch::create(BSON("a" << 1), getExpCtx()); const auto secondMatch = DocumentSourceMatch::create(BSON("b" << 1), getExpCtx()); match->joinMatchWith(secondMatch); const auto mock = DocumentSourceMock::create({Document{{"a", 1}, {"b", 1}}, Document{{"a", 2}, {"b", 1}}, Document{{"a", 1}, {"b", 2}}, Document{{"a", 2}, {"b", 2}}}); match->setSource(mock.get()); // The first result should match. auto next = match->getNext(); ASSERT_TRUE(next.isAdvanced()); ASSERT_DOCUMENT_EQ(next.releaseDocument(), (Document{{"a", 1}, {"b", 1}})); // The rest should not match. ASSERT_TRUE(match->getNext().isEOF()); ASSERT_TRUE(match->getNext().isEOF()); ASSERT_TRUE(match->getNext().isEOF()); }
TEST_F(DocumentSourceMatchTest, ShouldOnlyAddOuterFieldAsDependencyOfClausesWithinInternalSchemaObjectMatch) { auto query = fromjson( " {a: {$_internalSchemaObjectMatch: {" " b: {$_internalSchemaObjectMatch: {" " $or: [{c: {$type: 'string'}}, {c: {$gt: 0}}]" " }}}" " }}}"); auto match = DocumentSourceMatch::create(query, getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceFacetTest, ShouldRejectFacetsContainingAnOutStage) { auto ctx = getExpCtx(); auto spec = BSON("$facet" << BSON("a" << BSON_ARRAY(BSON("$out" << "out_collection")))); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); spec = BSON("$facet" << BSON("a" << BSON_ARRAY(BSON("$skip" << 1) << BSON("$out" << "out_collection")))); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); spec = BSON("$facet" << BSON("a" << BSON_ARRAY(BSON("$out" << "out_collection") << BSON("$skip" << 1)))); ASSERT_THROWS(DocumentSourceFacet::createFromBson(spec.firstElement(), ctx), UserException); }
TEST_F(DocumentSourceFacetTest, ShouldBeAbleToEvaluateMultipleStagesWithinOneSubPipeline) { auto ctx = getExpCtx(); auto firstDummy = DocumentSourcePassthrough::create(); auto secondDummy = DocumentSourcePassthrough::create(); auto pipeline = uassertStatusOK(Pipeline::create({firstDummy, secondDummy}, ctx)); auto facetStage = DocumentSourceFacet::create({{"subPipe", pipeline}}, ctx); deque<DocumentSource::GetNextResult> inputs = {Document{{"_id", 0}}, Document{{"_id", 1}}}; auto mock = DocumentSourceMock::create(inputs); facetStage->setSource(mock.get()); auto output = facetStage->getNext(); ASSERT(output.isAdvanced()); ASSERT_DOCUMENT_EQ(output.getDocument(), Document(fromjson("{subPipe: [{_id: 0}, {_id: 1}]}"))); }
TEST_F(DocumentSourceMatchTest, ShouldPropagatePauses) { auto match = DocumentSourceMatch::create(BSON("a" << 1), getExpCtx()); auto mock = DocumentSourceMock::create({DocumentSource::GetNextResult::makePauseExecution(), Document{{"a", 1}}, DocumentSource::GetNextResult::makePauseExecution(), Document{{"a", 2}}, Document{{"a", 2}}, DocumentSource::GetNextResult::makePauseExecution(), Document{{"a", 1}}}); match->setSource(mock.get()); ASSERT_TRUE(match->getNext().isPaused()); ASSERT_TRUE(match->getNext().isAdvanced()); ASSERT_TRUE(match->getNext().isPaused()); // {a: 2} doesn't match, should go directly to the next pause. ASSERT_TRUE(match->getNext().isPaused()); ASSERT_TRUE(match->getNext().isAdvanced()); ASSERT_TRUE(match->getNext().isEOF()); ASSERT_TRUE(match->getNext().isEOF()); ASSERT_TRUE(match->getNext().isEOF()); }
TEST_F(DocumentSourceFacetTest, ShouldCorrectlyHandleSubPipelinesYieldingDifferentNumbersOfResults) { auto ctx = getExpCtx(); auto passthrough = DocumentSourcePassthrough::create(); auto passthroughPipe = uassertStatusOK(Pipeline::create({passthrough}, ctx)); auto limit = DocumentSourceLimit::create(ctx, 1); auto limitedPipe = uassertStatusOK(Pipeline::create({limit}, ctx)); auto facetStage = DocumentSourceFacet::create({{"all", passthroughPipe}, {"first", limitedPipe}}, ctx); deque<DocumentSource::GetNextResult> inputs = { Document{{"_id", 0}}, Document{{"_id", 1}}, Document{{"_id", 2}}, Document{{"_id", 3}}}; auto mock = DocumentSourceMock::create(inputs); facetStage->setSource(mock.get()); vector<Value> expectedPassthroughOutput; for (auto&& input : inputs) { expectedPassthroughOutput.emplace_back(input.getDocument()); } auto output = facetStage->getNext(); // The output fields are in no guaranteed order. ASSERT(output.isAdvanced()); ASSERT_EQ(output.getDocument().size(), 2UL); ASSERT_VALUE_EQ(output.getDocument()["all"], Value(expectedPassthroughOutput)); ASSERT_VALUE_EQ(output.getDocument()["first"], Value(vector<Value>{Value(expectedPassthroughOutput.front())})); // Should be exhausted now. ASSERT(facetStage->getNext().isEOF()); ASSERT(facetStage->getNext().isEOF()); ASSERT(facetStage->getNext().isEOF()); }
// The first result should match. auto next = match->getNext(); ASSERT_TRUE(next.isAdvanced()); ASSERT_DOCUMENT_EQ(next.releaseDocument(), (Document{{"a", 1}, {"b", 1}})); // The rest should not match. ASSERT_TRUE(match->getNext().isEOF()); ASSERT_TRUE(match->getNext().isEOF()); ASSERT_TRUE(match->getNext().isEOF()); } DEATH_TEST_F(DocumentSourceMatchTest, ShouldFailToDescendExpressionOnPathThatIsNotACommonPrefix, "Invariant failure expression::isPathPrefixOf") { const auto expCtx = getExpCtx(); const auto matchSpec = BSON("a.b" << 1 << "b.c" << 1); const auto matchExpression = unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx)); DocumentSourceMatch::descendMatchOnPath(matchExpression.get(), "a", expCtx); } DEATH_TEST_F(DocumentSourceMatchTest, ShouldFailToDescendExpressionOnPathThatContainsElemMatchWithObject, "Invariant failure node->matchType()") { const auto expCtx = getExpCtx(); const auto matchSpec = BSON("a" << BSON("$elemMatch" << BSON("a.b" << 1))); const auto matchExpression = unittest::assertGet(MatchExpressionParser::parse(matchSpec, expCtx)); BSONObjBuilder out; matchExpression->serialize(&out);
TEST_F(DocumentSourceMatchTest, TextSearchShouldRequireWholeDocumentAndTextScore) { auto match = DocumentSourceMatch::create(fromjson("{$text: {$search: 'hello'} }"), getExpCtx()); DepsTracker dependencies(DepsTracker::MetadataAvailable::kTextScore); ASSERT_EQUALS(DepsTracker::State::EXHAUSTIVE_FIELDS, match->getDependencies(&dependencies)); ASSERT_EQUALS(true, dependencies.needWholeDocument); ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }
TEST_F(DocumentSourceMatchTest, ShouldOnlyAddOuterFieldAsDependencyOfImplicitEqualityPredicate) { // Parses to {a: {$eq: {notAField: {$gte: 4}}}}. auto match = DocumentSourceMatch::create(fromjson("{a: {notAField: {$gte: 4}}}"), getExpCtx()); DepsTracker dependencies; ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); }