summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/pipeline')
-rw-r--r--src/mongo/db/pipeline/SConscript2
-rw-r--r--src/mongo/db/pipeline/expression.cpp29
-rw-r--r--src/mongo/db/pipeline/expression.h22
-rw-r--r--src/mongo/db/pipeline/expression_test.cpp79
-rw-r--r--src/mongo/db/pipeline/expression_visitor.h2
5 files changed, 134 insertions, 0 deletions
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript
index 71f7524be9c..1929babc330 100644
--- a/src/mongo/db/pipeline/SConscript
+++ b/src/mongo/db/pipeline/SConscript
@@ -83,6 +83,7 @@ env.Library(
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/db/vector_clock',
+ '$BUILD_DIR/mongo/db/mongohasher',
],
)
@@ -392,6 +393,7 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/db/cst/cst',
'$BUILD_DIR/mongo/db/exec/document_value/document_value',
'$BUILD_DIR/mongo/db/exec/document_value/document_value_test_util',
+ '$BUILD_DIR/mongo/db/mongohasher',
'$BUILD_DIR/mongo/db/query/collation/collator_interface_mock',
'$BUILD_DIR/mongo/db/query/query_test_service_context',
'$BUILD_DIR/mongo/db/repl/oplog_entry',
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp
index 8c5ef56f5f2..71d24d13528 100644
--- a/src/mongo/db/pipeline/expression.cpp
+++ b/src/mongo/db/pipeline/expression.cpp
@@ -42,6 +42,7 @@
#include "mongo/db/commands/feature_compatibility_version_documentation.h"
#include "mongo/db/exec/document_value/document.h"
#include "mongo/db/exec/document_value/value.h"
+#include "mongo/db/hasher.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/pipeline/expression_context.h"
#include "mongo/db/query/datetime/date_time_support.h"
@@ -6481,4 +6482,32 @@ void ExpressionRandom::_doAddDependencies(DepsTracker* deps) const {
Value ExpressionRandom::serialize(const bool explain) const {
return Value(DOC(getOpName() << Document()));
}
+
+/* ------------------------- ExpressionToHashedIndexKey -------------------------- */
+REGISTER_EXPRESSION(toHashedIndexKey, ExpressionToHashedIndexKey::parse);
+
+boost::intrusive_ptr<Expression> ExpressionToHashedIndexKey::parse(ExpressionContext* const expCtx,
+ BSONElement expr,
+ const VariablesParseState& vps) {
+ return make_intrusive<ExpressionToHashedIndexKey>(expCtx, parseOperand(expCtx, expr, vps));
+}
+
+Value ExpressionToHashedIndexKey::evaluate(const Document& root, Variables* variables) const {
+ Value inpVal(_children[0]->evaluate(root, variables));
+ if (inpVal.missing()) {
+ inpVal = Value(BSONNULL);
+ }
+
+ return Value(BSONElementHasher::hash64(BSON("" << inpVal).firstElement(),
+ BSONElementHasher::DEFAULT_HASH_SEED));
+}
+
+Value ExpressionToHashedIndexKey::serialize(bool explain) const {
+ return Value(DOC("$toHashedIndexKey" << _children[0]->serialize(explain)));
+}
+
+void ExpressionToHashedIndexKey::_doAddDependencies(DepsTracker* deps) const {
+ // Nothing to do
+}
+
} // namespace mongo
diff --git a/src/mongo/db/pipeline/expression.h b/src/mongo/db/pipeline/expression.h
index 862a6a31da6..32b47f4562a 100644
--- a/src/mongo/db/pipeline/expression.h
+++ b/src/mongo/db/pipeline/expression.h
@@ -2908,4 +2908,26 @@ private:
double getRandomValue() const;
};
+
+class ExpressionToHashedIndexKey : public Expression {
+public:
+ ExpressionToHashedIndexKey(ExpressionContext* const expCtx,
+ boost::intrusive_ptr<Expression> inputExpression)
+ : Expression(expCtx, {inputExpression}){};
+
+ static boost::intrusive_ptr<Expression> parse(ExpressionContext* const expCtx,
+ BSONElement expr,
+ const VariablesParseState& vps);
+
+ void acceptVisitor(ExpressionVisitor* visitor) final {
+ return visitor->visit(this);
+ }
+
+ Value evaluate(const Document& root, Variables* variables) const;
+ Value serialize(bool explain) const final;
+
+protected:
+ void _doAddDependencies(DepsTracker* deps) const final;
+};
+
} // namespace mongo
diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp
index cf3929bf7aa..5288fe96c00 100644
--- a/src/mongo/db/pipeline/expression_test.cpp
+++ b/src/mongo/db/pipeline/expression_test.cpp
@@ -36,6 +36,7 @@
#include "mongo/db/exec/document_value/document.h"
#include "mongo/db/exec/document_value/document_value_test_util.h"
#include "mongo/db/exec/document_value/value_comparator.h"
+#include "mongo/db/hasher.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/pipeline/accumulator.h"
@@ -2983,4 +2984,82 @@ TEST(ExpressionRandom, Basic) {
};
assertRandomProperties(randFn);
}
+
+namespace ExpressionToHashedIndexKeyTest {
+
+TEST(ExpressionToHashedIndexKeyTest, StringInputSucceeds) {
+ auto expCtx = ExpressionContextForTest{};
+ const BSONObj obj = BSON("$toHashedIndexKey"
+ << "hashThisStringLiteral"_sd);
+ auto expression = Expression::parseExpression(&expCtx, obj, expCtx.variablesParseState);
+ Value result = expression->evaluate({}, &expCtx.variables);
+ ASSERT_VALUE_EQ(result, Value::createIntOrLong(-5776344739422278694));
+}
+
+TEST(ExpressionToHashedIndexKeyTest, IntInputSucceeds) {
+ auto expCtx = ExpressionContextForTest{};
+ const BSONObj obj = BSON("$toHashedIndexKey" << 123);
+ auto expression = Expression::parseExpression(&expCtx, obj, expCtx.variablesParseState);
+ Value result = expression->evaluate({}, &expCtx.variables);
+ ASSERT_VALUE_EQ(result, Value::createIntOrLong(-6548868637522515075));
+}
+
+TEST(ExpressionToHashedIndexKeyTest, TimestampInputSucceeds) {
+ auto expCtx = ExpressionContextForTest{};
+ const BSONObj obj = BSON("$toHashedIndexKey" << Timestamp(0, 0));
+ auto expression = Expression::parseExpression(&expCtx, obj, expCtx.variablesParseState);
+ Value result = expression->evaluate({}, &expCtx.variables);
+ ASSERT_VALUE_EQ(result, Value::createIntOrLong(-7867208682377458672));
+}
+
+TEST(ExpressionToHashedIndexKeyTest, ObjectIdInputSucceeds) {
+ auto expCtx = ExpressionContextForTest{};
+ const BSONObj obj = BSON("$toHashedIndexKey" << OID("47cc67093475061e3d95369d"));
+ auto expression = Expression::parseExpression(&expCtx, obj, expCtx.variablesParseState);
+ Value result = expression->evaluate({}, &expCtx.variables);
+ ASSERT_VALUE_EQ(result, Value::createIntOrLong(1576265281381834298));
+}
+
+TEST(ExpressionToHashedIndexKeyTest, DateInputSucceeds) {
+ auto expCtx = ExpressionContextForTest{};
+ const BSONObj obj = BSON("$toHashedIndexKey" << Date_t());
+ auto expression = Expression::parseExpression(&expCtx, obj, expCtx.variablesParseState);
+ Value result = expression->evaluate({}, &expCtx.variables);
+ ASSERT_VALUE_EQ(result, Value::createIntOrLong(-1178696894582842035));
+}
+
+TEST(ExpressionToHashedIndexKeyTest, MissingInputValueSucceeds) {
+ auto expCtx = ExpressionContextForTest{};
+ const BSONObj obj = BSON("$toHashedIndexKey"
+ << "$missingField");
+ auto expression = Expression::parseExpression(&expCtx, obj, expCtx.variablesParseState);
+ Value result = expression->evaluate({}, &expCtx.variables);
+ ASSERT_VALUE_EQ(result, Value::createIntOrLong(2338878944348059895));
+}
+
+TEST(ExpressionToHashedIndexKeyTest, NullInputSucceeds) {
+ auto expCtx = ExpressionContextForTest{};
+ const BSONObj obj = BSON("$toHashedIndexKey" << BSONNULL);
+ auto expression = Expression::parseExpression(&expCtx, obj, expCtx.variablesParseState);
+ Value result = expression->evaluate({}, &expCtx.variables);
+ ASSERT_VALUE_EQ(result, Value::createIntOrLong(2338878944348059895));
+}
+
+TEST(ExpressionToHashedIndexKeyTest, ExpressionInputSucceeds) {
+ auto expCtx = ExpressionContextForTest{};
+ const BSONObj obj = BSON("$toHashedIndexKey" << BSON("$pow" << BSON_ARRAY(2 << 4)));
+ auto expression = Expression::parseExpression(&expCtx, obj, expCtx.variablesParseState);
+ Value result = expression->evaluate({}, &expCtx.variables);
+ ASSERT_VALUE_EQ(result, Value::createIntOrLong(2598032665634823220));
+}
+
+TEST(ExpressionToHashedIndexKeyTest, UndefinedInputSucceeds) {
+ auto expCtx = ExpressionContextForTest{};
+ const BSONObj obj = BSON("$toHashedIndexKey" << BSONUndefined);
+ auto expression = Expression::parseExpression(&expCtx, obj, expCtx.variablesParseState);
+ Value result = expression->evaluate({}, &expCtx.variables);
+ ASSERT_VALUE_EQ(result, Value::createIntOrLong(40158834000849533LL));
+}
+
+} // namespace ExpressionToHashedIndexKeyTest
} // namespace ExpressionTests
diff --git a/src/mongo/db/pipeline/expression_visitor.h b/src/mongo/db/pipeline/expression_visitor.h
index d6b2b9d5042..a8b3d08e6c7 100644
--- a/src/mongo/db/pipeline/expression_visitor.h
+++ b/src/mongo/db/pipeline/expression_visitor.h
@@ -68,6 +68,7 @@ class ExpressionExp;
class ExpressionFieldPath;
class ExpressionFilter;
class ExpressionFloor;
+class ExpressionToHashedIndexKey;
class ExpressionHour;
class ExpressionIfNull;
class ExpressionIn;
@@ -299,6 +300,7 @@ public:
virtual void visit(ExpressionInternalFindSlice*) = 0;
virtual void visit(ExpressionInternalFindPositional*) = 0;
virtual void visit(ExpressionInternalFindElemMatch*) = 0;
+ virtual void visit(ExpressionToHashedIndexKey*) = 0;
};
} // namespace mongo