TEST_F(UnsetNodeTest, ApplyCannotRemoveRequiredPartOfDBRef) {
    auto update = fromjson("{$unset: {'a.$id': true}}");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    UnsetNode node;
    ASSERT_OK(node.init(update["$unset"]["a.$id"], expCtx));

    mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
    setPathTaken("a.$id");
    ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"]["$id"])),
                                AssertionException,
                                ErrorCodes::InvalidDBRef,
                                "The DBRef $ref field must be followed by a $id field");
}
Beispiel #2
0
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));

    mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
    setPathTaken("a.$id");
    ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"]["$id"])),
                                AssertionException,
                                ErrorCodes::InvalidDBRef,
                                "The DBRef $ref field must be followed by a $id field");
}
Beispiel #3
0
TEST_F(UnsetNodeTest, ApplyCannotRemovePrefixOfImmutablePath) {
    auto update = fromjson("{$unset: {a: true}}");
    const CollatorInterface* collator = nullptr;
    UnsetNode node;
    ASSERT_OK(node.init(update["$unset"]["a"], collator));

    mutablebson::Document doc(fromjson("{a: {b: 1}}"));
    setPathTaken("a");
    addImmutablePath("a.b");
    ASSERT_THROWS_CODE_AND_WHAT(node.apply(getApplyParams(doc.root()["a"])),
                                AssertionException,
                                ErrorCodes::ImmutableField,
                                "Unsetting the path 'a' would modify the immutable field 'a.b'");
}
Beispiel #4
0
TEST_F(UnsetNodeTest, ApplyNoIndexDataNoLogBuilder) {
    auto update = fromjson("{$unset: {a: 1}}");
    const CollatorInterface* collator = nullptr;
    UnsetNode node;
    ASSERT_OK(node.init(update["$unset"]["a"], collator));

    mutablebson::Document doc(fromjson("{a: 5}"));
    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_F(UnsetNodeTest, ApplyCannotRemoveSuffixOfImmutablePath) {
    auto update = fromjson("{$unset: {'a.b.c': true}}");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    UnsetNode node;
    ASSERT_OK(node.init(update["$unset"]["a.b.c"], expCtx));

    mutablebson::Document doc(fromjson("{a: {b: {c: 1}}}"));
    setPathTaken("a.b.c");
    addImmutablePath("a.b");
    ASSERT_THROWS_CODE_AND_WHAT(
        node.apply(getApplyParams(doc.root()["a"]["b"]["c"])),
        AssertionException,
        ErrorCodes::ImmutableField,
        "Performing an update on the path 'a.b.c' would modify the immutable field 'a.b'");
}
Beispiel #6
0
TEST_F(PopNodeTest, NoopWhenNumericalPathComponentExceedsArrayLength) {
    auto update = fromjson("{$pop: {'a.0': 1}}");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    PopNode popNode;
    ASSERT_OK(popNode.init(update["$pop"]["a.0"], expCtx));

    mmb::Document doc(fromjson("{a: []}"));
    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("{}"), getLogDoc());
}
Beispiel #7
0
TEST_F(PopNodeTest, ThrowsWhenPathIsBlockedByAScalar) {
    auto update = fromjson("{$pop: {'a.b': 1}}");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    PopNode popNode;
    ASSERT_OK(popNode.init(update["$pop"]["a.b"], expCtx));

    mmb::Document doc(fromjson("{a: 'foo'}"));
    setPathToCreate("b");
    setPathTaken("a");
    addIndexedPath("a.b");
    ASSERT_THROWS_CODE_AND_WHAT(
        popNode.apply(getApplyParams(doc.root()["a"])),
        AssertionException,
        ErrorCodes::PathNotViable,
        "Cannot use the part (b) of (a.b) to traverse the element ({a: \"foo\"})");
}
Beispiel #8
0
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));

    mutablebson::Document doc(fromjson("{a: 1}"));
    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("{}"), getLogDoc());
}
Beispiel #9
0
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));

    mutablebson::Document doc(fromjson("{a: 'cbc'}"));
    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'}}"), getLogDoc());
}
Beispiel #10
0
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));

    mutablebson::Document doc(fromjson("{a: 0.0}"));
    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("{}"), getLogDoc());
}
Beispiel #11
0
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));

    mutablebson::Document doc(fromjson("{'a.b':4, a: {b: 2}}"));
    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}}"), getLogDoc());
}
Beispiel #12
0
TEST_F(PopNodeTest, NoopWhenPathPartiallyExists) {
    auto update = fromjson("{$pop: {'a.b.c': 1}}");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    PopNode popNode;
    ASSERT_OK(popNode.init(update["$pop"]["a.b.c"], expCtx));

    mmb::Document doc(fromjson("{a: {}}"));
    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("{}"), getLogDoc());
}
TEST_F(UnsetNodeTest, ApplyNoIndexDataNoLogBuilder) {
    auto update = fromjson("{$unset: {a: 1}}");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    UnsetNode node;
    ASSERT_OK(node.init(update["$unset"]["a"], expCtx));

    mutablebson::Document doc(fromjson("{a: 5}"));
    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());
    ASSERT_EQUALS(getModifiedPaths(), "{a}");
}
TEST_F(UnsetNodeTest, ApplyFieldWithDot) {
    auto update = fromjson("{$unset: {'a.b': 1}}");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    UnsetNode node;
    ASSERT_OK(node.init(update["$unset"]["a.b"], expCtx));

    mutablebson::Document doc(fromjson("{'a.b':4, a: {b: 2}}"));
    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}}"), getLogDoc());
    ASSERT_EQUALS(getModifiedPaths(), "{a.b}");
}
Beispiel #15
0
TEST_F(UnsetNodeTest, UnsetPositional) {
    auto update = fromjson("{$unset: {'a.$': 1}}");
    const CollatorInterface* collator = nullptr;
    UnsetNode node;
    ASSERT_OK(node.init(update["$unset"]["a.$"], collator));

    mutablebson::Document doc(fromjson("{a: [0, 1, 2]}"));
    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}}"), getLogDoc());
}
TEST_F(UnsetNodeTest, UnsetPositional) {
    auto update = fromjson("{$unset: {'a.$': 1}}");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    UnsetNode node;
    ASSERT_OK(node.init(update["$unset"]["a.$"], expCtx));

    mutablebson::Document doc(fromjson("{a: [0, 1, 2]}"));
    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}}"), getLogDoc());
    ASSERT_EQUALS(getModifiedPaths(), "{a.1}");
}
Beispiel #17
0
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));

    mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
    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}}"), getLogDoc());
}
TEST_F(UnsetNodeTest, ApplyCanRemoveRequiredPartOfDBRefIfValidateForStorageIsFalse) {
    auto update = fromjson("{$unset: {'a.$id': true}}");
    boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
    UnsetNode node;
    ASSERT_OK(node.init(update["$unset"]["a.$id"], expCtx));

    mutablebson::Document doc(fromjson("{a: {$ref: 'c', $id: 0}}"));
    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}}"), getLogDoc());
    ASSERT_EQUALS(getModifiedPaths(), "{a.$id}");
}
Beispiel #19
0
TEST_F(CompareNodeTest, ApplyMaxRespectsCollationFromSetCollator) {
    auto update = fromjson("{$max: {a: 'abd'}}");
    const CollatorInterface* binaryComparisonCollator = nullptr;
    CompareNode node(CompareNode::CompareMode::kMax);
    ASSERT_OK(node.init(update["$max"]["a"], binaryComparisonCollator));

    const CollatorInterfaceMock reverseStringCollator(
        CollatorInterfaceMock::MockType::kReverseString);
    node.setCollator(&reverseStringCollator);

    mutablebson::Document doc(fromjson("{a: 'cbc'}"));
    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'}}"), getLogDoc());
}