diff options
author | Ian Boros <ian.boros@mongodb.com> | 2019-08-21 18:00:26 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-08-21 18:00:26 +0000 |
commit | d0662ae08dfff18472f5e91a3baee3687a33d7ea (patch) | |
tree | 22e5d53d18deb8179085ab64f533356bb01eb2bf | |
parent | 8775c15cca254796fa558312da1aa365912a2050 (diff) | |
download | mongo-d0662ae08dfff18472f5e91a3baee3687a33d7ea.tar.gz |
SERVER-42418 Allow ExpressionMeta to parse find() meta options
-rw-r--r-- | src/mongo/db/index/sort_key_generator.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_metadata_fields.cpp | 32 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_metadata_fields.h | 77 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_value_test.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.cpp | 107 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.h | 14 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_test.cpp | 87 |
7 files changed, 237 insertions, 86 deletions
diff --git a/src/mongo/db/index/sort_key_generator.cpp b/src/mongo/db/index/sort_key_generator.cpp index d47308c5e62..67f57d58a60 100644 --- a/src/mongo/db/index/sort_key_generator.cpp +++ b/src/mongo/db/index/sort_key_generator.cpp @@ -135,11 +135,11 @@ StatusWith<BSONObj> SortKeyGenerator::getSortKeyFromDocument(const BSONObj& obj, } invariant(part.expression); switch (part.expression->getMetaType()) { - case ExpressionMeta::MetaType::TEXT_SCORE: { + case DocumentMetadataFields::MetaType::kTextScore: { mergedKeyBob.append("", metadata->textScore); continue; } - case ExpressionMeta::MetaType::RAND_VAL: { + case DocumentMetadataFields::MetaType::kRandVal: { mergedKeyBob.append("", metadata->randVal); continue; } diff --git a/src/mongo/db/pipeline/document_metadata_fields.cpp b/src/mongo/db/pipeline/document_metadata_fields.cpp index bfca826cb8d..3116695af3a 100644 --- a/src/mongo/db/pipeline/document_metadata_fields.cpp +++ b/src/mongo/db/pipeline/document_metadata_fields.cpp @@ -133,35 +133,35 @@ void DocumentMetadataFields::serializeForSorter(BufBuilder& buf) const { } if (hasTextScore()) { - buf.appendNum(static_cast<char>(MetaType::TEXT_SCORE + 1)); + buf.appendNum(static_cast<char>(MetaType::kTextScore + 1)); buf.appendNum(getTextScore()); } if (hasRandVal()) { - buf.appendNum(static_cast<char>(MetaType::RAND_VAL + 1)); + buf.appendNum(static_cast<char>(MetaType::kRandVal + 1)); buf.appendNum(getRandVal()); } if (hasSortKey()) { - buf.appendNum(static_cast<char>(MetaType::SORT_KEY + 1)); + buf.appendNum(static_cast<char>(MetaType::kSortKey + 1)); getSortKey().appendSelfToBufBuilder(buf); } if (hasGeoNearDistance()) { - buf.appendNum(static_cast<char>(MetaType::GEONEAR_DIST + 1)); + buf.appendNum(static_cast<char>(MetaType::kGeoNearDist + 1)); buf.appendNum(getGeoNearDistance()); } if (hasGeoNearPoint()) { - buf.appendNum(static_cast<char>(MetaType::GEONEAR_POINT + 1)); + buf.appendNum(static_cast<char>(MetaType::kGeoNearPoint + 1)); getGeoNearPoint().serializeForSorter(buf); } if (hasSearchScore()) { - buf.appendNum(static_cast<char>(MetaType::SEARCH_SCORE + 1)); + buf.appendNum(static_cast<char>(MetaType::kSearchScore + 1)); buf.appendNum(getSearchScore()); } if (hasSearchHighlights()) { - buf.appendNum(static_cast<char>(MetaType::SEARCH_HIGHLIGHTS + 1)); + buf.appendNum(static_cast<char>(MetaType::kSearchHighlights + 1)); getSearchHighlights().serializeForSorter(buf); } if (hasIndexKey()) { - buf.appendNum(static_cast<char>(MetaType::INDEX_KEY + 1)); + buf.appendNum(static_cast<char>(MetaType::kIndexKey + 1)); getIndexKey().appendSelfToBufBuilder(buf); } buf.appendNum(static_cast<char>(0)); @@ -171,24 +171,24 @@ void DocumentMetadataFields::deserializeForSorter(BufReader& buf, DocumentMetada invariant(out); while (char marker = buf.read<char>()) { - if (marker == static_cast<char>(MetaType::TEXT_SCORE) + 1) { + if (marker == static_cast<char>(MetaType::kTextScore) + 1) { out->setTextScore(buf.read<LittleEndian<double>>()); - } else if (marker == static_cast<char>(MetaType::RAND_VAL) + 1) { + } else if (marker == static_cast<char>(MetaType::kRandVal) + 1) { out->setRandVal(buf.read<LittleEndian<double>>()); - } else if (marker == static_cast<char>(MetaType::SORT_KEY) + 1) { + } else if (marker == static_cast<char>(MetaType::kSortKey) + 1) { out->setSortKey( BSONObj::deserializeForSorter(buf, BSONObj::SorterDeserializeSettings())); - } else if (marker == static_cast<char>(MetaType::GEONEAR_DIST) + 1) { + } else if (marker == static_cast<char>(MetaType::kGeoNearDist) + 1) { out->setGeoNearDistance(buf.read<LittleEndian<double>>()); - } else if (marker == static_cast<char>(MetaType::GEONEAR_POINT) + 1) { + } else if (marker == static_cast<char>(MetaType::kGeoNearPoint) + 1) { out->setGeoNearPoint( Value::deserializeForSorter(buf, Value::SorterDeserializeSettings())); - } else if (marker == static_cast<char>(MetaType::SEARCH_SCORE) + 1) { + } else if (marker == static_cast<char>(MetaType::kSearchScore) + 1) { out->setSearchScore(buf.read<LittleEndian<double>>()); - } else if (marker == static_cast<char>(MetaType::SEARCH_HIGHLIGHTS) + 1) { + } else if (marker == static_cast<char>(MetaType::kSearchHighlights) + 1) { out->setSearchHighlights( Value::deserializeForSorter(buf, Value::SorterDeserializeSettings())); - } else if (marker == static_cast<char>(MetaType::INDEX_KEY) + 1) { + } else if (marker == static_cast<char>(MetaType::kIndexKey) + 1) { out->setIndexKey( BSONObj::deserializeForSorter(buf, BSONObj::SorterDeserializeSettings())); } else { diff --git a/src/mongo/db/pipeline/document_metadata_fields.h b/src/mongo/db/pipeline/document_metadata_fields.h index 95c11284580..a759d77406b 100644 --- a/src/mongo/db/pipeline/document_metadata_fields.h +++ b/src/mongo/db/pipeline/document_metadata_fields.h @@ -33,6 +33,7 @@ #include "mongo/bson/bsonobj.h" #include "mongo/db/pipeline/value.h" +#include "mongo/db/record_id.h" namespace mongo { @@ -54,17 +55,18 @@ namespace mongo { class DocumentMetadataFields { public: enum MetaType : char { - TEXT_SCORE, - RAND_VAL, - SORT_KEY, - GEONEAR_DIST, - GEONEAR_POINT, - SEARCH_SCORE, - SEARCH_HIGHLIGHTS, - INDEX_KEY, - - // New fields must be added before the NUM_FIELDS sentinel. - NUM_FIELDS + kGeoNearDist, + kGeoNearPoint, + kIndexKey, + kRandVal, + kRecordId, + kSearchHighlights, + kSearchScore, + kSortKey, + kTextScore, + + // New fields must be added before the kNumFields sentinel. + kNumFields }; /** @@ -115,7 +117,7 @@ public: } bool hasTextScore() const { - return _holder && _holder->metaFields.test(MetaType::TEXT_SCORE); + return _holder && _holder->metaFields.test(MetaType::kTextScore); } double getTextScore() const { @@ -128,12 +130,12 @@ public: _holder = std::make_unique<MetadataHolder>(); } - _holder->metaFields.set(MetaType::TEXT_SCORE); + _holder->metaFields.set(MetaType::kTextScore); _holder->textScore = score; } bool hasRandVal() const { - return _holder && _holder->metaFields.test(MetaType::RAND_VAL); + return _holder && _holder->metaFields.test(MetaType::kRandVal); } double getRandVal() const { @@ -146,12 +148,12 @@ public: _holder = std::make_unique<MetadataHolder>(); } - _holder->metaFields.set(MetaType::RAND_VAL); + _holder->metaFields.set(MetaType::kRandVal); _holder->randVal = val; } bool hasSortKey() const { - return _holder && _holder->metaFields.test(MetaType::SORT_KEY); + return _holder && _holder->metaFields.test(MetaType::kSortKey); } BSONObj getSortKey() const { @@ -164,12 +166,12 @@ public: _holder = std::make_unique<MetadataHolder>(); } - _holder->metaFields.set(MetaType::SORT_KEY); + _holder->metaFields.set(MetaType::kSortKey); _holder->sortKey = sortKey.getOwned(); } bool hasGeoNearDistance() const { - return _holder && _holder->metaFields.test(MetaType::GEONEAR_DIST); + return _holder && _holder->metaFields.test(MetaType::kGeoNearDist); } double getGeoNearDistance() const { @@ -182,12 +184,12 @@ public: _holder = std::make_unique<MetadataHolder>(); } - _holder->metaFields.set(MetaType::GEONEAR_DIST); + _holder->metaFields.set(MetaType::kGeoNearDist); _holder->geoNearDistance = dist; } bool hasGeoNearPoint() const { - return _holder && _holder->metaFields.test(MetaType::GEONEAR_POINT); + return _holder && _holder->metaFields.test(MetaType::kGeoNearPoint); } Value getGeoNearPoint() const { @@ -200,12 +202,12 @@ public: _holder = std::make_unique<MetadataHolder>(); } - _holder->metaFields.set(MetaType::GEONEAR_POINT); + _holder->metaFields.set(MetaType::kGeoNearPoint); _holder->geoNearPoint = std::move(point); } bool hasSearchScore() const { - return _holder && _holder->metaFields.test(MetaType::SEARCH_SCORE); + return _holder && _holder->metaFields.test(MetaType::kSearchScore); } double getSearchScore() const { @@ -218,12 +220,12 @@ public: _holder = std::make_unique<MetadataHolder>(); } - _holder->metaFields.set(MetaType::SEARCH_SCORE); + _holder->metaFields.set(MetaType::kSearchScore); _holder->searchScore = score; } bool hasSearchHighlights() const { - return _holder && _holder->metaFields.test(MetaType::SEARCH_HIGHLIGHTS); + return _holder && _holder->metaFields.test(MetaType::kSearchHighlights); } Value getSearchHighlights() const { @@ -236,12 +238,12 @@ public: _holder = std::make_unique<MetadataHolder>(); } - _holder->metaFields.set(MetaType::SEARCH_HIGHLIGHTS); + _holder->metaFields.set(MetaType::kSearchHighlights); _holder->searchHighlights = highlights; } bool hasIndexKey() const { - return _holder && _holder->metaFields.test(MetaType::INDEX_KEY); + return _holder && _holder->metaFields.test(MetaType::kIndexKey); } BSONObj getIndexKey() const { @@ -254,16 +256,34 @@ public: _holder = std::make_unique<MetadataHolder>(); } - _holder->metaFields.set(MetaType::INDEX_KEY); + _holder->metaFields.set(MetaType::kIndexKey); _holder->indexKey = indexKey.getOwned(); } + bool hasRecordId() const { + return _holder && _holder->metaFields.test(MetaType::kRecordId); + } + + RecordId getRecordId() const { + invariant(hasRecordId()); + return _holder->recordId; + } + + void setRecordId(RecordId rid) { + if (!_holder) { + _holder = std::make_unique<MetadataHolder>(); + } + + _holder->metaFields.set(MetaType::kRecordId); + _holder->recordId = rid; + } + void serializeForSorter(BufBuilder& buf) const; private: // A simple data struct housing all possible metadata fields. struct MetadataHolder { - std::bitset<MetaType::NUM_FIELDS> metaFields; + std::bitset<MetaType::kNumFields> metaFields; double textScore{0.0}; double randVal{0.0}; BSONObj sortKey; @@ -272,6 +292,7 @@ private: double searchScore{0.0}; Value searchHighlights; BSONObj indexKey; + RecordId recordId; }; // Null until the first setter is called, at which point a MetadataHolder struct is allocated. diff --git a/src/mongo/db/pipeline/document_value_test.cpp b/src/mongo/db/pipeline/document_value_test.cpp index e2910347e8f..0ae1e1fd377 100644 --- a/src/mongo/db/pipeline/document_value_test.cpp +++ b/src/mongo/db/pipeline/document_value_test.cpp @@ -746,7 +746,7 @@ TEST(MetaFields, BadSerialization) { // Signal there are 0 fields. bb.appendNum(0); // This would specify a meta field with an invalid type. - bb.appendNum(char(DocumentMetadataFields::MetaType::NUM_FIELDS) + 1); + bb.appendNum(char(DocumentMetadataFields::MetaType::kNumFields) + 1); // Signals end of input. bb.appendNum(char(0)); BufReader reader(bb.buf(), bb.len()); diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index 54b2b9f9933..674e7a5d718 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -1,4 +1,3 @@ - /** * Copyright (C) 2018-present MongoDB, Inc. * @@ -2524,19 +2523,54 @@ Expression::ComputedPaths ExpressionMap::getComputedPaths(const std::string& exp /* ------------------------- ExpressionMeta ----------------------------- */ REGISTER_EXPRESSION(meta, ExpressionMeta::parse); + +namespace { +const std::string textScoreName = "textScore"; +const std::string randValName = "randVal"; +const std::string searchScoreName = "searchScore"; +const std::string searchHighlightsName = "searchHighlights"; +const std::string geoNearDistanceName = "geoNearDistance"; +const std::string geoNearPointName = "geoNearPoint"; +const std::string recordIdName = "recordId"; +const std::string indexKeyName = "indexKey"; +const std::string sortKeyName = "sortKey"; + +using MetaType = DocumentMetadataFields::MetaType; +const StringMap<DocumentMetadataFields::MetaType> kMetaNameToMetaType = { + {geoNearDistanceName, MetaType::kGeoNearDist}, + {geoNearPointName, MetaType::kGeoNearPoint}, + {indexKeyName, MetaType::kIndexKey}, + {randValName, MetaType::kRandVal}, + {recordIdName, MetaType::kRecordId}, + {searchHighlightsName, MetaType::kSearchHighlights}, + {searchScoreName, MetaType::kSearchScore}, + {sortKeyName, MetaType::kSortKey}, + {textScoreName, MetaType::kTextScore}, +}; + +const stdx::unordered_map<DocumentMetadataFields::MetaType, StringData> kMetaTypeToMetaName = { + {MetaType::kGeoNearDist, geoNearDistanceName}, + {MetaType::kGeoNearPoint, geoNearPointName}, + {MetaType::kIndexKey, indexKeyName}, + {MetaType::kRandVal, randValName}, + {MetaType::kRecordId, recordIdName}, + {MetaType::kSearchHighlights, searchHighlightsName}, + {MetaType::kSearchScore, searchScoreName}, + {MetaType::kSortKey, sortKeyName}, + {MetaType::kTextScore, textScoreName}, +}; + +} // namespace + intrusive_ptr<Expression> ExpressionMeta::parse( const boost::intrusive_ptr<ExpressionContext>& expCtx, BSONElement expr, const VariablesParseState& vpsIn) { uassert(17307, "$meta only supports string arguments", expr.type() == String); - if (expr.valueStringData() == "textScore") { - return new ExpressionMeta(expCtx, MetaType::TEXT_SCORE); - } else if (expr.valueStringData() == "randVal") { - return new ExpressionMeta(expCtx, MetaType::RAND_VAL); - } else if (expr.valueStringData() == "searchScore") { - return new ExpressionMeta(expCtx, MetaType::SEARCH_SCORE); - } else if (expr.valueStringData() == "searchHighlights") { - return new ExpressionMeta(expCtx, MetaType::SEARCH_HIGHLIGHTS); + + const auto iter = kMetaNameToMetaType.find(expr.valueStringData()); + if (iter != kMetaNameToMetaType.end()) { + return new ExpressionMeta(expCtx, iter->second); } else { uasserted(17308, "Unsupported argument to $meta: " + expr.String()); } @@ -2547,44 +2581,59 @@ ExpressionMeta::ExpressionMeta(const boost::intrusive_ptr<ExpressionContext>& ex : Expression(expCtx), _metaType(metaType) {} Value ExpressionMeta::serialize(bool explain) const { - switch (_metaType) { - case MetaType::TEXT_SCORE: - return Value(DOC("$meta" - << "textScore"_sd)); - case MetaType::RAND_VAL: - return Value(DOC("$meta" - << "randVal"_sd)); - case MetaType::SEARCH_SCORE: - return Value(DOC("$meta" - << "searchScore"_sd)); - case MetaType::SEARCH_HIGHLIGHTS: - return Value(DOC("$meta" - << "searchHighlights"_sd)); - } - MONGO_UNREACHABLE; + const auto nameIter = kMetaTypeToMetaName.find(_metaType); + invariant(nameIter != kMetaTypeToMetaName.end()); + return Value(DOC("$meta" << nameIter->second)); } Value ExpressionMeta::evaluate(const Document& root, Variables* variables) const { const auto& metadata = root.metadata(); switch (_metaType) { - case MetaType::TEXT_SCORE: + case MetaType::kTextScore: return metadata.hasTextScore() ? Value(metadata.getTextScore()) : Value(); - case MetaType::RAND_VAL: + case MetaType::kRandVal: return metadata.hasRandVal() ? Value(metadata.getRandVal()) : Value(); - case MetaType::SEARCH_SCORE: + case MetaType::kSearchScore: return metadata.hasSearchScore() ? Value(metadata.getSearchScore()) : Value(); - case MetaType::SEARCH_HIGHLIGHTS: + case MetaType::kSearchHighlights: return metadata.hasSearchHighlights() ? Value(metadata.getSearchHighlights()) : Value(); + case MetaType::kGeoNearDist: + return metadata.hasGeoNearDistance() ? Value(metadata.getGeoNearDistance()) : Value(); + case MetaType::kGeoNearPoint: + return metadata.hasGeoNearPoint() ? Value(metadata.getGeoNearPoint()) : Value(); + case MetaType::kRecordId: + // Be sure that a RecordId can be represented by a long long. + static_assert(RecordId::kMinRepr >= std::numeric_limits<long long>::min()); + static_assert(RecordId::kMaxRepr <= std::numeric_limits<long long>::max()); + return metadata.hasRecordId() + ? Value{static_cast<long long>(metadata.getRecordId().repr())} + : Value(); + case MetaType::kIndexKey: + return metadata.hasIndexKey() ? Value(metadata.getIndexKey()) : Value(); + case MetaType::kSortKey: + return metadata.hasSortKey() ? Value(metadata.getSortKey()) : Value(); + default: + MONGO_UNREACHABLE; } MONGO_UNREACHABLE; } void ExpressionMeta::_doAddDependencies(DepsTracker* deps) const { - if (_metaType == MetaType::TEXT_SCORE) { + if (_metaType == MetaType::kTextScore) { deps->setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, true); // We do not add the dependencies for SEARCH_SCORE or SEARCH_HIGHLIGHTS because those values // are not stored in the collection (or in mongod at all). + } else if (_metaType == MetaType::kGeoNearDist) { + deps->setNeedsMetadata(DepsTracker::MetadataType::GEO_NEAR_DISTANCE, true); + } else if (_metaType == MetaType::kGeoNearPoint) { + deps->setNeedsMetadata(DepsTracker::MetadataType::GEO_NEAR_POINT, true); + } else if (_metaType == MetaType::kRecordId) { + // TODO: SERVER-42560 handle passing of metadata between PlanStage and DS layers. + } else if (_metaType == MetaType::kIndexKey) { + // TODO: SERVER-42560 handle passing of metadata between PlanStage and DS layers. + } else if (_metaType == MetaType::kSortKey) { + deps->setNeedsMetadata(DepsTracker::MetadataType::SORT_KEY, true); } } diff --git a/src/mongo/db/pipeline/expression.h b/src/mongo/db/pipeline/expression.h index 641d35d5aa4..8c8bbc54ae9 100644 --- a/src/mongo/db/pipeline/expression.h +++ b/src/mongo/db/pipeline/expression.h @@ -1642,13 +1642,6 @@ private: class ExpressionMeta final : public Expression { public: - enum MetaType { - TEXT_SCORE, - RAND_VAL, - SEARCH_SCORE, - SEARCH_HIGHLIGHTS, - }; - Value serialize(bool explain) const final; Value evaluate(const Document& root, Variables* variables) const final; @@ -1661,7 +1654,7 @@ public: return visitor->visit(this); } - MetaType getMetaType() { + DocumentMetadataFields::MetaType getMetaType() { return _metaType; } @@ -1669,9 +1662,10 @@ protected: void _doAddDependencies(DepsTracker* deps) const final; private: - ExpressionMeta(const boost::intrusive_ptr<ExpressionContext>& expCtx, MetaType metaType); + ExpressionMeta(const boost::intrusive_ptr<ExpressionContext>& expCtx, + DocumentMetadataFields::MetaType metaType); - MetaType _metaType; + DocumentMetadataFields::MetaType _metaType; }; class ExpressionMillisecond final : public DateExpressionAcceptingTimeZone<ExpressionMillisecond> { diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp index 5183ff386b0..38b676067f4 100644 --- a/src/mongo/db/pipeline/expression_test.cpp +++ b/src/mongo/db/pipeline/expression_test.cpp @@ -6153,6 +6153,93 @@ TEST(ExpressionMetaTest, ExpressionMetaSearchHighlights) { Value val = expressionMeta->evaluate(doc.freeze(), &expCtx->variables); ASSERT_DOCUMENT_EQ(val.getDocument(), highlights); } + +TEST(ExpressionMetaTest, ExpressionMetaGeoNearDistance) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + BSONObj expr = fromjson("{$meta: \"geoNearDistance\"}"); + auto expressionMeta = + ExpressionMeta::parse(expCtx, expr.firstElement(), expCtx->variablesParseState); + + MutableDocument doc; + doc.metadata().setGeoNearDistance(1.23); + Value val = expressionMeta->evaluate(doc.freeze(), &expCtx->variables); + ASSERT_EQ(val.getDouble(), 1.23); +} + +TEST(ExpressionMetaTest, ExpressionMetaGeoNearPoint) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + BSONObj expr = fromjson("{$meta: \"geoNearPoint\"}"); + auto expressionMeta = + ExpressionMeta::parse(expCtx, expr.firstElement(), expCtx->variablesParseState); + + MutableDocument doc; + Document pointDoc = Document{fromjson("{some: 'document'}")}; + doc.metadata().setGeoNearPoint(Value(pointDoc)); + Value val = expressionMeta->evaluate(doc.freeze(), &expCtx->variables); + ASSERT_DOCUMENT_EQ(val.getDocument(), pointDoc); +} + +TEST(ExpressionMetaTest, ExpressionMetaIndexKey) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + BSONObj expr = fromjson("{$meta: \"indexKey\"}"); + auto expressionMeta = + ExpressionMeta::parse(expCtx, expr.firstElement(), expCtx->variablesParseState); + + MutableDocument doc; + BSONObj ixKey = fromjson("{'': 1, '': 'string'}"); + doc.metadata().setIndexKey(ixKey); + Value val = expressionMeta->evaluate(doc.freeze(), &expCtx->variables); + ASSERT_DOCUMENT_EQ(val.getDocument(), Document(ixKey)); +} + +TEST(ExpressionMetaTest, ExpressionMetaRecordId) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + BSONObj expr = fromjson("{$meta: \"recordId\"}"); + auto expressionMeta = + ExpressionMeta::parse(expCtx, expr.firstElement(), expCtx->variablesParseState); + + MutableDocument doc; + doc.metadata().setRecordId(RecordId(123LL)); + Value val = expressionMeta->evaluate(doc.freeze(), &expCtx->variables); + ASSERT_EQ(val.getLong(), 123LL); +} + +TEST(ExpressionMetaTest, ExpressionMetaRandVal) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + BSONObj expr = fromjson("{$meta: \"randVal\"}"); + auto expressionMeta = + ExpressionMeta::parse(expCtx, expr.firstElement(), expCtx->variablesParseState); + + MutableDocument doc; + doc.metadata().setRandVal(1.23); + Value val = expressionMeta->evaluate(doc.freeze(), &expCtx->variables); + ASSERT_EQ(val.getDouble(), 1.23); +} + +TEST(ExpressionMetaTest, ExpressionMetaSortKey) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + BSONObj expr = fromjson("{$meta: \"sortKey\"}"); + auto expressionMeta = + ExpressionMeta::parse(expCtx, expr.firstElement(), expCtx->variablesParseState); + + MutableDocument doc; + BSONObj sortKey = BSON("" << 1 << "" << 2); + doc.metadata().setSortKey(sortKey); + Value val = expressionMeta->evaluate(doc.freeze(), &expCtx->variables); + ASSERT_DOCUMENT_EQ(val.getDocument(), Document(sortKey)); +} + +TEST(ExpressionMetaTest, ExpressionMetaTextScore) { + intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + BSONObj expr = fromjson("{$meta: \"textScore\"}"); + auto expressionMeta = + ExpressionMeta::parse(expCtx, expr.firstElement(), expCtx->variablesParseState); + + MutableDocument doc; + doc.metadata().setTextScore(1.23); + Value val = expressionMeta->evaluate(doc.freeze(), &expCtx->variables); + ASSERT_EQ(val.getDouble(), 1.23); +} } // namespace expression_meta_test namespace ExpressionRegexTest { |