summaryrefslogtreecommitdiff
path: root/src/mongo/db/update
diff options
context:
space:
mode:
authorTess Avitabile <tess.avitabile@mongodb.com>2017-07-27 11:06:55 -0400
committerTess Avitabile <tess.avitabile@mongodb.com>2017-07-31 14:42:24 -0400
commit3867d603a00888a4cd16d52380233f585db5c0fb (patch)
tree1f1f0485c1348700b2f30531e2fc9039473bdf90 /src/mongo/db/update
parent0a55ace0a362a5944fedbaec2d95b2d7cda750d6 (diff)
downloadmongo-3867d603a00888a4cd16d52380233f585db5c0fb.tar.gz
SERVER-28773 UpdateNode::apply should take a parameter struct
Diffstat (limited to 'src/mongo/db/update')
-rw-r--r--src/mongo/db/update/addtoset_node.cpp7
-rw-r--r--src/mongo/db/update/addtoset_node.h2
-rw-r--r--src/mongo/db/update/addtoset_node_test.cpp605
-rw-r--r--src/mongo/db/update/arithmetic_node.cpp5
-rw-r--r--src/mongo/db/update/arithmetic_node.h2
-rw-r--r--src/mongo/db/update/arithmetic_node_test.cpp1756
-rw-r--r--src/mongo/db/update/array_culling_node.cpp60
-rw-r--r--src/mongo/db/update/array_culling_node.h12
-rw-r--r--src/mongo/db/update/bit_node.cpp6
-rw-r--r--src/mongo/db/update/bit_node.h2
-rw-r--r--src/mongo/db/update/bit_node_test.cpp275
-rw-r--r--src/mongo/db/update/compare_node.cpp6
-rw-r--r--src/mongo/db/update/compare_node.h2
-rw-r--r--src/mongo/db/update/compare_node_test.cpp647
-rw-r--r--src/mongo/db/update/conflict_placeholder_node.h14
-rw-r--r--src/mongo/db/update/current_date_node.cpp4
-rw-r--r--src/mongo/db/update/current_date_node.h2
-rw-r--r--src/mongo/db/update/current_date_node_test.cpp288
-rw-r--r--src/mongo/db/update/object_replace_node.cpp51
-rw-r--r--src/mongo/db/update/object_replace_node.h24
-rw-r--r--src/mongo/db/update/object_replace_node_test.cpp527
-rw-r--r--src/mongo/db/update/path_creating_node.cpp91
-rw-r--r--src/mongo/db/update/path_creating_node.h16
-rw-r--r--src/mongo/db/update/pop_node.cpp72
-rw-r--r--src/mongo/db/update/pop_node.h12
-rw-r--r--src/mongo/db/update/pop_node_test.cpp589
-rw-r--r--src/mongo/db/update/pull_node_test.cpp1030
-rw-r--r--src/mongo/db/update/pullall_node_test.cpp417
-rw-r--r--src/mongo/db/update/rename_node.cpp66
-rw-r--r--src/mongo/db/update/rename_node.h12
-rw-r--r--src/mongo/db/update/rename_node_test.cpp843
-rw-r--r--src/mongo/db/update/set_node.cpp6
-rw-r--r--src/mongo/db/update/set_node.h2
-rw-r--r--src/mongo/db/update/set_node_test.cpp2288
-rw-r--r--src/mongo/db/update/unset_node.cpp54
-rw-r--r--src/mongo/db/update/unset_node.h12
-rw-r--r--src/mongo/db/update/unset_node_test.cpp720
-rw-r--r--src/mongo/db/update/update_array_node.cpp85
-rw-r--r--src/mongo/db/update/update_array_node.h12
-rw-r--r--src/mongo/db/update/update_array_node_test.cpp721
-rw-r--r--src/mongo/db/update/update_driver.cpp28
-rw-r--r--src/mongo/db/update/update_node.h87
-rw-r--r--src/mongo/db/update/update_node_test_fixture.h133
-rw-r--r--src/mongo/db/update/update_object_node.cpp164
-rw-r--r--src/mongo/db/update/update_object_node.h12
-rw-r--r--src/mongo/db/update/update_object_node_test.cpp832
46 files changed, 2766 insertions, 9835 deletions
diff --git a/src/mongo/db/update/addtoset_node.cpp b/src/mongo/db/update/addtoset_node.cpp
index 893f27ceeb2..70d88ebf411 100644
--- a/src/mongo/db/update/addtoset_node.cpp
+++ b/src/mongo/db/update/addtoset_node.cpp
@@ -102,7 +102,7 @@ void AddToSetNode::setCollator(const CollatorInterface* collator) {
deduplicate(_elements, _collator);
}
-void AddToSetNode::updateExistingElement(mutablebson::Element* element, bool* noop) const {
+bool AddToSetNode::updateExistingElement(mutablebson::Element* element) const {
uassert(ErrorCodes::BadValue,
str::stream() << "Cannot apply $addToSet to non-array field. Field named '"
<< element->getFieldName()
@@ -127,14 +127,15 @@ void AddToSetNode::updateExistingElement(mutablebson::Element* element, bool* no
}
if (elementsToAdd.empty()) {
- *noop = true;
- return;
+ return false;
}
for (auto&& elem : elementsToAdd) {
auto toAdd = element->getDocument().makeElement(elem);
invariantOK(element->pushBack(toAdd));
}
+
+ return true;
}
void AddToSetNode::setValueForNewElement(mutablebson::Element* element) const {
diff --git a/src/mongo/db/update/addtoset_node.h b/src/mongo/db/update/addtoset_node.h
index 6f9a2de2e49..c36d9415750 100644
--- a/src/mongo/db/update/addtoset_node.h
+++ b/src/mongo/db/update/addtoset_node.h
@@ -47,7 +47,7 @@ public:
void setCollator(const CollatorInterface* collator) final;
protected:
- void updateExistingElement(mutablebson::Element* element, bool* noop) const final;
+ bool updateExistingElement(mutablebson::Element* element) const final;
void setValueForNewElement(mutablebson::Element* element) const final;
private:
diff --git a/src/mongo/db/update/addtoset_node_test.cpp b/src/mongo/db/update/addtoset_node_test.cpp
index 3d9fd8aefb0..816cccf4899 100644
--- a/src/mongo/db/update/addtoset_node_test.cpp
+++ b/src/mongo/db/update/addtoset_node_test.cpp
@@ -34,12 +34,14 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
+namespace mongo {
namespace {
-using namespace mongo;
+using AddToSetNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
@@ -101,522 +103,243 @@ TEST(AddToSetNodeTest, InitSucceedsWithScaler) {
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
}
-TEST(AddToSetNodeTest, ApplyFailsOnNonArray) {
+TEST_F(AddToSetNodeTest, ApplyFailsOnNonArray) {
auto update = fromjson("{$addToSet: {a: 1}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: 2}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathTaken("a");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::BadValue,
"Cannot apply $addToSet to non-array field. Field named 'a' has non-array type int");
}
-TEST(AddToSetNodeTest, ApplyNonEach) {
+TEST_F(AddToSetNodeTest, ApplyNonEach) {
auto update = fromjson("{$addToSet: {a: 1}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyNonEachArray) {
+TEST_F(AddToSetNodeTest, ApplyNonEachArray) {
auto update = fromjson("{$addToSet: {a: [1]}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, [1]]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, [1]]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [0, [1]]}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyEach) {
+TEST_F(AddToSetNodeTest, ApplyEach) {
auto update = fromjson("{$addToSet: {a: {$each: [1, 2]}}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1, 2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1, 2]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [0, 1, 2]}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyToEmptyArray) {
+TEST_F(AddToSetNodeTest, ApplyToEmptyArray) {
auto update = fromjson("{$addToSet: {a: {$each: [1, 2]}}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 2]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [1, 2]}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyDeduplicateElementsToAdd) {
+TEST_F(AddToSetNodeTest, ApplyDeduplicateElementsToAdd) {
auto update = fromjson("{$addToSet: {a: {$each: [1, 1]}}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyDoNotAddExistingElements) {
+TEST_F(AddToSetNodeTest, ApplyDoNotAddExistingElements) {
auto update = fromjson("{$addToSet: {a: {$each: [0, 1]}}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyDoNotDeduplicateExistingElements) {
+TEST_F(AddToSetNodeTest, ApplyDoNotDeduplicateExistingElements) {
auto update = fromjson("{$addToSet: {a: {$each: [1]}}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: [0, 0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 0, 1]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [0, 0, 1]}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyNoElementsToAdd) {
+TEST_F(AddToSetNodeTest, ApplyNoElementsToAdd) {
auto update = fromjson("{$addToSet: {a: {$each: []}}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyNoNonDuplicateElementsToAdd) {
+TEST_F(AddToSetNodeTest, ApplyNoNonDuplicateElementsToAdd) {
auto update = fromjson("{$addToSet: {a: {$each: [0]}}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyCreateArray) {
+TEST_F(AddToSetNodeTest, ApplyCreateArray) {
auto update = fromjson("{$addToSet: {a: {$each: [0, 1]}}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyCreateEmptyArrayIsNotNoop) {
+TEST_F(AddToSetNodeTest, ApplyCreateEmptyArrayIsNotNoop) {
auto update = fromjson("{$addToSet: {a: {$each: []}}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyDeduplicationOfElementsToAddRespectsCollation) {
+TEST_F(AddToSetNodeTest, ApplyDeduplicationOfElementsToAddRespectsCollation) {
auto update = fromjson("{$addToSet: {a: {$each: ['abc', 'ABC', 'def', 'abc']}}}");
const CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kToLowerString);
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], &collator));
Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['abc', 'def']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['abc', 'def']}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: ['abc', 'def']}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyComparisonToExistingElementsRespectsCollation) {
+TEST_F(AddToSetNodeTest, ApplyComparisonToExistingElementsRespectsCollation) {
auto update = fromjson("{$addToSet: {a: {$each: ['abc', 'def']}}}");
const CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kToLowerString);
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], &collator));
Document doc(fromjson("{a: ['ABC']}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['ABC', 'def']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['ABC', 'def']}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: ['ABC', 'def']}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyRespectsCollationFromSetCollator) {
+TEST_F(AddToSetNodeTest, ApplyRespectsCollationFromSetCollator) {
auto update = fromjson("{$addToSet: {a: {$each: ['abc', 'ABC', 'def', 'abc']}}}");
const CollatorInterface* binaryComparisonCollator = nullptr;
AddToSetNode node;
@@ -627,34 +350,14 @@ TEST(AddToSetNodeTest, ApplyRespectsCollationFromSetCollator) {
node.setCollator(&caseInsensitiveCollator);
Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['abc', 'def']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['abc', 'def']}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: ['abc', 'def']}}"), getLogDoc());
}
DEATH_TEST(AddToSetNodeTest, CannotSetCollatorIfCollatorIsNonNull, "Invariant failure !_collator") {
@@ -678,112 +381,54 @@ DEATH_TEST(AddToSetNodeTest, CannotSetCollatorTwice, "Invariant failure !_collat
node.setCollator(&caseInsensitiveCollator);
}
-TEST(AddToSetNodeTest, ApplyNestedArray) {
+TEST_F(AddToSetNodeTest, ApplyNestedArray) {
auto update = fromjson("{ $addToSet : { 'a.1' : 1 } }");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a.1"], collator));
Document doc(fromjson("{ _id : 1, a : [ 1, [ ] ] }"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.1");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["1"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.1");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["1"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{ _id : 1, a : [ 1, [ 1 ] ] }"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{ $set : { 'a.1' : [ 1 ] } }"), logDoc);
+ ASSERT_EQUALS(fromjson("{ $set : { 'a.1' : [ 1 ] } }"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyIndexesNotAffected) {
+TEST_F(AddToSetNodeTest, ApplyIndexesNotAffected) {
auto update = fromjson("{$addToSet: {a: 1}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("b");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
- ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
+ setPathTaken("a");
+ addIndexedPath("b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [0, 1]}}"), getLogDoc());
}
-TEST(AddToSetNodeTest, ApplyNoIndexDataOrLogBuilder) {
+TEST_F(AddToSetNodeTest, ApplyNoIndexDataOrLogBuilder) {
auto update = fromjson("{$addToSet: {a: 1}}");
const CollatorInterface* collator = nullptr;
AddToSetNode node;
ASSERT_OK(node.init(update["$addToSet"]["a"], collator));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ setLogBuilderToNull();
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
} // namespace
+} // namespace mongo
diff --git a/src/mongo/db/update/arithmetic_node.cpp b/src/mongo/db/update/arithmetic_node.cpp
index 69c25a87da8..cb122bfa863 100644
--- a/src/mongo/db/update/arithmetic_node.cpp
+++ b/src/mongo/db/update/arithmetic_node.cpp
@@ -73,7 +73,7 @@ Status ArithmeticNode::init(BSONElement modExpr, const CollatorInterface* collat
return Status::OK();
}
-void ArithmeticNode::updateExistingElement(mutablebson::Element* element, bool* noop) const {
+bool ArithmeticNode::updateExistingElement(mutablebson::Element* element) const {
if (!element->isNumeric()) {
mutablebson::Element idElem =
mutablebson::findFirstChildNamed(element->getDocument().root(), "_id");
@@ -101,11 +101,12 @@ void ArithmeticNode::updateExistingElement(mutablebson::Element* element, bool*
// If the updated value is identical to the original value, treat this as a no-op. Caveat:
// if the found element is in a deserialized state, we can't do that.
if (element->getValue().ok() && valueToSet.isIdentical(originalValue)) {
- *noop = true;
+ return false;
} else {
// This can fail if 'valueToSet' is not representable as a 64-bit integer.
uassertStatusOK(element->setValueSafeNum(valueToSet));
+ return true;
}
}
diff --git a/src/mongo/db/update/arithmetic_node.h b/src/mongo/db/update/arithmetic_node.h
index e8f0917443d..7004adafcfe 100644
--- a/src/mongo/db/update/arithmetic_node.h
+++ b/src/mongo/db/update/arithmetic_node.h
@@ -51,7 +51,7 @@ public:
void setCollator(const CollatorInterface* collator) final {}
protected:
- void updateExistingElement(mutablebson::Element* element, bool* noop) const final;
+ bool updateExistingElement(mutablebson::Element* element) const final;
void setValueForNewElement(mutablebson::Element* element) const final;
private:
diff --git a/src/mongo/db/update/arithmetic_node_test.cpp b/src/mongo/db/update/arithmetic_node_test.cpp
index 9626125c29f..76855f66640 100644
--- a/src/mongo/db/update/arithmetic_node_test.cpp
+++ b/src/mongo/db/update/arithmetic_node_test.cpp
@@ -33,12 +33,14 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
namespace {
+using ArithmeticNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
@@ -108,695 +110,328 @@ TEST(ArithmeticNodeTest, InitFailsForArrayElement) {
ASSERT_EQ(result.reason(), "Cannot multiply with non-numeric argument: {a: []}");
}
-TEST(ArithmeticNodeTest, ApplyIncNoOp) {
+TEST_F(ArithmeticNodeTest, ApplyIncNoOp) {
auto update = fromjson("{$inc: {a: 0}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyMulNoOp) {
+TEST_F(ArithmeticNodeTest, ApplyMulNoOp) {
auto update = fromjson("{$mul: {a: 1}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply);
ASSERT_OK(node.init(update["$mul"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyRoundingNoOp) {
+TEST_F(ArithmeticNodeTest, ApplyRoundingNoOp) {
auto update = fromjson("{$inc: {a: 1.0}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: 6.022e23}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 6.022e23}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyEmptyPathToCreate) {
+TEST_F(ArithmeticNodeTest, ApplyEmptyPathToCreate) {
auto update = fromjson("{$inc: {a: 6}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 11}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 11}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 11}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyCreatePath) {
+TEST_F(ArithmeticNodeTest, ApplyCreatePath) {
auto update = fromjson("{$inc: {'a.b.c': 6}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b.c"], collator));
Document doc(fromjson("{a: {d: 5}}"));
- FieldRef pathToCreate("b.c");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b.c");
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {d: 5, b: {c: 6}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b.c': 6}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b.c': 6}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyExtendPath) {
+TEST_F(ArithmeticNodeTest, ApplyExtendPath) {
auto update = fromjson("{$inc: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{a: {c: 1}}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b");
+ setPathTaken("a");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {c: 1, b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyCreatePathFromRoot) {
+TEST_F(ArithmeticNodeTest, ApplyCreatePathFromRoot) {
auto update = fromjson("{$inc: {'a.b': 6}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{c: 5}"));
- FieldRef pathToCreate("a.b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{c: 5, a: {b: 6}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': 6}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': 6}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyPositional) {
+TEST_F(ArithmeticNodeTest, ApplyPositional) {
auto update = fromjson("{$inc: {'a.$': 6}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.$"], collator));
Document doc(fromjson("{a: [0, 1, 2]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.1");
- StringData matchedField("1");
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["1"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.1");
+ setMatchedField("1");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["1"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 7, 2]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1': 7}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.1': 7}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyNonViablePathToInc) {
+TEST_F(ArithmeticNodeTest, ApplyNonViablePathToInc) {
auto update = fromjson("{$inc: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field 'b' in element {a: 5}");
}
-TEST(ArithmeticNodeTest, ApplyNonViablePathToCreateFromReplicationIsNoOp) {
+TEST_F(ArithmeticNodeTest, ApplyNonViablePathToCreateFromReplicationIsNoOp) {
auto update = fromjson("{$inc: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ setFromReplication(true);
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyNoIndexDataNoLogBuilder) {
+TEST_F(ArithmeticNodeTest, ApplyNoIndexDataNoLogBuilder) {
auto update = fromjson("{$inc: {a: 6}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ setLogBuilderToNull();
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 11}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyDoesNotAffectIndexes) {
+TEST_F(ArithmeticNodeTest, ApplyDoesNotAffectIndexes) {
auto update = fromjson("{$inc: {a: 6}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 11}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, IncTypePromotionIsNotANoOp) {
+TEST_F(ArithmeticNodeTest, IncTypePromotionIsNotANoOp) {
auto update = fromjson("{$inc: {a: NumberLong(0)}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: NumberInt(2)}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberLong(2)}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, MulTypePromotionIsNotANoOp) {
+TEST_F(ArithmeticNodeTest, MulTypePromotionIsNotANoOp) {
auto update = fromjson("{$mul: {a: NumberLong(1)}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply);
ASSERT_OK(node.init(update["$mul"]["a"], collator));
Document doc(fromjson("{a: NumberInt(2)}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberLong(2)}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, TypePromotionFromIntToDecimalIsNotANoOp) {
+TEST_F(ArithmeticNodeTest, TypePromotionFromIntToDecimalIsNotANoOp) {
auto update = fromjson("{$inc: {a: NumberDecimal(\"0.0\")}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: NumberInt(5)}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberDecimal(\"5.0\")}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"5.0\")}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"5.0\")}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, TypePromotionFromLongToDecimalIsNotANoOp) {
+TEST_F(ArithmeticNodeTest, TypePromotionFromLongToDecimalIsNotANoOp) {
auto update = fromjson("{$inc: {a: NumberDecimal(\"0.0\")}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: NumberLong(5)}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberDecimal(\"5.0\")}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"5.0\")}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"5.0\")}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, TypePromotionFromDoubleToDecimalIsNotANoOp) {
+TEST_F(ArithmeticNodeTest, TypePromotionFromDoubleToDecimalIsNotANoOp) {
auto update = fromjson("{$inc: {a: NumberDecimal(\"0.0\")}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: 5.25}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberDecimal(\"5.25\")}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"5.25\")}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"5.25\")}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyPromoteToFloatingPoint) {
+TEST_F(ArithmeticNodeTest, ApplyPromoteToFloatingPoint) {
auto update = fromjson("{$inc: {a: 0.2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: NumberLong(1)}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1.2}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, IncrementedDecimalStaysDecimal) {
+TEST_F(ArithmeticNodeTest, IncrementedDecimalStaysDecimal) {
auto update = fromjson("{$inc: {a: 5.25}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: NumberDecimal(\"6.25\")}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberDecimal(\"11.5\")}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"11.5\")}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: NumberDecimal(\"11.5\")}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, OverflowIntToLong) {
+TEST_F(ArithmeticNodeTest, OverflowIntToLong) {
auto update = fromjson("{$inc: {a: 1}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
@@ -805,37 +440,17 @@ TEST(ArithmeticNodeTest, OverflowIntToLong) {
const int initialValue = std::numeric_limits<int>::max();
Document doc(BSON("a" << initialValue));
ASSERT_EQUALS(mongo::NumberInt, doc.root()["a"].getType());
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(mongo::NumberLong, doc.root()["a"].getType());
ASSERT_EQUALS(BSON("a" << static_cast<long long>(initialValue) + 1), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, UnderflowIntToLong) {
+TEST_F(ArithmeticNodeTest, UnderflowIntToLong) {
auto update = fromjson("{$inc: {a: -1}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
@@ -844,37 +459,17 @@ TEST(ArithmeticNodeTest, UnderflowIntToLong) {
const int initialValue = std::numeric_limits<int>::min();
Document doc(BSON("a" << initialValue));
ASSERT_EQUALS(mongo::NumberInt, doc.root()["a"].getType());
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(mongo::NumberLong, doc.root()["a"].getType());
ASSERT_EQUALS(BSON("a" << static_cast<long long>(initialValue) - 1), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, IncModeCanBeReused) {
+TEST_F(ArithmeticNodeTest, IncModeCanBeReused) {
auto update = fromjson("{$inc: {a: 1}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
@@ -882,1065 +477,492 @@ TEST(ArithmeticNodeTest, IncModeCanBeReused) {
Document doc1(fromjson("{a: 1}"));
Document doc2(fromjson("{a: 2}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc1.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc1.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc1);
ASSERT_TRUE(doc1.isInPlaceModeEnabled());
- indexesAffected = false;
- noop = false;
- node.apply(doc2.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ resetApplyParams();
+ setPathTaken("a");
+ addIndexedPath("a");
+ result = node.apply(getApplyParams(doc2.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 3}"), doc2);
ASSERT_TRUE(doc1.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, CreatedNumberHasSameTypeAsInc) {
+TEST_F(ArithmeticNodeTest, CreatedNumberHasSameTypeAsInc) {
auto update = fromjson("{$inc: {a: NumberLong(5)}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{b: 6}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 6, a: NumberLong(5)}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, CreatedNumberHasSameTypeAsMul) {
+TEST_F(ArithmeticNodeTest, CreatedNumberHasSameTypeAsMul) {
auto update = fromjson("{$mul: {a: NumberLong(5)}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply);
ASSERT_OK(node.init(update["$mul"]["a"], collator));
Document doc(fromjson("{b: 6}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 6, a: NumberLong(0)}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyEmptyDocument) {
+TEST_F(ArithmeticNodeTest, ApplyEmptyDocument) {
auto update = fromjson("{$inc: {a: 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyIncToObjectFails) {
+TEST_F(ArithmeticNodeTest, ApplyIncToObjectFails) {
auto update = fromjson("{$inc: {a: 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{_id: 'test_object', a: {b: 1}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::TypeMismatch,
"Cannot apply $inc to a value of non-numeric type. {_id: "
"\"test_object\"} has the field 'a' of non-numeric type object");
}
-TEST(ArithmeticNodeTest, ApplyIncToArrayFails) {
+TEST_F(ArithmeticNodeTest, ApplyIncToArrayFails) {
auto update = fromjson("{$inc: {a: 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{_id: 'test_object', a: []}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::TypeMismatch,
"Cannot apply $inc to a value of non-numeric type. {_id: "
"\"test_object\"} has the field 'a' of non-numeric type array");
}
-TEST(ArithmeticNodeTest, ApplyIncToStringFails) {
+TEST_F(ArithmeticNodeTest, ApplyIncToStringFails) {
auto update = fromjson("{$inc: {a: 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{_id: 'test_object', a: \"foo\"}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::TypeMismatch,
"Cannot apply $inc to a value of non-numeric type. {_id: "
"\"test_object\"} has the field 'a' of non-numeric type string");
}
-TEST(ArithmeticNodeTest, ApplyNewPath) {
+TEST_F(ArithmeticNodeTest, ApplyNewPath) {
auto update = fromjson("{$inc: {a: 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{b: 1}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 1, a: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyEmptyIndexData) {
+TEST_F(ArithmeticNodeTest, ApplyEmptyIndexData) {
auto update = fromjson("{$inc: {a: 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
+ setPathTaken("a");
+ node.apply(getApplyParams(doc.root()["a"]));
ASSERT_EQUALS(fromjson("{a: 3}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {a: 3}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {a: 3}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyNoOpDottedPath) {
+TEST_F(ArithmeticNodeTest, ApplyNoOpDottedPath) {
auto update = fromjson("{$inc: {'a.b': 0}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b : 2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, TypePromotionOnDottedPathIsNotANoOp) {
+TEST_F(ArithmeticNodeTest, TypePromotionOnDottedPathIsNotANoOp) {
auto update = fromjson("{$inc: {'a.b': NumberLong(0)}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{a: {b: NumberInt(2)}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b : NumberLong(2)}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyPathNotViableArray) {
+TEST_F(ArithmeticNodeTest, ApplyPathNotViableArray) {
auto update = fromjson("{$inc: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{a:[{b:1}]}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("b");
+ setPathTaken("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field 'b' in element {a: [ { b: 1 } ]}");
}
-TEST(ArithmeticNodeTest, ApplyInPlaceDottedPath) {
+TEST_F(ArithmeticNodeTest, ApplyInPlaceDottedPath) {
auto update = fromjson("{$inc: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{a: {b: 1}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 3}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyPromotionDottedPath) {
+TEST_F(ArithmeticNodeTest, ApplyPromotionDottedPath) {
auto update = fromjson("{$inc: {'a.b': NumberLong(2)}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{a: {b: NumberInt(3)}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: NumberLong(5)}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyDottedPathEmptyDoc) {
+TEST_F(ArithmeticNodeTest, ApplyDottedPathEmptyDoc) {
auto update = fromjson("{$inc: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a.b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyFieldWithDot) {
+TEST_F(ArithmeticNodeTest, ApplyFieldWithDot) {
auto update = fromjson("{$inc: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.b"], collator));
Document doc(fromjson("{'a.b':4}"));
- FieldRef pathToCreate("a.b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{'a.b':4, a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyNoOpArrayIndex) {
+TEST_F(ArithmeticNodeTest, ApplyNoOpArrayIndex) {
auto update = fromjson("{$inc: {'a.2.b': 0}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b: 0},{b: 1},{b: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.2.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["2"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.2.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["2"]["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0},{b: 1},{b: 2}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, TypePromotionInArrayIsNotANoOp) {
+TEST_F(ArithmeticNodeTest, TypePromotionInArrayIsNotANoOp) {
auto update = fromjson("{$set: {'a.2.b': NumberLong(0)}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b: NumberInt(0)},{b: NumberInt(1)},{b: NumberInt(2)}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.2.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["2"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.2.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["2"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0},{b: 1},{b: NumberLong(2)}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyNonViablePathThroughArray) {
+TEST_F(ArithmeticNodeTest, ApplyNonViablePathThroughArray) {
auto update = fromjson("{$inc: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field '2' in element {a: 0}");
}
-TEST(ArithmeticNodeTest, ApplyInPlaceArrayIndex) {
+TEST_F(ArithmeticNodeTest, ApplyInPlaceArrayIndex) {
auto update = fromjson("{$inc: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b: 0},{b: 1},{b: 1}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.2.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["2"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.2.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["2"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0},{b: 1},{b: 3}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyAppendArray) {
+TEST_F(ArithmeticNodeTest, ApplyAppendArray) {
auto update = fromjson("{$inc: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b: 0},{b: 1}]}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0},{b: 1},{b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyPaddingArray) {
+TEST_F(ArithmeticNodeTest, ApplyPaddingArray) {
auto update = fromjson("{$inc: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b: 0}]}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0},null,{b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyNumericObject) {
+TEST_F(ArithmeticNodeTest, ApplyNumericObject) {
auto update = fromjson("{$inc: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: {b: 0}}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 0, '2': {b: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyNumericField) {
+TEST_F(ArithmeticNodeTest, ApplyNumericField) {
auto update = fromjson("{$inc: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: {'2': {b: 1}}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.2.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["2"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.2.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["2"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {'2': {b: 3}}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyExtendNumericField) {
+TEST_F(ArithmeticNodeTest, ApplyExtendNumericField) {
auto update = fromjson("{$inc: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: {'2': {c: 1}}}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a.2");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["2"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b");
+ setPathTaken("a.2");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["2"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {'2': {c: 1, b: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyNumericFieldToEmptyObject) {
+TEST_F(ArithmeticNodeTest, ApplyNumericFieldToEmptyObject) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: {}}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {'2': {b: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyEmptyArray) {
+TEST_F(ArithmeticNodeTest, ApplyEmptyArray) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [null, null, {b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(ArithmeticNodeTest, ApplyLogDottedPath) {
+TEST_F(ArithmeticNodeTest, ApplyLogDottedPath) {
auto update = fromjson("{$inc: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b:0}, {b:1}]}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ node.apply(getApplyParams(doc.root()["a"]));
ASSERT_EQUALS(fromjson("{a: [{b:0}, {b:1}, {b:2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, LogEmptyArray) {
+TEST_F(ArithmeticNodeTest, LogEmptyArray) {
auto update = fromjson("{$inc: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ node.apply(getApplyParams(doc.root()["a"]));
ASSERT_EQUALS(fromjson("{a: [null, null, {b:2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, LogEmptyObject) {
+TEST_F(ArithmeticNodeTest, LogEmptyObject) {
auto update = fromjson("{$inc: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kAdd);
ASSERT_OK(node.init(update["$inc"]["a.2.b"], collator));
Document doc(fromjson("{a: {}}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ node.apply(getApplyParams(doc.root()["a"]));
ASSERT_EQUALS(fromjson("{a: {'2': {b: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyDeserializedDocNotNoOp) {
+TEST_F(ArithmeticNodeTest, ApplyDeserializedDocNotNoOp) {
auto update = fromjson("{$mul: {b: NumberInt(1)}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply);
@@ -1950,36 +972,16 @@ TEST(ArithmeticNodeTest, ApplyDeserializedDocNotNoOp) {
// De-serialize the int.
doc.root()["a"].setValueInt(1).transitional_ignore();
- FieldRef pathToCreate("b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("b");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1, b: NumberInt(0)}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {b: NumberInt(0)}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {b: NumberInt(0)}}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyToDeserializedDocNoOp) {
+TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNoOp) {
auto update = fromjson("{$mul: {a: NumberInt(1)}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply);
@@ -1989,36 +991,16 @@ TEST(ArithmeticNodeTest, ApplyToDeserializedDocNoOp) {
// De-serialize the int.
doc.root()["a"].setValueInt(2).transitional_ignore();
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberInt(2)}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyToDeserializedDocNestedNoop) {
+TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNestedNoop) {
auto update = fromjson("{$mul: {'a.b': NumberInt(1)}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply);
@@ -2028,36 +1010,16 @@ TEST(ArithmeticNodeTest, ApplyToDeserializedDocNestedNoop) {
// De-serialize the int.
doc.root().appendObject("a", BSON("b" << static_cast<int>(1))).transitional_ignore();
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: NumberInt(1)}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(ArithmeticNodeTest, ApplyToDeserializedDocNestedNotNoop) {
+TEST_F(ArithmeticNodeTest, ApplyToDeserializedDocNestedNotNoop) {
auto update = fromjson("{$mul: {'a.b': 3}}");
const CollatorInterface* collator = nullptr;
ArithmeticNode node(ArithmeticNode::ArithmeticOp::kMultiply);
@@ -2067,33 +1029,13 @@ TEST(ArithmeticNodeTest, ApplyToDeserializedDocNestedNotNoop) {
// De-serialize the int.
doc.root().appendObject("a", BSON("b" << static_cast<int>(1))).transitional_ignore();
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 3}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': 3}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': 3}}"), getLogDoc());
}
} // namespace
diff --git a/src/mongo/db/update/array_culling_node.cpp b/src/mongo/db/update/array_culling_node.cpp
index 90943c0e288..166c1b21fa5 100644
--- a/src/mongo/db/update/array_culling_node.cpp
+++ b/src/mongo/db/update/array_culling_node.cpp
@@ -32,37 +32,24 @@
namespace mongo {
-void ArrayCullingNode::apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const {
- *indexesAffected = false;
- *noop = false;
-
- if (!pathToCreate->empty()) {
+UpdateNode::ApplyResult ArrayCullingNode::apply(ApplyParams applyParams) const {
+ if (!applyParams.pathToCreate->empty()) {
// There were path components we could not traverse. We treat this as a no-op, unless it
// would have been impossible to create those elements, which we check with
// checkViability().
- UpdateLeafNode::checkViability(element, *pathToCreate, *pathTaken);
+ UpdateLeafNode::checkViability(
+ applyParams.element, *(applyParams.pathToCreate), *(applyParams.pathTaken));
- *noop = true;
- return;
+ return ApplyResult::noopResult();
}
// This operation only applies to arrays
uassert(ErrorCodes::BadValue,
"Cannot apply $pull to a non-array value",
- element.getType() == mongo::Array);
+ applyParams.element.getType() == mongo::Array);
size_t numRemoved = 0;
- auto cursor = element.leftChild();
+ auto cursor = applyParams.element.leftChild();
while (cursor.ok()) {
// Make sure to get the next array element now, because if we remove the 'cursor' element,
// the rightSibling pointer will be invalidated.
@@ -75,34 +62,39 @@ void ArrayCullingNode::apply(mutablebson::Element element,
}
if (numRemoved == 0) {
- *noop = true;
- return; // Skip the index check, immutable path check, and logging steps.
+ return ApplyResult::noopResult(); // Skip the index check, immutable path check, and
+ // logging steps.
}
+ ApplyResult applyResult;
+
// Determine if indexes are affected.
- if (indexData && indexData->mightBeIndexed(pathTaken->dottedField())) {
- *indexesAffected = true;
+ if (!applyParams.indexData ||
+ !applyParams.indexData->mightBeIndexed(applyParams.pathTaken->dottedField())) {
+ applyResult.indexesAffected = false;
}
// No need to validate for storage, since we cannot have increased the BSON depth or interfered
// with a DBRef.
// Ensure we are not changing any immutable paths.
- for (const auto& immutablePath : immutablePaths) {
+ for (const auto& immutablePath : applyParams.immutablePaths) {
uassert(ErrorCodes::ImmutableField,
- str::stream() << "Performing an update on the path '" << pathTaken->dottedField()
+ str::stream() << "Performing an update on the path '"
+ << applyParams.pathTaken->dottedField()
<< "' would modify the immutable field '"
<< immutablePath->dottedField()
<< "'",
- pathTaken->commonPrefixSize(*immutablePath) <
- std::min(pathTaken->numParts(), immutablePath->numParts()));
+ applyParams.pathTaken->commonPrefixSize(*immutablePath) <
+ std::min(applyParams.pathTaken->numParts(), immutablePath->numParts()));
}
- if (logBuilder) {
- auto& doc = logBuilder->getDocument();
- auto logElement = doc.makeElementArray(pathTaken->dottedField());
+ if (applyParams.logBuilder) {
+ auto& doc = applyParams.logBuilder->getDocument();
+ auto logElement = doc.makeElementArray(applyParams.pathTaken->dottedField());
- for (auto cursor = element.leftChild(); cursor.ok(); cursor = cursor.rightSibling()) {
+ for (auto cursor = applyParams.element.leftChild(); cursor.ok();
+ cursor = cursor.rightSibling()) {
dassert(cursor.hasValue());
auto copy = doc.makeElementWithNewFieldName(StringData(), cursor.getValue());
@@ -110,8 +102,10 @@ void ArrayCullingNode::apply(mutablebson::Element element,
uassertStatusOK(logElement.pushBack(copy));
}
- uassertStatusOK(logBuilder->addToSets(logElement));
+ uassertStatusOK(applyParams.logBuilder->addToSets(logElement));
}
+
+ return applyResult;
}
} // namespace mongo
diff --git a/src/mongo/db/update/array_culling_node.h b/src/mongo/db/update/array_culling_node.h
index 09705f86482..cad10143f7e 100644
--- a/src/mongo/db/update/array_culling_node.h
+++ b/src/mongo/db/update/array_culling_node.h
@@ -43,17 +43,7 @@ namespace mongo {
*/
class ArrayCullingNode : public UpdateLeafNode {
public:
- void apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const final;
+ ApplyResult apply(ApplyParams applyParams) const final;
void setCollator(const CollatorInterface* collator) final {
_matcher->setCollator(collator);
diff --git a/src/mongo/db/update/bit_node.cpp b/src/mongo/db/update/bit_node.cpp
index 57fbb57aa2b..fa8f0960c83 100644
--- a/src/mongo/db/update/bit_node.cpp
+++ b/src/mongo/db/update/bit_node.cpp
@@ -89,7 +89,7 @@ Status BitNode::init(BSONElement modExpr, const CollatorInterface* collator) {
return Status::OK();
}
-void BitNode::updateExistingElement(mutablebson::Element* element, bool* noop) const {
+bool BitNode::updateExistingElement(mutablebson::Element* element) const {
if (!element->isIntegral()) {
mutablebson::Element idElem =
mutablebson::findFirstChildNamed(element->getDocument().root(), "_id");
@@ -105,10 +105,10 @@ void BitNode::updateExistingElement(mutablebson::Element* element, bool* noop) c
SafeNum value = applyOpList(element->getValueSafeNum());
if (!value.isIdentical(element->getValueSafeNum())) {
- *noop = false;
invariantOK(element->setValueSafeNum(value));
+ return true;
} else {
- *noop = true;
+ return false;
}
}
diff --git a/src/mongo/db/update/bit_node.h b/src/mongo/db/update/bit_node.h
index 98e89e47aa6..0e5f21f4e06 100644
--- a/src/mongo/db/update/bit_node.h
+++ b/src/mongo/db/update/bit_node.h
@@ -47,7 +47,7 @@ public:
void setCollator(const CollatorInterface* collator) final {}
protected:
- void updateExistingElement(mutablebson::Element* element, bool* noop) const final;
+ bool updateExistingElement(mutablebson::Element* element) const final;
void setValueForNewElement(mutablebson::Element* element) const final;
private:
diff --git a/src/mongo/db/update/bit_node_test.cpp b/src/mongo/db/update/bit_node_test.cpp
index 518b41ab048..54db7ccdafb 100644
--- a/src/mongo/db/update/bit_node_test.cpp
+++ b/src/mongo/db/update/bit_node_test.cpp
@@ -33,12 +33,14 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
+namespace mongo {
namespace {
-using namespace mongo;
+using BitNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
@@ -148,252 +150,112 @@ TEST(BitNodeTest, ParsesXorLong) {
ASSERT_OK(node.init(update["$bit"]["a"], collator));
}
-TEST(BitNodeTest, ApplyAndLogEmptyDocumentAnd) {
+TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentAnd) {
auto update = fromjson("{$bit: {a: {and: 1}}}");
const CollatorInterface* collator = nullptr;
BitNode node;
ASSERT_OK(node.init(update["$bit"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
+ setPathToCreate("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: 0}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), getLogDoc());
}
-TEST(BitNodeTest, ApplyAndLogEmptyDocumentOr) {
+TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentOr) {
auto update = fromjson("{$bit: {a: {or: 1}}}");
const CollatorInterface* collator = nullptr;
BitNode node;
ASSERT_OK(node.init(update["$bit"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
+ setPathToCreate("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 1}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 1}}"), getLogDoc());
}
-TEST(BitNodeTest, ApplyAndLogEmptyDocumentXor) {
+TEST_F(BitNodeTest, ApplyAndLogEmptyDocumentXor) {
auto update = fromjson("{$bit: {a: {xor: 1}}}");
const CollatorInterface* collator = nullptr;
BitNode node;
ASSERT_OK(node.init(update["$bit"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
+ setPathToCreate("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 1}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 1}}"), getLogDoc());
}
-TEST(BitNodeTest, ApplyAndLogSimpleDocumentAnd) {
+TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentAnd) {
auto update = BSON("$bit" << BSON("a" << BSON("and" << 0b0110)));
const CollatorInterface* collator = nullptr;
BitNode node;
ASSERT_OK(node.init(update["$bit"]["a"], collator));
Document doc(BSON("a" << 0b0101));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
+ setPathTaken("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(BSON("a" << 0b0100), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0100)), logDoc);
+ ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0100)), getLogDoc());
}
-TEST(BitNodeTest, ApplyAndLogSimpleDocumentOr) {
+TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentOr) {
auto update = BSON("$bit" << BSON("a" << BSON("or" << 0b0110)));
const CollatorInterface* collator = nullptr;
BitNode node;
ASSERT_OK(node.init(update["$bit"]["a"], collator));
Document doc(BSON("a" << 0b0101));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
+ setPathTaken("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(BSON("a" << 0b0111), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0111)), logDoc);
+ ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0111)), getLogDoc());
}
-TEST(BitNodeTest, ApplyAndLogSimpleDocumentXor) {
+TEST_F(BitNodeTest, ApplyAndLogSimpleDocumentXor) {
auto update = BSON("$bit" << BSON("a" << BSON("xor" << 0b0110)));
const CollatorInterface* collator = nullptr;
BitNode node;
ASSERT_OK(node.init(update["$bit"]["a"], collator));
Document doc(BSON("a" << 0b0101));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
+ setPathTaken("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(BSON("a" << 0b0011), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0011)), logDoc);
+ ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0011)), getLogDoc());
}
-TEST(BitNodeTest, ApplyShouldReportNoOp) {
+TEST_F(BitNodeTest, ApplyShouldReportNoOp) {
auto update = BSON("$bit" << BSON("a" << BSON("and" << static_cast<int>(1))));
const CollatorInterface* collator = nullptr;
BitNode node;
ASSERT_OK(node.init(update["$bit"]["a"], collator));
Document doc(BSON("a" << 1));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
+ setPathTaken("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
ASSERT_EQUALS(BSON("a" << static_cast<int>(1)), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(BitNodeTest, ApplyMultipleBitOps) {
+TEST_F(BitNodeTest, ApplyMultipleBitOps) {
// End-of-line comments help clang-format break up this line more readably.
auto update = BSON("$bit" << BSON("a" << BSON("and" << 0b1111000011110000 //
<< //
@@ -405,67 +267,28 @@ TEST(BitNodeTest, ApplyMultipleBitOps) {
ASSERT_OK(node.init(update["$bit"]["a"], collator));
Document doc(BSON("a" << 0b1111111100000000));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
+ setPathTaken("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(BSON("a" << 0b0101011001100110), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0101011001100110)), logDoc);
+ ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b0101011001100110)), getLogDoc());
}
-TEST(BitNodeTest, ApplyRepeatedBitOps) {
+TEST_F(BitNodeTest, ApplyRepeatedBitOps) {
auto update = BSON("$bit" << BSON("a" << BSON("xor" << 0b11001100 << "xor" << 0b10101010)));
const CollatorInterface* collator = nullptr;
BitNode node;
ASSERT_OK(node.init(update["$bit"]["a"], collator));
Document doc(BSON("a" << 0b11110000));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
+ setPathTaken("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(BSON("a" << 0b10010110), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b10010110)), logDoc);
+ ASSERT_EQUALS(BSON("$set" << BSON("a" << 0b10010110)), getLogDoc());
}
} // namespace
+} // namepace mongo
diff --git a/src/mongo/db/update/compare_node.cpp b/src/mongo/db/update/compare_node.cpp
index d42d8be621f..c41dbe886b1 100644
--- a/src/mongo/db/update/compare_node.cpp
+++ b/src/mongo/db/update/compare_node.cpp
@@ -46,13 +46,13 @@ void CompareNode::setCollator(const CollatorInterface* collator) {
_collator = collator;
}
-void CompareNode::updateExistingElement(mutablebson::Element* element, bool* noop) const {
+bool CompareNode::updateExistingElement(mutablebson::Element* element) const {
const auto compareVal = element->compareWithBSONElement(_val, _collator, false);
if ((compareVal == 0) || ((_mode == CompareMode::kMax) ? (compareVal > 0) : (compareVal < 0))) {
- *noop = true;
+ return false;
} else {
- *noop = false;
invariantOK(element->setValueBSONElement(_val));
+ return true;
}
}
diff --git a/src/mongo/db/update/compare_node.h b/src/mongo/db/update/compare_node.h
index 0a4cfac3379..eb071652d5d 100644
--- a/src/mongo/db/update/compare_node.h
+++ b/src/mongo/db/update/compare_node.h
@@ -51,7 +51,7 @@ public:
void setCollator(const CollatorInterface* collator) final;
protected:
- void updateExistingElement(mutablebson::Element* element, bool* noop) const final;
+ bool updateExistingElement(mutablebson::Element* element) const final;
void setValueForNewElement(mutablebson::Element* element) const final;
private:
diff --git a/src/mongo/db/update/compare_node_test.cpp b/src/mongo/db/update/compare_node_test.cpp
index 1f0a9c40c96..d69ac1c5d8b 100644
--- a/src/mongo/db/update/compare_node_test.cpp
+++ b/src/mongo/db/update/compare_node_test.cpp
@@ -34,12 +34,14 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
+namespace mongo {
namespace {
-using namespace mongo;
+using CompareNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
@@ -51,562 +53,262 @@ DEATH_TEST(CompareNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr
node.init(update["$max"].embeddedObject().firstElement(), collator).ignore();
}
-TEST(CompareNodeTest, ApplyMaxSameNumber) {
+TEST_F(CompareNodeTest, ApplyMaxSameNumber) {
auto update = fromjson("{$max: {a: 1}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMinSameNumber) {
+TEST_F(CompareNodeTest, ApplyMinSameNumber) {
auto update = fromjson("{$min: {a: 1}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMin);
ASSERT_OK(node.init(update["$min"]["a"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMaxNumberIsLess) {
+TEST_F(CompareNodeTest, ApplyMaxNumberIsLess) {
auto update = fromjson("{$max: {a: 0}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMinNumberIsMore) {
+TEST_F(CompareNodeTest, ApplyMinNumberIsMore) {
auto update = fromjson("{$min: {a: 2}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMin);
ASSERT_OK(node.init(update["$min"]["a"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMaxSameValInt) {
+TEST_F(CompareNodeTest, ApplyMaxSameValInt) {
auto update = BSON("$max" << BSON("a" << 1LL));
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{a: 1.0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1.0}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMaxSameValIntZero) {
+TEST_F(CompareNodeTest, ApplyMaxSameValIntZero) {
auto update = BSON("$max" << BSON("a" << 0LL));
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{a: 0.0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 0.0}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMinSameValIntZero) {
+TEST_F(CompareNodeTest, ApplyMinSameValIntZero) {
auto update = BSON("$min" << BSON("a" << 0LL));
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMin);
ASSERT_OK(node.init(update["$min"]["a"], collator));
Document doc(fromjson("{a: 0.0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 0.0}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMissingFieldMinNumber) {
+TEST_F(CompareNodeTest, ApplyMissingFieldMinNumber) {
auto update = fromjson("{$min: {a: 0}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMin);
ASSERT_OK(node.init(update["$min"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 0}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyExistingNumberMinNumber) {
+TEST_F(CompareNodeTest, ApplyExistingNumberMinNumber) {
auto update = fromjson("{$min: {a: 0}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMin);
ASSERT_OK(node.init(update["$min"]["a"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 0}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMissingFieldMaxNumber) {
+TEST_F(CompareNodeTest, ApplyMissingFieldMaxNumber) {
auto update = fromjson("{$max: {a: 0}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 0}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 0}}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyExistingNumberMaxNumber) {
+TEST_F(CompareNodeTest, ApplyExistingNumberMaxNumber) {
auto update = fromjson("{$max: {a: 2}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 2}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 2}}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyExistingDateMaxDate) {
+TEST_F(CompareNodeTest, ApplyExistingDateMaxDate) {
auto update = fromjson("{$max: {a: {$date: 123123123}}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{a: {$date: 0}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {$date: 123123123}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: {$date: 123123123}}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: {$date: 123123123}}}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyExistingEmbeddedDocMaxDoc) {
+TEST_F(CompareNodeTest, ApplyExistingEmbeddedDocMaxDoc) {
auto update = fromjson("{$max: {a: {b: 3}}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 3}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: {b: 3}}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: {b: 3}}}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyExistingEmbeddedDocMaxNumber) {
+TEST_F(CompareNodeTest, ApplyExistingEmbeddedDocMaxNumber) {
auto update = fromjson("{$max: {a: 3}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMinRespectsCollation) {
+TEST_F(CompareNodeTest, ApplyMinRespectsCollation) {
auto update = fromjson("{$min: {a: 'dba'}}");
const CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
CompareNode node(CompareNode::CompareMode::kMin);
ASSERT_OK(node.init(update["$min"]["a"], &collator));
Document doc(fromjson("{a: 'cbc'}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 'dba'}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 'dba'}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 'dba'}}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMinRespectsCollationFromSetCollator) {
+TEST_F(CompareNodeTest, ApplyMinRespectsCollationFromSetCollator) {
auto update = fromjson("{$min: {a: 'dba'}}");
const CollatorInterface* binaryComparisonCollator = nullptr;
CompareNode node(CompareNode::CompareMode::kMin);
@@ -617,37 +319,17 @@ TEST(CompareNodeTest, ApplyMinRespectsCollationFromSetCollator) {
node.setCollator(&reverseStringCollator);
Document doc(fromjson("{a: 'cbc'}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 'dba'}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 'dba'}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 'dba'}}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyMaxRespectsCollationFromSetCollator) {
+TEST_F(CompareNodeTest, ApplyMaxRespectsCollationFromSetCollator) {
auto update = fromjson("{$max: {a: 'abd'}}");
const CollatorInterface* binaryComparisonCollator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
@@ -658,34 +340,14 @@ TEST(CompareNodeTest, ApplyMaxRespectsCollationFromSetCollator) {
node.setCollator(&reverseStringCollator);
Document doc(fromjson("{a: 'cbc'}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 'abd'}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 'abd'}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 'abd'}}"), getLogDoc());
}
DEATH_TEST(CompareNodeTest, CannotSetCollatorIfCollatorIsNonNull, "Invariant failure !_collator") {
@@ -709,75 +371,38 @@ DEATH_TEST(CompareNodeTest, CannotSetCollatorTwice, "Invariant failure !_collato
node.setCollator(&caseInsensitiveCollator);
}
-TEST(CompareNodeTest, ApplyIndexesNotAffected) {
+TEST_F(CompareNodeTest, ApplyIndexesNotAffected) {
auto update = fromjson("{$max: {a: 1}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("b");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 1}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 1}}"), getLogDoc());
}
-TEST(CompareNodeTest, ApplyNoIndexDataOrLogBuilder) {
+TEST_F(CompareNodeTest, ApplyNoIndexDataOrLogBuilder) {
auto update = fromjson("{$max: {a: 1}}");
const CollatorInterface* collator = nullptr;
CompareNode node(CompareNode::CompareMode::kMax);
ASSERT_OK(node.init(update["$max"]["a"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ setLogBuilderToNull();
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
} // namespace
+} // namespace mongo
diff --git a/src/mongo/db/update/conflict_placeholder_node.h b/src/mongo/db/update/conflict_placeholder_node.h
index 4684226e409..ceb88d69e20 100644
--- a/src/mongo/db/update/conflict_placeholder_node.h
+++ b/src/mongo/db/update/conflict_placeholder_node.h
@@ -54,17 +54,9 @@ public:
void setCollator(const CollatorInterface* collator) final {}
- void apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const final {}
+ ApplyResult apply(ApplyParams applyParams) const final {
+ return ApplyResult::noopResult();
+ }
};
} // namespace mongo
diff --git a/src/mongo/db/update/current_date_node.cpp b/src/mongo/db/update/current_date_node.cpp
index acca32d4cb8..0224fc9ba33 100644
--- a/src/mongo/db/update/current_date_node.cpp
+++ b/src/mongo/db/update/current_date_node.cpp
@@ -93,9 +93,9 @@ Status CurrentDateNode::init(BSONElement modExpr, const CollatorInterface* colla
return Status::OK();
}
-void CurrentDateNode::updateExistingElement(mutablebson::Element* element, bool* noop) const {
- *noop = false;
+bool CurrentDateNode::updateExistingElement(mutablebson::Element* element) const {
setValue(element, _typeIsDate);
+ return true;
}
void CurrentDateNode::setValueForNewElement(mutablebson::Element* element) const {
diff --git a/src/mongo/db/update/current_date_node.h b/src/mongo/db/update/current_date_node.h
index c6881d27fb3..c30fd5b1974 100644
--- a/src/mongo/db/update/current_date_node.h
+++ b/src/mongo/db/update/current_date_node.h
@@ -47,7 +47,7 @@ public:
void setCollator(const CollatorInterface* collator) final {}
protected:
- void updateExistingElement(mutablebson::Element* element, bool* noop) const final;
+ bool updateExistingElement(mutablebson::Element* element) const final;
void setValueForNewElement(mutablebson::Element* element) const final;
private:
diff --git a/src/mongo/db/update/current_date_node_test.cpp b/src/mongo/db/update/current_date_node_test.cpp
index 8efb36e79c7..7a5005b83d8 100644
--- a/src/mongo/db/update/current_date_node_test.cpp
+++ b/src/mongo/db/update/current_date_node_test.cpp
@@ -33,31 +33,18 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
-#include "mongo/db/logical_clock.h"
-#include "mongo/db/service_context_noop.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
+namespace mongo {
namespace {
-using namespace mongo;
+using CurrentDateNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
-class CurrentDateNodeTest : public mongo::unittest::Test {
-public:
- ~CurrentDateNodeTest() override = default;
-
-protected:
- void setUp() override {
- auto service = mongo::getGlobalServiceContext();
- auto logicalClock = mongo::stdx::make_unique<mongo::LogicalClock>(service);
- mongo::LogicalClock::set(service, std::move(logicalClock));
- }
- void tearDown() override{};
-};
-
DEATH_TEST(CurrentDateNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr.ok()") {
auto update = fromjson("{$currentDate: {}}");
const CollatorInterface* collator = nullptr;
@@ -142,41 +129,21 @@ TEST_F(CurrentDateNodeTest, ApplyTrue) {
ASSERT_OK(node.init(update["$currentDate"]["a"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(doc.root().countChildren(), 1U);
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::Date);
- ASSERT_EQUALS(logDoc.root().countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"]["a"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"]["a"].getType(), BSONType::Date);
+ ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::Date);
}
TEST_F(CurrentDateNodeTest, ApplyFalse) {
@@ -186,41 +153,21 @@ TEST_F(CurrentDateNodeTest, ApplyFalse) {
ASSERT_OK(node.init(update["$currentDate"]["a"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(doc.root().countChildren(), 1U);
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::Date);
- ASSERT_EQUALS(logDoc.root().countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"]["a"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"]["a"].getType(), BSONType::Date);
+ ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::Date);
}
TEST_F(CurrentDateNodeTest, ApplyDate) {
@@ -230,41 +177,21 @@ TEST_F(CurrentDateNodeTest, ApplyDate) {
ASSERT_OK(node.init(update["$currentDate"]["a"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(doc.root().countChildren(), 1U);
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::Date);
- ASSERT_EQUALS(logDoc.root().countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"]["a"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"]["a"].getType(), BSONType::Date);
+ ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::Date);
}
TEST_F(CurrentDateNodeTest, ApplyTimestamp) {
@@ -274,41 +201,21 @@ TEST_F(CurrentDateNodeTest, ApplyTimestamp) {
ASSERT_OK(node.init(update["$currentDate"]["a"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(doc.root().countChildren(), 1U);
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::bsonTimestamp);
- ASSERT_EQUALS(logDoc.root().countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"]["a"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"]["a"].getType(), BSONType::bsonTimestamp);
+ ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::bsonTimestamp);
}
TEST_F(CurrentDateNodeTest, ApplyFieldDoesNotExist) {
@@ -318,41 +225,21 @@ TEST_F(CurrentDateNodeTest, ApplyFieldDoesNotExist) {
ASSERT_OK(node.init(update["$currentDate"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(doc.root().countChildren(), 1U);
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::Date);
- ASSERT_EQUALS(logDoc.root().countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"]["a"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"]["a"].getType(), BSONType::Date);
+ ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::Date);
}
TEST_F(CurrentDateNodeTest, ApplyIndexesNotAffected) {
@@ -362,41 +249,21 @@ TEST_F(CurrentDateNodeTest, ApplyIndexesNotAffected) {
ASSERT_OK(node.init(update["$currentDate"]["a"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("b");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(doc.root().countChildren(), 1U);
ASSERT_TRUE(doc.root()["a"].ok());
ASSERT_EQUALS(doc.root()["a"].getType(), BSONType::Date);
- ASSERT_EQUALS(logDoc.root().countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"].countChildren(), 1U);
- ASSERT_TRUE(logDoc.root()["$set"]["a"].ok());
- ASSERT_EQUALS(logDoc.root()["$set"]["a"].getType(), BSONType::Date);
+ ASSERT_EQUALS(getLogDoc().root().countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"].countChildren(), 1U);
+ ASSERT_TRUE(getLogDoc().root()["$set"]["a"].ok());
+ ASSERT_EQUALS(getLogDoc().root()["$set"]["a"].getType(), BSONType::Date);
}
TEST_F(CurrentDateNodeTest, ApplyNoIndexDataOrLogBuilder) {
@@ -406,29 +273,11 @@ TEST_F(CurrentDateNodeTest, ApplyNoIndexDataOrLogBuilder) {
ASSERT_OK(node.init(update["$currentDate"]["a"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ setLogBuilderToNull();
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(doc.root().countChildren(), 1U);
ASSERT_TRUE(doc.root()["a"].ok());
@@ -436,3 +285,4 @@ TEST_F(CurrentDateNodeTest, ApplyNoIndexDataOrLogBuilder) {
}
} // namespace
+} // namespace
diff --git a/src/mongo/db/update/object_replace_node.cpp b/src/mongo/db/update/object_replace_node.cpp
index 974e4d59a3e..151db825dba 100644
--- a/src/mongo/db/update/object_replace_node.cpp
+++ b/src/mongo/db/update/object_replace_node.cpp
@@ -69,34 +69,19 @@ ObjectReplaceNode::ObjectReplaceNode(BSONObj val)
}
}
-void ObjectReplaceNode::apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const {
- invariant(pathToCreate->empty());
- invariant(pathTaken->empty());
-
- auto original = element.getDocument().getObject();
+UpdateNode::ApplyResult ObjectReplaceNode::apply(ApplyParams applyParams) const {
+ invariant(applyParams.pathToCreate->empty());
+ invariant(applyParams.pathTaken->empty());
+
+ auto original = applyParams.element.getDocument().getObject();
// Check for noop.
if (original.binaryEqual(_val)) {
- *indexesAffected = false;
- *noop = true;
- return;
+ return ApplyResult::noopResult();
}
- *indexesAffected = true;
- *noop = false;
-
// Remove the contents of the provided document.
- auto current = element.leftChild();
+ auto current = applyParams.element.leftChild();
while (current.ok()) {
// Keep the _id if the replacement document does not have one.
@@ -112,19 +97,20 @@ void ObjectReplaceNode::apply(mutablebson::Element element,
// Insert the provided contents instead.
for (auto&& elem : _val) {
- invariantOK(element.appendElement(elem));
+ invariantOK(applyParams.element.appendElement(elem));
}
// Validate for storage.
- if (validateForStorage) {
- storage_validation::storageValid(element.getDocument());
+ if (applyParams.validateForStorage) {
+ storage_validation::storageValid(applyParams.element.getDocument());
}
// Check immutable paths.
- for (auto path = immutablePaths.begin(); path != immutablePaths.end(); ++path) {
+ for (auto path = applyParams.immutablePaths.begin(); path != applyParams.immutablePaths.end();
+ ++path) {
// Find the updated field in the updated document.
- auto newElem = element;
+ auto newElem = applyParams.element;
for (size_t i = 0; i < (*path)->numParts(); ++i) {
newElem = newElem[(*path)->getPart(i)];
if (!newElem.ok()) {
@@ -156,13 +142,16 @@ void ObjectReplaceNode::apply(mutablebson::Element element,
}
}
- if (logBuilder) {
- auto replacementObject = logBuilder->getDocument().end();
- invariantOK(logBuilder->getReplacementObject(&replacementObject));
- for (auto current = element.leftChild(); current.ok(); current = current.rightSibling()) {
+ if (applyParams.logBuilder) {
+ auto replacementObject = applyParams.logBuilder->getDocument().end();
+ invariantOK(applyParams.logBuilder->getReplacementObject(&replacementObject));
+ for (auto current = applyParams.element.leftChild(); current.ok();
+ current = current.rightSibling()) {
invariantOK(replacementObject.appendElement(current.getValue()));
}
}
+
+ return ApplyResult();
}
} // namespace mongo
diff --git a/src/mongo/db/update/object_replace_node.h b/src/mongo/db/update/object_replace_node.h
index c85371828a0..bc626fd0cf3 100644
--- a/src/mongo/db/update/object_replace_node.h
+++ b/src/mongo/db/update/object_replace_node.h
@@ -52,25 +52,13 @@ public:
void setCollator(const CollatorInterface* collator) final {}
/**
- * Replaces the document that 'element' belongs to with '_val'. If '_val' does not contain an
- * _id, the _id from the original document is preserved. 'element' must be the root of the
- * document. 'pathToCreate' and 'pathTaken' must be empty. If 'validateForStorage' is true, the
- * modified document is validated for storage. Throws if any path in 'immutablePaths' is
- * modified (but it may be created if it did not yet exist). Logs the update as a
- * replacement-style update. Always outputs that indexes are affected when the replacement is
- * not a noop.
+ * Replaces the document that 'applyParams.element' belongs to with '_val'. If '_val' does not
+ * contain an _id, the _id from the original document is preserved. 'applyParams.element' must
+ * be the root of the document. 'applyParams.pathToCreate' and 'applyParams.pathTaken' must be
+ * empty. Always returns a result stating that indexes are affected when the replacement is not
+ * a noop.
*/
- void apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const final;
+ ApplyResult apply(ApplyParams applyParams) const final;
private:
// Object to replace with.
diff --git a/src/mongo/db/update/object_replace_node_test.cpp b/src/mongo/db/update/object_replace_node_test.cpp
index d567c730bce..69c3bbf6070 100644
--- a/src/mongo/db/update/object_replace_node_test.cpp
+++ b/src/mongo/db/update/object_replace_node_test.cpp
@@ -35,60 +35,28 @@
#include "mongo/db/json.h"
#include "mongo/db/logical_clock.h"
#include "mongo/db/service_context_noop.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
namespace {
+using ObjectReplaceNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
-class ObjectReplaceNodeTest : public mongo::unittest::Test {
-public:
- ~ObjectReplaceNodeTest() override = default;
-
-protected:
- void setUp() override {
- auto service = mongo::getGlobalServiceContext();
- auto logicalClock = mongo::stdx::make_unique<mongo::LogicalClock>(service);
- mongo::LogicalClock::set(service, std::move(logicalClock));
- }
- void tearDown() override{};
-};
-
TEST_F(ObjectReplaceNodeTest, Noop) {
auto obj = fromjson("{a: 1, b: 2}");
ObjectReplaceNode node(obj);
Document doc(fromjson("{a: 1, b: 2}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1, b: 2}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, ShouldNotCreateIdIfNoIdExistsAndNoneIsSpecified) {
@@ -96,33 +64,12 @@ TEST_F(ObjectReplaceNodeTest, ShouldNotCreateIdIfNoIdExistsAndNoneIsSpecified) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{c: 1, d: 2}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1, b: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{a: 1, b: 2}"), logDoc);
+ ASSERT_EQUALS(fromjson("{a: 1, b: 2}"), getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, ShouldPreserveIdOfExistingDocumentIfIdNotSpecified) {
@@ -130,33 +77,12 @@ TEST_F(ObjectReplaceNodeTest, ShouldPreserveIdOfExistingDocumentIfIdNotSpecified
ObjectReplaceNode node(obj);
Document doc(fromjson("{_id: 0, c: 1, d: 2}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id: 0, a: 1, b: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{_id: 0, a: 1, b: 2}"), logDoc);
+ ASSERT_EQUALS(fromjson("{_id: 0, a: 1, b: 2}"), getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, ShouldSucceedWhenImmutableIdIsNotModified) {
@@ -164,35 +90,13 @@ TEST_F(ObjectReplaceNodeTest, ShouldSucceedWhenImmutableIdIsNotModified) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{_id: 0, c: 1, d: 2}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("_id");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ addImmutablePath("_id");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id: 0, a: 1, b: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{_id: 0, a: 1, b: 2}"), logDoc);
+ ASSERT_EQUALS(fromjson("{_id: 0, a: 1, b: 2}"), getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, IdTimestampNotModified) {
@@ -200,33 +104,12 @@ TEST_F(ObjectReplaceNodeTest, IdTimestampNotModified) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id: Timestamp(0,0)}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{_id: Timestamp(0,0)}"), logDoc);
+ ASSERT_EQUALS(fromjson("{_id: Timestamp(0,0)}"), getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, NonIdTimestampsModified) {
@@ -234,30 +117,9 @@ TEST_F(ObjectReplaceNodeTest, NonIdTimestampsModified) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(doc.root().countChildren(), 2U);
@@ -274,7 +136,7 @@ TEST_F(ObjectReplaceNodeTest, NonIdTimestampsModified) {
ASSERT_NOT_EQUALS(0U, elemB.getValueTimestamp().getInc());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(doc, logDoc);
+ ASSERT_EQUALS(doc, getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, ComplexDoc) {
@@ -282,33 +144,12 @@ TEST_F(ObjectReplaceNodeTest, ComplexDoc) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{a: 1, b: [0, 2, 2], e: []}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1, b: [0, 1, 2], c: {d: 1}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{a: 1, b: [0, 1, 2], c: {d: 1}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{a: 1, b: [0, 1, 2], c: {d: 1}}"), getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, CannotRemoveImmutablePath) {
@@ -316,30 +157,8 @@ TEST_F(ObjectReplaceNodeTest, CannotRemoveImmutablePath) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{_id: 0, a: {b: 1}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ addImmutablePath("a.b");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::ImmutableField,
"After applying the update, the 'a.b' (required and immutable) "
@@ -351,35 +170,13 @@ TEST_F(ObjectReplaceNodeTest, IdFieldIsNotRemoved) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{_id: 0, b: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("_id");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ addImmutablePath("_id");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id: 0, a: 1}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{_id: 0, a: 1}"), logDoc);
+ ASSERT_EQUALS(fromjson("{_id: 0, a: 1}"), getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, CannotReplaceImmutablePathWithArrayField) {
@@ -387,30 +184,8 @@ TEST_F(ObjectReplaceNodeTest, CannotReplaceImmutablePathWithArrayField) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{_id: 0, a: {b: 1}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ addImmutablePath("a.b");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::NotSingleValueField,
"After applying the update to the document, the (immutable) field "
@@ -422,30 +197,8 @@ TEST_F(ObjectReplaceNodeTest, CannotMakeImmutablePathArrayDescendant) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{_id: 0, a: {'0': 1}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.0");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ addImmutablePath("a.0");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::NotSingleValueField,
"After applying the update to the document, the (immutable) field "
@@ -457,30 +210,8 @@ TEST_F(ObjectReplaceNodeTest, CannotModifyImmutablePath) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{_id: 0, a: {b: 1}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ addImmutablePath("a.b");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::ImmutableField,
"After applying the update, the (immutable) field 'a.b' was found "
@@ -492,30 +223,8 @@ TEST_F(ObjectReplaceNodeTest, CannotModifyImmutableId) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{_id: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("_id");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ addImmutablePath("_id");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::ImmutableField,
"After applying the update, the (immutable) field '_id' was found "
@@ -527,35 +236,13 @@ TEST_F(ObjectReplaceNodeTest, CanAddImmutableField) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{c: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ addImmutablePath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 1}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{a: {b: 1}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{a: {b: 1}}"), getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, CanAddImmutableId) {
@@ -563,35 +250,13 @@ TEST_F(ObjectReplaceNodeTest, CanAddImmutableId) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{c: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("_id");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ addImmutablePath("_id");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id: 0}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{_id: 0}"), logDoc);
+ ASSERT_EQUALS(fromjson("{_id: 0}"), getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, CannotCreateDollarPrefixedNameWhenValidateForStorageIsTrue) {
@@ -599,29 +264,8 @@ TEST_F(ObjectReplaceNodeTest, CannotCreateDollarPrefixedNameWhenValidateForStora
ObjectReplaceNode node(obj);
Document doc(fromjson("{}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::DollarPrefixedFieldName,
"The dollar ($) prefixed field '$bad' in 'a.$bad' is not valid for storage.");
@@ -632,33 +276,13 @@ TEST_F(ObjectReplaceNodeTest, CanCreateDollarPrefixedNameWhenValidateForStorageI
ObjectReplaceNode node(obj);
Document doc(fromjson("{}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = false;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setValidateForStorage(false);
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 1, $bad: 1}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{a: {b: 1, $bad: 1}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{a: {b: 1, $bad: 1}}"), getLogDoc());
}
TEST_F(ObjectReplaceNodeTest, NoLogBuilder) {
@@ -666,29 +290,10 @@ TEST_F(ObjectReplaceNodeTest, NoLogBuilder) {
ObjectReplaceNode node(obj);
Document doc(fromjson("{b: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setLogBuilderToNull();
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
diff --git a/src/mongo/db/update/path_creating_node.cpp b/src/mongo/db/update/path_creating_node.cpp
index 97feb3fb17e..396ffdaf247 100644
--- a/src/mongo/db/update/path_creating_node.cpp
+++ b/src/mongo/db/update/path_creating_node.cpp
@@ -107,60 +107,49 @@ void checkImmutablePathsNotModified(mutablebson::Element element,
} // namespace
-void PathCreatingNode::apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const {
- *indexesAffected = false;
- *noop = false;
-
+UpdateNode::ApplyResult PathCreatingNode::apply(ApplyParams applyParams) const {
// The value in this Element gets used to create a logging entry (if we have a LogBuilder).
- mutablebson::Element valueToLog = element.getDocument().end();
+ mutablebson::Element valueToLog = applyParams.element.getDocument().end();
- if (pathToCreate->empty()) {
+ if (applyParams.pathToCreate->empty()) {
// If 'pathTaken' is a strict prefix of any immutable path, store the original document to
// ensure the immutable path does not change.
BSONObj original;
- for (auto immutablePath = immutablePaths.begin(); immutablePath != immutablePaths.end();
+ for (auto immutablePath = applyParams.immutablePaths.begin();
+ immutablePath != applyParams.immutablePaths.end();
++immutablePath) {
- if (pathTaken->isPrefixOf(**immutablePath)) {
- original = element.getDocument().getObject();
+ if (applyParams.pathTaken->isPrefixOf(**immutablePath)) {
+ original = applyParams.element.getDocument().getObject();
break;
}
}
// We found an existing element at the update path.
- updateExistingElement(&element, noop);
- if (*noop) {
- return; // Successful no-op update.
+ if (!updateExistingElement(&applyParams.element)) {
+ return ApplyResult::noopResult(); // Successful no-op update.
}
- if (validateForStorage) {
+ if (applyParams.validateForStorage) {
const bool doRecursiveCheck = true;
- const uint32_t recursionLevel = pathTaken->numParts();
- storage_validation::storageValid(element, doRecursiveCheck, recursionLevel);
+ const uint32_t recursionLevel = applyParams.pathTaken->numParts();
+ storage_validation::storageValid(applyParams.element, doRecursiveCheck, recursionLevel);
}
- checkImmutablePathsNotModified(element, pathTaken, immutablePaths, original);
+ checkImmutablePathsNotModified(
+ applyParams.element, applyParams.pathTaken.get(), applyParams.immutablePaths, original);
- valueToLog = element;
+ valueToLog = applyParams.element;
} else {
// We did not find an element at the update path. Create one.
- auto newElementFieldName = pathToCreate->getPart(pathToCreate->numParts() - 1);
- auto newElement = element.getDocument().makeElementNull(newElementFieldName);
+ auto newElementFieldName =
+ applyParams.pathToCreate->getPart(applyParams.pathToCreate->numParts() - 1);
+ auto newElement = applyParams.element.getDocument().makeElementNull(newElementFieldName);
setValueForNewElement(&newElement);
invariant(newElement.ok());
- auto statusWithFirstCreatedElem =
- pathsupport::createPathAt(*pathToCreate, 0, element, newElement);
+ auto statusWithFirstCreatedElem = pathsupport::createPathAt(
+ *(applyParams.pathToCreate), 0, applyParams.element, newElement);
if (!statusWithFirstCreatedElem.isOK()) {
// $sets on non-viable paths are ignored when the update came from replication. We do
// not error because idempotency requires that any other update modifiers must still be
@@ -174,33 +163,35 @@ void PathCreatingNode::apply(mutablebson::Element element,
// replication, so we are not concerned with their behavior when "fromReplication" is
// true.)
if (statusWithFirstCreatedElem.getStatus().code() == ErrorCodes::PathNotViable &&
- fromReplication) {
- *noop = true;
- return;
+ applyParams.fromReplication) {
+ return ApplyResult::noopResult();
}
uassertStatusOK(statusWithFirstCreatedElem);
MONGO_UNREACHABLE; // The previous uassertStatusOK should always throw.
}
- if (validateForStorage) {
+ if (applyParams.validateForStorage) {
const bool doRecursiveCheck = true;
- const uint32_t recursionLevel = pathTaken->numParts() + 1;
+ const uint32_t recursionLevel = applyParams.pathTaken->numParts() + 1;
storage_validation::storageValid(
statusWithFirstCreatedElem.getValue(), doRecursiveCheck, recursionLevel);
}
- for (auto immutablePath = immutablePaths.begin(); immutablePath != immutablePaths.end();
+ for (auto immutablePath = applyParams.immutablePaths.begin();
+ immutablePath != applyParams.immutablePaths.end();
++immutablePath) {
// If 'immutablePath' is a (strict or non-strict) prefix of 'pathTaken', then we are
// modifying 'immutablePath'. For example, adding '_id.x' will illegally modify '_id'.
uassert(ErrorCodes::ImmutableField,
- str::stream() << "Updating the path '" << pathTaken->dottedField() << "' to "
- << element.toString()
+ str::stream() << "Updating the path '" << applyParams.pathTaken->dottedField()
+ << "' to "
+ << applyParams.element.toString()
<< " would modify the immutable field '"
<< (*immutablePath)->dottedField()
<< "'",
- pathTaken->commonPrefixSize(**immutablePath) != (*immutablePath)->numParts());
+ applyParams.pathTaken->commonPrefixSize(**immutablePath) !=
+ (*immutablePath)->numParts());
}
valueToLog = newElement;
@@ -208,24 +199,28 @@ void PathCreatingNode::apply(mutablebson::Element element,
// Create full field path of set element.
StringBuilder builder;
- builder << pathTaken->dottedField();
- if (!pathTaken->empty() && !pathToCreate->empty()) {
+ builder << applyParams.pathTaken->dottedField();
+ if (!applyParams.pathTaken->empty() && !applyParams.pathToCreate->empty()) {
builder << ".";
}
- builder << pathToCreate->dottedField();
+ builder << applyParams.pathToCreate->dottedField();
auto fullPath = builder.str();
+ ApplyResult applyResult;
+
// Determine if indexes are affected.
- if (indexData && indexData->mightBeIndexed(fullPath)) {
- *indexesAffected = true;
+ if (!applyParams.indexData || !applyParams.indexData->mightBeIndexed(fullPath)) {
+ applyResult.indexesAffected = false;
}
// Log the operation.
- if (logBuilder) {
+ if (applyParams.logBuilder) {
auto logElement =
- logBuilder->getDocument().makeElementWithNewFieldName(fullPath, valueToLog);
+ applyParams.logBuilder->getDocument().makeElementWithNewFieldName(fullPath, valueToLog);
invariant(logElement.ok());
- uassertStatusOK(logBuilder->addToSets(logElement));
+ uassertStatusOK(applyParams.logBuilder->addToSets(logElement));
}
+
+ return applyResult;
}
} // namespace mongo
diff --git a/src/mongo/db/update/path_creating_node.h b/src/mongo/db/update/path_creating_node.h
index adbf770022c..22c7b6a44ad 100644
--- a/src/mongo/db/update/path_creating_node.h
+++ b/src/mongo/db/update/path_creating_node.h
@@ -41,25 +41,15 @@ namespace mongo {
*/
class PathCreatingNode : public UpdateLeafNode {
public:
- void apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const final;
+ ApplyResult apply(ApplyParams applyParams) const final;
protected:
/**
* PathCreatingNode::apply() calls the updateExistingElement() method when applying its update
* to an existing path. The child's implementation of this method is responsible for either
- * updating the given Element or setting *noop to true to indicate that no update is necessary.
+ * updating the given Element or returning false to indicate that no update is necessary.
*/
- virtual void updateExistingElement(mutablebson::Element* element, bool* noop) const = 0;
+ virtual bool updateExistingElement(mutablebson::Element* element) const = 0;
/**
* PathCreatingNode::apply() calls the setValueForNewElement() method when it must materialize a
diff --git a/src/mongo/db/update/pop_node.cpp b/src/mongo/db/update/pop_node.cpp
index 4b3f6273db3..3a862413853 100644
--- a/src/mongo/db/update/pop_node.cpp
+++ b/src/mongo/db/update/pop_node.cpp
@@ -47,79 +47,73 @@ Status PopNode::init(BSONElement modExpr, const CollatorInterface* collator) {
return Status::OK();
}
-void PopNode::apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const {
- *indexesAffected = false;
- *noop = false;
-
- if (pathTaken->empty()) {
+UpdateNode::ApplyResult PopNode::apply(ApplyParams applyParams) const {
+ if (applyParams.pathTaken->empty()) {
// No components of the path existed. The pop is treated as a no-op in this case.
- *noop = true;
- return;
+ return ApplyResult::noopResult();
}
- if (!pathToCreate->empty()) {
+ if (!applyParams.pathToCreate->empty()) {
// There were path components we could not traverse. We treat this as a no-op, unless it
// would have been impossible to create those elements, which we check with
// checkViability().
- UpdateLeafNode::checkViability(element, *pathToCreate, *pathTaken);
+ UpdateLeafNode::checkViability(
+ applyParams.element, *(applyParams.pathToCreate), *(applyParams.pathTaken));
- *noop = true;
- return;
+ return ApplyResult::noopResult();
}
- invariant(!pathTaken->empty());
- invariant(pathToCreate->empty());
+ invariant(!applyParams.pathTaken->empty());
+ invariant(applyParams.pathToCreate->empty());
// The full path existed, but we must fail if the element at that path is not an array.
- invariant(element.ok());
+ invariant(applyParams.element.ok());
uassert(ErrorCodes::TypeMismatch,
- str::stream() << "Path '" << pathTaken->dottedField()
+ str::stream() << "Path '" << applyParams.pathTaken->dottedField()
<< "' contains an element of non-array type '"
- << typeName(element.getType())
+ << typeName(applyParams.element.getType())
<< "'",
- element.getType() == BSONType::Array);
+ applyParams.element.getType() == BSONType::Array);
- if (!element.hasChildren()) {
+ if (!applyParams.element.hasChildren()) {
// The path exists and contains an array, but the array is empty.
- *noop = true;
- return;
+ return ApplyResult::noopResult();
}
- if (indexData && indexData->mightBeIndexed(pathTaken->dottedField())) {
- *indexesAffected = true;
+ ApplyResult applyResult;
+
+ if (!applyParams.indexData ||
+ !applyParams.indexData->mightBeIndexed(applyParams.pathTaken->dottedField())) {
+ applyResult.indexesAffected = false;
}
- auto elementToRemove = _popFromFront ? element.leftChild() : element.rightChild();
+ auto elementToRemove =
+ _popFromFront ? applyParams.element.leftChild() : applyParams.element.rightChild();
invariantOK(elementToRemove.remove());
// No need to validate for storage, since we cannot have increased the BSON depth or interfered
// with a DBRef.
// Ensure we are not changing any immutable paths.
- for (auto immutablePath = immutablePaths.begin(); immutablePath != immutablePaths.end();
+ for (auto immutablePath = applyParams.immutablePaths.begin();
+ immutablePath != applyParams.immutablePaths.end();
++immutablePath) {
uassert(ErrorCodes::ImmutableField,
- str::stream() << "Performing a $pop on the path '" << pathTaken->dottedField()
+ str::stream() << "Performing a $pop on the path '"
+ << applyParams.pathTaken->dottedField()
<< "' would modify the immutable field '"
<< (*immutablePath)->dottedField()
<< "'",
- pathTaken->commonPrefixSize(**immutablePath) <
- std::min(pathTaken->numParts(), (*immutablePath)->numParts()));
+ applyParams.pathTaken->commonPrefixSize(**immutablePath) <
+ std::min(applyParams.pathTaken->numParts(), (*immutablePath)->numParts()));
}
- if (logBuilder) {
- uassertStatusOK(logBuilder->addToSetsWithNewFieldName(pathTaken->dottedField(), element));
+ if (applyParams.logBuilder) {
+ uassertStatusOK(applyParams.logBuilder->addToSetsWithNewFieldName(
+ applyParams.pathTaken->dottedField(), applyParams.element));
}
+
+ return applyResult;
}
} // namespace mongo
diff --git a/src/mongo/db/update/pop_node.h b/src/mongo/db/update/pop_node.h
index 7d7a2d13f14..1cbdac4b1bc 100644
--- a/src/mongo/db/update/pop_node.h
+++ b/src/mongo/db/update/pop_node.h
@@ -37,17 +37,7 @@ class PopNode final : public UpdateLeafNode {
public:
Status init(BSONElement modExpr, const CollatorInterface* collator) final;
- void apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const final;
+ ApplyResult apply(ApplyParams applyParams) const final;
std::unique_ptr<UpdateNode> clone() const final {
return stdx::make_unique<PopNode>(*this);
diff --git a/src/mongo/db/update/pop_node_test.cpp b/src/mongo/db/update/pop_node_test.cpp
index 9442544af47..4cb14505988 100644
--- a/src/mongo/db/update/pop_node_test.cpp
+++ b/src/mongo/db/update/pop_node_test.cpp
@@ -32,6 +32,7 @@
#include "mongo/bson/json.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
@@ -39,6 +40,7 @@ namespace mongo {
namespace {
namespace mmb = mongo::mutablebson;
+using PopNodeTest = UpdateNodeTest;
TEST(PopNodeTest, InitSucceedsPositiveOne) {
auto update = fromjson("{$pop: {a: 1}}");
@@ -98,254 +100,119 @@ TEST(PopNodeTest, InitFailsBool) {
ASSERT_EQ(ErrorCodes::FailedToParse, popNode.init(update["$pop"]["a"], collator));
}
-TEST(PopNodeTest, NoopWhenFirstPathComponentDoesNotExist) {
+TEST_F(PopNodeTest, NoopWhenFirstPathComponentDoesNotExist) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator));
mmb::Document doc(fromjson("{b: [1, 2, 3]}"));
- FieldRef pathToCreate("a.b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("a.b");
+ addIndexedPath("a.b");
+ auto result = popNode.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: [1, 2, 3]}"), doc);
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PopNodeTest, NoopWhenPathPartiallyExists) {
+TEST_F(PopNodeTest, NoopWhenPathPartiallyExists) {
auto update = fromjson("{$pop: {'a.b.c': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
ASSERT_OK(popNode.init(update["$pop"]["a.b.c"], collator));
mmb::Document doc(fromjson("{a: {}}"));
- FieldRef pathToCreate("b.c");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b.c");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("b.c");
+ setPathTaken("a");
+ addIndexedPath("a.b.c");
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {}}"), doc);
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PopNodeTest, NoopWhenNumericalPathComponentExceedsArrayLength) {
+TEST_F(PopNodeTest, NoopWhenNumericalPathComponentExceedsArrayLength) {
auto update = fromjson("{$pop: {'a.0': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
ASSERT_OK(popNode.init(update["$pop"]["a.0"], collator));
mmb::Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("0");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.0");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("0");
+ setPathTaken("a");
+ addIndexedPath("a.0");
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PopNodeTest, ThrowsWhenPathIsBlockedByAScalar) {
+TEST_F(PopNodeTest, ThrowsWhenPathIsBlockedByAScalar) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator));
mmb::Document doc(fromjson("{a: 'foo'}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
+ setPathToCreate("b");
+ setPathTaken("a");
+ addIndexedPath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- popNode.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ popNode.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::PathNotViable,
"Cannot use the part (b) of (a.b) to traverse the element ({a: \"foo\"})");
}
-DEATH_TEST(PopNodeTest, NonOkElementWhenPathExistsIsFatal, "Invariant failure element.ok()") {
+DEATH_TEST_F(PopNodeTest,
+ NonOkElementWhenPathExistsIsFatal,
+ "Invariant failure applyParams.element.ok()") {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator));
mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.end(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ popNode.apply(getApplyParams(doc.end()));
}
-TEST(PopNodeTest, ThrowsWhenPathExistsButDoesNotContainAnArray) {
+TEST_F(PopNodeTest, ThrowsWhenPathExistsButDoesNotContainAnArray) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator));
mmb::Document doc(fromjson("{a: {b: 'foo'}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- ASSERT_THROWS_CODE_AND_WHAT(popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ ASSERT_THROWS_CODE_AND_WHAT(popNode.apply(getApplyParams(doc.root()["a"]["b"])),
UserException,
ErrorCodes::TypeMismatch,
"Path 'a.b' contains an element of non-array type 'string'");
}
-TEST(PopNodeTest, NoopWhenPathContainsAnEmptyArray) {
+TEST_F(PopNodeTest, NoopWhenPathContainsAnEmptyArray) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator));
mmb::Document doc(fromjson("{a: {b: []}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: []}}"), doc);
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PopNodeTest, PopsSingleElementFromTheBack) {
+TEST_F(PopNodeTest, PopsSingleElementFromTheBack) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
@@ -353,36 +220,16 @@ TEST(PopNodeTest, PopsSingleElementFromTheBack) {
ASSERT_FALSE(popNode.popFromFront());
mmb::Document doc(fromjson("{a: {b: [1]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: []}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': []}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': []}}"), getLogDoc());
}
-TEST(PopNodeTest, PopsSingleElementFromTheFront) {
+TEST_F(PopNodeTest, PopsSingleElementFromTheFront) {
auto update = fromjson("{$pop: {'a.b': -1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
@@ -390,36 +237,16 @@ TEST(PopNodeTest, PopsSingleElementFromTheFront) {
ASSERT_TRUE(popNode.popFromFront());
mmb::Document doc(fromjson("{a: {b: [[1]]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a");
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: []}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': []}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': []}}"), getLogDoc());
}
-TEST(PopNodeTest, PopsFromTheBackOfMultiElementArray) {
+TEST_F(PopNodeTest, PopsFromTheBackOfMultiElementArray) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
@@ -427,36 +254,16 @@ TEST(PopNodeTest, PopsFromTheBackOfMultiElementArray) {
ASSERT_FALSE(popNode.popFromFront());
mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b.c");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b.c");
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [1, 2]}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [1, 2]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': [1, 2]}}"), getLogDoc());
}
-TEST(PopNodeTest, PopsFromTheFrontOfMultiElementArray) {
+TEST_F(PopNodeTest, PopsFromTheFrontOfMultiElementArray) {
auto update = fromjson("{$pop: {'a.b': -1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
@@ -464,36 +271,16 @@ TEST(PopNodeTest, PopsFromTheFrontOfMultiElementArray) {
ASSERT_TRUE(popNode.popFromFront());
mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [2, 3]}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [2, 3]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': [2, 3]}}"), getLogDoc());
}
-TEST(PopNodeTest, PopsFromTheFrontOfMultiElementArrayWithoutAffectingIndexes) {
+TEST_F(PopNodeTest, PopsFromTheFrontOfMultiElementArrayWithoutAffectingIndexes) {
auto update = fromjson("{$pop: {'a.b': -1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
@@ -501,36 +288,16 @@ TEST(PopNodeTest, PopsFromTheFrontOfMultiElementArrayWithoutAffectingIndexes) {
ASSERT_TRUE(popNode.popFromFront());
mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("unrelated.path");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("unrelated.path");
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [2, 3]}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [2, 3]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': [2, 3]}}"), getLogDoc());
}
-TEST(PopNodeTest, SucceedsWithNullUpdateIndexData) {
+TEST_F(PopNodeTest, SucceedsWithNullUpdateIndexData) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
@@ -538,34 +305,15 @@ TEST(PopNodeTest, SucceedsWithNullUpdateIndexData) {
ASSERT_FALSE(popNode.popFromFront());
mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- nullptr,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.b");
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [1, 2]}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [1, 2]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': [1, 2]}}"), getLogDoc());
}
-TEST(PopNodeTest, SucceedsWithNullLogBuilder) {
+TEST_F(PopNodeTest, SucceedsWithNullLogBuilder) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
@@ -573,71 +321,33 @@ TEST(PopNodeTest, SucceedsWithNullLogBuilder) {
ASSERT_FALSE(popNode.popFromFront());
mmb::Document doc(fromjson("{a: {b: [1, 2, 3]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b.c");
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- nullptr,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b.c");
+ setLogBuilderToNull();
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [1, 2]}}"), doc);
}
-TEST(PopNodeTest, ThrowsWhenPathIsImmutable) {
+TEST_F(PopNodeTest, ThrowsWhenPathIsImmutable) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator));
mmb::Document doc(fromjson("{a: {b: [0]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
+ setPathTaken("a.b");
+ addImmutablePath("a.b");
+ addIndexedPath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ popNode.apply(getApplyParams(doc.root()["a"]["b"])),
UserException,
ErrorCodes::ImmutableField,
"Performing a $pop on the path 'a.b' would modify the immutable field 'a.b'");
}
-TEST(PopNodeTest, ThrowsWhenPathIsPrefixOfImmutable) {
+TEST_F(PopNodeTest, ThrowsWhenPathIsPrefixOfImmutable) {
// This is only possible for an upsert, since it is not legal to have an array in an immutable
// path. If this update did not fail, we would fail later for storing an immutable path with an
@@ -649,111 +359,48 @@ TEST(PopNodeTest, ThrowsWhenPathIsPrefixOfImmutable) {
ASSERT_OK(popNode.init(update["$pop"]["a"], collator));
mmb::Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.0");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
+ setPathTaken("a");
+ addImmutablePath("a.0");
+ addIndexedPath("a");
ASSERT_THROWS_CODE_AND_WHAT(
- popNode.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ popNode.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::ImmutableField,
"Performing a $pop on the path 'a' would modify the immutable field 'a.0'");
}
-TEST(PopNodeTest, ThrowsWhenPathIsSuffixOfImmutable) {
+TEST_F(PopNodeTest, ThrowsWhenPathIsSuffixOfImmutable) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator));
mmb::Document doc(fromjson("{a: {b: [0]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
+ setPathTaken("a.b");
+ addImmutablePath("a");
+ addIndexedPath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ popNode.apply(getApplyParams(doc.root()["a"]["b"])),
UserException,
ErrorCodes::ImmutableField,
"Performing a $pop on the path 'a.b' would modify the immutable field 'a'");
}
-TEST(PopNodeTest, NoopOnImmutablePathSucceeds) {
+TEST_F(PopNodeTest, NoopOnImmutablePathSucceeds) {
auto update = fromjson("{$pop: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
PopNode popNode;
ASSERT_OK(popNode.init(update["$pop"]["a.b"], collator));
mmb::Document doc(fromjson("{a: {b: []}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- mmb::Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- popNode.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.b");
+ addImmutablePath("a.b");
+ addIndexedPath("a.b");
+ auto result = popNode.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: []}}"), doc);
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
} // namespace
diff --git a/src/mongo/db/update/pull_node_test.cpp b/src/mongo/db/update/pull_node_test.cpp
index b00a4fbd36d..f158b1c0678 100644
--- a/src/mongo/db/update/pull_node_test.cpp
+++ b/src/mongo/db/update/pull_node_test.cpp
@@ -34,12 +34,14 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
+namespace mongo {
namespace {
-using namespace mongo;
+using PullNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
@@ -62,406 +64,190 @@ TEST(PullNodeTest, InitWithBadTopLevelOperatorFails) {
ASSERT_EQUALS(ErrorCodes::BadValue, status);
}
-TEST(PullNodeTest, TargetNotFound) {
+TEST_F(PullNodeTest, TargetNotFound) {
auto update = fromjson("{$pull : {a: {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyToStringFails) {
+TEST_F(PullNodeTest, ApplyToStringFails) {
auto update = fromjson("{$pull : {a: {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: 'foo'}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::BadValue,
"Cannot apply $pull to a non-array value");
}
-TEST(PullNodeTest, ApplyToObjectFails) {
+TEST_F(PullNodeTest, ApplyToObjectFails) {
auto update = fromjson("{$pull : {a: {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: {foo: 'bar'}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::BadValue,
"Cannot apply $pull to a non-array value");
}
-TEST(PullNodeTest, ApplyToNonViablePathFails) {
+TEST_F(PullNodeTest, ApplyToNonViablePathFails) {
auto update = fromjson("{$pull : {'a.b': {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a.b"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("b");
+ setPathTaken("a");
+ addIndexedPath("a");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::PathNotViable,
"Cannot use the part (b) of (a.b) to traverse the element ({a: 1})");
}
-TEST(PullNodeTest, ApplyToMissingElement) {
+TEST_F(PullNodeTest, ApplyToMissingElement) {
auto update = fromjson("{$pull: {'a.b.c.d': {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a.b.c.d"], collator));
Document doc(fromjson("{a: {b: {c: {}}}}"));
- FieldRef pathToCreate("d");
- FieldRef pathTaken("a.b.c");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"]["c"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("d");
+ setPathTaken("a.b.c");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]["c"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: {c: {}}}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyToEmptyArray) {
+TEST_F(PullNodeTest, ApplyToEmptyArray) {
auto update = fromjson("{$pull : {a: {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyToArrayMatchingNone) {
+TEST_F(PullNodeTest, ApplyToArrayMatchingNone) {
auto update = fromjson("{$pull : {a: {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: [2, 3, 4, 5]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [2, 3, 4, 5]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyToArrayMatchingOne) {
+TEST_F(PullNodeTest, ApplyToArrayMatchingOne) {
auto update = fromjson("{$pull : {a: {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: [0, 1, 2, 3]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 2, 3]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 2, 3]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [1, 2, 3]}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyToArrayMatchingSeveral) {
+TEST_F(PullNodeTest, ApplyToArrayMatchingSeveral) {
auto update = fromjson("{$pull : {a: {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 2, 3, 4, 5]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 2, 3, 4, 5]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [1, 2, 3, 4, 5]}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyToArrayMatchingAll) {
+TEST_F(PullNodeTest, ApplyToArrayMatchingAll) {
auto update = fromjson("{$pull : {a: {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: [0, -1, -2, -3, -4, -5]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyNoIndexDataNoLogBuilder) {
+TEST_F(PullNodeTest, ApplyNoIndexDataNoLogBuilder) {
auto update = fromjson("{$pull : {a: {$lt: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: [0, 1, 2, 3]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ setLogBuilderToNull();
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 2, 3]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(PullNodeTest, ApplyWithCollation) {
+TEST_F(PullNodeTest, ApplyWithCollation) {
// With the collation, this update will pull any string whose reverse is greater than the
// reverse of the "abc" string.
auto update = fromjson("{$pull : {a: {$gt: 'abc'}}}");
@@ -470,185 +256,85 @@ TEST(PullNodeTest, ApplyWithCollation) {
ASSERT_OK(node.init(update["$pull"]["a"], &collator));
Document doc(fromjson("{a: ['zaa', 'zcc', 'zbb', 'zee']}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['zaa', 'zbb']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['zaa', 'zbb']}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: ['zaa', 'zbb']}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyWithCollationDoesNotAffectNonStringMatches) {
+TEST_F(PullNodeTest, ApplyWithCollationDoesNotAffectNonStringMatches) {
auto update = fromjson("{$pull : {a: {$lt: 1}}}");
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual);
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], &collator));
Document doc(fromjson("{a: [2, 1, 0, -1, -2, -3]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [2, 1]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [2, 1]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [2, 1]}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyWithCollationDoesNotAffectRegexMatches) {
+TEST_F(PullNodeTest, ApplyWithCollationDoesNotAffectRegexMatches) {
auto update = fromjson("{$pull : {a: /a/}}");
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual);
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], &collator));
Document doc(fromjson("{a: ['b', 'a', 'aab', 'cb', 'bba']}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['b', 'cb']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['b', 'cb']}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: ['b', 'cb']}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyStringLiteralMatchWithCollation) {
+TEST_F(PullNodeTest, ApplyStringLiteralMatchWithCollation) {
auto update = fromjson("{$pull : {a: 'c'}}");
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual);
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], &collator));
Document doc(fromjson("{a: ['b', 'a', 'aab', 'cb', 'bba']}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyCollationDoesNotAffectNumberLiteralMatches) {
+TEST_F(PullNodeTest, ApplyCollationDoesNotAffectNumberLiteralMatches) {
auto update = fromjson("{$pull : {a: 99}}");
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual);
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], &collator));
Document doc(fromjson("{a: ['a', 99, 'b', 2, 'c', 99, 'd']}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['a', 'b', 2, 'c', 'd']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['a', 'b', 2, 'c', 'd']}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: ['a', 'b', 2, 'c', 'd']}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyStringMatchAfterSetCollator) {
+TEST_F(PullNodeTest, ApplyStringMatchAfterSetCollator) {
auto update = fromjson("{$pull : {a: 'c'}}");
PullNode node;
const CollatorInterface* collator = nullptr;
@@ -656,56 +342,27 @@ TEST(PullNodeTest, ApplyStringMatchAfterSetCollator) {
// First without a collator.
Document doc(fromjson("{ a : ['a', 'b', 'c', 'd'] }"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['a', 'b', 'd']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
// Now with a collator.
CollatorInterfaceMock mockCollator(CollatorInterfaceMock::MockType::kAlwaysEqual);
node.setCollator(&mockCollator);
- indexesAffected = false;
- noop = false;
Document doc2(fromjson("{ a : ['a', 'b', 'c', 'd'] }"));
- node.apply(doc2.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ resetApplyParams();
+ setPathTaken("a");
+ result = node.apply(getApplyParams(doc2.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc2);
ASSERT_FALSE(doc2.isInPlaceModeEnabled());
}
-TEST(PullNodeTest, SetCollatorDoesNotAffectClone) {
+TEST_F(PullNodeTest, SetCollatorDoesNotAffectClone) {
auto update = fromjson("{$pull : {a: 'c'}}");
PullNode node;
const CollatorInterface* collator = nullptr;
@@ -718,54 +375,25 @@ TEST(PullNodeTest, SetCollatorDoesNotAffectClone) {
// The original node should now have collation.
Document doc(fromjson("{ a : ['a', 'b', 'c', 'd'] }"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
// The clone should have exact string matches (no collation).
- indexesAffected = false;
- noop = false;
Document doc2(fromjson("{ a : ['a', 'b', 'c', 'd'] }"));
- cloneNode->apply(doc2.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ resetApplyParams();
+ setPathTaken("a");
+ result = cloneNode->apply(getApplyParams(doc2.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['a', 'b', 'd']}"), doc2);
ASSERT_FALSE(doc2.isInPlaceModeEnabled());
}
-TEST(PullNodeTest, ApplyComplexDocAndMatching1) {
+TEST_F(PullNodeTest, ApplyComplexDocAndMatching1) {
auto update = fromjson(
"{$pull: {'a.b': {$or: ["
" {'y': {$exists: true }},"
@@ -776,440 +404,202 @@ TEST(PullNodeTest, ApplyComplexDocAndMatching1) {
ASSERT_OK(node.init(update["$pull"]["a.b"], collator));
Document doc(fromjson("{a: {b: [{x: 1}, {y: 'y'}, {x: 2}, {z: 'z'}]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [{x: 1}, {x: 2}]}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [{x: 1}, {x: 2}]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': [{x: 1}, {x: 2}]}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyComplexDocAndMatching2) {
+TEST_F(PullNodeTest, ApplyComplexDocAndMatching2) {
auto update = fromjson("{$pull: {'a.b': {'y': {$exists: true}}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a.b"], collator));
Document doc(fromjson("{a: {b: [{x: 1}, {y: 'y'}, {x: 2}, {z: 'z'}]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [{x: 1}, {x: 2}, {z: 'z'}]}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [{x: 1}, {x: 2}, {z: 'z'}]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': [{x: 1}, {x: 2}, {z: 'z'}]}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyComplexDocAndMatching3) {
+TEST_F(PullNodeTest, ApplyComplexDocAndMatching3) {
auto update = fromjson("{$pull: {'a.b': {$in: [{x: 1}, {y: 'y'}]}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a.b"], collator));
Document doc(fromjson("{a: {b: [{x: 1}, {y: 'y'}, {x: 2}, {z: 'z'}]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: [{x: 2}, {z: 'z'}]}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': [{x: 2}, {z: 'z'}]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': [{x: 2}, {z: 'z'}]}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyFullPredicateWithCollation) {
+TEST_F(PullNodeTest, ApplyFullPredicateWithCollation) {
auto update = fromjson("{$pull: {'a.b': {x: 'blah'}}}");
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kAlwaysEqual);
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a.b"], &collator));
Document doc(fromjson("{a: {b: [{x: 'foo', y: 1}, {x: 'bar', y: 2}, {x: 'baz', y: 3}]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: []}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': []}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': []}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyScalarValueMod) {
+TEST_F(PullNodeTest, ApplyScalarValueMod) {
auto update = fromjson("{$pull: {a: 1}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: [1, 2, 1, 2, 1, 2]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [2, 2, 2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [2, 2, 2]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [2, 2, 2]}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyObjectValueMod) {
+TEST_F(PullNodeTest, ApplyObjectValueMod) {
auto update = fromjson("{$pull: {a: {y: 2}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: [{x: 1}, {y: 2}, {x: 1}, {y: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{x: 1}, {x: 1}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{x: 1}, {x: 1}]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [{x: 1}, {x: 1}]}}"), getLogDoc());
}
-TEST(PullNodeTest, DocumentationExample1) {
+TEST_F(PullNodeTest, DocumentationExample1) {
auto update = fromjson("{$pull: {flags: 'msr'}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["flags"], collator));
Document doc(fromjson("{flags: ['vme', 'de', 'pse', 'tsc', 'msr', 'pae', 'mce']}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("flags");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["flags"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("flags");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["flags"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{flags: ['vme', 'de', 'pse', 'tsc', 'pae', 'mce']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {flags: ['vme', 'de', 'pse', 'tsc', 'pae', 'mce']}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {flags: ['vme', 'de', 'pse', 'tsc', 'pae', 'mce']}}"),
+ getLogDoc());
}
-TEST(PullNodeTest, DocumentationExample2a) {
+TEST_F(PullNodeTest, DocumentationExample2a) {
auto update = fromjson("{$pull: {votes: 7}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["votes"], collator));
Document doc(fromjson("{votes: [3, 5, 6, 7, 7, 8]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("votes");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["votes"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("votes");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["votes"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{votes: [3, 5, 6, 8]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {votes: [3, 5, 6, 8]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {votes: [3, 5, 6, 8]}}"), getLogDoc());
}
-TEST(PullNodeTest, DocumentationExample2b) {
+TEST_F(PullNodeTest, DocumentationExample2b) {
auto update = fromjson("{$pull: {votes: {$gt: 6}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["votes"], collator));
Document doc(fromjson("{votes: [3, 5, 6, 7, 7, 8]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("votes");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["votes"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("votes");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["votes"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{votes: [3, 5, 6]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {votes: [3, 5, 6]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {votes: [3, 5, 6]}}"), getLogDoc());
}
-TEST(PullNodeTest, ApplyPullWithObjectValueToArrayWithNonObjectValue) {
+TEST_F(PullNodeTest, ApplyPullWithObjectValueToArrayWithNonObjectValue) {
auto update = fromjson("{$pull: {a: {x: 1}}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["a"], collator));
Document doc(fromjson("{a: [{x: 1}, 2]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [2]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [2]}}"), getLogDoc());
}
-TEST(PullNodeTest, CannotModifyImmutableField) {
+TEST_F(PullNodeTest, CannotModifyImmutableField) {
auto update = fromjson("{$pull: {'_id.a': 1}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["_id.a"], collator));
Document doc(fromjson("{_id: {a: [0, 1, 2]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("_id.a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("_id");
- immutablePaths.insert(&path);
- UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathTaken("_id.a");
+ addImmutablePath("_id");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["_id"]["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["_id"]["a"])),
UserException,
ErrorCodes::ImmutableField,
"Performing an update on the path '_id.a' would modify the immutable field '_id'");
}
-TEST(PullNodeTest, SERVER_3988) {
+TEST_F(PullNodeTest, SERVER_3988) {
auto update = fromjson("{$pull: {y: /yz/}}");
const CollatorInterface* collator = nullptr;
PullNode node;
ASSERT_OK(node.init(update["$pull"]["y"], collator));
Document doc(fromjson("{x: 1, y: [2, 3, 4, 'abc', 'xyz']}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("y");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["y"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("y");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["y"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{x: 1, y: [2, 3, 4, 'abc']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {y: [2, 3, 4, 'abc']}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {y: [2, 3, 4, 'abc']}}"), getLogDoc());
}
+} // namespace
} // namespace mongo
diff --git a/src/mongo/db/update/pullall_node_test.cpp b/src/mongo/db/update/pullall_node_test.cpp
index 38c1c7ff2fb..1928b5f6223 100644
--- a/src/mongo/db/update/pullall_node_test.cpp
+++ b/src/mongo/db/update/pullall_node_test.cpp
@@ -34,12 +34,14 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
+namespace mongo {
namespace {
-using namespace mongo;
+using PullAllNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
@@ -80,409 +82,192 @@ TEST(PullAllNodeTest, InitWithBoolFails) {
ASSERT_EQUALS(ErrorCodes::BadValue, status);
}
-TEST(PullAllNodeTest, TargetNotFound) {
+TEST_F(PullAllNodeTest, TargetNotFound) {
auto update = fromjson("{$pullAll : {b: [1]}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["b"], collator));
Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PullAllNodeTest, TargetArrayElementNotFound) {
+TEST_F(PullAllNodeTest, TargetArrayElementNotFound) {
auto update = fromjson("{$pullAll : {'a.2': [1]}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["a.2"], collator));
Document doc(fromjson("{a: [1, 2]}"));
- FieldRef pathToCreate("2");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("2");
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 2]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PullAllNodeTest, ApplyToNonArrayFails) {
+TEST_F(PullAllNodeTest, ApplyToNonArrayFails) {
auto update = fromjson("{$pullAll : {'a.0': [1, 2]}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["a.0"], collator));
Document doc(fromjson("{a: [1, 2]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.0");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"][0],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a.0");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"][0])),
UserException,
ErrorCodes::BadValue,
"Cannot apply $pull to a non-array value");
}
-TEST(PullAllNodeTest, ApplyWithSingleNumber) {
+TEST_F(PullAllNodeTest, ApplyWithSingleNumber) {
auto update = fromjson("{$pullAll : {a: [1]}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["a"], collator));
Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['a', {r: 1, b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['a', {r: 1, b: 2}]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: ['a', {r: 1, b: 2}]}}"), getLogDoc());
}
-TEST(PullAllNodeTest, ApplyNoIndexDataNoLogBuilder) {
+TEST_F(PullAllNodeTest, ApplyNoIndexDataNoLogBuilder) {
auto update = fromjson("{$pullAll : {a: [1]}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["a"], collator));
Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ setLogBuilderToNull();
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['a', {r: 1, b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(PullAllNodeTest, ApplyWithElementNotPresentInArray) {
+TEST_F(PullAllNodeTest, ApplyWithElementNotPresentInArray) {
auto update = fromjson("{$pullAll : {a: ['r']}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["a"], collator));
Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(PullAllNodeTest, ApplyWithWithTwoElements) {
+TEST_F(PullAllNodeTest, ApplyWithWithTwoElements) {
auto update = fromjson("{$pullAll : {a: [1, 'a']}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["a"], collator));
Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{r: 1, b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{r: 1, b: 2}]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [{r: 1, b: 2}]}}"), getLogDoc());
}
-TEST(PullAllNodeTest, ApplyWithAllArrayElements) {
+TEST_F(PullAllNodeTest, ApplyWithAllArrayElements) {
auto update = fromjson("{$pullAll : {a: [1, 'a', {r: 1, b: 2}]}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["a"], collator));
Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
}
-TEST(PullAllNodeTest, ApplyWithAllArrayElementsButOutOfOrder) {
+TEST_F(PullAllNodeTest, ApplyWithAllArrayElementsButOutOfOrder) {
auto update = fromjson("{$pullAll : {a: [{r: 1, b: 2}, 1, 'a']}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["a"], collator));
Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
}
-TEST(PullAllNodeTest, ApplyWithAllArrayElementsAndThenSome) {
+TEST_F(PullAllNodeTest, ApplyWithAllArrayElementsAndThenSome) {
auto update = fromjson("{$pullAll : {a: [2, 3, 1, 'r', {r: 1, b: 2}, 'a']}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["a"], collator));
Document doc(fromjson("{a: [1, 'a', {r: 1, b: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: []}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: []}}"), getLogDoc());
}
-TEST(PullAllNodeTest, ApplyWithCollator) {
+TEST_F(PullAllNodeTest, ApplyWithCollator) {
auto update = fromjson("{$pullAll : {a: ['FOO', 'BAR']}}");
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kToLowerString);
PullAllNode node;
ASSERT_OK(node.init(update["$pullAll"]["a"], &collator));
Document doc(fromjson("{a: ['foo', 'bar', 'baz']}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['baz']}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: ['baz']}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: ['baz']}}"), getLogDoc());
}
-TEST(PullAllNodeTest, ApplyAfterSetCollator) {
+TEST_F(PullAllNodeTest, ApplyAfterSetCollator) {
auto update = fromjson("{$pullAll : {a: ['FOO', 'BAR']}}");
const CollatorInterface* collator = nullptr;
PullAllNode node;
@@ -490,52 +275,24 @@ TEST(PullAllNodeTest, ApplyAfterSetCollator) {
// First without a collator.
Document doc(fromjson("{a: ['foo', 'bar', 'baz']}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
+ setPathTaken("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
ASSERT_EQUALS(fromjson("{a: ['foo', 'bar', 'baz']}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
// Now with a collator.
CollatorInterfaceMock mockCollator(CollatorInterfaceMock::MockType::kToLowerString);
node.setCollator(&mockCollator);
- indexesAffected = false;
- noop = false;
Document doc2(fromjson("{a: ['foo', 'bar', 'baz']}"));
- node.apply(doc2.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ resetApplyParams();
+ setPathTaken("a");
+ result = node.apply(getApplyParams(doc2.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: ['baz']}"), doc2);
ASSERT_FALSE(doc2.isInPlaceModeEnabled());
}
+} // namespace
} // namespace mongo
diff --git a/src/mongo/db/update/rename_node.cpp b/src/mongo/db/update/rename_node.cpp
index b12810e2636..bf108c54aa2 100644
--- a/src/mongo/db/update/rename_node.cpp
+++ b/src/mongo/db/update/rename_node.cpp
@@ -63,7 +63,7 @@ public:
return Status::OK();
}
- void updateExistingElement(mutablebson::Element* element, bool* noop) const final {
+ bool updateExistingElement(mutablebson::Element* element) const final {
// In the case of a $rename where the source and destination have the same value, (e.g., we
// are applying {$rename: {a: b}} to the document {a: "foo", b: "foo"}), there's no need to
// modify the destination element. However, the source and destination values must be
@@ -71,10 +71,10 @@ public:
StringData::ComparatorInterface* comparator = nullptr;
auto considerFieldName = false;
if (_elemToSet.compareWithElement(*element, comparator, considerFieldName) != 0) {
- *noop = false;
invariantOK(element->setValueElement(_elemToSet));
+ return true;
} else {
- *noop = true;
+ return false;
}
}
@@ -138,26 +138,13 @@ Status RenameNode::init(BSONElement modExpr, const CollatorInterface* collator)
return Status::OK();
}
-void RenameNode::apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const {
- *indexesAffected = false;
- *noop = false;
-
+UpdateNode::ApplyResult RenameNode::apply(ApplyParams applyParams) const {
// It would make sense to store fromFieldRef and toFieldRef as members during
// RenameNode::init(), but FieldRef is not copyable.
FieldRef fromFieldRef(_val.fieldName());
FieldRef toFieldRef(_val.valueStringData());
- mutablebson::Document& document = element.getDocument();
+ mutablebson::Document& document = applyParams.element.getDocument();
size_t fromIdxFound;
mutablebson::Element fromElement(document.end());
@@ -175,8 +162,7 @@ void RenameNode::apply(mutablebson::Element element,
// The element we want to rename does not exist. When that happens, we treat the operation
// as a no-op.
- *noop = true;
- return;
+ return ApplyResult::noopResult();
}
// Renaming through an array is prohibited. Check that our source path does not contain an
@@ -200,7 +186,8 @@ void RenameNode::apply(mutablebson::Element element,
// Check that our destination path does not contain an array. (If the rename will overwrite an
// existing element, that element may be an array. Iff pathToCreate is empty, "element"
// represents an element that we are going to overwrite.)
- for (auto currentElement = pathToCreate->empty() ? element.parent() : element;
+ for (auto currentElement = applyParams.pathToCreate->empty() ? applyParams.element.parent()
+ : applyParams.element;
currentElement != document.root();
currentElement = currentElement.parent()) {
invariant(currentElement.ok());
@@ -217,20 +204,8 @@ void RenameNode::apply(mutablebson::Element element,
}
}
- bool setAffectedIndexes = false;
- bool setWasNoop = false;
SetElementNode setElement(fromElement);
- setElement.apply(element,
- pathToCreate,
- pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &setAffectedIndexes,
- &setWasNoop);
+ auto setElementApplyResult = setElement.apply(applyParams);
auto leftSibling = fromElement.leftSibling();
auto rightSibling = fromElement.rightSibling();
@@ -238,15 +213,15 @@ void RenameNode::apply(mutablebson::Element element,
invariant(fromElement.parent().ok());
invariantOK(fromElement.remove());
- if (setAffectedIndexes) {
- *indexesAffected = true;
- } else if (indexData && indexData->mightBeIndexed(fromFieldRef.dottedField())) {
- *indexesAffected = true;
- } else {
- // *indexedAffected remains false
+ ApplyResult applyResult;
+
+ if (!applyParams.indexData ||
+ (!setElementApplyResult.indexesAffected &&
+ !applyParams.indexData->mightBeIndexed(fromFieldRef.dottedField()))) {
+ applyResult.indexesAffected = false;
}
- if (validateForStorage) {
+ if (applyParams.validateForStorage) {
// Validate the left and right sibling, in case this element was part of a DBRef.
if (leftSibling.ok()) {
@@ -263,7 +238,8 @@ void RenameNode::apply(mutablebson::Element element,
}
// Ensure we are not changing any immutable paths.
- for (auto immutablePath = immutablePaths.begin(); immutablePath != immutablePaths.end();
+ for (auto immutablePath = applyParams.immutablePaths.begin();
+ immutablePath != applyParams.immutablePaths.end();
++immutablePath) {
uassert(ErrorCodes::ImmutableField,
str::stream() << "Unsetting the path '" << fromFieldRef.dottedField()
@@ -275,9 +251,11 @@ void RenameNode::apply(mutablebson::Element element,
}
// Log the $unset. The $set was already logged by SetElementNode::apply().
- if (logBuilder) {
- uassertStatusOK(logBuilder->addToUnsets(fromFieldRef.dottedField()));
+ if (applyParams.logBuilder) {
+ uassertStatusOK(applyParams.logBuilder->addToUnsets(fromFieldRef.dottedField()));
}
+
+ return applyResult;
}
} // namespace mongo
diff --git a/src/mongo/db/update/rename_node.h b/src/mongo/db/update/rename_node.h
index 096740e1907..240ac32ebd4 100644
--- a/src/mongo/db/update/rename_node.h
+++ b/src/mongo/db/update/rename_node.h
@@ -51,17 +51,7 @@ public:
void setCollator(const CollatorInterface* collator) final {}
- void apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const final;
+ ApplyResult apply(ApplyParams applyParams) const final;
private:
BSONElement _val;
diff --git a/src/mongo/db/update/rename_node_test.cpp b/src/mongo/db/update/rename_node_test.cpp
index 95a6d337d4a..84f46f0651f 100644
--- a/src/mongo/db/update/rename_node_test.cpp
+++ b/src/mongo/db/update/rename_node_test.cpp
@@ -33,12 +33,14 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
namespace {
+using RenameNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
@@ -107,972 +109,439 @@ TEST(RenameNodeTest, MoveToSelfNotAllowed) {
ASSERT_EQUALS(ErrorCodes::BadValue, status);
}
-TEST(RenameNodeTest, SimpleNumberAtRoot) {
+TEST_F(RenameNodeTest, SimpleNumberAtRoot) {
auto update = fromjson("{$rename: {'a': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: 2}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: 2}, $unset: {a: true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {b: 2}, $unset: {a: true}}"), getLogDoc());
}
-TEST(RenameNodeTest, ToExistsAtSameLevel) {
+TEST_F(RenameNodeTest, ToExistsAtSameLevel) {
auto update = fromjson("{$rename: {'a': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: 2, b: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: 2}, $unset: {a: true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {b: 2}, $unset: {a: true}}"), getLogDoc());
}
-TEST(RenameNodeTest, ToAndFromHaveSameValue) {
+TEST_F(RenameNodeTest, ToAndFromHaveSameValue) {
auto update = fromjson("{$rename: {'a': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: 2, b: 2}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
- ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), getLogDoc());
}
-TEST(RenameNodeTest, FromDottedElement) {
+TEST_F(RenameNodeTest, FromDottedElement) {
auto update = fromjson("{$rename: {'a.c': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a.c"], collator));
Document doc(fromjson("{a: {c: {d: 6}}, b: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {}, b: {d: 6}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: {d: 6}}, $unset: {'a.c': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {b: {d: 6}}, $unset: {'a.c': true}}"), getLogDoc());
}
-TEST(RenameNodeTest, RenameToExistingNestedFieldDoesNotReorderFields) {
+TEST_F(RenameNodeTest, RenameToExistingNestedFieldDoesNotReorderFields) {
auto update = fromjson("{$rename: {'c.d': 'a.b.c'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["c.d"], collator));
Document doc(fromjson("{a: {b: {c: 1, d: 2}}, b: 3, c: {d: 4}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b.c");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"]["c"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b.c");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]["c"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: {c: 4, d: 2}}, b: 3, c: {}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'a.b.c': 4}, $unset: {'c.d': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b.c': 4}, $unset: {'c.d': true}}"), getLogDoc());
}
-TEST(RenameNodeTest, MissingCompleteTo) {
+TEST_F(RenameNodeTest, MissingCompleteTo) {
auto update = fromjson("{$rename: {a: 'c.r.d'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: 2, b: 1, c: {}}"));
- FieldRef pathToCreate("r.d");
- FieldRef pathTaken("c");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["c"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("r.d");
+ setPathTaken("c");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["c"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 1, c: {r: {d: 2}}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'c.r.d': 2}, $unset: {'a': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'c.r.d': 2}, $unset: {'a': true}}"), getLogDoc());
}
-TEST(RenameNodeTest, ToIsCompletelyMissing) {
+TEST_F(RenameNodeTest, ToIsCompletelyMissing) {
auto update = fromjson("{$rename: {a: 'b.c.d'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: 2}"));
- FieldRef pathToCreate("b.c.d");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b.c.d");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: {c: {d: 2}}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'b.c.d': 2}, $unset: {'a': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'b.c.d': 2}, $unset: {'a': true}}"), getLogDoc());
}
-TEST(RenameNodeTest, ToMissingDottedField) {
+TEST_F(RenameNodeTest, ToMissingDottedField) {
auto update = fromjson("{$rename: {a: 'b.c.d'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: [{a:2, b:1}]}"));
- FieldRef pathToCreate("b.c.d");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b.c.d");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: {c: {d: [{a:2, b:1}]}}}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {'b.c.d': [{a:2, b:1}]}, $unset: {'a': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'b.c.d': [{a:2, b:1}]}, $unset: {'a': true}}"), getLogDoc());
}
-TEST(RenameNodeTest, MoveIntoArray) {
+TEST_F(RenameNodeTest, MoveIntoArray) {
auto update = fromjson("{$rename: {b: 'a.2'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["b"], collator));
Document doc(fromjson("{_id: 'test_object', a: [1, 2], b: 2}"));
- FieldRef pathToCreate("2");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("2");
+ setPathTaken("a");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::BadValue,
"The destination field cannot be an array element, 'a.2' in doc "
"with _id: \"test_object\" has an array field called 'a'");
}
-TEST(RenameNodeTest, MoveIntoArrayNoId) {
+TEST_F(RenameNodeTest, MoveIntoArrayNoId) {
auto update = fromjson("{$rename: {b: 'a.2'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["b"], collator));
Document doc(fromjson("{a: [1, 2], b: 2}"));
- FieldRef pathToCreate("2");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("2");
+ setPathTaken("a");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::BadValue,
"The destination field cannot be an array element, 'a.2' in doc "
"with no id has an array field called 'a'");
}
-TEST(RenameNodeTest, MoveToArrayElement) {
+TEST_F(RenameNodeTest, MoveToArrayElement) {
auto update = fromjson("{$rename: {b: 'a.1'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["b"], collator));
Document doc(fromjson("{_id: 'test_object', a: [1, 2], b: 2}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.1");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"]["1"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a.1");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"]["1"])),
UserException,
ErrorCodes::BadValue,
"The destination field cannot be an array element, 'a.1' in doc "
"with _id: \"test_object\" has an array field called 'a'");
}
-TEST(RenameNodeTest, MoveOutOfArray) {
+TEST_F(RenameNodeTest, MoveOutOfArray) {
auto update = fromjson("{$rename: {'a.0': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a.0"], collator));
Document doc(fromjson("{_id: 'test_object', a: [1, 2]}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("b");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::BadValue,
"The source field cannot be an array element, 'a.0' in doc with "
"_id: \"test_object\" has an array field called 'a'");
}
-TEST(RenameNodeTest, MoveNonexistentEmbeddedFieldOut) {
+TEST_F(RenameNodeTest, MoveNonexistentEmbeddedFieldOut) {
auto update = fromjson("{$rename: {'a.a': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a.a"], collator));
Document doc(fromjson("{a: [{a: 1}, {b: 2}]}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("b");
+ addIndexedPath("a");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::PathNotViable,
"cannot use the part (a of a.a) to traverse the element ({a: [ { a: 1 }, { b: 2 } ]})");
}
-TEST(RenameNodeTest, MoveEmbeddedFieldOutWithElementNumber) {
+TEST_F(RenameNodeTest, MoveEmbeddedFieldOutWithElementNumber) {
auto update = fromjson("{$rename: {'a.0.a': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a.0.a"], collator));
Document doc(fromjson("{_id: 'test_object', a: [{a: 1}, {b: 2}]}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("b");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::BadValue,
"The source field cannot be an array element, 'a.0.a' in doc with "
"_id: \"test_object\" has an array field called 'a'");
}
-TEST(RenameNodeTest, ReplaceArrayField) {
+TEST_F(RenameNodeTest, ReplaceArrayField) {
auto update = fromjson("{$rename: {a: 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: 2, b: []}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: 2}, $unset: {a: true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {b: 2}, $unset: {a: true}}"), getLogDoc());
}
-TEST(RenameNodeTest, ReplaceWithArrayField) {
+TEST_F(RenameNodeTest, ReplaceWithArrayField) {
auto update = fromjson("{$rename: {a: 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: [], b: 2}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: []}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {b: []}, $unset: {a: true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {b: []}, $unset: {a: true}}"), getLogDoc());
}
-TEST(RenameNodeTest, CanRenameFromInvalidFieldName) {
+TEST_F(RenameNodeTest, CanRenameFromInvalidFieldName) {
auto update = fromjson("{$rename: {'$a': 'a'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["$a"], collator));
Document doc(fromjson("{$a: 2}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
- ASSERT_EQUALS(fromjson("{$set: {a: 2}, $unset: {'$a': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 2}, $unset: {'$a': true}}"), getLogDoc());
}
-TEST(RenameNodeTest, RenameWithoutLogBuilderOrIndexData) {
+TEST_F(RenameNodeTest, RenameWithoutLogBuilderOrIndexData) {
auto update = fromjson("{$rename: {'a': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: 2}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
+ setPathToCreate("b");
+ setLogBuilderToNull();
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
}
-TEST(RenameNodeTest, RenameFromNonExistentPathIsNoOp) {
+TEST_F(RenameNodeTest, RenameFromNonExistentPathIsNoOp) {
auto update = fromjson("{$rename: {'a': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{b: 2}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 2}"), doc);
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(RenameNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) {
+TEST_F(RenameNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) {
auto update = fromjson("{$rename: {'a.$id': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a.$id"], collator));
Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("b");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::InvalidDBRef,
"The DBRef $ref field must be followed by a $id field");
}
-TEST(RenameNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFalse) {
+TEST_F(RenameNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFalse) {
auto update = fromjson("{$rename: {'a.$id': 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a.$id"], collator));
Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = false;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b");
+ addIndexedPath("a");
+ setValidateForStorage(false);
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
auto updated = BSON("a" << BSON("$ref"
<< "c")
<< "b"
<< 0);
ASSERT_EQUALS(updated, doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'b': 0}, $unset: {'a.$id': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'b': 0}, $unset: {'a.$id': true}}"), getLogDoc());
}
-TEST(RenameNodeTest, ApplyCannotRemoveImmutablePath) {
+TEST_F(RenameNodeTest, ApplyCannotRemoveImmutablePath) {
auto update = fromjson("{$rename: {'a.b': 'c'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a.b"], collator));
Document doc(fromjson("{a: {b: 1}}"));
- FieldRef pathToCreate("c");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("c");
+ addImmutablePath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::ImmutableField,
"Unsetting the path 'a.b' using $rename would modify the immutable field 'a.b'");
}
-TEST(RenameNodeTest, ApplyCannotRemovePrefixOfImmutablePath) {
+TEST_F(RenameNodeTest, ApplyCannotRemovePrefixOfImmutablePath) {
auto update = fromjson("{$rename: {a: 'c'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: {b: 1}}"));
- FieldRef pathToCreate("c");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("c");
+ addImmutablePath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::ImmutableField,
"Unsetting the path 'a' using $rename would modify the immutable field 'a.b'");
}
-TEST(RenameNodeTest, ApplyCannotRemoveSuffixOfImmutablePath) {
+TEST_F(RenameNodeTest, ApplyCannotRemoveSuffixOfImmutablePath) {
auto update = fromjson("{$rename: {'a.b.c': 'd'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a.b.c"], collator));
Document doc(fromjson("{a: {b: {c: 1}}}"));
- FieldRef pathToCreate("d");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("d");
+ addImmutablePath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::ImmutableField,
"Unsetting the path 'a.b.c' using $rename would modify the immutable field 'a.b'");
}
-TEST(RenameNodeTest, ApplyCanRemoveImmutablePathIfNoop) {
+TEST_F(RenameNodeTest, ApplyCanRemoveImmutablePathIfNoop) {
auto update = fromjson("{$rename: {'a.b.c': 'd'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a.b.c"], collator));
Document doc(fromjson("{a: {b: {}}}"));
- FieldRef pathToCreate("d");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = false;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("d");
+ addImmutablePath("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: {}}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(RenameNodeTest, ApplyCannotCreateDollarPrefixedField) {
+TEST_F(RenameNodeTest, ApplyCannotCreateDollarPrefixedField) {
auto update = fromjson("{$rename: {a: '$bad'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("$bad");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("$bad");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::DollarPrefixedFieldName,
"The dollar ($) prefixed field '$bad' in '$bad' is not valid for storage.");
}
-TEST(RenameNodeTest, ApplyCannotOverwriteImmutablePath) {
+TEST_F(RenameNodeTest, ApplyCannotOverwriteImmutablePath) {
auto update = fromjson("{$rename: {a: 'b'}}");
const CollatorInterface* collator = nullptr;
RenameNode node;
ASSERT_OK(node.init(update["$rename"]["a"], collator));
Document doc(fromjson("{a: 0, b: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathTaken("b");
+ addImmutablePath("b");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["b"])),
UserException,
ErrorCodes::ImmutableField,
"Updating the path 'b' to b: 0 would modify the immutable field 'b'");
diff --git a/src/mongo/db/update/set_node.cpp b/src/mongo/db/update/set_node.cpp
index 8980247c8d6..7d824c044fc 100644
--- a/src/mongo/db/update/set_node.cpp
+++ b/src/mongo/db/update/set_node.cpp
@@ -42,14 +42,14 @@ Status SetNode::init(BSONElement modExpr, const CollatorInterface* collator) {
return Status::OK();
}
-void SetNode::updateExistingElement(mutablebson::Element* element, bool* noop) const {
+bool SetNode::updateExistingElement(mutablebson::Element* element) const {
// If 'element' is deserialized, then element.getValue() will be EOO, which will never equal
// _val.
if (element->getValue().binaryEqualValues(_val)) {
- *noop = true;
+ return false;
} else {
- *noop = false;
invariantOK(element->setValueBSONElement(_val));
+ return true;
}
}
diff --git a/src/mongo/db/update/set_node.h b/src/mongo/db/update/set_node.h
index 915b214b9b5..626d47be7ed 100644
--- a/src/mongo/db/update/set_node.h
+++ b/src/mongo/db/update/set_node.h
@@ -47,7 +47,7 @@ public:
void setCollator(const CollatorInterface* collator) final {}
protected:
- void updateExistingElement(mutablebson::Element* element, bool* noop) const final;
+ bool updateExistingElement(mutablebson::Element* element) const final;
void setValueForNewElement(mutablebson::Element* element) const final;
private:
diff --git a/src/mongo/db/update/set_node_test.cpp b/src/mongo/db/update/set_node_test.cpp
index 0df17390b0b..932798e61e7 100644
--- a/src/mongo/db/update/set_node_test.cpp
+++ b/src/mongo/db/update/set_node_test.cpp
@@ -33,12 +33,14 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
+namespace mongo {
namespace {
-using namespace mongo;
+using SetNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
@@ -57,368 +59,177 @@ TEST(SetNodeTest, InitSucceedsForNonemptyElement) {
ASSERT_OK(node.init(update["$set"]["a"], collator));
}
-TEST(SetNodeTest, ApplyNoOp) {
+TEST_F(SetNodeTest, ApplyNoOp) {
auto update = fromjson("{$set: {a: 5}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyEmptyPathToCreate) {
+TEST_F(SetNodeTest, ApplyEmptyPathToCreate) {
auto update = fromjson("{$set: {a: 6}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 6}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 6}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 6}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyCreatePath) {
+TEST_F(SetNodeTest, ApplyCreatePath) {
auto update = fromjson("{$set: {'a.b.c': 6}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b.c"], collator));
Document doc(fromjson("{a: {d: 5}}"));
- FieldRef pathToCreate("b.c");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b.c");
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {d: 5, b: {c: 6}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b.c': 6}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b.c': 6}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyCreatePathFromRoot) {
+TEST_F(SetNodeTest, ApplyCreatePathFromRoot) {
auto update = fromjson("{$set: {'a.b': 6}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{c: 5}"));
- FieldRef pathToCreate("a.b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{c: 5, a: {b: 6}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.b': 6}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': 6}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyPositional) {
+TEST_F(SetNodeTest, ApplyPositional) {
auto update = fromjson("{$set: {'a.$': 6}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.$"], collator));
Document doc(fromjson("{a: [0, 1, 2]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.1");
- StringData matchedField("1");
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["1"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.1");
+ setMatchedField("1");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["1"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, 6, 2]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1': 6}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.1': 6}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyNonViablePathToCreate) {
+TEST_F(SetNodeTest, ApplyNonViablePathToCreate) {
auto update = fromjson("{$set: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field 'b' in element {a: 5}");
}
-TEST(SetNodeTest, ApplyNonViablePathToCreateFromReplicationIsNoOp) {
+TEST_F(SetNodeTest, ApplyNonViablePathToCreateFromReplicationIsNoOp) {
auto update = fromjson("{$set: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ setFromReplication(true);
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyNoIndexDataNoLogBuilder) {
+TEST_F(SetNodeTest, ApplyNoIndexDataNoLogBuilder) {
auto update = fromjson("{$set: {a: 6}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ setLogBuilderToNull();
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 6}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyDoesNotAffectIndexes) {
+TEST_F(SetNodeTest, ApplyDoesNotAffectIndexes) {
auto update = fromjson("{$set: {a: 6}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 6}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, TypeChangeIsNotANoop) {
+TEST_F(SetNodeTest, TypeChangeIsNotANoop) {
auto update = fromjson("{$set: {a: NumberLong(2)}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: NumberInt(2)}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: NumberLong(2)}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, IdentityOpOnDeserializedIsNotANoOp) {
+TEST_F(SetNodeTest, IdentityOpOnDeserializedIsNotANoOp) {
// Apply an op that would be a no-op.
auto update = fromjson("{$set: {a: {b : NumberInt(2)}}}");
const CollatorInterface* collator = nullptr;
@@ -429,1503 +240,707 @@ TEST(SetNodeTest, IdentityOpOnDeserializedIsNotANoOp) {
// Apply a mutation to the document that will make it non-serialized.
doc.root()["a"]["b"].setValueInt(2).transitional_ignore();
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b : NumberInt(2)}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyEmptyDocument) {
+TEST_F(SetNodeTest, ApplyEmptyDocument) {
auto update = fromjson("{$set: {a: 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyInPlace) {
+TEST_F(SetNodeTest, ApplyInPlace) {
auto update = fromjson("{$set: {a: 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyOverridePath) {
+TEST_F(SetNodeTest, ApplyOverridePath) {
auto update = fromjson("{$set: {a: 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: {b: 1}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyChangeType) {
+TEST_F(SetNodeTest, ApplyChangeType) {
auto update = fromjson("{$set: {a: 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: 'str'}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyNewPath) {
+TEST_F(SetNodeTest, ApplyNewPath) {
auto update = fromjson("{$set: {a: 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{b: 1}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 1, a: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyLog) {
+TEST_F(SetNodeTest, ApplyLog) {
auto update = fromjson("{$set: {a: 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
+ setPathTaken("a");
+ node.apply(getApplyParams(doc.root()["a"]));
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {a: 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {a: 2}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyNoOpDottedPath) {
+TEST_F(SetNodeTest, ApplyNoOpDottedPath) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b : 2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, TypeChangeOnDottedPathIsNotANoOp) {
+TEST_F(SetNodeTest, TypeChangeOnDottedPathIsNotANoOp) {
auto update = fromjson("{$set: {'a.b': NumberInt(2)}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: {b: NumberLong(2)}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b : NumberLong(2)}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyPathNotViable) {
+TEST_F(SetNodeTest, ApplyPathNotViable) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a:1}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("b");
+ setPathTaken("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field 'b' in element {a: 1}");
}
-TEST(SetNodeTest, ApplyPathNotViableArrray) {
+TEST_F(SetNodeTest, ApplyPathNotViableArrray) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a:[{b:1}]}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("b");
+ setPathTaken("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field 'b' in element {a: [ { b: 1 } ]}");
}
-TEST(SetNodeTest, ApplyInPlaceDottedPath) {
+TEST_F(SetNodeTest, ApplyInPlaceDottedPath) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: {b: 1}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyChangeTypeDottedPath) {
+TEST_F(SetNodeTest, ApplyChangeTypeDottedPath) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: {b: 'str'}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyChangePath) {
+TEST_F(SetNodeTest, ApplyChangePath) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: {b: {c: 1}}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyExtendPath) {
+TEST_F(SetNodeTest, ApplyExtendPath) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: {c: 1}}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b");
+ setPathTaken("a");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {c: 1, b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyNewDottedPath) {
+TEST_F(SetNodeTest, ApplyNewDottedPath) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{c: 1}"));
- FieldRef pathToCreate("a.b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{c: 1, a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyEmptyDoc) {
+TEST_F(SetNodeTest, ApplyEmptyDoc) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a.b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyFieldWithDot) {
+TEST_F(SetNodeTest, ApplyFieldWithDot) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{'a.b':4}"));
- FieldRef pathToCreate("a.b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a.b");
+ addIndexedPath("a.b");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{'a.b':4, a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyNoOpArrayIndex) {
+TEST_F(SetNodeTest, ApplyNoOpArrayIndex) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b: 0},{b: 1},{b: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.2.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.2.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["2"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.2.b");
+ addIndexedPath("a.2.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["2"]["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0},{b: 1},{b: 2}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, TypeChangeInArrayIsNotANoOp) {
+TEST_F(SetNodeTest, TypeChangeInArrayIsNotANoOp) {
auto update = fromjson("{$set: {'a.2.b': NumberInt(2)}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b: 0},{b: 1},{b: 2.0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.2.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.2.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["2"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.2.b");
+ addIndexedPath("a.2.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["2"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0},{b: 1},{b: NumberInt(2)}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyNonViablePath) {
+TEST_F(SetNodeTest, ApplyNonViablePath) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field '2' in element {a: 0}");
}
-TEST(SetNodeTest, ApplyInPlaceArrayIndex) {
+TEST_F(SetNodeTest, ApplyInPlaceArrayIndex) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b: 0},{b: 1},{b: 1}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.2.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.2.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["2"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.2.b");
+ addIndexedPath("a.2.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["2"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0},{b: 1},{b: 2}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyNormalArray) {
+TEST_F(SetNodeTest, ApplyNormalArray) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b: 0},{b: 1}]}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.2.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ addIndexedPath("a.2.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0},{b: 1},{b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyPaddingArray) {
+TEST_F(SetNodeTest, ApplyPaddingArray) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b: 0}]}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.2.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ addIndexedPath("a.2.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: 0},null,{b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyNumericObject) {
+TEST_F(SetNodeTest, ApplyNumericObject) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: {b: 0}}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.2.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ addIndexedPath("a.2.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 0, '2': {b: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyNumericField) {
+TEST_F(SetNodeTest, ApplyNumericField) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: {'2': {b: 1}}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.2.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.2.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["2"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.2.b");
+ addIndexedPath("a.2.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["2"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {'2': {b: 2}}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyExtendNumericField) {
+TEST_F(SetNodeTest, ApplyExtendNumericField) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: {'2': {c: 1}}}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a.2");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.2.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["2"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b");
+ setPathTaken("a.2");
+ addIndexedPath("a.2.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["2"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {'2': {c: 1, b: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyEmptyObject) {
+TEST_F(SetNodeTest, ApplyEmptyObject) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: {}}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.2.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ addIndexedPath("a.2.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {'2': {b: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyEmptyArray) {
+TEST_F(SetNodeTest, ApplyEmptyArray) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.2.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ addIndexedPath("a.2.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [null, null, {b: 2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyLogDottedPath) {
+TEST_F(SetNodeTest, ApplyLogDottedPath) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: [{b:0}, {b:1}]}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ node.apply(getApplyParams(doc.root()["a"]));
ASSERT_EQUALS(fromjson("{a: [{b:0}, {b:1}, {b:2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
}
-TEST(SetNodeTest, LogEmptyArray) {
+TEST_F(SetNodeTest, LogEmptyArray) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ node.apply(getApplyParams(doc.root()["a"]));
ASSERT_EQUALS(fromjson("{a: [null, null, {b:2}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
}
-TEST(SetNodeTest, LogEmptyObject) {
+TEST_F(SetNodeTest, LogEmptyObject) {
auto update = fromjson("{$set: {'a.2.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.2.b"], collator));
Document doc(fromjson("{a: {}}"));
- FieldRef pathToCreate("2.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
+ setPathToCreate("2.b");
+ setPathTaken("a");
+ node.apply(getApplyParams(doc.root()["a"]));
ASSERT_EQUALS(fromjson("{a: {'2': {b: 2}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {'a.2.b': 2}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyNoOpComplex) {
+TEST_F(SetNodeTest, ApplyNoOpComplex) {
auto update = fromjson("{$set: {'a.1.b': {c: 1, d: 1}}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.1.b"], collator));
Document doc(fromjson("{a: [{b: {c: 0, d: 0}}, {b: {c: 1, d: 1}}]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.1.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.1.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["1"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.1.b");
+ addIndexedPath("a.1.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["1"]["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: {c: 0, d: 0}}, {b: {c: 1, d: 1}}]}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplySameStructure) {
+TEST_F(SetNodeTest, ApplySameStructure) {
auto update = fromjson("{$set: {'a.1.b': {c: 1, d: 1}}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.1.b"], collator));
Document doc(fromjson("{a: [{b: {c: 0, d: 0}}, {b: {c: 1, xxx: 1}}]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.1.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.1.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["1"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.1.b");
+ addIndexedPath("a.1.b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["1"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [{b: {c: 0, d: 0}}, {b: {c: 1, d: 1}}]}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, NonViablePathWithoutRepl) {
+TEST_F(SetNodeTest, NonViablePathWithoutRepl) {
auto update = fromjson("{$set: {'a.1.b': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.1.b"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("1.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathToCreate("1.b");
+ setPathTaken("a");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field '1' in element {a: 1}");
}
-TEST(SetNodeTest, SingleFieldFromReplication) {
+TEST_F(SetNodeTest, SingleFieldFromReplication) {
auto update = fromjson("{$set: {'a.1.b': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.1.b"], collator));
Document doc(fromjson("{_id:1, a: 1}"));
- FieldRef pathToCreate("1.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.1.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("1.b");
+ setPathTaken("a");
+ addIndexedPath("a.1.b");
+ setFromReplication(true);
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id:1, a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, SingleFieldNoIdFromReplication) {
+TEST_F(SetNodeTest, SingleFieldNoIdFromReplication) {
auto update = fromjson("{$set: {'a.1.b': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.1.b"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("1.b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.1.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("1.b");
+ setPathTaken("a");
+ addIndexedPath("a.1.b");
+ setFromReplication(true);
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 1}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, NestedFieldFromReplication) {
+TEST_F(SetNodeTest, NestedFieldFromReplication) {
auto update = fromjson("{$set: {'a.a.1.b': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.a.1.b"], collator));
Document doc(fromjson("{_id:1, a: {a: 1}}"));
- FieldRef pathToCreate("1.b");
- FieldRef pathTaken("a.a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.a.1.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("1.b");
+ setPathTaken("a.a");
+ addIndexedPath("a.a.1.b");
+ setFromReplication(true);
+ auto result = node.apply(getApplyParams(doc.root()["a"]["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id:1, a: {a: 1}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, DoubleNestedFieldFromReplication) {
+TEST_F(SetNodeTest, DoubleNestedFieldFromReplication) {
auto update = fromjson("{$set: {'a.b.c.d': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b.c.d"], collator));
Document doc(fromjson("{_id:1, a: {b: {c: 1}}}"));
- FieldRef pathToCreate("d");
- FieldRef pathTaken("a.b.c");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.b.c.d");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"]["c"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("d");
+ setPathTaken("a.b.c");
+ addIndexedPath("a.b.c.d");
+ setFromReplication(true);
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]["c"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id:1, a: {b: {c: 1}}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, NestedFieldNoIdFromReplication) {
+TEST_F(SetNodeTest, NestedFieldNoIdFromReplication) {
auto update = fromjson("{$set: {'a.a.1.b': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.a.1.b"], collator));
Document doc(fromjson("{a: {a: 1}}"));
- FieldRef pathToCreate("1.b");
- FieldRef pathTaken("a.a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.a.1.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("1.b");
+ setPathTaken("a.a");
+ addIndexedPath("a.a.1.b");
+ setFromReplication(true);
+ auto result = node.apply(getApplyParams(doc.root()["a"]["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {a: 1}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ReplayArrayFieldNotAppendedIntermediateFromReplication) {
+TEST_F(SetNodeTest, ReplayArrayFieldNotAppendedIntermediateFromReplication) {
auto update = fromjson("{$set: {'a.0.b': [0,2]}}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.0.b"], collator));
Document doc(fromjson("{_id: 0, a: [1, {b: [1]}]}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a.0");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.0.b");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["0"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("b");
+ setPathTaken("a.0");
+ addIndexedPath("a.1.b");
+ setFromReplication(true);
+ auto result = node.apply(getApplyParams(doc.root()["a"]["0"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id: 0, a: [1, {b: [1]}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, Set6) {
+TEST_F(SetNodeTest, Set6) {
auto update = fromjson("{$set: {'r.a': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["r.a"], collator));
Document doc(fromjson("{_id: 1, r: {a:1, b:2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("r.a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("r.a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["r"]["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("r.a");
+ addIndexedPath("r.a");
+ auto result = node.apply(getApplyParams(doc.root()["r"]["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id: 1, r: {a:2, b:2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'r.a': 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {'r.a': 2}}"), getLogDoc());
}
-TEST(SetNodeTest, Set6FromRepl) {
+TEST_F(SetNodeTest, Set6FromRepl) {
auto update = fromjson("{$set: { 'r.a': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["r.a"], collator));
Document doc(fromjson("{_id: 1, r: {a:1, b:2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("r.a");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("r.a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["r"]["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("r.a");
+ addIndexedPath("r.a");
+ setFromReplication(true);
+ auto result = node.apply(getApplyParams(doc.root()["r"]["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{_id: 1, r: {a:2, b:2} }"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'r.a': 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {'r.a': 2}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplySetModToEphemeralDocument) {
+TEST_F(SetNodeTest, ApplySetModToEphemeralDocument) {
// The following mod when applied to a document constructed node by node exposed a
// latent debug only defect in mutable BSON, so this is more a test of mutable than
// $set.
@@ -1940,702 +955,325 @@ TEST(SetNodeTest, ApplySetModToEphemeralDocument) {
Element a = doc.makeElementInt("a", 100);
x.pushBack(a).transitional_ignore();
- FieldRef pathToCreate("");
- FieldRef pathTaken("x");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("x");
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["x"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("x");
+ addIndexedPath("x");
+ auto result = node.apply(getApplyParams(doc.root()["x"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{ x : { a : 100, b : 2 } }"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldInsideSetElement) {
+TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldInsideSetElement) {
auto update = fromjson("{$set: {a: {$bad: 1}}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathTaken("a");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::DollarPrefixedFieldName,
"The dollar ($) prefixed field '$bad' in 'a.$bad' is not valid for storage.");
}
-TEST(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldAtStartOfPath) {
+TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldAtStartOfPath) {
auto update = fromjson("{$set: {'$bad.a': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["$bad.a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("$bad.a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("$bad.a");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::DollarPrefixedFieldName,
"The dollar ($) prefixed field '$bad' in '$bad' is not valid for storage.");
}
-TEST(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldInMiddleOfPath) {
+TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldInMiddleOfPath) {
auto update = fromjson("{$set: {'a.$bad.b': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.$bad.b"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a.$bad.b");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("a.$bad.b");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::DollarPrefixedFieldName,
"The dollar ($) prefixed field '$bad' in 'a.$bad' is not valid for storage.");
}
-TEST(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldAtEndOfPath) {
+TEST_F(SetNodeTest, ApplyCannotCreateDollarPrefixedFieldAtEndOfPath) {
auto update = fromjson("{$set: {'a.$bad': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.$bad"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a.$bad");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("a.$bad");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::DollarPrefixedFieldName,
"The dollar ($) prefixed field '$bad' in 'a.$bad' is not valid for storage.");
}
-TEST(SetNodeTest, ApplyCanCreateDollarPrefixedFieldNameWhenValidateForStorageIsFalse) {
+TEST_F(SetNodeTest, ApplyCanCreateDollarPrefixedFieldNameWhenValidateForStorageIsFalse) {
auto update = fromjson("{$set: {$bad: 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["$bad"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("$bad");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = false;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("$bad");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("$bad");
+ addIndexedPath("$bad");
+ setValidateForStorage(false);
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{$bad: 1}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {$bad: 1}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {$bad: 1}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyCannotOverwriteImmutablePath) {
+TEST_F(SetNodeTest, ApplyCannotOverwriteImmutablePath) {
auto update = fromjson("{$set: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathTaken("a.b");
+ addImmutablePath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["a"]["b"])),
UserException,
ErrorCodes::ImmutableField,
"Updating the path 'a.b' to b: 1 would modify the immutable field 'a.b'");
}
-TEST(SetNodeTest, ApplyCanPerformNoopOnImmutablePath) {
+TEST_F(SetNodeTest, ApplyCanPerformNoopOnImmutablePath) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.b");
+ addImmutablePath("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 0u);
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 0u);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyCannotOverwritePrefixToRemoveImmutablePath) {
+TEST_F(SetNodeTest, ApplyCannotOverwritePrefixToRemoveImmutablePath) {
auto update = fromjson("{$set: {a: 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathTaken("a");
+ addImmutablePath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::ImmutableField,
"After applying the update, the immutable field 'a.b' was found to have been removed.");
}
-TEST(SetNodeTest, ApplyCannotOverwritePrefixToModifyImmutablePath) {
+TEST_F(SetNodeTest, ApplyCannotOverwritePrefixToModifyImmutablePath) {
auto update = fromjson("{$set: {a: {b: 1}}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a");
+ addImmutablePath("a.b");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::ImmutableField,
"After applying the update, the immutable field 'a.b' was found to "
"have been altered to b: 1");
}
-TEST(SetNodeTest, ApplyCanPerformNoopOnPrefixOfImmutablePath) {
+TEST_F(SetNodeTest, ApplyCanPerformNoopOnPrefixOfImmutablePath) {
auto update = fromjson("{$set: {a: {b: 2}}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addImmutablePath("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 0u);
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 0u);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyCanOverwritePrefixToCreateImmutablePath) {
+TEST_F(SetNodeTest, ApplyCanOverwritePrefixToCreateImmutablePath) {
auto update = fromjson("{$set: {a: {b: 2}}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: 1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addImmutablePath("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {a: {b: 2}}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {a: {b: 2}}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyCanOverwritePrefixOfImmutablePathIfNoopOnImmutablePath) {
+TEST_F(SetNodeTest, ApplyCanOverwritePrefixOfImmutablePathIfNoopOnImmutablePath) {
auto update = fromjson("{$set: {a: {b: 2, c: 3}}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addImmutablePath("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2, c: 3}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {a: {b: 2, c: 3}}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {a: {b: 2, c: 3}}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyCannotOverwriteSuffixOfImmutablePath) {
+TEST_F(SetNodeTest, ApplyCannotOverwriteSuffixOfImmutablePath) {
auto update = fromjson("{$set: {'a.b.c': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b.c"], collator));
Document doc(fromjson("{a: {b: {c: 2}}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b.c");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathTaken("a.b.c");
+ addImmutablePath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["a"]["b"]["c"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["a"]["b"]["c"])),
UserException,
ErrorCodes::ImmutableField,
"Updating the path 'a.b.c' to c: 1 would modify the immutable field 'a.b'");
}
-TEST(SetNodeTest, ApplyCanPerformNoopOnSuffixOfImmutablePath) {
+TEST_F(SetNodeTest, ApplyCanPerformNoopOnSuffixOfImmutablePath) {
auto update = fromjson("{$set: {'a.b.c': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b.c"], collator));
Document doc(fromjson("{a: {b: {c: 2}}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b.c");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"]["c"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a.b.c");
+ addImmutablePath("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]["c"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: {c: 2}}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 0u);
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 0u);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyCannotCreateFieldAtEndOfImmutablePath) {
+TEST_F(SetNodeTest, ApplyCannotCreateFieldAtEndOfImmutablePath) {
auto update = fromjson("{$set: {'a.b.c': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b.c"], collator));
Document doc(fromjson("{a: {b: {}}}"));
- FieldRef pathToCreate("c");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("c");
+ setPathTaken("a.b");
+ addImmutablePath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["a"]["b"])),
UserException,
ErrorCodes::ImmutableField,
"Updating the path 'a.b' to b: { c: 1 } would modify the immutable field 'a.b'");
}
-TEST(SetNodeTest, ApplyCannotCreateFieldBeyondEndOfImmutablePath) {
+TEST_F(SetNodeTest, ApplyCannotCreateFieldBeyondEndOfImmutablePath) {
auto update = fromjson("{$set: {'a.b.c': 1}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b.c"], collator));
Document doc(fromjson("{a: {b: {}}}"));
- FieldRef pathToCreate("c");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathToCreate("c");
+ setPathTaken("a.b");
+ addImmutablePath("a");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["a"]["b"])),
UserException,
ErrorCodes::ImmutableField,
"Updating the path 'a.b' to b: { c: 1 } would modify the immutable field 'a'");
}
-TEST(SetNodeTest, ApplyCanCreateImmutablePath) {
+TEST_F(SetNodeTest, ApplyCanCreateImmutablePath) {
auto update = fromjson("{$set: {'a.b': 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a.b"], collator));
Document doc(fromjson("{a: {}}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("b");
+ setPathTaken("a");
+ addImmutablePath("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 2}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {'a.b': 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {'a.b': 2}}"), getLogDoc());
}
-TEST(SetNodeTest, ApplyCanCreatePrefixOfImmutablePath) {
+TEST_F(SetNodeTest, ApplyCanCreatePrefixOfImmutablePath) {
auto update = fromjson("{$set: {a: 2}}");
const CollatorInterface* collator = nullptr;
SetNode node;
ASSERT_OK(node.init(update["$set"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathToCreate("a");
+ addImmutablePath("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 2}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(countChildren(logDoc.root()), 1u);
- ASSERT_EQUALS(fromjson("{$set: {a: 2}}"), logDoc);
+ ASSERT_EQUALS(countChildren(getLogDoc().root()), 1u);
+ ASSERT_EQUALS(fromjson("{$set: {a: 2}}"), getLogDoc());
}
} // namespace
+} // namespace mongo
diff --git a/src/mongo/db/update/unset_node.cpp b/src/mongo/db/update/unset_node.cpp
index c7266ecb2d0..243e3918027 100644
--- a/src/mongo/db/update/unset_node.cpp
+++ b/src/mongo/db/update/unset_node.cpp
@@ -40,47 +40,36 @@ Status UnsetNode::init(BSONElement modExpr, const CollatorInterface* collator) {
return Status::OK();
}
-void UnsetNode::apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const {
- *indexesAffected = false;
- *noop = false;
-
- if (!pathToCreate->empty()) {
+UpdateNode::ApplyResult UnsetNode::apply(ApplyParams applyParams) const {
+ if (!applyParams.pathToCreate->empty()) {
// A non-empty "pathToCreate" implies that our search did not find the field that we wanted
// to delete. We employ a simple and efficient strategy for deleting fields that don't yet
// exist.
- *noop = true;
- return;
+ return ApplyResult::noopResult();
}
+ ApplyResult applyResult;
+
// Determine if indexes are affected.
- if (indexData && indexData->mightBeIndexed(pathTaken->dottedField())) {
- *indexesAffected = true;
+ if (!applyParams.indexData ||
+ !applyParams.indexData->mightBeIndexed(applyParams.pathTaken->dottedField())) {
+ applyResult.indexesAffected = false;
}
- auto parent = element.parent();
- auto leftSibling = element.leftSibling();
- auto rightSibling = element.rightSibling();
+ auto parent = applyParams.element.parent();
+ auto leftSibling = applyParams.element.leftSibling();
+ auto rightSibling = applyParams.element.rightSibling();
invariant(parent.ok());
if (!parent.isType(BSONType::Array)) {
- invariantOK(element.remove());
+ invariantOK(applyParams.element.remove());
} else {
// Special case: An $unset on an array element sets it to null instead of removing it from
// the array.
- invariantOK(element.setValueNull());
+ invariantOK(applyParams.element.setValueNull());
}
- if (validateForStorage) {
+ if (applyParams.validateForStorage) {
// Validate the left and right sibling, in case this element was part of a DBRef.
if (leftSibling.ok()) {
@@ -97,21 +86,24 @@ void UnsetNode::apply(mutablebson::Element element,
}
// Ensure we are not changing any immutable paths.
- for (auto immutablePath = immutablePaths.begin(); immutablePath != immutablePaths.end();
+ for (auto immutablePath = applyParams.immutablePaths.begin();
+ immutablePath != applyParams.immutablePaths.end();
++immutablePath) {
uassert(ErrorCodes::ImmutableField,
- str::stream() << "Unsetting the path '" << pathTaken->dottedField()
+ str::stream() << "Unsetting the path '" << applyParams.pathTaken->dottedField()
<< "' would modify the immutable field '"
<< (*immutablePath)->dottedField()
<< "'",
- pathTaken->commonPrefixSize(**immutablePath) <
- std::min(pathTaken->numParts(), (*immutablePath)->numParts()));
+ applyParams.pathTaken->commonPrefixSize(**immutablePath) <
+ std::min(applyParams.pathTaken->numParts(), (*immutablePath)->numParts()));
}
// Log the unset.
- if (logBuilder) {
- uassertStatusOK(logBuilder->addToUnsets(pathTaken->dottedField()));
+ if (applyParams.logBuilder) {
+ uassertStatusOK(applyParams.logBuilder->addToUnsets(applyParams.pathTaken->dottedField()));
}
+
+ return applyResult;
}
} // namespace mongo
diff --git a/src/mongo/db/update/unset_node.h b/src/mongo/db/update/unset_node.h
index 973eb300bef..a8d19f9ade8 100644
--- a/src/mongo/db/update/unset_node.h
+++ b/src/mongo/db/update/unset_node.h
@@ -46,17 +46,7 @@ public:
void setCollator(const CollatorInterface* collator) final {}
- void apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const final;
+ ApplyResult apply(ApplyParams applyParams) const final;
};
} // namespace mongo
diff --git a/src/mongo/db/update/unset_node_test.cpp b/src/mongo/db/update/unset_node_test.cpp
index 8c64cf5201c..ad8f373e943 100644
--- a/src/mongo/db/update/unset_node_test.cpp
+++ b/src/mongo/db/update/unset_node_test.cpp
@@ -33,12 +33,14 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
+namespace mongo {
namespace {
-using namespace mongo;
+using UnsetNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
using mongo::mutablebson::countChildren;
@@ -50,34 +52,14 @@ DEATH_TEST(UnsetNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr.o
node.init(update["$unset"].embeddedObject().firstElement(), collator).transitional_ignore();
}
-DEATH_TEST(UnsetNodeTest, ApplyToRootFails, "Invariant failure parent.ok()") {
+DEATH_TEST_F(UnsetNodeTest, ApplyToRootFails, "Invariant failure parent.ok()") {
auto update = fromjson("{$unset: {}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
+ node.apply(getApplyParams(doc.root()));
}
TEST(UnsetNodeTest, InitSucceedsForNonemptyElement) {
@@ -88,773 +70,361 @@ TEST(UnsetNodeTest, InitSucceedsForNonemptyElement) {
}
/* This is a no-op because we are unsetting a field that does not exit. */
-TEST(UnsetNodeTest, UnsetNoOp) {
+TEST_F(UnsetNodeTest, UnsetNoOp) {
auto update = fromjson("{$unset: {a: 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a"], collator));
Document doc(fromjson("{b: 5}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(UnsetNodeTest, UnsetNoOpDottedPath) {
+TEST_F(UnsetNodeTest, UnsetNoOpDottedPath) {
auto update = fromjson("{$unset: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.b"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: 5}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(UnsetNodeTest, UnsetNoOpThroughArray) {
+TEST_F(UnsetNodeTest, UnsetNoOpThroughArray) {
auto update = fromjson("{$unset: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.b"], collator));
Document doc(fromjson("{a:[{b:1}]}"));
- FieldRef pathToCreate("b");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("b");
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a:[{b:1}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(UnsetNodeTest, UnsetNoOpEmptyDoc) {
+TEST_F(UnsetNodeTest, UnsetNoOpEmptyDoc) {
auto update = fromjson("{$unset: {a: 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a"], collator));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("a");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(UnsetNodeTest, UnsetTopLevelPath) {
+TEST_F(UnsetNodeTest, UnsetTopLevelPath) {
auto update = fromjson("{$unset: {a: 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, UnsetNestedPath) {
+TEST_F(UnsetNodeTest, UnsetNestedPath) {
auto update = fromjson("{$unset: {'a.b.c': 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.b.c"], collator));
Document doc(fromjson("{a: {b: {c: 6}}}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b.c");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"]["c"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b.c");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]["c"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: {}}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.b.c': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {'a.b.c': true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, UnsetObject) {
+TEST_F(UnsetNodeTest, UnsetObject) {
auto update = fromjson("{$unset: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.b"], collator));
Document doc(fromjson("{a: {b: {c: 6}}}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.b': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {'a.b': true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, UnsetArrayElement) {
+TEST_F(UnsetNodeTest, UnsetArrayElement) {
auto update = fromjson("{$unset: {'a.0': 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.0"], collator));
Document doc(fromjson("{a:[1], b:1}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.0");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["0"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.0");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["0"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a:[null], b:1}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.0': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {'a.0': true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, UnsetPositional) {
+TEST_F(UnsetNodeTest, UnsetPositional) {
auto update = fromjson("{$unset: {'a.$': 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.$"], collator));
Document doc(fromjson("{a: [0, 1, 2]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.1");
- StringData matchedField = "1";
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["1"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.1");
+ setMatchedField("1");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["1"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: [0, null, 2]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.1': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {'a.1': true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, UnsetEntireArray) {
+TEST_F(UnsetNodeTest, UnsetEntireArray) {
auto update = fromjson("{$unset: {'a': 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a"], collator));
Document doc(fromjson("{a: [0, 1, 2]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, UnsetFromObjectInArray) {
+TEST_F(UnsetNodeTest, UnsetFromObjectInArray) {
auto update = fromjson("{$unset: {'a.0.b': 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.0.b"], collator));
Document doc(fromjson("{a: [{b: 1}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.0.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["0"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.0.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["0"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a:[{}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.0.b': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {'a.0.b': true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, CanUnsetInvalidField) {
+TEST_F(UnsetNodeTest, CanUnsetInvalidField) {
auto update = fromjson("{$unset: {'a.$.$b': true}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.$.$b"], collator));
Document doc(fromjson("{b: 1, a: [{$b: 1}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.0.$b");
- StringData matchedField = "0";
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["0"]["$b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.0.$b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["0"]["$b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{b: 1, a: [{}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.0.$b': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {'a.0.$b': true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, ApplyNoIndexDataNoLogBuilder) {
+TEST_F(UnsetNodeTest, ApplyNoIndexDataNoLogBuilder) {
auto update = fromjson("{$unset: {a: 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ setLogBuilderToNull();
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
}
-TEST(UnsetNodeTest, ApplyDoesNotAffectIndexes) {
+TEST_F(UnsetNodeTest, ApplyDoesNotAffectIndexes) {
auto update = fromjson("{$unset: {a: 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a"], collator));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("b");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathTaken("a");
+ addIndexedPath("b");
+ auto result = node.apply(getApplyParams(doc.root()["a"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {a: true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, ApplyFieldWithDot) {
+TEST_F(UnsetNodeTest, ApplyFieldWithDot) {
auto update = fromjson("{$unset: {'a.b': 1}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.b"], collator));
Document doc(fromjson("{'a.b':4, a: {b: 2}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{'a.b':4, a: {}}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.b': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {'a.b': true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) {
+TEST_F(UnsetNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) {
auto update = fromjson("{$unset: {'a.$id': true}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.$id"], collator));
Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.$id");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"]["$id"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a.$id");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"]["$id"])),
UserException,
ErrorCodes::InvalidDBRef,
"The DBRef $ref field must be followed by a $id field");
}
-TEST(UnsetNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFalse) {
+TEST_F(UnsetNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFalse) {
auto update = fromjson("{$unset: {'a.$id': true}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.$id"], collator));
Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.$id");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = false;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["$id"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_TRUE(indexesAffected);
+ setPathTaken("a.$id");
+ addIndexedPath("a");
+ setValidateForStorage(false);
+ auto result = node.apply(getApplyParams(doc.root()["a"]["$id"]));
+ ASSERT_FALSE(result.noop);
+ ASSERT_TRUE(result.indexesAffected);
auto updated = BSON("a" << BSON("$ref"
<< "c"));
ASSERT_EQUALS(updated, doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$unset: {'a.$id': true}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$unset: {'a.$id': true}}"), getLogDoc());
}
-TEST(UnsetNodeTest, ApplyCannotRemoveImmutablePath) {
+TEST_F(UnsetNodeTest, ApplyCannotRemoveImmutablePath) {
auto update = fromjson("{$unset: {'a.b': true}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.b"], collator));
Document doc(fromjson("{a: {b: 1}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a.b");
+ addImmutablePath("a.b");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"]["b"])),
UserException,
ErrorCodes::ImmutableField,
"Unsetting the path 'a.b' would modify the immutable field 'a.b'");
}
-TEST(UnsetNodeTest, ApplyCannotRemovePrefixOfImmutablePath) {
+TEST_F(UnsetNodeTest, ApplyCannotRemovePrefixOfImmutablePath) {
auto update = fromjson("{$unset: {a: true}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a"], collator));
Document doc(fromjson("{a: {b: 1}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(node.apply(doc.root()["a"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ setPathTaken("a");
+ addImmutablePath("a.b");
+ ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
UserException,
ErrorCodes::ImmutableField,
"Unsetting the path 'a' would modify the immutable field 'a.b'");
}
-TEST(UnsetNodeTest, ApplyCannotRemoveSuffixOfImmutablePath) {
+TEST_F(UnsetNodeTest, ApplyCannotRemoveSuffixOfImmutablePath) {
auto update = fromjson("{$unset: {'a.b.c': true}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.b.c"], collator));
Document doc(fromjson("{a: {b: {c: 1}}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("a.b.c");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
+ setPathTaken("a.b.c");
+ addImmutablePath("a.b");
ASSERT_THROWS_CODE_AND_WHAT(
- node.apply(doc.root()["a"]["b"]["c"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop),
+ node.apply(getApplyParams(doc.root()["a"]["b"]["c"])),
UserException,
ErrorCodes::ImmutableField,
"Unsetting the path 'a.b.c' would modify the immutable field 'a.b'");
}
-TEST(UnsetNodeTest, ApplyCanRemoveImmutablePathIfNoop) {
+TEST_F(UnsetNodeTest, ApplyCanRemoveImmutablePathIfNoop) {
auto update = fromjson("{$unset: {'a.b.c': true}}");
const CollatorInterface* collator = nullptr;
UnsetNode node;
ASSERT_OK(node.init(update["$unset"]["a.b.c"], collator));
Document doc(fromjson("{a: {b: 1}}"));
- FieldRef pathToCreate("c");
- FieldRef pathTaken("a.b");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = false;
- FieldRefSet immutablePaths;
- FieldRef path("a.b");
- immutablePaths.insert(&path);
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- node.apply(doc.root()["a"]["b"],
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(noop);
- ASSERT_FALSE(indexesAffected);
+ setPathToCreate("c");
+ setPathTaken("a.b");
+ addImmutablePath("a.b");
+ addIndexedPath("a");
+ auto result = node.apply(getApplyParams(doc.root()["a"]["b"]));
+ ASSERT_TRUE(result.noop);
+ ASSERT_FALSE(result.indexesAffected);
ASSERT_EQUALS(fromjson("{a: {b: 1}}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
} // namespace
+} // namespace mongo
diff --git a/src/mongo/db/update/update_array_node.cpp b/src/mongo/db/update/update_array_node.cpp
index e82e5d8aef3..02f904d77b2 100644
--- a/src/mongo/db/update/update_array_node.cpp
+++ b/src/mongo/db/update/update_array_node.cpp
@@ -46,33 +46,20 @@ std::unique_ptr<UpdateNode> UpdateArrayNode::createUpdateNodeByMerging(
return std::move(mergedNode);
}
-void UpdateArrayNode::apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const {
- *indexesAffected = false;
- *noop = true;
-
- if (!pathToCreate->empty()) {
- for (size_t i = 0; i < pathToCreate->numParts(); ++i) {
- pathTaken->appendPart(pathToCreate->getPart(i));
+UpdateNode::ApplyResult UpdateArrayNode::apply(ApplyParams applyParams) const {
+ if (!applyParams.pathToCreate->empty()) {
+ for (size_t i = 0; i < applyParams.pathToCreate->numParts(); ++i) {
+ applyParams.pathTaken->appendPart(applyParams.pathToCreate->getPart(i));
}
uasserted(ErrorCodes::BadValue,
- str::stream() << "The path '" << pathTaken->dottedField()
+ str::stream() << "The path '" << applyParams.pathTaken->dottedField()
<< "' must exist in the document in order to apply array updates.");
}
uassert(ErrorCodes::BadValue,
str::stream() << "Cannot apply array updates to non-array element "
- << element.toString(),
- element.getType() == BSONType::Array);
+ << applyParams.element.toString(),
+ applyParams.element.getType() == BSONType::Array);
// Construct a map from the array index to the set of updates that should be applied to the
// array element at that index. We do not apply the updates yet because we need to know how many
@@ -80,7 +67,7 @@ void UpdateArrayNode::apply(mutablebson::Element element,
// UpdateNode children.
std::map<size_t, std::vector<UpdateNode*>> matchingElements;
size_t i = 0;
- for (auto childElement = element.leftChild(); childElement.ok();
+ for (auto childElement = applyParams.element.leftChild(); childElement.ok();
childElement = childElement.rightSibling()) {
// 'childElement' will always be serialized because no updates have been performed on the
@@ -118,8 +105,9 @@ void UpdateArrayNode::apply(mutablebson::Element element,
size_t nModified = 0;
// Update array elements.
+ auto applyResult = ApplyResult::noopResult();
i = 0;
- for (auto childElement = element.leftChild(); childElement.ok();
+ for (auto childElement = applyParams.element.leftChild(); childElement.ok();
childElement = childElement.rightSibling()) {
auto updates = matchingElements.find(i);
if (updates != matchingElements.end()) {
@@ -127,7 +115,7 @@ void UpdateArrayNode::apply(mutablebson::Element element,
// Merge all of the updates for this array element.
invariant(updates->second.size() > 0);
auto mergedChild = updates->second[0];
- FieldRefTempAppend tempAppend(*pathTaken, childElement.getFieldName());
+ FieldRefTempAppend tempAppend(*(applyParams.pathTaken), childElement.getFieldName());
for (size_t j = 1; j < updates->second.size(); ++j) {
// Use the cached merge result, if it is available.
@@ -141,28 +129,22 @@ void UpdateArrayNode::apply(mutablebson::Element element,
// result.
_mergedChildrenCache[mergedChild][updates->second[j]] =
UpdateNode::createUpdateNodeByMerging(
- *mergedChild, *updates->second[j], pathTaken);
+ *mergedChild, *updates->second[j], applyParams.pathTaken.get());
mergedChild = _mergedChildrenCache[mergedChild][updates->second[j]].get();
}
- bool childAffectsIndexes = false;
- bool childNoop = false;
-
- mergedChild->apply(childElement,
- pathToCreate,
- pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- childrenShouldLogThemselves ? logBuilder : nullptr,
- &childAffectsIndexes,
- &childNoop);
-
- *indexesAffected = *indexesAffected || childAffectsIndexes;
- *noop = *noop && childNoop;
- if (!childNoop) {
+ auto childApplyParams = applyParams;
+ childApplyParams.element = childElement;
+ if (!childrenShouldLogThemselves) {
+ childApplyParams.logBuilder = nullptr;
+ }
+
+ auto childApplyResult = mergedChild->apply(childApplyParams);
+
+ applyResult.indexesAffected =
+ applyResult.indexesAffected || childApplyResult.indexesAffected;
+ applyResult.noop = applyResult.noop && childApplyResult.noop;
+ if (!childApplyResult.noop) {
modifiedElement = childElement;
++nModified;
}
@@ -172,25 +154,28 @@ void UpdateArrayNode::apply(mutablebson::Element element,
}
// If the child updates have not been logged, log the updated array elements.
- if (!childrenShouldLogThemselves && logBuilder) {
+ if (!childrenShouldLogThemselves && applyParams.logBuilder) {
if (nModified > 1) {
// Log the entire array.
- auto logElement = logBuilder->getDocument().makeElementWithNewFieldName(
- pathTaken->dottedField(), element);
+ auto logElement = applyParams.logBuilder->getDocument().makeElementWithNewFieldName(
+ applyParams.pathTaken->dottedField(), applyParams.element);
invariant(logElement.ok());
- uassertStatusOK(logBuilder->addToSets(logElement));
+ uassertStatusOK(applyParams.logBuilder->addToSets(logElement));
} else if (nModified == 1) {
// Log the modified array element.
invariant(modifiedElement);
- FieldRefTempAppend tempAppend(*pathTaken, modifiedElement->getFieldName());
- auto logElement = logBuilder->getDocument().makeElementWithNewFieldName(
- pathTaken->dottedField(), *modifiedElement);
+ FieldRefTempAppend tempAppend(*(applyParams.pathTaken),
+ modifiedElement->getFieldName());
+ auto logElement = applyParams.logBuilder->getDocument().makeElementWithNewFieldName(
+ applyParams.pathTaken->dottedField(), *modifiedElement);
invariant(logElement.ok());
- uassertStatusOK(logBuilder->addToSets(logElement));
+ uassertStatusOK(applyParams.logBuilder->addToSets(logElement));
}
}
+
+ return applyResult;
}
UpdateNode* UpdateArrayNode::getChild(const std::string& field) const {
diff --git a/src/mongo/db/update/update_array_node.h b/src/mongo/db/update/update_array_node.h
index 8ccd8d028f8..ef535419b7f 100644
--- a/src/mongo/db/update/update_array_node.h
+++ b/src/mongo/db/update/update_array_node.h
@@ -72,17 +72,7 @@ public:
}
}
- void apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const final;
+ ApplyResult apply(ApplyParams applyParams) const final;
UpdateNode* getChild(const std::string& field) const final;
diff --git a/src/mongo/db/update/update_array_node_test.cpp b/src/mongo/db/update/update_array_node_test.cpp
index a142c04a1f0..60c5bfb4448 100644
--- a/src/mongo/db/update/update_array_node_test.cpp
+++ b/src/mongo/db/update/update_array_node_test.cpp
@@ -33,6 +33,7 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/db/update/update_object_node.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
@@ -40,10 +41,11 @@
namespace mongo {
namespace {
+using UpdateArrayNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
-TEST(UpdateArrayNodeTest, ApplyCreatePathFails) {
+TEST_F(UpdateArrayNodeTest, ApplyCreatePathFails) {
auto update = fromjson("{$set: {'a.b.$[i]': 0}}");
auto arrayFilter = fromjson("{i: 0}");
const CollatorInterface* collator = nullptr;
@@ -59,36 +61,15 @@ TEST(UpdateArrayNodeTest, ApplyCreatePathFails) {
foundIdentifiers));
Document doc(fromjson("{a: {}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
+ addIndexedPath("a");
ASSERT_THROWS_CODE_AND_WHAT(
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ root.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::BadValue,
"The path 'a.b' must exist in the document in order to apply array updates.");
}
-TEST(UpdateArrayNodeTest, ApplyToNonArrayFails) {
+TEST_F(UpdateArrayNodeTest, ApplyToNonArrayFails) {
auto update = fromjson("{$set: {'a.$[i]': 0}}");
auto arrayFilter = fromjson("{i: 0}");
const CollatorInterface* collator = nullptr;
@@ -104,35 +85,14 @@ TEST(UpdateArrayNodeTest, ApplyToNonArrayFails) {
foundIdentifiers));
Document doc(fromjson("{a: {}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(root.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::BadValue,
"Cannot apply array updates to non-array element a: {}");
}
-TEST(UpdateArrayNodeTest, UpdateIsAppliedToAllMatchingElements) {
+TEST_F(UpdateArrayNodeTest, UpdateIsAppliedToAllMatchingElements) {
auto update = fromjson("{$set: {'a.$[i]': 2}}");
auto arrayFilter = fromjson("{i: 0}");
const CollatorInterface* collator = nullptr;
@@ -148,39 +108,18 @@ TEST(UpdateArrayNodeTest, UpdateIsAppliedToAllMatchingElements) {
foundIdentifiers));
Document doc(fromjson("{a: [0, 1, 0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [2, 1, 2]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [2, 1, 2]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [2, 1, 2]}}"), getLogDoc());
}
-DEATH_TEST(UpdateArrayNodeTest,
- ArrayElementsMustNotBeDeserialized,
- "Invariant failure childElement.hasValue()") {
+DEATH_TEST_F(UpdateArrayNodeTest,
+ ArrayElementsMustNotBeDeserialized,
+ "Invariant failure childElement.hasValue()") {
auto update = fromjson("{$set: {'a.$[i].b': 0}}");
auto arrayFilter = fromjson("{'i.c': 0}");
const CollatorInterface* collator = nullptr;
@@ -198,32 +137,11 @@ DEATH_TEST(UpdateArrayNodeTest,
Document doc(fromjson("{a: [{c: 0}, {c: 0}, {c: 1}]}"));
doc.root()["a"]["1"]["c"].setValueInt(1).transitional_ignore();
doc.root()["a"]["2"]["c"].setValueInt(0).transitional_ignore();
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
+ addIndexedPath("a");
+ root.apply(getApplyParams(doc.root()));
}
-TEST(UpdateArrayNodeTest, UpdateForEmptyIdentifierIsAppliedToAllArrayElements) {
+TEST_F(UpdateArrayNodeTest, UpdateForEmptyIdentifierIsAppliedToAllArrayElements) {
auto update = fromjson("{$set: {'a.$[]': 1}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -237,37 +155,16 @@ TEST(UpdateArrayNodeTest, UpdateForEmptyIdentifierIsAppliedToAllArrayElements) {
foundIdentifiers));
Document doc(fromjson("{a: [0, 0, 0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [1, 1, 1]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [1, 1, 1]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [1, 1, 1]}}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElement) {
+TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElement) {
auto update = fromjson("{$set: {'a.$[i].b': 1, 'a.$[j].c': 1, 'a.$[k].d': 1}}");
auto arrayFilterI = fromjson("{'i.b': 0}");
auto arrayFilterJ = fromjson("{'j.c': 0}");
@@ -299,37 +196,16 @@ TEST(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElement) {
foundIdentifiers));
Document doc(fromjson("{a: [{b: 0, c: 0, d: 0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{b: 1, c: 1, d: 1}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.0.b': 1, 'a.0.c': 1, 'a.0.d': 1}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.0.b': 1, 'a.0.c': 1, 'a.0.d': 1}}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsUsingMergedChildrenCache) {
+TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsUsingMergedChildrenCache) {
auto update = fromjson("{$set: {'a.$[i].b': 1, 'a.$[j].c': 1}}");
auto arrayFilterI = fromjson("{'i.b': 0}");
auto arrayFilterJ = fromjson("{'j.c': 0}");
@@ -353,37 +229,16 @@ TEST(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsUsingMergedChildren
foundIdentifiers));
Document doc(fromjson("{a: [{b: 0, c: 0}, {b: 0, c: 0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- auto fromReplication = false;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{b: 1, c: 1}, {b: 1, c: 1}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{b: 1, c: 1}, {b: 1, c: 1}]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [{b: 1, c: 1}, {b: 1, c: 1}]}}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsWithoutMergedChildrenCache) {
+TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsWithoutMergedChildrenCache) {
auto update = fromjson("{$set: {'a.$[i].b': 2, 'a.$[j].c': 2, 'a.$[k].d': 2}}");
auto arrayFilterI = fromjson("{'i.b': 0}");
auto arrayFilterJ = fromjson("{'j.c': 0}");
@@ -415,37 +270,16 @@ TEST(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementsWithoutMergedChildr
foundIdentifiers));
Document doc(fromjson("{a: [{b: 0, c: 0, d: 1}, {b: 1, c: 0, d: 0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{b: 2, c: 2, d: 1}, {b: 1, c: 2, d: 2}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{b: 2, c: 2, d: 1}, {b: 1, c: 2, d: 2}]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [{b: 2, c: 2, d: 1}, {b: 1, c: 2, d: 2}]}}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementWithEmptyIdentifiers) {
+TEST_F(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementWithEmptyIdentifiers) {
auto update = fromjson("{$set: {'a.$[].b': 1, 'a.$[].c': 1}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -465,37 +299,16 @@ TEST(UpdateArrayNodeTest, ApplyMultipleUpdatesToArrayElementWithEmptyIdentifiers
foundIdentifiers));
Document doc(fromjson("{a: [{b: 0, c: 0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{b: 1, c: 1}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.0.b': 1, 'a.0.c': 1}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.0.b': 1, 'a.0.c': 1}}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, ApplyNestedArrayUpdates) {
+TEST_F(UpdateArrayNodeTest, ApplyNestedArrayUpdates) {
auto update = fromjson("{$set: {'a.$[i].b.$[j].c': 1, 'a.$[k].b.$[l].d': 1}}");
auto arrayFilterI = fromjson("{'i.x': 0}");
auto arrayFilterJ = fromjson("{'j.c': 0}");
@@ -523,37 +336,16 @@ TEST(UpdateArrayNodeTest, ApplyNestedArrayUpdates) {
foundIdentifiers));
Document doc(fromjson("{a: [{x: 0, b: [{c: 0, d: 0}]}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{x: 0, b: [{c: 1, d: 1}]}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.0.b.0.c': 1, 'a.0.b.0.d': 1}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.0.b.0.c': 1, 'a.0.b.0.d': 1}}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, ApplyUpdatesWithMergeConflictToArrayElementFails) {
+TEST_F(UpdateArrayNodeTest, ApplyUpdatesWithMergeConflictToArrayElementFails) {
auto update = fromjson("{$set: {'a.$[i]': 1, 'a.$[j]': 1}}");
auto arrayFilterI = fromjson("{'i': 0}");
auto arrayFilterJ = fromjson("{'j': 0}");
@@ -577,35 +369,14 @@ TEST(UpdateArrayNodeTest, ApplyUpdatesWithMergeConflictToArrayElementFails) {
foundIdentifiers));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(root.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::ConflictingUpdateOperators,
"Update created a conflict at 'a.0'");
}
-TEST(UpdateArrayNodeTest, ApplyUpdatesWithEmptyIdentifiersWithMergeConflictToArrayElementFails) {
+TEST_F(UpdateArrayNodeTest, ApplyUpdatesWithEmptyIdentifiersWithMergeConflictToArrayElementFails) {
auto update = fromjson("{$set: {'a.$[].b.$[i]': 1, 'a.$[].b.$[j]': 1}}");
auto arrayFilterI = fromjson("{'i': 0}");
auto arrayFilterJ = fromjson("{'j': 0}");
@@ -629,35 +400,14 @@ TEST(UpdateArrayNodeTest, ApplyUpdatesWithEmptyIdentifiersWithMergeConflictToArr
foundIdentifiers));
Document doc(fromjson("{a: [{b: [0]}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(root.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::ConflictingUpdateOperators,
"Update created a conflict at 'a.0.b.0'");
}
-TEST(UpdateArrayNodeTest, ApplyNestedArrayUpdatesWithMergeConflictFails) {
+TEST_F(UpdateArrayNodeTest, ApplyNestedArrayUpdatesWithMergeConflictFails) {
auto update = fromjson("{$set: {'a.$[i].b.$[j]': 1, 'a.$[k].b.$[l]': 1}}");
auto arrayFilterI = fromjson("{'i.c': 0}");
auto arrayFilterJ = fromjson("{j: 0}");
@@ -685,35 +435,14 @@ TEST(UpdateArrayNodeTest, ApplyNestedArrayUpdatesWithMergeConflictFails) {
foundIdentifiers));
Document doc(fromjson("{a: [{b: [0], c: 0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(root.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::ConflictingUpdateOperators,
"Update created a conflict at 'a.0.b.0'");
}
-TEST(UpdateArrayNodeTest, NoArrayElementsMatch) {
+TEST_F(UpdateArrayNodeTest, NoArrayElementsMatch) {
auto update = fromjson("{$set: {'a.$[i]': 1}}");
auto arrayFilter = fromjson("{'i': 0}");
const CollatorInterface* collator = nullptr;
@@ -729,37 +458,16 @@ TEST(UpdateArrayNodeTest, NoArrayElementsMatch) {
foundIdentifiers));
Document doc(fromjson("{a: [2, 2, 2]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(indexesAffected);
- ASSERT_TRUE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.indexesAffected);
+ ASSERT_TRUE(result.noop);
ASSERT_EQUALS(fromjson("{a: [2, 2, 2]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, UpdatesToAllArrayElementsAreNoops) {
+TEST_F(UpdateArrayNodeTest, UpdatesToAllArrayElementsAreNoops) {
auto update = fromjson("{$set: {'a.$[i]': 1}}");
auto arrayFilter = fromjson("{'i': 0}");
const CollatorInterface* collator = nullptr;
@@ -775,37 +483,16 @@ TEST(UpdateArrayNodeTest, UpdatesToAllArrayElementsAreNoops) {
foundIdentifiers));
Document doc(fromjson("{a: [1, 1, 1]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(indexesAffected);
- ASSERT_TRUE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.indexesAffected);
+ ASSERT_TRUE(result.noop);
ASSERT_EQUALS(fromjson("{a: [1, 1, 1]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, NoArrayElementAffectsIndexes) {
+TEST_F(UpdateArrayNodeTest, NoArrayElementAffectsIndexes) {
auto update = fromjson("{$set: {'a.$[i].b': 0}}");
auto arrayFilter = fromjson("{'i.c': 0}");
const CollatorInterface* collator = nullptr;
@@ -821,37 +508,16 @@ TEST(UpdateArrayNodeTest, NoArrayElementAffectsIndexes) {
foundIdentifiers));
Document doc(fromjson("{a: [{c: 0}, {c: 0}, {c: 0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a.c");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a.c");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{c: 0, b: 0}, {c: 0, b: 0}, {c: 0, b: 0}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: [{c: 0, b: 0}, {c: 0, b: 0}, {c: 0, b: 0}]}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: [{c: 0, b: 0}, {c: 0, b: 0}, {c: 0, b: 0}]}}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, WhenOneElementIsMatchedLogElementUpdateDirectly) {
+TEST_F(UpdateArrayNodeTest, WhenOneElementIsMatchedLogElementUpdateDirectly) {
auto update = fromjson("{$set: {'a.$[i].b': 0}}");
auto arrayFilter = fromjson("{'i.c': 0}");
const CollatorInterface* collator = nullptr;
@@ -867,37 +533,16 @@ TEST(UpdateArrayNodeTest, WhenOneElementIsMatchedLogElementUpdateDirectly) {
foundIdentifiers));
Document doc(fromjson("{a: [{c: 1}, {c: 0}, {c: 1}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{c: 1}, {c: 0, b: 0}, {c: 1}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1.b': 0}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.1.b': 0}}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, WhenOneElementIsModifiedLogElement) {
+TEST_F(UpdateArrayNodeTest, WhenOneElementIsModifiedLogElement) {
auto update = fromjson("{$set: {'a.$[i].b': 0}}");
auto arrayFilter = fromjson("{'i.c': 0}");
const CollatorInterface* collator = nullptr;
@@ -913,37 +558,16 @@ TEST(UpdateArrayNodeTest, WhenOneElementIsModifiedLogElement) {
foundIdentifiers));
Document doc(fromjson("{a: [{c: 0, b: 0}, {c: 0}, {c: 1}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{c: 0, b: 0}, {c: 0, b: 0}, {c: 1}]}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.1': {c: 0, b: 0}}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.1': {c: 0, b: 0}}}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, ArrayUpdateOnEmptyArrayIsANoop) {
+TEST_F(UpdateArrayNodeTest, ArrayUpdateOnEmptyArrayIsANoop) {
auto update = fromjson("{$set: {'a.$[]': 0}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -957,37 +581,16 @@ TEST(UpdateArrayNodeTest, ArrayUpdateOnEmptyArrayIsANoop) {
foundIdentifiers));
Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(indexesAffected);
- ASSERT_TRUE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.indexesAffected);
+ ASSERT_TRUE(result.noop);
ASSERT_EQUALS(fromjson("{a: []}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, ApplyPositionalInsideArrayUpdate) {
+TEST_F(UpdateArrayNodeTest, ApplyPositionalInsideArrayUpdate) {
auto update = fromjson("{$set: {'a.$[i].b.$': 1}}");
auto arrayFilter = fromjson("{'i.c': 0}");
const CollatorInterface* collator = nullptr;
@@ -1003,37 +606,17 @@ TEST(UpdateArrayNodeTest, ApplyPositionalInsideArrayUpdate) {
foundIdentifiers));
Document doc(fromjson("{a: [{b: [0, 0], c: 0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField = "1";
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ setMatchedField("1");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [{b: [0, 1], c: 0}]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {'a.0.b.1': 1}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {'a.0.b.1': 1}}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, ApplyArrayUpdateFromReplication) {
+TEST_F(UpdateArrayNodeTest, ApplyArrayUpdateFromReplication) {
auto update = fromjson("{$set: {'a.$[i].b': 1}}");
auto arrayFilter = fromjson("{'i': 0}");
const CollatorInterface* collator = nullptr;
@@ -1049,37 +632,17 @@ TEST(UpdateArrayNodeTest, ApplyArrayUpdateFromReplication) {
foundIdentifiers));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(indexesAffected);
- ASSERT_TRUE(noop);
+ addIndexedPath("a");
+ setFromReplication(true);
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.indexesAffected);
+ ASSERT_TRUE(result.noop);
ASSERT_EQUALS(fromjson("{a: [0]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{}"), logDoc);
+ ASSERT_EQUALS(fromjson("{}"), getLogDoc());
}
-TEST(UpdateArrayNodeTest, ApplyArrayUpdateNotFromReplication) {
+TEST_F(UpdateArrayNodeTest, ApplyArrayUpdateNotFromReplication) {
auto update = fromjson("{$set: {'a.$[i].b': 1}}");
auto arrayFilter = fromjson("{'i': 0}");
const CollatorInterface* collator = nullptr;
@@ -1095,35 +658,14 @@ TEST(UpdateArrayNodeTest, ApplyArrayUpdateNotFromReplication) {
foundIdentifiers));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(root.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field 'b' in element {0: 0}");
}
-TEST(UpdateArrayNodeTest, ApplyArrayUpdateWithoutLogBuilderOrIndexData) {
+TEST_F(UpdateArrayNodeTest, ApplyArrayUpdateWithoutLogBuilderOrIndexData) {
auto update = fromjson("{$set: {'a.$[i]': 1}}");
auto arrayFilter = fromjson("{'i': 0}");
const CollatorInterface* collator = nullptr;
@@ -1139,29 +681,10 @@ TEST(UpdateArrayNodeTest, ApplyArrayUpdateWithoutLogBuilderOrIndexData) {
foundIdentifiers));
Document doc(fromjson("{a: [0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- LogBuilder* logBuilder = nullptr;
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(indexesAffected);
- ASSERT_FALSE(noop);
+ setLogBuilderToNull();
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: [1]}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
}
diff --git a/src/mongo/db/update/update_driver.cpp b/src/mongo/db/update/update_driver.cpp
index b094dcef6f9..8402971f9af 100644
--- a/src/mongo/db/update/update_driver.cpp
+++ b/src/mongo/db/update/update_driver.cpp
@@ -289,27 +289,21 @@ Status UpdateDriver::update(StringData matchedField,
if (_root) {
// We parsed using the new UpdateNode implementation.
- FieldRef pathToCreate;
- FieldRef pathTaken;
- bool indexesAffected = false;
- bool noop = false;
- _root->apply(doc->root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- _modOptions.fromReplication,
- validateForStorage,
- immutablePaths,
- _indexedFields,
- (_logOp && logOpRec) ? &logBuilder : nullptr,
- &indexesAffected,
- &noop);
- if (indexesAffected) {
+ UpdateNode::ApplyParams applyParams(doc->root(), immutablePaths);
+ applyParams.matchedField = matchedField;
+ applyParams.fromReplication = _modOptions.fromReplication;
+ applyParams.validateForStorage = validateForStorage;
+ applyParams.indexData = _indexedFields;
+ if (_logOp && logOpRec) {
+ applyParams.logBuilder = &logBuilder;
+ }
+ auto applyResult = _root->apply(applyParams);
+ if (applyResult.indexesAffected) {
_affectIndices = true;
doc->disableInPlaceUpdates();
}
if (docWasModified) {
- *docWasModified = !noop;
+ *docWasModified = !applyResult.noop;
}
} else {
diff --git a/src/mongo/db/update/update_node.h b/src/mongo/db/update/update_node.h
index a553b9ef111..f2dccbad85d 100644
--- a/src/mongo/db/update/update_node.h
+++ b/src/mongo/db/update/update_node.h
@@ -76,32 +76,69 @@ public:
virtual void setCollator(const CollatorInterface* collator) = 0;
/**
- * Applies the update node to 'element', creating the fields in 'pathToCreate' if required by
- * the leaves (i.e. the leaves are not all $unset). 'pathTaken' is the path through the root
- * document to 'element', ending with the field name of 'element'. 'pathToCreate' is the path
- * taken through the UpdateNode tree beyond where the path existed in the document. For example,
- * if the update is {$set: {'a.b.c': 5}}, and the document is {a: {}}, then at the leaf node,
- * pathTaken="a" and pathToCreate="b.c" If there was a positional ($) element in the update
- * expression, 'matchedField' is the index of the array element that caused the query to match
- * the document. 'fromReplication' is provided because some modifiers may ignore certain errors
- * when the update is from replication. Uses the index information in 'indexData' to determine
- * whether indexes are affected. If a LogBuilder is provided, logs the update. Outputs whether
- * the operation was a no-op. Trips a uassert (which throws UserException) if the update node
- * cannot be applied to the document. If 'validateForStorage' is true, ensures that modified
- * elements do not violate depth or DBRef constraints. Ensures that no paths in 'immutablePaths'
- * are modified (though they may be created, if they do not yet exist).
+ * The parameters required by UpdateNode::apply.
*/
- virtual void apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const = 0;
+ struct ApplyParams {
+ ApplyParams(mutablebson::Element element, const FieldRefSet& immutablePaths)
+ : element(element), immutablePaths(immutablePaths) {}
+
+ // The element to update.
+ mutablebson::Element element;
+
+ // UpdateNode::apply uasserts if it modifies an immutable path.
+ const FieldRefSet& immutablePaths;
+
+ // The path taken through the UpdateNode tree beyond where the path existed in the document.
+ // For example, if the update is {$set: {'a.b.c': 5}}, and the document is {a: {}}, then at
+ // the leaf node, 'pathToCreate'="b.c".
+ std::shared_ptr<FieldRef> pathToCreate = std::make_shared<FieldRef>();
+
+ // The path through the root document to 'element', ending with the field name of 'element'.
+ // For example, if the update is {$set: {'a.b.c': 5}}, and the document is {a: {}}, then at
+ // the leaf node, 'pathTaken'="a".
+ std::shared_ptr<FieldRef> pathTaken = std::make_shared<FieldRef>();
+
+ // If there was a positional ($) element in the update expression, 'matchedField' is the
+ // index of the array element that caused the query to match the document.
+ StringData matchedField;
+
+ // This is provided because some modifiers may ignore certain errors when the update is from
+ // replication.
+ bool fromReplication = false;
+
+ // If true, UpdateNode::apply ensures that modified elements do not violate depth or DBRef
+ // constraints.
+ bool validateForStorage = true;
+
+ // Used to determine whether indexes are affected.
+ const UpdateIndexData* indexData = nullptr;
+
+ // If provided, UpdateNode::apply will log the update here.
+ LogBuilder* logBuilder = nullptr;
+ };
+
+ /**
+ * The outputs of apply().
+ */
+ struct ApplyResult {
+ static ApplyResult noopResult() {
+ ApplyResult applyResult;
+ applyResult.indexesAffected = false;
+ applyResult.noop = true;
+ return applyResult;
+ }
+
+ bool indexesAffected = true;
+ bool noop = false;
+ };
+
+ /**
+ * Applies the update node to 'applyParams.element', creating the fields in
+ * 'applyParams.pathToCreate' if required by the leaves (i.e. the leaves are not all $unset).
+ * Returns an ApplyResult specifying whether the operation was a no-op and whether indexes are
+ * affected.
+ */
+ virtual ApplyResult apply(ApplyParams applyParams) const = 0;
/**
* Creates a new node by merging the contents of two input nodes. The semantics of the merge
diff --git a/src/mongo/db/update/update_node_test_fixture.h b/src/mongo/db/update/update_node_test_fixture.h
new file mode 100644
index 00000000000..29766992539
--- /dev/null
+++ b/src/mongo/db/update/update_node_test_fixture.h
@@ -0,0 +1,133 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/db/logical_clock.h"
+#include "mongo/db/service_context_noop.h"
+#include "mongo/db/update/update_node.h"
+#include "mongo/unittest/unittest.h"
+
+namespace mongo {
+
+class UpdateNodeTest : public mongo::unittest::Test {
+public:
+ ~UpdateNodeTest() override = default;
+
+protected:
+ void setUp() override {
+ resetApplyParams();
+
+ // Set up the logical clock needed by CurrentDateNode and ObjectReplaceNode.
+ auto service = mongo::getGlobalServiceContext();
+ auto logicalClock = mongo::stdx::make_unique<mongo::LogicalClock>(service);
+ mongo::LogicalClock::set(service, std::move(logicalClock));
+ }
+
+ void resetApplyParams() {
+ _immutablePathsVector.clear();
+ _immutablePaths.clear();
+ _pathToCreate = std::make_shared<FieldRef>();
+ _pathTaken = std::make_shared<FieldRef>();
+ _matchedField = StringData();
+ _fromReplication = false;
+ _validateForStorage = true;
+ _indexData.reset();
+ _logDoc.reset();
+ _logBuilder = stdx::make_unique<LogBuilder>(_logDoc.root());
+ }
+
+ UpdateNode::ApplyParams getApplyParams(mutablebson::Element element) {
+ UpdateNode::ApplyParams applyParams(element, _immutablePaths);
+ applyParams.pathToCreate = _pathToCreate;
+ applyParams.pathTaken = _pathTaken;
+ applyParams.matchedField = _matchedField;
+ applyParams.fromReplication = _fromReplication;
+ applyParams.validateForStorage = _validateForStorage;
+ applyParams.indexData = _indexData.get();
+ applyParams.logBuilder = _logBuilder.get();
+ return applyParams;
+ }
+
+ void addImmutablePath(StringData path) {
+ auto fieldRef = stdx::make_unique<FieldRef>(path);
+ _immutablePathsVector.push_back(std::move(fieldRef));
+ _immutablePaths.insert(_immutablePathsVector.back().get());
+ }
+
+ void setPathToCreate(StringData path) {
+ _pathToCreate->clear();
+ _pathToCreate->parse(path);
+ }
+
+ void setPathTaken(StringData path) {
+ _pathTaken->clear();
+ _pathTaken->parse(path);
+ }
+
+ void setMatchedField(StringData matchedField) {
+ _matchedField = matchedField;
+ }
+
+ void setFromReplication(bool fromReplication) {
+ _fromReplication = fromReplication;
+ }
+
+ void setValidateForStorage(bool validateForStorage) {
+ _validateForStorage = validateForStorage;
+ }
+
+ void addIndexedPath(StringData path) {
+ if (!_indexData) {
+ _indexData = stdx::make_unique<UpdateIndexData>();
+ }
+ _indexData->addPath(path);
+ }
+
+ void setLogBuilderToNull() {
+ _logBuilder.reset();
+ }
+
+ const mutablebson::Document& getLogDoc() {
+ return _logDoc;
+ }
+
+private:
+ std::vector<std::unique_ptr<FieldRef>> _immutablePathsVector;
+ FieldRefSet _immutablePaths;
+ std::shared_ptr<FieldRef> _pathToCreate;
+ std::shared_ptr<FieldRef> _pathTaken;
+ StringData _matchedField;
+ bool _fromReplication;
+ bool _validateForStorage;
+ std::unique_ptr<UpdateIndexData> _indexData;
+ mutablebson::Document _logDoc;
+ std::unique_ptr<LogBuilder> _logBuilder;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/update/update_object_node.cpp b/src/mongo/db/update/update_object_node.cpp
index 25c51dc32a2..dd615278e46 100644
--- a/src/mongo/db/update/update_object_node.cpp
+++ b/src/mongo/db/update/update_object_node.cpp
@@ -81,39 +81,32 @@ StatusWith<std::string> parseArrayFilterIdentifier(
}
/**
- * Applies 'child' to the child of 'element' named 'field' (which will create it, if it does not
- * exist). If 'pathToCreate' is created, then 'pathToCreate' is moved to the end of 'pathTaken', and
- * 'element' is advanced to the end of 'pathTaken'.
+ * Applies 'child' to the child of 'applyParams->element' named 'field' (which will create it, if it
+ * does not exist). If 'applyParams->pathToCreate' is created, then 'applyParams->pathToCreate' is
+ * moved to the end of 'applyParams->pathTaken', and 'applyParams->element' is advanced to the end
+ * of 'applyParams->pathTaken'. Updates 'applyResult' based on whether 'child' was a noop or
+ * affected indexes.
*/
void applyChild(const UpdateNode& child,
StringData field,
- mutablebson::Element* element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) {
-
- auto pathTakenSizeBefore = pathTaken->numParts();
+ UpdateNode::ApplyParams* applyParams,
+ UpdateNode::ApplyResult* applyResult) {
+
+ auto pathTakenSizeBefore = applyParams->pathTaken->numParts();
// A non-ok value for childElement will indicate that we need to append 'field' to the
// 'pathToCreate' FieldRef.
- auto childElement = element->getDocument().end();
+ auto childElement = applyParams->element.getDocument().end();
invariant(!childElement.ok());
- if (!pathToCreate->empty()) {
+ if (!applyParams->pathToCreate->empty()) {
// We're already traversing a path with elements that don't exist yet, so we will definitely
// need to append.
- } else if (element->getType() == BSONType::Object) {
- childElement = element->findFirstChildNamed(field);
- } else if (element->getType() == BSONType::Array) {
+ } else if (applyParams->element.getType() == BSONType::Object) {
+ childElement = applyParams->element[field];
+ } else if (applyParams->element.getType() == BSONType::Array) {
boost::optional<size_t> indexFromField = parseUnsignedBase10Integer(field);
if (indexFromField) {
- childElement = element->findNthChild(*indexFromField);
+ childElement = applyParams->element.findNthChild(*indexFromField);
} else {
// We're trying to traverse an array element, but the path specifies a name instead of
// an index. We append the name to 'pathToCreate' for now, even though we know we won't
@@ -126,65 +119,54 @@ void applyChild(const UpdateNode& child,
// The path we've traversed so far already exists in our document, and 'childElement'
// represents the Element indicated by the 'field' name or index, which we indicate by
// updating the 'pathTaken' FieldRef.
- pathTaken->appendPart(field);
+ applyParams->pathTaken->appendPart(field);
} else {
// We are traversing path components that do not exist in our document. Any update modifier
// that creates new path components (i.e., any PathCreatingNode update nodes) will need to
// create this component, so we append it to the 'pathToCreate' FieldRef.
- childElement = *element;
- pathToCreate->appendPart(field);
+ childElement = applyParams->element;
+ applyParams->pathToCreate->appendPart(field);
}
- bool childAffectsIndexes = false;
- bool childNoop = false;
-
- child.apply(childElement,
- pathToCreate,
- pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- &childAffectsIndexes,
- &childNoop);
+ auto childApplyParams = *applyParams;
+ childApplyParams.element = childElement;
+ auto childApplyResult = child.apply(childApplyParams);
- *indexesAffected = *indexesAffected || childAffectsIndexes;
- *noop = *noop && childNoop;
+ applyResult->indexesAffected = applyResult->indexesAffected || childApplyResult.indexesAffected;
+ applyResult->noop = applyResult->noop && childApplyResult.noop;
// Pop 'field' off of 'pathToCreate' or 'pathTaken'.
- if (!pathToCreate->empty()) {
- pathToCreate->removeLastPart();
+ if (!applyParams->pathToCreate->empty()) {
+ applyParams->pathToCreate->removeLastPart();
} else {
- pathTaken->removeLastPart();
+ applyParams->pathTaken->removeLastPart();
}
// If the child is an internal node, it may have created 'pathToCreate' and moved 'pathToCreate'
// to the end of 'pathTaken'. We should advance 'element' to the end of 'pathTaken'.
- if (pathTaken->numParts() > pathTakenSizeBefore) {
- for (auto i = pathTakenSizeBefore; i < pathTaken->numParts(); ++i) {
- *element = (*element)[pathTaken->getPart(i)];
- invariant(element->ok());
+ if (applyParams->pathTaken->numParts() > pathTakenSizeBefore) {
+ for (auto i = pathTakenSizeBefore; i < applyParams->pathTaken->numParts(); ++i) {
+ applyParams->element = applyParams->element[applyParams->pathTaken->getPart(i)];
+ invariant(applyParams->element.ok());
}
- } else if (!pathToCreate->empty()) {
+ } else if (!applyParams->pathToCreate->empty()) {
// If the child is a leaf node, it may have created 'pathToCreate' without moving
// 'pathToCreate' to the end of 'pathTaken'. We should move 'pathToCreate' to the end of
// 'pathTaken' and advance 'element' to the end of 'pathTaken'.
- childElement = (*element)[pathToCreate->getPart(0)];
+ childElement = applyParams->element[applyParams->pathToCreate->getPart(0)];
if (childElement.ok()) {
- *element = childElement;
- pathTaken->appendPart(pathToCreate->getPart(0));
+ applyParams->element = childElement;
+ applyParams->pathTaken->appendPart(applyParams->pathToCreate->getPart(0));
// Either the path was fully created or not created at all.
- for (size_t i = 1; i < pathToCreate->numParts(); ++i) {
- *element = (*element)[pathToCreate->getPart(i)];
- invariant(element->ok());
- pathTaken->appendPart(pathToCreate->getPart(i));
+ for (size_t i = 1; i < applyParams->pathToCreate->numParts(); ++i) {
+ applyParams->element = applyParams->element[applyParams->pathToCreate->getPart(i)];
+ invariant(applyParams->element.ok());
+ applyParams->pathTaken->appendPart(applyParams->pathToCreate->getPart(i));
}
- pathToCreate->clear();
+ applyParams->pathToCreate->clear();
}
}
}
@@ -384,72 +366,43 @@ void UpdateObjectNode::setChild(std::string field, std::unique_ptr<UpdateNode> c
}
}
-void UpdateObjectNode::apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const {
- *indexesAffected = false;
- *noop = true;
-
+UpdateNode::ApplyResult UpdateObjectNode::apply(ApplyParams applyParams) const {
bool applyPositional = _positionalChild.get();
if (applyPositional) {
uassert(ErrorCodes::BadValue,
"The positional operator did not find the match needed from the query.",
- !matchedField.empty());
+ !applyParams.matchedField.empty());
}
- // Capture arguments to applyChild() to avoid code duplication.
- auto applyChildClosure = [=, &element, &immutablePaths](const UpdateNode& child,
- StringData field) {
- applyChild(child,
- field,
- &element,
- pathToCreate,
- pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- logBuilder,
- indexesAffected,
- noop);
- };
+ auto applyResult = ApplyResult::noopResult();
for (const auto& pair : _children) {
// If this child has the same field name as the positional child, they must be merged and
// applied.
- if (applyPositional && pair.first == matchedField) {
+ if (applyPositional && pair.first == applyParams.matchedField) {
// Check if we have stored the result of merging the positional child with this child.
auto mergedChild = _mergedChildrenCache.find(pair.first);
if (mergedChild == _mergedChildrenCache.end()) {
// The full path to the merged field is required for error reporting.
- for (size_t i = 0; i < pathToCreate->numParts(); ++i) {
- pathTaken->appendPart(pathToCreate->getPart(i));
+ for (size_t i = 0; i < applyParams.pathToCreate->numParts(); ++i) {
+ applyParams.pathTaken->appendPart(applyParams.pathToCreate->getPart(i));
}
- pathTaken->appendPart(matchedField);
- auto insertResult = _mergedChildrenCache.emplace(
- std::make_pair(pair.first,
- UpdateNode::createUpdateNodeByMerging(
- *_positionalChild, *pair.second, pathTaken)));
- for (size_t i = 0; i < pathToCreate->numParts() + 1; ++i) {
- pathTaken->removeLastPart();
+ applyParams.pathTaken->appendPart(applyParams.matchedField);
+ auto insertResult = _mergedChildrenCache.emplace(std::make_pair(
+ pair.first,
+ UpdateNode::createUpdateNodeByMerging(
+ *_positionalChild, *pair.second, applyParams.pathTaken.get())));
+ for (size_t i = 0; i < applyParams.pathToCreate->numParts() + 1; ++i) {
+ applyParams.pathTaken->removeLastPart();
}
invariant(insertResult.second);
mergedChild = insertResult.first;
}
- applyChildClosure(*mergedChild->second.get(), pair.first);
+ applyChild(*mergedChild->second.get(), pair.first, &applyParams, &applyResult);
applyPositional = false;
continue;
@@ -457,19 +410,22 @@ void UpdateObjectNode::apply(mutablebson::Element element,
// If 'matchedField' is alphabetically before the current child, we should apply the
// positional child now.
- if (applyPositional && matchedField < pair.first) {
- applyChildClosure(*_positionalChild.get(), matchedField);
+ if (applyPositional && applyParams.matchedField < pair.first) {
+ applyChild(
+ *_positionalChild.get(), applyParams.matchedField, &applyParams, &applyResult);
applyPositional = false;
}
// Apply the current child.
- applyChildClosure(*pair.second, pair.first);
+ applyChild(*pair.second, pair.first, &applyParams, &applyResult);
}
// 'matchedField' is alphabetically after all children, so we apply it now.
if (applyPositional) {
- applyChildClosure(*_positionalChild.get(), matchedField);
+ applyChild(*_positionalChild.get(), applyParams.matchedField, &applyParams, &applyResult);
}
+
+ return applyResult;
}
} // namespace mongo
diff --git a/src/mongo/db/update/update_object_node.h b/src/mongo/db/update/update_object_node.h
index 07ed5b77dfd..81608da70c1 100644
--- a/src/mongo/db/update/update_object_node.h
+++ b/src/mongo/db/update/update_object_node.h
@@ -91,17 +91,7 @@ public:
}
}
- void apply(mutablebson::Element element,
- FieldRef* pathToCreate,
- FieldRef* pathTaken,
- StringData matchedField,
- bool fromReplication,
- bool validateForStorage,
- const FieldRefSet& immutablePaths,
- const UpdateIndexData* indexData,
- LogBuilder* logBuilder,
- bool* indexesAffected,
- bool* noop) const final;
+ ApplyResult apply(ApplyParams applyParams) const final;
UpdateNode* getChild(const std::string& field) const final;
diff --git a/src/mongo/db/update/update_object_node_test.cpp b/src/mongo/db/update/update_object_node_test.cpp
index 3257380011e..f991d33f7ab 100644
--- a/src/mongo/db/update/update_object_node_test.cpp
+++ b/src/mongo/db/update/update_object_node_test.cpp
@@ -37,12 +37,14 @@
#include "mongo/db/update/conflict_placeholder_node.h"
#include "mongo/db/update/rename_node.h"
#include "mongo/db/update/update_array_node.h"
+#include "mongo/db/update/update_node_test_fixture.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
namespace {
+using UpdateObjectNodeTest = UpdateNodeTest;
using mongo::mutablebson::Document;
using mongo::mutablebson::Element;
@@ -1704,7 +1706,7 @@ TEST(UpdateObjectNodeTest, NoMergeConflictThroughArrayNodesSucceeds) {
ASSERT_TRUE(fieldsMatch({"b", "c"}, *iNode));
}
-TEST(UpdateObjectNodeTest, ApplyCreateField) {
+TEST_F(UpdateObjectNodeTest, ApplyCreateField) {
auto setUpdate = fromjson("{$set: {b: 6}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -1718,37 +1720,16 @@ TEST(UpdateObjectNodeTest, ApplyCreateField) {
foundIdentifiers));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("b");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("b");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: 5, b: 6}"), doc);
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {b: 6}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {b: 6}}"), getLogDoc());
}
-TEST(UpdateObjectNodeTest, ApplyExistingField) {
+TEST_F(UpdateObjectNodeTest, ApplyExistingField) {
auto setUpdate = fromjson("{$set: {a: 6}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -1762,37 +1743,16 @@ TEST(UpdateObjectNodeTest, ApplyExistingField) {
foundIdentifiers));
Document doc(fromjson("{a: 5}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_EQUALS(fromjson("{a: 6}"), doc);
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_EQUALS(fromjson("{$set: {a: 6}}"), logDoc);
+ ASSERT_EQUALS(fromjson("{$set: {a: 6}}"), getLogDoc());
}
-TEST(UpdateObjectNodeTest, ApplyExistingAndNonexistingFields) {
+TEST_F(UpdateObjectNodeTest, ApplyExistingAndNonexistingFields) {
auto setUpdate = fromjson("{$set: {a: 5, b: 6, c: 7, d: 8}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -1824,37 +1784,16 @@ TEST(UpdateObjectNodeTest, ApplyExistingAndNonexistingFields) {
foundIdentifiers));
Document doc(fromjson("{a: 0, c: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: 5, c: 7, b: 6, d: 8}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {a: 5, b: 6, c: 7, d: 8}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {a: 5, b: 6, c: 7, d: 8}}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyExistingNestedPaths) {
+TEST_F(UpdateObjectNodeTest, ApplyExistingNestedPaths) {
auto setUpdate = fromjson("{$set: {'a.b': 6, 'a.c': 7, 'b.d': 8, 'b.e': 9}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -1886,38 +1825,17 @@ TEST(UpdateObjectNodeTest, ApplyExistingNestedPaths) {
foundIdentifiers));
Document doc(fromjson("{a: {b: 5, c: 5}, b: {d: 5, e: 5}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: {b: 6, c: 7}, b: {d: 8, e: 9}}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.b': 6, 'a.c': 7, 'b.d': 8, 'b.e': 9}}"),
- logDoc.getObject());
+ getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyCreateNestedPaths) {
+TEST_F(UpdateObjectNodeTest, ApplyCreateNestedPaths) {
auto setUpdate = fromjson("{$set: {'a.b': 6, 'a.c': 7, 'b.d': 8, 'b.e': 9}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -1949,38 +1867,17 @@ TEST(UpdateObjectNodeTest, ApplyCreateNestedPaths) {
foundIdentifiers));
Document doc(fromjson("{z: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{z: 0, a: {b: 6, c: 7}, b: {d: 8, e: 9}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.b': 6, 'a.c': 7, 'b.d': 8, 'b.e': 9}}"),
- logDoc.getObject());
+ getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyCreateDeeplyNestedPaths) {
+TEST_F(UpdateObjectNodeTest, ApplyCreateDeeplyNestedPaths) {
auto setUpdate = fromjson("{$set: {'a.b.c.d': 6, 'a.b.c.e': 7, 'a.f': 8}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2006,38 +1903,17 @@ TEST(UpdateObjectNodeTest, ApplyCreateDeeplyNestedPaths) {
foundIdentifiers));
Document doc(fromjson("{z: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{z: 0, a: {b: {c: {d: 6, e: 7}}, f: 8}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.b.c.d': 6, 'a.b.c.e': 7, 'a.f': 8}}"),
- logDoc.getObject());
+ getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ChildrenShouldBeAppliedInAlphabeticalOrder) {
+TEST_F(UpdateObjectNodeTest, ChildrenShouldBeAppliedInAlphabeticalOrder) {
auto setUpdate = fromjson("{$set: {a: 5, d: 6, c: 7, b: 8, z: 9}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2075,37 +1951,16 @@ TEST(UpdateObjectNodeTest, ChildrenShouldBeAppliedInAlphabeticalOrder) {
foundIdentifiers));
Document doc(fromjson("{z: 0, a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{z: 9, a: 5, b: 8, c: 7, d: 6}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {a: 5, b: 8, c: 7, d: 6, z: 9}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {a: 5, b: 8, c: 7, d: 6, z: 9}}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, CollatorShouldNotAffectUpdateOrder) {
+TEST_F(UpdateObjectNodeTest, CollatorShouldNotAffectUpdateOrder) {
auto setUpdate = fromjson("{$set: {abc: 5, cba: 6}}");
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2125,37 +1980,16 @@ TEST(UpdateObjectNodeTest, CollatorShouldNotAffectUpdateOrder) {
foundIdentifiers));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("abc");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("abc");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{abc: 5, cba: 6}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {abc: 5, cba: 6}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {abc: 5, cba: 6}}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyNoop) {
+TEST_F(UpdateObjectNodeTest, ApplyNoop) {
auto setUpdate = fromjson("{$set: {a: 5, b: 6, c: 7}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2181,39 +2015,18 @@ TEST(UpdateObjectNodeTest, ApplyNoop) {
foundIdentifiers));
Document doc(fromjson("{a: 5, b: 6, c: 7}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- indexData.addPath("b");
- indexData.addPath("c");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(indexesAffected);
- ASSERT_TRUE(noop);
+ addIndexedPath("a");
+ addIndexedPath("b");
+ addIndexedPath("c");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.indexesAffected);
+ ASSERT_TRUE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: 5, b: 6, c: 7}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplySomeChildrenNoops) {
+TEST_F(UpdateObjectNodeTest, ApplySomeChildrenNoops) {
auto setUpdate = fromjson("{$set: {a: 5, b: 6, c: 7}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2239,39 +2052,18 @@ TEST(UpdateObjectNodeTest, ApplySomeChildrenNoops) {
foundIdentifiers));
Document doc(fromjson("{a: 5, b: 0, c: 7}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- indexData.addPath("b");
- indexData.addPath("c");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ addIndexedPath("b");
+ addIndexedPath("c");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: 5, b: 6, c: 7}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {b: 6}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {b: 6}}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyBlockingElement) {
+TEST_F(UpdateObjectNodeTest, ApplyBlockingElement) {
auto setUpdate = fromjson("{$set: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2285,35 +2077,14 @@ TEST(UpdateObjectNodeTest, ApplyBlockingElement) {
foundIdentifiers));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(root.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field 'b' in element {a: 0}");
}
-TEST(UpdateObjectNodeTest, ApplyBlockingElementFromReplication) {
+TEST_F(UpdateObjectNodeTest, ApplyBlockingElementFromReplication) {
auto setUpdate = fromjson("{$set: {'a.b': 5, b: 6}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2333,37 +2104,17 @@ TEST(UpdateObjectNodeTest, ApplyBlockingElementFromReplication) {
foundIdentifiers));
Document doc(fromjson("{a: 0}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = true;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ setFromReplication(true);
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: 0, b: 6}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {b: 6}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {b: 6}}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyPositionalMissingMatchedField) {
+TEST_F(UpdateObjectNodeTest, ApplyPositionalMissingMatchedField) {
auto setUpdate = fromjson("{$set: {'a.$': 5}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2377,36 +2128,15 @@ TEST(UpdateObjectNodeTest, ApplyPositionalMissingMatchedField) {
foundIdentifiers));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
+ addIndexedPath("a");
ASSERT_THROWS_CODE_AND_WHAT(
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ root.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::BadValue,
"The positional operator did not find the match needed from the query.");
}
-TEST(UpdateObjectNodeTest, ApplyMergePositionalChild) {
+TEST_F(UpdateObjectNodeTest, ApplyMergePositionalChild) {
auto setUpdate = fromjson("{$set: {'a.0.b': 5, 'a.$.c': 6}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2426,37 +2156,17 @@ TEST(UpdateObjectNodeTest, ApplyMergePositionalChild) {
foundIdentifiers));
Document doc(fromjson("{a: [{b: 0, c: 0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField = "0";
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ setMatchedField("0");
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [{b: 5, c: 6}]}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyOrderMergedPositionalChild) {
+TEST_F(UpdateObjectNodeTest, ApplyOrderMergedPositionalChild) {
auto setUpdate = fromjson("{$set: {'a.2': 5, 'a.1.b': 6, 'a.0': 7, 'a.$.c': 8}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2488,38 +2198,18 @@ TEST(UpdateObjectNodeTest, ApplyOrderMergedPositionalChild) {
foundIdentifiers));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField = "1";
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ setMatchedField("1");
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: {'0': 7, '1': {b: 6, c: 8}, '2': 5}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0': 7, 'a.1.b': 6, 'a.1.c': 8, 'a.2': 5}}"),
- logDoc.getObject());
+ getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyMergeConflictWithPositionalChild) {
+TEST_F(UpdateObjectNodeTest, ApplyMergeConflictWithPositionalChild) {
auto setUpdate = fromjson("{$set: {'a.0': 5, 'a.$': 6}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2539,35 +2229,15 @@ TEST(UpdateObjectNodeTest, ApplyMergeConflictWithPositionalChild) {
foundIdentifiers));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField = "0";
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ setMatchedField("0");
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(root.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::ConflictingUpdateOperators,
"Update created a conflict at 'a.0'");
}
-TEST(UpdateObjectNodeTest, ApplyDoNotMergePositionalChild) {
+TEST_F(UpdateObjectNodeTest, ApplyDoNotMergePositionalChild) {
auto setUpdate = fromjson("{$set: {'a.0': 5, 'a.2': 6, 'a.$': 7}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2593,37 +2263,17 @@ TEST(UpdateObjectNodeTest, ApplyDoNotMergePositionalChild) {
foundIdentifiers));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField = "1";
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ setMatchedField("1");
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: {'0': 5, '1': 7, '2': 6}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0': 5, 'a.1': 7, 'a.2': 6}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0': 5, 'a.1': 7, 'a.2': 6}}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyPositionalChildLast) {
+TEST_F(UpdateObjectNodeTest, ApplyPositionalChildLast) {
auto setUpdate = fromjson("{$set: {'a.$': 5, 'a.0': 6, 'a.1': 7}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2649,37 +2299,17 @@ TEST(UpdateObjectNodeTest, ApplyPositionalChildLast) {
foundIdentifiers));
Document doc(fromjson("{}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField = "2";
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ setMatchedField("2");
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: {'0': 6, '1': 7, '2': 5}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0': 6, 'a.1': 7, 'a.2': 5}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0': 6, 'a.1': 7, 'a.2': 5}}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyUseStoredMergedPositional) {
+TEST_F(UpdateObjectNodeTest, ApplyUseStoredMergedPositional) {
auto setUpdate = fromjson("{$set: {'a.0.b': 5, 'a.$.c': 6}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2699,57 +2329,28 @@ TEST(UpdateObjectNodeTest, ApplyUseStoredMergedPositional) {
foundIdentifiers));
Document doc(fromjson("{a: [{b: 0, c: 0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField = "0";
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ setMatchedField("0");
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [{b: 5, c: 6}]}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"), getLogDoc().getObject());
Document doc2(fromjson("{a: [{b: 0, c: 0}]}"));
- Document logDoc2;
- LogBuilder logBuilder2(logDoc2.root());
- root.apply(doc2.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder2,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ resetApplyParams();
+ setMatchedField("0");
+ addIndexedPath("a");
+ result = root.apply(getApplyParams(doc2.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [{b: 5, c: 6}]}"), doc2.getObject());
ASSERT_TRUE(doc2.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"), logDoc2.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6}}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyDoNotUseStoredMergedPositional) {
+TEST_F(UpdateObjectNodeTest, ApplyDoNotUseStoredMergedPositional) {
auto setUpdate = fromjson("{$set: {'a.0.b': 5, 'a.$.c': 6, 'a.1.d': 7}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2775,56 +2376,27 @@ TEST(UpdateObjectNodeTest, ApplyDoNotUseStoredMergedPositional) {
foundIdentifiers));
Document doc(fromjson("{a: [{b: 0, c: 0}, {c: 0, d: 0}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField = "0";
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ setMatchedField("0");
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [{b: 5, c: 6}, {c: 0, d: 7}]}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6, 'a.1.d': 7}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.0.c': 6, 'a.1.d': 7}}"),
+ getLogDoc().getObject());
Document doc2(fromjson("{a: [{b: 0, c: 0}, {c: 0, d: 0}]}"));
- StringData matchedField2 = "1";
- Document logDoc2;
- LogBuilder logBuilder2(logDoc2.root());
- root.apply(doc2.root(),
- &pathToCreate,
- &pathTaken,
- matchedField2,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder2,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ resetApplyParams();
+ setMatchedField("1");
+ addIndexedPath("a");
+ result = root.apply(getApplyParams(doc2.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [{b: 5, c: 0}, {c: 6, d: 7}]}"), doc2.getObject());
ASSERT_TRUE(doc2.isInPlaceModeEnabled());
ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.0.b': 5, 'a.1.c': 6, 'a.1.d': 7}}"),
- logDoc2.getObject());
+ getLogDoc().getObject());
}
/**
@@ -2832,7 +2404,7 @@ TEST(UpdateObjectNodeTest, ApplyDoNotUseStoredMergedPositional) {
* string, a leading zero will cause the lookup to fail. That is, even if 'element' is an array,
* element["02"] will not find the element with subscript 2.
*/
-TEST(UpdateObjectNodeTest, ApplyToArrayByIndexWithLeadingZero) {
+TEST_F(UpdateObjectNodeTest, ApplyToArrayByIndexWithLeadingZero) {
auto setUpdate = fromjson("{$set: {'a.02': 2}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2846,34 +2418,13 @@ TEST(UpdateObjectNodeTest, ApplyToArrayByIndexWithLeadingZero) {
foundIdentifiers));
Document doc(fromjson("{a: [0, 0, 0, 0, 0]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: [0, 0, 2, 0, 0]}"), doc.getObject());
ASSERT_TRUE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.02': 2}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.02': 2}}"), getLogDoc().getObject());
}
/**
@@ -2882,7 +2433,7 @@ TEST(UpdateObjectNodeTest, ApplyToArrayByIndexWithLeadingZero) {
elements did not have field names to match their array indexes. As a result, the 'a.2' update
failed.
*/
-TEST(UpdateObjectNodeTest, ApplyMultipleArrayUpdates) {
+TEST_F(UpdateObjectNodeTest, ApplyMultipleArrayUpdates) {
auto setUpdate = fromjson("{$set: {'a.2': 2, 'a.10': 10}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2902,39 +2453,18 @@ TEST(UpdateObjectNodeTest, ApplyMultipleArrayUpdates) {
foundIdentifiers));
Document doc(fromjson("{a: []}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_TRUE(indexesAffected);
- ASSERT_FALSE(noop);
+ addIndexedPath("a");
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_TRUE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(
fromjson("{a: [null, null, 2, null, null, null, null, null, null, null, 10]}"),
doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.10': 10, 'a.2': 2}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.10': 10, 'a.2': 2}}"), getLogDoc().getObject());
}
-TEST(UpdateObjectNodeTest, ApplyUpdateToNonViablePathInArray) {
+TEST_F(UpdateObjectNodeTest, ApplyUpdateToNonViablePathInArray) {
auto setUpdate = fromjson("{$set: {'a.b': 3}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2948,35 +2478,14 @@ TEST(UpdateObjectNodeTest, ApplyUpdateToNonViablePathInArray) {
foundIdentifiers));
Document doc(fromjson("{a: [{b: 1}, {b: 2}]}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- UpdateIndexData indexData;
- indexData.addPath("a");
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- auto indexesAffected = false;
- auto noop = false;
- ASSERT_THROWS_CODE_AND_WHAT(root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- &indexData,
- &logBuilder,
- &indexesAffected,
- &noop),
+ addIndexedPath("a");
+ ASSERT_THROWS_CODE_AND_WHAT(root.apply(getApplyParams(doc.root())),
UserException,
ErrorCodes::PathNotViable,
"Cannot create field 'b' in element {a: [ { b: 1 }, { b: 2 } ]}");
}
-TEST(UpdateObjectNodeTest, SetAndPopModifiersWithCommonPrefixApplySuccessfully) {
+TEST_F(UpdateObjectNodeTest, SetAndPopModifiersWithCommonPrefixApplySuccessfully) {
auto update = fromjson("{$set: {'a.b': 5}, $pop: {'a.c': -1}}");
const CollatorInterface* collator = nullptr;
std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters;
@@ -2996,33 +2505,12 @@ TEST(UpdateObjectNodeTest, SetAndPopModifiersWithCommonPrefixApplySuccessfully)
foundIdentifiers));
Document doc(fromjson("{a: {b: 3, c: [1, 2, 3, 4]}}"));
- FieldRef pathToCreate("");
- FieldRef pathTaken("");
- StringData matchedField;
- auto fromReplication = false;
- auto validateForStorage = true;
- FieldRefSet immutablePaths;
- const UpdateIndexData* indexData = nullptr;
- Document logDoc;
- LogBuilder logBuilder(logDoc.root());
- bool indexesAffected;
- bool noop;
- root.apply(doc.root(),
- &pathToCreate,
- &pathTaken,
- matchedField,
- fromReplication,
- validateForStorage,
- immutablePaths,
- indexData,
- &logBuilder,
- &indexesAffected,
- &noop);
- ASSERT_FALSE(noop);
- ASSERT_FALSE(indexesAffected);
+ auto result = root.apply(getApplyParams(doc.root()));
+ ASSERT_FALSE(result.indexesAffected);
+ ASSERT_FALSE(result.noop);
ASSERT_BSONOBJ_EQ(fromjson("{a: {b: 5, c: [2, 3, 4]}}"), doc.getObject());
ASSERT_FALSE(doc.isInPlaceModeEnabled());
- ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.b': 5, 'a.c': [2, 3, 4]}}"), logDoc.getObject());
+ ASSERT_BSONOBJ_EQ(fromjson("{$set: {'a.b': 5, 'a.c': [2, 3, 4]}}"), getLogDoc().getObject());
}
TEST(ParseRenameTest, RenameToStringWithEmbeddedNullFails) {