summaryrefslogtreecommitdiff
path: root/src/mongo/db/update/update_object_node_test.cpp
diff options
context:
space:
mode:
authorTess Avitabile <tess.avitabile@mongodb.com>2017-06-05 14:22:26 -0400
committerTess Avitabile <tess.avitabile@mongodb.com>2017-06-14 13:07:13 -0400
commit676206d10e8a626e9c5e39045468dbe0bb2bd75a (patch)
treeb58e3870549031f651473582af72ff164a05c51b /src/mongo/db/update/update_object_node_test.cpp
parent023c34f624656d53ae1f6b015998f3fc035cb1eb (diff)
downloadmongo-676206d10e8a626e9c5e39045468dbe0bb2bd75a.tar.gz
SERVER-28763 Create UpdateArrayNode
Diffstat (limited to 'src/mongo/db/update/update_object_node_test.cpp')
-rw-r--r--src/mongo/db/update/update_object_node_test.cpp1734
1 files changed, 1484 insertions, 250 deletions
diff --git a/src/mongo/db/update/update_object_node_test.cpp b/src/mongo/db/update/update_object_node_test.cpp
index f0bd1e0d1c8..5f0d0b6d134 100644
--- a/src/mongo/db/update/update_object_node_test.cpp
+++ b/src/mongo/db/update/update_object_node_test.cpp
@@ -33,7 +33,10 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/json.h"
+#include "mongo/db/matcher/extensions_callback_noop.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
+#include "mongo/db/update/update_array_node.h"
+#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -45,9 +48,15 @@ using mongo::mutablebson::Element;
TEST(UpdateObjectNodeTest, InvalidPathFailsToParse) {
auto update = fromjson("{$set: {'': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"][""], collator);
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"][""],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::EmptyFieldName);
ASSERT_EQ(result.getStatus().reason(), "An empty update path is not valid.");
@@ -56,41 +65,71 @@ TEST(UpdateObjectNodeTest, InvalidPathFailsToParse) {
TEST(UpdateObjectNodeTest, ValidIncPathParsesSuccessfully) {
auto update = fromjson("{$inc: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_INC, update["$inc"]["a.b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_INC,
+ update["$inc"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, ValidMulPathParsesSuccessfully) {
auto update = fromjson("{$mul: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_MUL, update["$mul"]["a.b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_MUL,
+ update["$mul"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, ValidSetPathParsesSuccessfully) {
auto update = fromjson("{$set: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, ValidUnsetPathParsesSuccessfully) {
auto update = fromjson("{$unset: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_UNSET, update["$unset"]["a.b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_UNSET,
+ update["$unset"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, MultiplePositionalElementsFailToParse) {
auto update = fromjson("{$set: {'a.$.b.$': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b.$"], collator);
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$.b.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue);
ASSERT_EQ(result.getStatus().reason(),
@@ -100,9 +139,15 @@ TEST(UpdateObjectNodeTest, MultiplePositionalElementsFailToParse) {
TEST(UpdateObjectNodeTest, ParsingSetsPositionalTrue) {
auto update = fromjson("{$set: {'a.$.b': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator);
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_OK(result);
ASSERT_TRUE(result.getValue());
}
@@ -110,9 +155,15 @@ TEST(UpdateObjectNodeTest, ParsingSetsPositionalTrue) {
TEST(UpdateObjectNodeTest, ParsingSetsPositionalFalse) {
auto update = fromjson("{$set: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator);
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_OK(result);
ASSERT_FALSE(result.getValue());
}
@@ -120,9 +171,15 @@ TEST(UpdateObjectNodeTest, ParsingSetsPositionalFalse) {
TEST(UpdateObjectNodeTest, PositionalElementFirstPositionFailsToParse) {
auto update = fromjson("{$set: {'$': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["$"], collator);
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue);
ASSERT_EQ(result.getStatus().reason(),
@@ -133,9 +190,15 @@ TEST(UpdateObjectNodeTest, PositionalElementFirstPositionFailsToParse) {
TEST(UpdateObjectNodeTest, PushFailsToParse) {
auto update = fromjson("{$push: {a: 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_PUSH, update["$push"]["a"], collator);
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_PUSH,
+ update["$push"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::FailedToParse);
ASSERT_EQ(result.getStatus().reason(), "Cannot construct modifier of type 10");
@@ -144,11 +207,21 @@ TEST(UpdateObjectNodeTest, PushFailsToParse) {
TEST(UpdateObjectNodeTest, TwoModifiersOnSameFieldFailToParse) {
auto update = fromjson("{$set: {a: 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator));
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator);
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
ASSERT_EQ(result.getStatus().reason(), "Updating the path 'a' would create a conflict at 'a'");
@@ -157,21 +230,41 @@ TEST(UpdateObjectNodeTest, TwoModifiersOnSameFieldFailToParse) {
TEST(UpdateObjectNodeTest, TwoModifiersOnDifferentFieldsParseSuccessfully) {
auto update = fromjson("{$set: {a: 5, b: 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, TwoModifiersWithSameDottedPathFailToParse) {
auto update = fromjson("{$set: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator));
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator);
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
ASSERT_EQ(result.getStatus().reason(),
@@ -181,11 +274,21 @@ TEST(UpdateObjectNodeTest, TwoModifiersWithSameDottedPathFailToParse) {
TEST(UpdateObjectNodeTest, FirstModifierPrefixOfSecondFailToParse) {
auto update = fromjson("{$set: {a: 5, 'a.b': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator));
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator);
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
ASSERT_EQ(result.getStatus().reason(),
@@ -195,11 +298,21 @@ TEST(UpdateObjectNodeTest, FirstModifierPrefixOfSecondFailToParse) {
TEST(UpdateObjectNodeTest, FirstModifierDottedPrefixOfSecondFailsToParse) {
auto update = fromjson("{$set: {'a.b': 5, 'a.b.c': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator));
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator);
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
ASSERT_EQ(result.getStatus().reason(),
@@ -209,11 +322,21 @@ TEST(UpdateObjectNodeTest, FirstModifierDottedPrefixOfSecondFailsToParse) {
TEST(UpdateObjectNodeTest, SecondModifierPrefixOfFirstFailsToParse) {
auto update = fromjson("{$set: {'a.b': 5, a: 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator));
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator);
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
ASSERT_EQ(result.getStatus().reason(), "Updating the path 'a' would create a conflict at 'a'");
@@ -222,11 +345,21 @@ TEST(UpdateObjectNodeTest, SecondModifierPrefixOfFirstFailsToParse) {
TEST(UpdateObjectNodeTest, SecondModifierDottedPrefixOfFirstFailsToParse) {
auto update = fromjson("{$set: {'a.b.c': 5, 'a.b': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator));
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator);
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
ASSERT_EQ(result.getStatus().reason(),
@@ -236,41 +369,81 @@ TEST(UpdateObjectNodeTest, SecondModifierDottedPrefixOfFirstFailsToParse) {
TEST(UpdateObjectNodeTest, ModifiersWithCommonPrefixParseSuccessfully) {
auto update = fromjson("{$set: {'a.b': 5, 'a.c': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, ModifiersWithCommonDottedPrefixParseSuccessfully) {
auto update = fromjson("{$set: {'a.b.c': 5, 'a.b.d': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.d"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b.d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, ModifiersWithCommonPrefixDottedSuffixParseSuccessfully) {
auto update = fromjson("{$set: {'a.b.c': 5, 'a.d.e': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.d.e"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.b.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.d.e"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, TwoModifiersOnSamePositionalFieldFailToParse) {
auto update = fromjson("{$set: {'a.$': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator));
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator);
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
ASSERT_EQ(result.getStatus().reason(),
@@ -280,31 +453,61 @@ TEST(UpdateObjectNodeTest, TwoModifiersOnSamePositionalFieldFailToParse) {
TEST(UpdateObjectNodeTest, PositionalFieldsWithDifferentPrefixesParseSuccessfully) {
auto update = fromjson("{$set: {'a.$': 5, 'b.$': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["b.$"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["b.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, PositionalAndNonpositionalFieldWithCommonPrefixParseSuccessfully) {
auto update = fromjson("{$set: {'a.$': 5, 'a.0': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.0"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.0"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, TwoModifiersWithSamePositionalDottedPathFailToParse) {
auto update = fromjson("{$set: {'a.$.b': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator));
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator);
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
ASSERT_EQ(result.getStatus().reason(),
@@ -314,11 +517,21 @@ TEST(UpdateObjectNodeTest, TwoModifiersWithSamePositionalDottedPathFailToParse)
TEST(UpdateObjectNodeTest, FirstModifierPositionalPrefixOfSecondFailsToParse) {
auto update = fromjson("{$set: {'a.$': 5, 'a.$.b': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator));
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator);
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
ASSERT_EQ(result.getStatus().reason(),
@@ -328,11 +541,21 @@ TEST(UpdateObjectNodeTest, FirstModifierPositionalPrefixOfSecondFailsToParse) {
TEST(UpdateObjectNodeTest, SecondModifierPositionalPrefixOfFirstFailsToParse) {
auto update = fromjson("{$set: {'a.$.b': 5, 'a.$': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator));
- auto result = UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator);
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
ASSERT_NOT_OK(result);
ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
ASSERT_EQ(result.getStatus().reason(),
@@ -342,37 +565,460 @@ TEST(UpdateObjectNodeTest, SecondModifierPositionalPrefixOfFirstFailsToParse) {
TEST(UpdateObjectNodeTest, FirstModifierFieldPrefixOfSecondParsesSuccessfully) {
auto update = fromjson("{$set: {'a': 5, 'ab': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["ab"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["ab"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
}
TEST(UpdateObjectNodeTest, SecondModifierFieldPrefixOfSecondParsesSuccessfully) {
auto update = fromjson("{$set: {'ab': 5, 'a': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["ab"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["ab"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+}
+
+TEST(UpdateObjectNodeTest, IdentifierWithoutArrayFilterFailsToParse) {
+ auto update = fromjson("{$set: {'a.$[i]': 5}}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue);
+ ASSERT_EQ(result.getStatus().reason(),
+ "No array filter found for identifier 'i' in path 'a.$[i]'");
+}
+
+TEST(UpdateObjectNodeTest, IdentifierInMiddleOfPathWithoutArrayFilterFailsToParse) {
+ auto update = fromjson("{$set: {'a.$[i].b': 5}}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i].b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue);
+ ASSERT_EQ(result.getStatus().reason(),
+ "No array filter found for identifier 'i' in path 'a.$[i].b'");
+}
+
+TEST(UpdateObjectNodeTest, EmptyIdentifierParsesSuccessfully) {
+ auto update = fromjson("{$set: {'a.$[]': 5}}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_TRUE(foundIdentifiers.empty());
+}
+
+TEST(UpdateObjectNodeTest, EmptyIdentifierInMiddleOfPathParsesSuccessfully) {
+ auto update = fromjson("{$set: {'a.$[].b': 5}}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[].b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_TRUE(foundIdentifiers.empty());
+}
+
+TEST(UpdateObjectNodeTest, IdentifierWithArrayFilterParsesSuccessfully) {
+ auto update = fromjson("{$set: {'a.$[i]': 5}}");
+ auto arrayFilter = fromjson("{i: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 1U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+}
+
+TEST(UpdateObjectNodeTest, IdentifierWithArrayFilterInMiddleOfPathParsesSuccessfully) {
+ auto update = fromjson("{$set: {'a.$[i].b': 5}}");
+ auto arrayFilter = fromjson("{i: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i].b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 1U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+}
+
+TEST(UpdateObjectNodeTest, IdentifierInFirstPositionFailsToParse) {
+ auto update = fromjson("{$set: {'$[i]': 5}}");
+ auto arrayFilter = fromjson("{i: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Cannot have array filter identifier (i.e. '$[<id>]') element in the first position "
+ "in path '$[i]'");
+}
+
+TEST(UpdateObjectNodeTest, IdentifierInFirstPositionWithSuffixFailsToParse) {
+ auto update = fromjson("{$set: {'$[i].a': 5}}");
+ auto arrayFilter = fromjson("{i: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["$[i].a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Cannot have array filter identifier (i.e. '$[<id>]') element in the first position "
+ "in path '$[i].a'");
+}
+
+TEST(UpdateObjectNodeTest, CreateObjectNodeInSamePositionAsArrayNodeFailsToParse) {
+ auto update = fromjson("{$set: {'a.$[i]': 5, 'a.0': 6}}");
+ auto arrayFilter = fromjson("{i: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 1U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.0"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.0' would create a conflict at 'a'");
+}
+
+TEST(UpdateObjectNodeTest, CreateArrayNodeInSamePositionAsObjectNodeFailsToParse) {
+ auto update = fromjson("{$set: {'a.0': 5, 'a.$[i]': 6}}");
+ auto arrayFilter = fromjson("{i: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.0"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.$[i]' would create a conflict at 'a'");
+}
+
+TEST(UpdateObjectNodeTest, CreateLeafNodeInSamePositionAsArrayNodeFailsToParse) {
+ auto update = fromjson("{$set: {'a.$[i]': 5, a: 6}}");
+ auto arrayFilter = fromjson("{i: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 1U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(), "Updating the path 'a' would create a conflict at 'a'");
+}
+
+TEST(UpdateObjectNodeTest, CreateArrayNodeInSamePositionAsLeafNodeFailsToParse) {
+ auto update = fromjson("{$set: {a: 5, 'a.$[i]': 6}}");
+ auto arrayFilter = fromjson("{i: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.$[i]' would create a conflict at 'a'");
+}
+
+TEST(UpdateObjectNodeTest, CreateTwoChildrenOfArrayNodeParsesSuccessfully) {
+ auto update = fromjson("{$set: {'a.$[i]': 5, 'a.$[j]': 6}}");
+ auto arrayFilterI = fromjson("{i: 0}");
+ auto arrayFilterJ = fromjson("{j: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterI, ExtensionsCallbackNoop(), collator));
+ arrayFilters["j"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterJ, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 1U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[j]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 2U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+ ASSERT_TRUE(foundIdentifiers.find("j") != foundIdentifiers.end());
+}
+
+TEST(UpdateObjectNodeTest, ConflictAtArrayNodeChildFailsToParse) {
+ auto update1 = fromjson("{$set: {'a.$[i]': 5}}");
+ auto update2 = fromjson("{$set: {'a.$[i]': 6}}");
+ auto arrayFilterI = fromjson("{i: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterI, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update1["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 1U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update2["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.$[i]' would create a conflict at 'a.$[i]'");
+}
+
+TEST(UpdateObjectNodeTest, ConflictThroughArrayNodeChildFailsToParse) {
+ auto update = fromjson("{$set: {'a.$[i].b': 5, 'a.$[i].b.c': 6}}");
+ auto arrayFilterI = fromjson("{i: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterI, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i].b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 1U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+ auto result = UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i].b.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.$[i].b.c' would create a conflict at 'a.$[i].b'");
+}
+
+TEST(UpdateObjectNodeTest, NoConflictDueToDifferentArrayNodeChildrenParsesSuccessfully) {
+ auto update = fromjson("{$set: {'a.$[i].b': 5, 'a.$[j].b.c': 6}}");
+ auto arrayFilterI = fromjson("{i: 0}");
+ auto arrayFilterJ = fromjson("{j: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterI, ExtensionsCallbackNoop(), collator));
+ arrayFilters["j"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterJ, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i].b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 1U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[j].b.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 2U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+ ASSERT_TRUE(foundIdentifiers.find("j") != foundIdentifiers.end());
+}
+
+TEST(UpdateObjectNodeTest, MultipleArrayNodesAlongPathParsesSuccessfully) {
+ auto update = fromjson("{$set: {'a.$[i].$[j].$[i]': 5}}");
+ auto arrayFilterI = fromjson("{i: 0}");
+ auto arrayFilterJ = fromjson("{j: 0}");
+ const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterI, ExtensionsCallbackNoop(), collator));
+ arrayFilters["j"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterJ, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ update["$set"]["a.$[i].$[j].$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_EQ(foundIdentifiers.size(), 2U);
+ ASSERT_TRUE(foundIdentifiers.find("i") != foundIdentifiers.end());
+ ASSERT_TRUE(foundIdentifiers.find("j") != foundIdentifiers.end());
}
/**
* Used to test if the fields in an input UpdateObjectNode match an expected set of fields.
*/
static bool fieldsMatch(const std::vector<std::string>& expectedFields,
- const UpdateObjectNode& node) {
+ const UpdateInternalNode& node) {
for (const std::string& fieldName : expectedFields) {
if (!node.getChild(fieldName)) {
return false;
}
}
- // There are no expected fields that aren't in the UpdateObjectNode. There is no way to check
- // if UpdateObjectNodes contains any fields that are not in the expected set, because the
- // UpdateObjectNodes API does not expose its list of child fields in any way other than
+ // There are no expected fields that aren't in the UpdateInternalNode. There is no way to check
+ // if UpdateInternalNodes contains any fields that are not in the expected set, because the
+ // UpdateInternalNodes API does not expose its list of child fields in any way other than
// getChild().
return true;
}
@@ -382,11 +1028,21 @@ TEST(UpdateObjectNodeTest, DistinctFieldsMergeCorrectly) {
auto setUpdate2 = fromjson("{$set: {'ab': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["ab"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["ab"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
auto result = UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef);
ASSERT_TRUE(result);
@@ -402,11 +1058,21 @@ TEST(UpdateObjectNodeTest, NestedMergeSucceeds) {
auto setUpdate2 = fromjson("{$set: {'a.d': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.d"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
auto result = UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef);
ASSERT_TRUE(result);
@@ -428,11 +1094,21 @@ TEST(UpdateObjectNodeTest, DoublyNestedMergeSucceeds) {
auto setUpdate2 = fromjson("{$set: {'a.b.d': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.b.c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.b.d"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.b.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.b.d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
auto result = UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef);
ASSERT_TRUE(result);
@@ -460,11 +1136,21 @@ TEST(UpdateObjectNodeTest, FieldAndPositionalMergeCorrectly) {
auto setUpdate2 = fromjson("{$set: {'a.$': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
auto result = UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef);
ASSERT_TRUE(result);
@@ -487,11 +1173,21 @@ TEST(UpdateObjectNodeTest, MergeThroughPositionalSucceeds) {
auto setUpdate2 = fromjson("{$set: {'a.$.c': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$.c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.$.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.$.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
auto result = UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef);
ASSERT_TRUE(result);
@@ -519,11 +1215,21 @@ TEST(UpdateObjectNodeTest, TopLevelConflictFails) {
auto setUpdate2 = fromjson("{$set: {'a': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
std::unique_ptr<UpdateNode> result;
ASSERT_THROWS_CODE_AND_WHAT(
@@ -538,11 +1244,21 @@ TEST(UpdateObjectNodeTest, NestedConflictFails) {
auto setUpdate2 = fromjson("{$set: {'a.b': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
std::unique_ptr<UpdateNode> result;
ASSERT_THROWS_CODE_AND_WHAT(
@@ -557,11 +1273,21 @@ TEST(UpdateObjectNodeTest, LeftPrefixMergeFails) {
auto setUpdate2 = fromjson("{$set: {'a.b.c': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.b.c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.b.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
std::unique_ptr<UpdateNode> result;
ASSERT_THROWS_CODE_AND_WHAT(
@@ -576,11 +1302,21 @@ TEST(UpdateObjectNodeTest, RightPrefixMergeFails) {
auto setUpdate2 = fromjson("{$set: {'a.b': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.b.c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.b.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
std::unique_ptr<UpdateNode> result;
ASSERT_THROWS_CODE_AND_WHAT(
@@ -595,11 +1331,21 @@ TEST(UpdateObjectNodeTest, LeftPrefixMergeThroughPositionalFails) {
auto setUpdate2 = fromjson("{$set: {'a.$.c.d': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$.c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$.c.d"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.$.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.$.c.d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
std::unique_ptr<UpdateNode> result;
ASSERT_THROWS_CODE_AND_WHAT(
@@ -614,11 +1360,21 @@ TEST(UpdateObjectNodeTest, RightPrefixMergeThroughPositionalFails) {
auto setUpdate2 = fromjson("{$set: {'a.$.c': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$.c.d"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$.c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.$.c.d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.$.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
std::unique_ptr<UpdateNode> result;
ASSERT_THROWS_CODE_AND_WHAT(
@@ -633,11 +1389,21 @@ TEST(UpdateObjectNodeTest, MergeWithConflictingPositionalFails) {
auto setUpdate2 = fromjson("{$set: {'a.$': 6}}");
FieldRef fakeFieldRef("root");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode setRoot1, setRoot2;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot1, modifiertable::ModifierType::MOD_SET, setUpdate1["$set"]["a.$"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &setRoot2, modifiertable::ModifierType::MOD_SET, setUpdate2["$set"]["a.$"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
std::unique_ptr<UpdateNode> result;
ASSERT_THROWS_CODE_AND_WHAT(
@@ -647,12 +1413,234 @@ TEST(UpdateObjectNodeTest, MergeWithConflictingPositionalFails) {
"Update created a conflict at 'root.a.$'");
}
+DEATH_TEST(UpdateObjectNodeTest,
+ MergingArrayNodesWithDifferentArrayFiltersFails,
+ "Invariant failure &leftNode._arrayFilters == &rightNode._arrayFilters") {
+ auto setUpdate1 = fromjson("{$set: {'a.$[i]': 5}}");
+ auto setUpdate2 = fromjson("{$set: {'a.$[j]': 6}}");
+ FieldRef fakeFieldRef("root");
+ const CollatorInterface* collator = nullptr;
+ auto arrayFilterI = fromjson("{i: 0}");
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters1;
+ arrayFilters1["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterI, ExtensionsCallbackNoop(), collator));
+ auto arrayFilterJ = fromjson("{j: 0}");
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters2;
+ arrayFilters2["j"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterJ, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode setRoot1, setRoot2;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.$[i]"],
+ collator,
+ arrayFilters1,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.$[j]"],
+ collator,
+ arrayFilters2,
+ foundIdentifiers));
+
+ UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef);
+}
+
+TEST(UpdateObjectNodeTest, MergingArrayNodeWithObjectNodeFails) {
+ auto setUpdate1 = fromjson("{$set: {'a.$[i]': 5}}");
+ auto setUpdate2 = fromjson("{$set: {'a.b': 6}}");
+ FieldRef fakeFieldRef("root");
+ const CollatorInterface* collator = nullptr;
+ auto arrayFilter = fromjson("{i: 0}");
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode setRoot1, setRoot2;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+
+ std::unique_ptr<UpdateNode> result;
+ ASSERT_THROWS_CODE_AND_WHAT(
+ result = UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef),
+ UserException,
+ ErrorCodes::ConflictingUpdateOperators,
+ "Update created a conflict at 'root.a'");
+}
+
+TEST(UpdateObjectNodeTest, MergingArrayNodeWithLeafNodeFails) {
+ auto setUpdate1 = fromjson("{$set: {'a.$[i]': 5}}");
+ auto setUpdate2 = fromjson("{$set: {'a': 6}}");
+ FieldRef fakeFieldRef("root");
+ const CollatorInterface* collator = nullptr;
+ auto arrayFilter = fromjson("{i: 0}");
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode setRoot1, setRoot2;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+
+ std::unique_ptr<UpdateNode> result;
+ ASSERT_THROWS_CODE_AND_WHAT(
+ result = UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef),
+ UserException,
+ ErrorCodes::ConflictingUpdateOperators,
+ "Update created a conflict at 'root.a'");
+}
+
+TEST(UpdateObjectNodeTest, MergingTwoArrayNodesSucceeds) {
+ auto setUpdate1 = fromjson("{$set: {'a.$[i]': 5}}");
+ auto setUpdate2 = fromjson("{$set: {'a.$[j]': 6}}");
+ FieldRef fakeFieldRef("root");
+ const CollatorInterface* collator = nullptr;
+ auto arrayFilterI = fromjson("{i: 0}");
+ auto arrayFilterJ = fromjson("{j: 0}");
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterI, ExtensionsCallbackNoop(), collator));
+ arrayFilters["j"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilterJ, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode setRoot1, setRoot2;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.$[i]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.$[j]"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+
+ auto result = UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef);
+ ASSERT_TRUE(result);
+
+ ASSERT_TRUE(result->type == UpdateNode::Type::Object);
+ ASSERT_TRUE(typeid(*result) == typeid(UpdateObjectNode&));
+ auto mergedRootNode = static_cast<UpdateObjectNode*>(result.get());
+ ASSERT_TRUE(fieldsMatch({"a"}, *mergedRootNode));
+
+ ASSERT_TRUE(mergedRootNode->getChild("a"));
+ ASSERT_TRUE(mergedRootNode->getChild("a")->type == UpdateNode::Type::Array);
+ ASSERT_TRUE(typeid(*mergedRootNode->getChild("a")) == typeid(UpdateArrayNode&));
+ auto aNode = static_cast<UpdateArrayNode*>(mergedRootNode->getChild("a"));
+ ASSERT_TRUE(fieldsMatch({"i", "j"}, *aNode));
+}
+
+TEST(UpdateObjectNodeTest, MergeConflictThroughArrayNodesFails) {
+ auto setUpdate1 = fromjson("{$set: {'a.$[i].b.c': 5}}");
+ auto setUpdate2 = fromjson("{$set: {'a.$[i].b': 6}}");
+ FieldRef fakeFieldRef("root");
+ const CollatorInterface* collator = nullptr;
+ auto arrayFilter = fromjson("{i: 0}");
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode setRoot1, setRoot2;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.$[i].b.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.$[i].b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+
+ std::unique_ptr<UpdateNode> result;
+ ASSERT_THROWS_CODE_AND_WHAT(
+ result = UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef),
+ UserException,
+ ErrorCodes::ConflictingUpdateOperators,
+ "Update created a conflict at 'root.a.$[i].b'");
+}
+
+TEST(UpdateObjectNodeTest, NoMergeConflictThroughArrayNodesSucceeds) {
+ auto setUpdate1 = fromjson("{$set: {'a.$[i].b': 5}}");
+ auto setUpdate2 = fromjson("{$set: {'a.$[i].c': 6}}");
+ FieldRef fakeFieldRef("root");
+ const CollatorInterface* collator = nullptr;
+ auto arrayFilter = fromjson("{i: 0}");
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ arrayFilters["i"] =
+ uassertStatusOK(ArrayFilter::parse(arrayFilter, ExtensionsCallbackNoop(), collator));
+ std::set<std::string> foundIdentifiers;
+ UpdateObjectNode setRoot1, setRoot2;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot1,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate1["$set"]["a.$[i].b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&setRoot2,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate2["$set"]["a.$[i].c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+
+ auto result = UpdateNode::createUpdateNodeByMerging(setRoot1, setRoot2, &fakeFieldRef);
+ ASSERT_TRUE(result);
+
+ ASSERT_TRUE(result->type == UpdateNode::Type::Object);
+ ASSERT_TRUE(typeid(*result) == typeid(UpdateObjectNode&));
+ auto mergedRootNode = static_cast<UpdateObjectNode*>(result.get());
+ ASSERT_TRUE(fieldsMatch({"a"}, *mergedRootNode));
+
+ ASSERT_TRUE(mergedRootNode->getChild("a"));
+ ASSERT_TRUE(mergedRootNode->getChild("a")->type == UpdateNode::Type::Array);
+ ASSERT_TRUE(typeid(*mergedRootNode->getChild("a")) == typeid(UpdateArrayNode&));
+ auto aNode = static_cast<UpdateArrayNode*>(mergedRootNode->getChild("a"));
+ ASSERT_TRUE(fieldsMatch({"i"}, *aNode));
+
+ ASSERT_TRUE(aNode->getChild("i"));
+ ASSERT_TRUE(aNode->getChild("i")->type == UpdateNode::Type::Object);
+ ASSERT_TRUE(typeid(*aNode->getChild("i")) == typeid(UpdateObjectNode&));
+ auto iNode = static_cast<UpdateObjectNode*>(aNode->getChild("i"));
+ ASSERT_TRUE(fieldsMatch({"b", "c"}, *iNode));
+}
+
TEST(UpdateObjectNodeTest, ApplyCreateField) {
auto setUpdate = fromjson("{$set: {b: 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: 5}"));
FieldRef pathToCreate("");
@@ -684,9 +1672,15 @@ TEST(UpdateObjectNodeTest, ApplyCreateField) {
TEST(UpdateObjectNodeTest, ApplyExistingField) {
auto setUpdate = fromjson("{$set: {a: 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: 5}"));
FieldRef pathToCreate("");
@@ -718,15 +1712,33 @@ TEST(UpdateObjectNodeTest, ApplyExistingField) {
TEST(UpdateObjectNodeTest, ApplyExistingAndNonexistingFields) {
auto setUpdate = fromjson("{$set: {a: 5, b: 6, c: 7, d: 8}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["d"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: 0, c: 0}"));
FieldRef pathToCreate("");
@@ -758,15 +1770,33 @@ TEST(UpdateObjectNodeTest, ApplyExistingAndNonexistingFields) {
TEST(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<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b.d"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b.e"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["b.d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["b.e"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: {b: 5, c: 5}, b: {d: 5, e: 5}}"));
FieldRef pathToCreate("");
@@ -799,15 +1829,33 @@ TEST(UpdateObjectNodeTest, ApplyExistingNestedPaths) {
TEST(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<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b.d"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b.e"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["b.d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["b.e"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{z: 0}"));
FieldRef pathToCreate("");
@@ -840,13 +1888,27 @@ TEST(UpdateObjectNodeTest, ApplyCreateNestedPaths) {
TEST(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<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b.c.d"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b.c.e"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.f"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.b.c.d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.b.c.e"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.f"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{z: 0}"));
FieldRef pathToCreate("");
@@ -879,17 +1941,39 @@ TEST(UpdateObjectNodeTest, ApplyCreateDeeplyNestedPaths) {
TEST(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<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["d"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["z"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["z"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{z: 0, a: 0}"));
FieldRef pathToCreate("");
@@ -921,11 +2005,21 @@ TEST(UpdateObjectNodeTest, ChildrenShouldBeAppliedInAlphabeticalOrder) {
TEST(UpdateObjectNodeTest, CollatorShouldNotAffectUpdateOrder) {
auto setUpdate = fromjson("{$set: {abc: 5, cba: 6}}");
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["abc"], &collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["cba"], &collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["abc"],
+ &collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["cba"],
+ &collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{}"));
FieldRef pathToCreate("");
@@ -957,13 +2051,27 @@ TEST(UpdateObjectNodeTest, CollatorShouldNotAffectUpdateOrder) {
TEST(UpdateObjectNodeTest, ApplyNoop) {
auto setUpdate = fromjson("{$set: {a: 5, b: 6, c: 7}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: 5, b: 6, c: 7}"));
FieldRef pathToCreate("");
@@ -997,13 +2105,27 @@ TEST(UpdateObjectNodeTest, ApplyNoop) {
TEST(UpdateObjectNodeTest, ApplySomeChildrenNoops) {
auto setUpdate = fromjson("{$set: {a: 5, b: 6, c: 7}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: 5, b: 0, c: 7}"));
FieldRef pathToCreate("");
@@ -1037,9 +2159,15 @@ TEST(UpdateObjectNodeTest, ApplySomeChildrenNoops) {
TEST(UpdateObjectNodeTest, ApplyBlockingElement) {
auto setUpdate = fromjson("{$set: {'a.b': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: 0}"));
FieldRef pathToCreate("");
@@ -1069,11 +2197,21 @@ TEST(UpdateObjectNodeTest, ApplyBlockingElement) {
TEST(UpdateObjectNodeTest, ApplyBlockingElementFromReplication) {
auto setUpdate = fromjson("{$set: {'a.b': 5, b: 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: 0}"));
FieldRef pathToCreate("");
@@ -1105,9 +2243,15 @@ TEST(UpdateObjectNodeTest, ApplyBlockingElementFromReplication) {
TEST(UpdateObjectNodeTest, ApplyPositionalMissingMatchedField) {
auto setUpdate = fromjson("{$set: {'a.$': 5}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{}"));
FieldRef pathToCreate("");
@@ -1138,11 +2282,21 @@ TEST(UpdateObjectNodeTest, ApplyPositionalMissingMatchedField) {
TEST(UpdateObjectNodeTest, ApplyMergePositionalChild) {
auto setUpdate = fromjson("{$set: {'a.0.b': 5, 'a.$.c': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$.c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.0.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.$.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: [{b: 0, c: 0}]}"));
FieldRef pathToCreate("");
@@ -1174,15 +2328,33 @@ TEST(UpdateObjectNodeTest, ApplyMergePositionalChild) {
TEST(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<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.2"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.1.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$.c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.2"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.1.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.0"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.$.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{}"));
FieldRef pathToCreate("");
@@ -1215,11 +2387,21 @@ TEST(UpdateObjectNodeTest, ApplyOrderMergedPositionalChild) {
TEST(UpdateObjectNodeTest, ApplyMergeConflictWithPositionalChild) {
auto setUpdate = fromjson("{$set: {'a.0': 5, 'a.$': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.0"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{}"));
FieldRef pathToCreate("");
@@ -1249,13 +2431,27 @@ TEST(UpdateObjectNodeTest, ApplyMergeConflictWithPositionalChild) {
TEST(UpdateObjectNodeTest, ApplyDoNotMergePositionalChild) {
auto setUpdate = fromjson("{$set: {'a.0': 5, 'a.2': 6, 'a.$': 7}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.2"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.0"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.2"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{}"));
FieldRef pathToCreate("");
@@ -1287,13 +2483,27 @@ TEST(UpdateObjectNodeTest, ApplyDoNotMergePositionalChild) {
TEST(UpdateObjectNodeTest, ApplyPositionalChildLast) {
auto setUpdate = fromjson("{$set: {'a.$': 5, 'a.0': 6, 'a.1': 7}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.1"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.$"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.0"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.1"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{}"));
FieldRef pathToCreate("");
@@ -1325,11 +2535,21 @@ TEST(UpdateObjectNodeTest, ApplyPositionalChildLast) {
TEST(UpdateObjectNodeTest, ApplyUseStoredMergedPositional) {
auto setUpdate = fromjson("{$set: {'a.0.b': 5, 'a.$.c': 6}}");
const CollatorInterface* collator = nullptr;
+ std::map<StringData, std::unique_ptr<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$.c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.0.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.$.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: [{b: 0, c: 0}]}"));
FieldRef pathToCreate("");
@@ -1379,13 +2599,27 @@ TEST(UpdateObjectNodeTest, ApplyUseStoredMergedPositional) {
TEST(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<ArrayFilter>> arrayFilters;
+ std::set<std::string> foundIdentifiers;
UpdateObjectNode root;
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.0.b"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.$.c"], collator));
- ASSERT_OK(UpdateObjectNode::parseAndMerge(
- &root, modifiertable::ModifierType::MOD_SET, setUpdate["$set"]["a.1.d"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.0.b"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.$.c"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(&root,
+ modifiertable::ModifierType::MOD_SET,
+ setUpdate["$set"]["a.1.d"],
+ collator,
+ arrayFilters,
+ foundIdentifiers));
Document doc(fromjson("{a: [{b: 0, c: 0}, {c: 0, d: 0}]}"));
FieldRef pathToCreate("");