summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/index/sort_key_generator.cpp4
-rw-r--r--src/mongo/db/pipeline/document_metadata_fields.cpp32
-rw-r--r--src/mongo/db/pipeline/document_metadata_fields.h77
-rw-r--r--src/mongo/db/pipeline/document_value_test.cpp2
-rw-r--r--src/mongo/db/pipeline/expression.cpp107
-rw-r--r--src/mongo/db/pipeline/expression.h14
-rw-r--r--src/mongo/db/pipeline/expression_test.cpp87
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 {