From b91d22d97d8c4dfce1ffb1ef9f32c16bc0a84687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20G=C3=B6dderz?= Date: Wed, 25 Jul 2018 12:28:16 +0200 Subject: [PATCH] [3.3] Bugfix: Fix `_rev` handling in `UPDATE`/`REPLACE` `WITH` clauses (#5967) --- CHANGELOG | 3 + arangod/Aql/ModificationBlocks.cpp | 42 ++- js/server/tests/aql/aql-modify.js | 581 ++++++++++++++++++++++++++++- 3 files changed, 619 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 740a1cb070..5851e4f55f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ v3.3.13 (XXXX-XX-XX) -------------------- +* Bugfix: The AQL syntax variants `UPDATE/REPLACE k WITH d` now correctly take + _rev from k instead of d (when ignoreRevs is false) and ignore d._rev. + * put an upper bound on the number of documents to be scanned when using `db..any()` in the RocksDB storage engine diff --git a/arangod/Aql/ModificationBlocks.cpp b/arangod/Aql/ModificationBlocks.cpp index 546075f1a8..54a6e114c9 100644 --- a/arangod/Aql/ModificationBlocks.cpp +++ b/arangod/Aql/ModificationBlocks.cpp @@ -660,6 +660,7 @@ AqlItemBlock* UpdateBlock::work(std::vector& blocks) { } std::string key; + std::string rev; // loop over the complete block std::vector wasTaken; @@ -678,7 +679,14 @@ AqlItemBlock* UpdateBlock::work(std::vector& blocks) { if (hasKeyVariable) { // separate key specification AqlValue const& k = res->getValueReference(i, keyRegisterId); - errorCode = extractKey(k, key); + if (options.ignoreRevs) { + errorCode = extractKey(k, key); + } else { + rev.clear(); + // does nothing to rev unless k is an object that contains _rev, + // and _rev is a string. + errorCode = extractKeyAndRev(k, key, rev); + } } else { errorCode = extractKey(a, key); } @@ -697,9 +705,18 @@ AqlItemBlock* UpdateBlock::work(std::vector& blocks) { keyBuilder.clear(); keyBuilder.openObject(); keyBuilder.add(StaticStrings::KeyString, VPackValue(key)); + if (!options.ignoreRevs && !rev.empty()) { + keyBuilder.add(StaticStrings::RevString, VPackValue(rev)); + } else { + // we must never take _rev from the document if there is a key + // expression. + keyBuilder.add(StaticStrings::RevString, + VPackValue(VPackValueType::Null)); + } keyBuilder.close(); - VPackCollection::merge(object, a.slice(), keyBuilder.slice(), false, false); + VPackCollection::merge(object, a.slice(), keyBuilder.slice(), false, + true); } else { // use original slice for updating @@ -1128,6 +1145,7 @@ AqlItemBlock* ReplaceBlock::work(std::vector& blocks) { } std::string key; + std::string rev; // loop over the complete block std::vector wasTaken; @@ -1146,7 +1164,14 @@ AqlItemBlock* ReplaceBlock::work(std::vector& blocks) { if (hasKeyVariable) { // separate key specification AqlValue const& k = res->getValueReference(i, keyRegisterId); - errorCode = extractKey(k, key); + if (options.ignoreRevs) { + errorCode = extractKey(k, key); + } else { + rev.clear(); + // does nothing to rev unless k is an object that contains _rev, + // and _rev is a string. + errorCode = extractKeyAndRev(k, key, rev); + } } else { errorCode = extractKey(a, key); } @@ -1165,9 +1190,18 @@ AqlItemBlock* ReplaceBlock::work(std::vector& blocks) { keyBuilder.clear(); keyBuilder.openObject(); keyBuilder.add(StaticStrings::KeyString, VPackValue(key)); + if (!options.ignoreRevs && !rev.empty()) { + keyBuilder.add(StaticStrings::RevString, VPackValue(rev)); + } else { + // we must never take _rev from the document if there is a key + // expression. + keyBuilder.add(StaticStrings::RevString, + VPackValue(VPackValueType::Null)); + } keyBuilder.close(); - VPackCollection::merge(object, a.slice(), keyBuilder.slice(), false, false); + VPackCollection::merge(object, a.slice(), keyBuilder.slice(), false, + true); } else { // Use the original slice for updating object.add(a.slice()); diff --git a/js/server/tests/aql/aql-modify.js b/js/server/tests/aql/aql-modify.js index ad111891bc..50753db16c 100644 --- a/js/server/tests/aql/aql-modify.js +++ b/js/server/tests/aql/aql-modify.js @@ -193,6 +193,290 @@ function aqlUpdateOptionsSuite () { let docs = buildSetOfDocs(); db._query(q); + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateSingleWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `UPDATE {_key: @key, _rev: @rev, val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key, rev: d._rev}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateManyWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs + UPDATE {_key: doc._key, _rev: doc._rev, val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateEnumerationWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + UPDATE {_key: doc._key, _rev: doc._rev, val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + }; +}; + +function aqlUpdateWithOptionsSuite () { + + return { + setUp, tearDown, + + testUpdateWithSingleWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `UPDATE {_key: @key, _rev: "invalid"} WITH {val: "${invalid}"} IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + try { + db._query(q, {key: d._key}); + fail(); + } catch (err) { + assertEqual(err.errorNum, errors.ERROR_ARANGO_CONFLICT.code); + } + } + validateDocsAreUpdated(docs, invalid, false); + }, + + testUpdateWithManyWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs UPDATE {_key: doc._key, _rev: "invalid"} WITH {val: "${invalid}"} IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(10); + try { + db._query(q, {docs: [...docs]}); + fail(); + } catch (err) { + assertEqual(err.errorNum, errors.ERROR_ARANGO_CONFLICT.code); + } + + validateDocsAreUpdated(docs, invalid, false); + }, + + testUpdateWithEnumerationWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + UPDATE {_key: doc._key, _rev: "invalid"} WITH {val: "${invalid}"} + IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(); + try { + db._query(q); + fail(); + } catch (err) { + assertEqual(err.errorNum, errors.ERROR_ARANGO_CONFLICT.code); + } + + validateDocsAreUpdated(docs, invalid, false); + }, + + testUpdateWithSingleWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `UPDATE {_key: @key, _rev: "invalid"} WITH {val: "${invalid}"} IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithManyWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs UPDATE {_key: doc._key, _rev: "invalid"} WITH {val: "${invalid}"} IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithEnumerationWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + UPDATE {_key: doc._key, _rev: "invalid"} WITH {val: "${invalid}"} + IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithSingleWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `UPDATE {_key: @key, _rev: "invalid"} WITH {val: "${invalid}"} IN ${collectionName}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithManyWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs UPDATE {_key: doc._key, _rev: "invalid"} WITH {val: "${invalid}"} IN ${collectionName}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithEnumerationWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + UPDATE {_key: doc._key, _rev: "invalid"} WITH {val: "${invalid}"} + IN ${collectionName}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithSingleWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `UPDATE {_key: @key, _rev: @rev} + WITH {val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key, rev: d._rev}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithManyWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs + UPDATE {_key: doc._key, _rev: doc._rev} + WITH {val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithEnumerationWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + UPDATE {_key: doc._key, _rev: doc._rev} + WITH {val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + }; +}; + +function aqlUpdateWithRevOptionsSuite () { + + return { + setUp, tearDown, + + testUpdateWithRevSingleWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `UPDATE {_key: @key} WITH {_rev: "invalid", val: "${invalid}"} IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithRevManyWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs UPDATE {_key: doc._key} WITH {_rev: "invalid", val: "${invalid}"} IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithRevEnumerationWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + UPDATE {_key: doc._key} WITH {_rev: "invalid", val: "${invalid}"} + IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithRevSingleWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `UPDATE {_key: @key} WITH {_rev: "invalid", val: "${invalid}"} IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithRevManyWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs UPDATE {_key: doc._key} WITH {_rev: "invalid", val: "${invalid}"} IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithRevEnumerationWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + UPDATE {_key: doc._key} WITH {_rev: "invalid", val: "${invalid}"} + IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithRevSingleWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `UPDATE {_key: @key} WITH {_rev: "invalid", val: "${invalid}"} IN ${collectionName}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithRevManyWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs UPDATE {_key: doc._key} WITH {_rev: "invalid", val: "${invalid}"} IN ${collectionName}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testUpdateWithRevEnumerationWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + UPDATE {_key: doc._key} WITH {_rev: "invalid", val: "${invalid}"} + IN ${collectionName}`; + let docs = buildSetOfDocs(); + db._query(q); + validateDocsAreUpdated(docs, invalid, true); } }; @@ -306,11 +590,298 @@ function aqlReplaceOptionsSuite () { db._query(q); validateDocsAreUpdated(docs, invalid, true); - } - + }, + + testReplaceSingleWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `REPLACE {_key: @key, _rev: @rev, val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key, rev: d._rev}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceManyWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs + REPLACE {_key: doc._key, _rev: doc._rev, val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceEnumerationWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + REPLACE {_key: doc._key, _rev: doc._rev, val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + }; }; +function aqlReplaceWithOptionsSuite () { + + return { + setUp, tearDown, + + testReplaceWithSingleWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `REPLACE {_key: @key, _rev: "invalid"} WITH { val: "${invalid}" } IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + try { + db._query(q, {key: d._key}); + fail(); + } catch (err) { + assertEqual(err.errorNum, errors.ERROR_ARANGO_CONFLICT.code); + } + } + validateDocsAreUpdated(docs, invalid, false); + }, + + testReplaceWithManyWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs REPLACE {_key: doc._key, _rev: "invalid"} WITH { val: "${invalid}" } IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(10); + try { + db._query(q, {docs: [...docs]}); + fail(); + } catch (err) { + assertEqual(err.errorNum, errors.ERROR_ARANGO_CONFLICT.code); + } + + validateDocsAreUpdated(docs, invalid, false); + }, + + testReplaceWithEnumerationWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + REPLACE {_key: doc._key, _rev: "invalid"} WITH { val: "${invalid}" } + IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(); + try { + db._query(q); + fail(); + } catch (err) { + assertEqual(err.errorNum, errors.ERROR_ARANGO_CONFLICT.code); + } + + validateDocsAreUpdated(docs, invalid, false); + }, + + testReplaceWithSingleWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `REPLACE {_key: @key, _rev: "invalid"} WITH { val: "${invalid}" } IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithManyWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs REPLACE {_key: doc._key, _rev: "invalid"} WITH { val: "${invalid}" } IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithEnumerationWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + REPLACE {_key: doc._key, _rev: "invalid"} WITH { val: "${invalid}" } + IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithSingleWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `REPLACE {_key: @key, _rev: "invalid"} WITH { val: "${invalid}" } IN ${collectionName}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithManyWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs REPLACE {_key: doc._key, _rev: "invalid"} WITH { val: "${invalid}" } IN ${collectionName}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithEnumerationWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + REPLACE {_key: doc._key, _rev: "invalid"} WITH { val: "${invalid}" } + IN ${collectionName}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithSingleWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `REPLACE {_key: @key, _rev: @rev} + WITH {val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key, rev: d._rev}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithManyWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs + REPLACE {_key: doc._key, _rev: doc._rev} + WITH {val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithEnumerationWithValidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + REPLACE {_key: doc._key, _rev: doc._rev} + WITH {val: "${invalid}"} + IN ${collectionName} + OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + + }; +}; + +function aqlReplaceWithRevOptionsSuite () { + + return { + setUp, tearDown, + + testReplaceWithRevSingleWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `REPLACE {_key: @key} WITH { _rev: "invalid", val: "${invalid}" } IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithRevManyWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs REPLACE {_key: doc._key} WITH { _rev: "invalid", val: "${invalid}" } IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithRevEnumerationWithInvalidRev : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + REPLACE {_key: doc._key} WITH { _rev: "invalid", val: "${invalid}" } + IN ${collectionName} OPTIONS {ignoreRevs: false}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithRevSingleWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `REPLACE {_key: @key} WITH { _rev: "invalid", val: "${invalid}" } IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithRevManyWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs REPLACE {_key: doc._key} WITH { _rev: "invalid", val: "${invalid}" } IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithRevEnumerationWithInvalidRevIgnore : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + REPLACE {_key: doc._key} WITH { _rev: "invalid", val: "${invalid}" } + IN ${collectionName} OPTIONS {ignoreRevs: true}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithRevSingleWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `REPLACE {_key: @key} WITH { _rev: "invalid", val: "${invalid}" } IN ${collectionName}`; + let docs = buildSetOfDocs(1); + for (let d of docs) { + db._query(q, {key: d._key}); + } + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithRevManyWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN @docs REPLACE {_key: doc._key} WITH { _rev: "invalid", val: "${invalid}" } IN ${collectionName}`; + let docs = buildSetOfDocs(10); + db._query(q, {docs: [...docs]}); + + validateDocsAreUpdated(docs, invalid, true); + }, + + testReplaceWithRevEnumerationWithInvalidRevDefault : function () { + const invalid = genInvalidValue(); + let q = `FOR doc IN ${collectionName} + REPLACE {_key: doc._key} WITH { _rev: "invalid", val: "${invalid}" } + IN ${collectionName}`; + let docs = buildSetOfDocs(); + db._query(q); + + validateDocsAreUpdated(docs, invalid, true); + } + + }; +}; + + //////////////////////////////////////////////////////////////////////////////// /// @brief test suite //////////////////////////////////////////////////////////////////////////////// @@ -440,7 +1011,7 @@ function aqlUpsertOptionsSuite () { let q = `UPSERT {_key: @key} INSERT {} UPDATE {_rev: "invalid", val: "${invalid}"} IN ${collectionName} OPTIONS {ignoreRevs: false}`; let docs = buildSetOfDocs(1); for (let d of docs) { - try { + try { db._query(q, {key: d._key}); fail(); } catch (err) { @@ -687,7 +1258,11 @@ function aqlUpsertOptionsSuite () { //////////////////////////////////////////////////////////////////////////////// jsunity.run(aqlUpdateOptionsSuite); +jsunity.run(aqlUpdateWithOptionsSuite); +jsunity.run(aqlUpdateWithRevOptionsSuite); jsunity.run(aqlReplaceOptionsSuite); +jsunity.run(aqlReplaceWithOptionsSuite); +jsunity.run(aqlReplaceWithRevOptionsSuite); jsunity.run(aqlRemoveOptionsSuite); jsunity.run(aqlUpsertOptionsSuite); return jsunity.done();