diff --git a/arangod/Agency/Node.cpp b/arangod/Agency/Node.cpp index 03eabbd8ce..2fa4c3d031 100644 --- a/arangod/Agency/Node.cpp +++ b/arangod/Agency/Node.cpp @@ -464,24 +464,55 @@ bool Node::handle(VPackSlice const& slice) { return true; } -/// Remove element from any place in array by value array -template <> -bool Node::handle(VPackSlice const& slice) { - if (!slice.hasKey("val")) { +/// Remove element from any place in array by value or position +template <> bool Node::handle(VPackSlice const& slice) { + bool haveVal = slice.hasKey("val"); + bool havePos = slice.hasKey("pos"); + + if (!haveVal && !havePos) { LOG_TOPIC(WARN, Logger::AGENCY) - << "Operator erase without value to be erased: " << slice.toJson(); + << "Operator erase without value or position to be erased is illegal: " + << slice.toJson(); return false; + } else if (haveVal && havePos) { + LOG_TOPIC(WARN, Logger::AGENCY) + << "Operator erase with value and position to be erased is illegal: " + << slice.toJson(); + return false; + } else if (havePos && + (!slice.get("pos").isUInt() && !slice.get("pos").isSmallInt())) { + LOG_TOPIC(WARN, Logger::AGENCY) + << "Operator erase with non-positive integer position is illegal: " + << slice.toJson(); } + Builder tmp; { VPackArrayBuilder t(&tmp); + if (this->slice().isArray()) { - for (auto const& old : VPackArrayIterator(this->slice())) { - if (old != slice.get("val")) { - tmp.add(old); + if (haveVal) { + for (auto const& old : VPackArrayIterator(this->slice())) { + if (old != slice.get("val")) { + tmp.add(old); + } + } + } else { + size_t pos = slice.get("pos").getNumber(); + if (pos >= this->slice().length()) { + return false; + } + size_t n = 0; + for (const auto& old : VPackArrayIterator(this->slice())) { + if (n != pos) { + tmp.add(old); + } + ++n; } } } + } + *this = tmp.slice(); return true; } diff --git a/js/client/tests/agency/agency-test.js b/js/client/tests/agency/agency-test.js index 322c00103e..8eea2f03aa 100644 --- a/js/client/tests/agency/agency-test.js +++ b/js/client/tests/agency/agency-test.js @@ -605,7 +605,9 @@ function agencyTestSuite () { //////////////////////////////////////////////////////////////////////////////// testOpErase : function () { + writeAndCheck([[{"/version":{"op":"delete"}}]]); + writeAndCheck([[{"/a":[0,1,2,3,4,5,6,7,8,9]}]]); // none before assertEqual(readAndCheck([["/a"]]), [{a:[0,1,2,3,4,5,6,7,8,9]}]); writeAndCheck([[{"a":{"op":"erase","val":3}}]]); @@ -629,6 +631,28 @@ function agencyTestSuite () { writeAndCheck([[{"a":{"op":"erase","val":6}}], [{"a":{"op":"erase","val":8}}]]); assertEqual(readAndCheck([["/a"]]), [{a:[]}]); + + writeAndCheck([[{"/a":[0,1,2,3,4,5,6,7,8,9]}]]); // none before + assertEqual(readAndCheck([["/a"]]), [{a:[0,1,2,3,4,5,6,7,8,9]}]); + writeAndCheck([[{"a":{"op":"erase","pos":3}}]]); + assertEqual(readAndCheck([["/a"]]), [{a:[0,1,2,4,5,6,7,8,9]}]); + writeAndCheck([[{"a":{"op":"erase","pos":0}}]]); + assertEqual(readAndCheck([["/a"]]), [{a:[1,2,4,5,6,7,8,9]}]); + writeAndCheck([[{"a":{"op":"erase","pos":0}}]]); + assertEqual(readAndCheck([["/a"]]), [{a:[2,4,5,6,7,8,9]}]); + writeAndCheck([[{"a":{"op":"erase","pos":2}}]]); + assertEqual(readAndCheck([["/a"]]), [{a:[2,4,6,7,8,9]}]); + writeAndCheck([[{"a":{"op":"erase","pos":4}}]]); + assertEqual(readAndCheck([["/a"]]), [{a:[2,4,6,7,9]}]); + writeAndCheck([[{"a":{"op":"erase","pos":2}}]]); + assertEqual(readAndCheck([["/a"]]), [{a:[2,4,7,9]}]); + writeAndCheck([[{"a":{"op":"erase","pos":2}}]]); + assertEqual(readAndCheck([["/a"]]), [{a:[2,4,9]}]); + writeAndCheck([[{"a":{"op":"erase","pos":0}}]]); + assertEqual(readAndCheck([["/a"]]), [{a:[4,9]}]); + writeAndCheck([[{"a":{"op":"erase","pos":1}}], + [{"a":{"op":"erase","pos":0}}]]); + assertEqual(readAndCheck([["/a"]]), [{a:[]}]); }, ////////////////////////////////////////////////////////////////////////////////