1
0
Fork 0
arangodb/tests/js/server/aql/aql-multi-modify.js

540 lines
24 KiB
JavaScript

/*jshint globalstrict:false, strict:false, sub: true, maxlen: 500 */
/*global assertEqual, assertFalse, assertTrue, AQL_EXECUTE, AQL_EXPLAIN */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for multi-modify operations
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var internal = require("internal");
var db = require("@arangodb").db;
var jsunity = require("jsunity");
var helper = require("@arangodb/aql-helper");
var assertQueryError = helper.assertQueryError;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function ahuacatlMultiModifySuite () {
var errors = internal.errors;
var cn1 = "UnitTestsAhuacatlModify1";
var cn2 = "UnitTestsAhuacatlModify2";
var cn3 = "UnitTestsAhuacatlModify3";
var c1, c2, c3;
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
db._drop(cn1);
db._drop(cn2);
db._drop(cn3);
c1 = db._create(cn1);
c2 = db._create(cn2);
c3 = db._createEdgeCollection(cn3);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
db._drop(cn1);
db._drop(cn2);
db._drop(cn3);
c1 = null;
c2 = null;
c3 = null;
},
testTraversalAndModification : function () {
c1.insert({ _key: "1" });
c1.insert({ _key: "2" });
c1.insert({ _key: "3" });
c1.insert({ _key: "4" });
c3.insert(cn1 + "/1", cn1 + "/2", { });
c3.insert(cn1 + "/2", cn1 + "/3", { });
var q = "FOR v IN 1..99 OUTBOUND '" + cn1 + "/1' @@e REMOVE v._key IN @@cn";
var actual = AQL_EXECUTE(q, { "@cn": cn1, "@e": cn3 });
assertEqual([ ], actual.json);
assertEqual(2, actual.stats.writesExecuted);
assertEqual(2, c1.count());
assertTrue(c1.exists("1"));
assertTrue(c1.exists("4"));
assertEqual(2, c3.count());
},
testTraversalAndModificationBig : function () {
var i;
for (i = 1; i <= 2010; ++i) {
c1.insert({ _key: String(i) });
if (i !== 2010) {
c3.insert(cn1 + "/" + String(i), cn1 + "/" + String(i + 1), { });
}
}
var q = "FOR v IN 1..2010 OUTBOUND '" + cn1 + "/1' @@e REMOVE v._key IN @@cn";
var actual = AQL_EXECUTE(q, { "@cn": cn1, "@e": cn3 });
assertEqual([ ], actual.json);
assertEqual(2009, actual.stats.writesExecuted);
assertEqual(1, c1.count());
assertTrue(c1.exists("1"));
assertEqual(2009, c3.count());
// check that 'readCompleteInput' option is set
var nodes = AQL_EXPLAIN(q, { "@cn": cn1, "@e": cn3 }).plan.nodes, found = false;
nodes.forEach(function(node) {
if (node.type === 'RemoveNode') {
assertTrue(node.modificationFlags.readCompleteInput);
found = true;
}
});
assertTrue(found);
},
testWithDeclarationAndModification : function () {
var q = "WITH @@cn RETURN (INSERT {} INTO @@cn)";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual([ [ ] ], actual.json);
assertEqual(1, actual.stats.writesExecuted);
assertEqual(1, c1.count());
assertEqual(0, c2.count());
},
testWithDeclarationsAndSingleModificationMultipleCollections : function () {
var q = "WITH @@cn1, @@cn2 RETURN (INSERT {} INTO @@cn1)";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2" : cn2 });
assertEqual([ [ ] ], actual.json);
assertEqual(1, actual.stats.writesExecuted);
assertEqual(1, c1.count());
assertEqual(0, c2.count());
},
testWithDeclarationsAndMultiModificationMultipleCollections : function () {
var q = "WITH @@cn1, @@cn2 RETURN [(INSERT {} INTO @@cn1), (INSERT {} INTO @@cn2)]";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2" : cn2 });
assertEqual([ [ [ ], [ ] ] ], actual.json);
assertEqual(2, actual.stats.writesExecuted);
assertEqual(1, c1.count());
assertEqual(1, c2.count());
},
testWithDeclarationsAndModificationWriteRead : function () {
var q = "WITH @@cn1, @@cn2 RETURN [(INSERT {} INTO @@cn1), (FOR doc IN @@cn2 RETURN doc)]";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2" : cn2 });
assertEqual([ [ [ ], [ ] ] ], actual.json);
assertEqual(1, actual.stats.writesExecuted);
assertEqual(1, c1.count());
assertEqual(0, c2.count());
},
testWithDeclarationSameCollectionWriteThenRead : function () {
var q = "WITH @@cn1 RETURN [(INSERT {} INTO @@cn1), (FOR doc IN @@cn1 RETURN doc)]";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn1": cn1 });
},
testWithDeclarationAndModificationMultipleCollectionsThenRead : function () {
var q = "WITH @@cn1 LET x = (INSERT {} INTO @@cn1) FOR doc IN @@cn1 RETURN doc";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn1": cn1 });
},
testTraversalAfterModification : function () {
var q = "INSERT { _key: '1', foo: 'bar' } INTO @@cn FOR doc IN OUTBOUND 'v/1' @@e RETURN doc";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1, "@e": cn3 });
},
testInsertAfterModification : function () {
var q = "INSERT { _key: '1', foo: 'bar' } INTO @@cn INSERT { _key: '2', foo: 'baz' } INTO @@cn";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1 });
},
testUpdateAfterModification : function () {
var q = "INSERT { _key: '1', foo: 'bar' } INTO @@cn UPDATE '1' WITH { foo: 'baz' } INTO @@cn";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1 });
},
testReplaceAfterModification : function () {
var q = "INSERT { _key: '1', foo: 'bar' } INTO @@cn REPLACE '1' WITH { foo: 'baz' } INTO @@cn";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1 });
},
testRemoveAfterModification : function () {
var q = "INSERT { _key: '1', foo: 'bar' } INTO @@cn REMOVE '1' IN @@cn";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1 });
},
testUpsertAfterModification : function () {
var q = "INSERT { _key: '1', foo: 'bar' } INTO @@cn UPSERT { foo: 'bar' } INSERT { foo: 'bar' } UPDATE { foo: 'baz' } IN @@cn";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1 });
},
testDocumentAfterModification : function () {
var q = "INSERT { _key: '1', foo: 'bar' } INTO @@cn RETURN DOCUMENT(@@cn, '1')";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1 });
},
testEdgeAfterModification : function () {
var q = "INSERT { _from: @from, _to: @to } INTO @@cn RETURN DOCUMENT(@@cn, NEW._key)";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn3, from: cn2 + "/1", to: cn2 + "/2" });
},
testEdgesAfterModification : function () {
var q = "INSERT { _from: @from, _to: @to } INTO @@cn FOR v, e IN OUTBOUND @from @@cn RETURN e";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn3, from: cn2 + "/1", to: cn2 + "/2" });
},
testMultiInsertSameCollection : function () {
var q = "INSERT { value: 1 } INTO @@cn INSERT { value: 2 } INTO @@cn";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1 });
},
testMultiInsertOtherCollection : function () {
var q = "INSERT { value: 1 } INTO @@cn1 INSERT { value: 2 } INTO @@cn2";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2": cn2 });
assertEqual([ ], actual.json);
assertEqual(2, actual.stats.writesExecuted);
assertEqual(1, c1.count());
assertEqual(1, c1.any().value);
assertEqual(1, c2.count());
assertEqual(2, c2.any().value);
},
testMultiInsertLoopSameCollection : function () {
var q = "FOR i IN 1..10 INSERT { value: i } INTO @@cn INSERT { value: i + 1 } INTO @@cn";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, {"@cn": cn1 });
},
testMultiInsertLoopOtherCollection : function () {
var q = "FOR i IN 1..10 INSERT { value: i } INTO @@cn1 INSERT { value: i + 1 } INTO @@cn2";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2": cn2 });
assertEqual([ ], actual.json);
assertEqual(20, actual.stats.writesExecuted);
assertEqual(10, c1.count());
assertEqual(10, c2.count());
},
testMultiInsertLoopSubquerySingle : function () {
var q = "FOR i IN 1..1 LET sub = (FOR j IN 1..i INSERT { value: j } INTO @@cn) RETURN 1";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual(1, actual.json.length);
assertEqual([ 1 ], actual.json);
assertEqual(1, c1.count());
},
testMultiInsertLoopSubquerySingleReturnInside : function () {
var q = "FOR i IN 1..1 LET sub = (FOR j IN 1..i INSERT { value: j } INTO @@cn RETURN NEW.value) RETURN sub";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual(1, actual.json.length);
assertEqual([ [ 1 ] ], actual.json);
assertEqual(1, c1.count());
},
testMultiInsertLoopSubquerySingleReturned : function () {
var q = "FOR i IN 1..1 LET sub = (FOR j IN 1..i INSERT { value: j } INTO @@cn) RETURN sub";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual(1, actual.json.length);
assertEqual([ [ ] ], actual.json);
assertEqual(1, c1.count());
},
testMultiInsertLoopSubqueryTwo : function () {
var q = "FOR i IN 1..2 LET sub = (FOR j IN 1..i INSERT { value: j } INTO @@cn) RETURN 1";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual(2, actual.json.length);
assertEqual([ 1, 1 ], actual.json);
assertEqual(3, c1.count());
},
testMultiInsertLoopSubqueryTwoReturnInside : function () {
var q = "FOR i IN 1..2 LET sub = (FOR j IN 1..i INSERT { value: j } INTO @@cn RETURN NEW._key) RETURN 1";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual(2, actual.json.length);
assertEqual([ 1, 1 ], actual.json);
assertEqual(3, c1.count());
},
testMultiInsertLoopSubqueryTwoReturned : function () {
var q = "FOR i IN 1..2 LET sub = (FOR j IN 1..i INSERT { value: j } INTO @@cn) RETURN sub";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual(2, actual.json.length);
assertEqual([ [ ], [ ] ], actual.json);
assertEqual(3, c1.count());
},
testMultiInsertLoopSubqueryMore : function () {
var q = "FOR i IN 1..10 LET sub = (FOR j IN 1..i INSERT { value: j } INTO @@cn) RETURN 1";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual(10, actual.json.length);
assertEqual(55, c1.count());
},
testMultiInsertLoopSubqueryReturned : function () {
var q = "FOR i IN 1..2 LET sub = (FOR j IN 1..i INSERT { value: j } INTO @@cn) RETURN sub";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual(2, actual.json.length);
assertEqual([ [ ], [ ] ], actual.json);
assertEqual(3, c1.count());
},
testMultiInsertLoopSubquerySameCollection : function () {
AQL_EXECUTE("FOR i IN 1..10 INSERT { value: i } INTO @@cn", { "@cn" : cn1 });
var q = "FOR i IN @@cn LET sub = (FOR j IN 1..2 INSERT { value: j } INTO @@cn) RETURN 1";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1 });
},
testMultiInsertLoopSubqueryOtherCollection : function () {
AQL_EXECUTE("FOR i IN 1..10 INSERT { value: i } INTO @@cn", { "@cn" : cn1 });
var q = "FOR i IN @@cn1 LET sub = (FOR j IN 1..2 INSERT { value: j } INTO @@cn2) RETURN 1";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2" : cn2 });
assertEqual(10, actual.json.length);
assertEqual(20, actual.stats.writesExecuted);
assertEqual(10, c1.count());
assertEqual(20, c2.count());
},
testMultiInsertLoopSubqueryOtherCollectionReturnInside : function () {
AQL_EXECUTE("FOR i IN 1..10 INSERT { value: i } INTO @@cn", { "@cn" : cn1 });
var q = "FOR i IN @@cn1 LET sub = (FOR j IN 1..2 INSERT { value: j } INTO @@cn2 RETURN NEW.value) RETURN sub";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2" : cn2 });
assertEqual(10, actual.json.length);
assertEqual(20, actual.stats.writesExecuted);
assertEqual(10, c1.count());
assertEqual(20, c2.count());
},
testMultiInsertLoopSubquerySameCollectionIndependent : function () {
AQL_EXECUTE("FOR i IN 1..10 INSERT { value: i } INTO @@cn", { "@cn" : cn1 });
var q = "FOR i IN @@cn LET sub1 = (FOR j IN 1..2 INSERT { value: j } INTO @@cn) LET sub2 = (FOR j IN 1..2 INSERT { value: j } INTO @@cn) RETURN 1";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, {"@cn": cn1 });
},
testMultiRemoveSameCollection : function () {
var q = "INSERT { value: 1 } INTO @@cn LET doc = NEW REMOVE doc._key INTO @@cn";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1 });
},
testMultiRemoveOtherCollection : function () {
AQL_EXECUTE("FOR i IN 1..10 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn2 });
var q = "INSERT { value: 1 } INTO @@cn1 REMOVE { _key: 'test9' } INTO @@cn2";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2": cn2 });
assertEqual([ ], actual.json);
assertEqual(2, actual.stats.writesExecuted);
assertEqual(1, c1.count());
assertEqual(1, c1.any().value);
assertEqual(9, c2.count());
assertFalse(c2.exists('test9'));
assertTrue(c2.exists('test10'));
},
testMultiRemoveLoopSameCollection : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn1 });
var q = "FOR i IN 1..2010 INSERT { value: i } INTO @@cn REMOVE { _key: CONCAT('test', i) } INTO @@cn";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, {"@cn": cn1 });
},
testMultiRemoveLoopSameCollectionWithRead : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn1 });
var q = "FOR doc IN @@cn1 INSERT { _key: doc._key } INTO @@cn2 REMOVE doc IN @@cn1";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2": cn2 });
assertEqual([ ], actual.json);
assertEqual(4020, actual.stats.writesExecuted);
assertEqual(0, c1.count());
assertEqual(2010, c2.count());
// check that 'readCompleteInput' option is set
var nodes = AQL_EXPLAIN(q, { "@cn1": cn1, "@cn2": cn2 }).plan.nodes, found = false;
nodes.forEach(function(node) {
if (node.type === 'RemoveNode') {
assertEqual(db._engine().name === 'mmfiles', node.modificationFlags.readCompleteInput);
found = true;
}
});
assertTrue(found);
},
testMultiRemoveLoopOtherCollection : function () {
AQL_EXECUTE("FOR i IN 1..10 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn2 });
var q = "FOR i IN 1..10 INSERT { value: i } INTO @@cn1 REMOVE { _key: CONCAT('test', i) } INTO @@cn2";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2": cn2 });
assertEqual([ ], actual.json);
assertEqual(20, actual.stats.writesExecuted);
assertEqual(10, c1.count());
assertEqual(0, c2.count());
},
testMultiRemoveLoopSubquery : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn1 });
var q = "FOR i IN 1..2010 LET sub = (REMOVE { _key: CONCAT('test', i) } INTO @@cn) RETURN 1";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual(2010, actual.json.length);
assertEqual(2010, actual.stats.writesExecuted);
assertEqual(0, c1.count());
},
testMultiRemoveLoopSubqueryReturnInside : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn1 });
var q = "FOR i IN 1..2010 LET sub = (REMOVE { _key: CONCAT('test', i) } INTO @@cn RETURN OLD._key) RETURN sub";
var actual = AQL_EXECUTE(q, { "@cn": cn1 });
assertEqual(2010, actual.json.length);
assertEqual(2010, actual.stats.writesExecuted);
assertEqual(0, c1.count());
},
testMultiRemoveLoopSubquerySameCollection : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn1 });
var q = "FOR i IN @@cn LET sub = (REMOVE { _key: i._key } INTO @@cn) RETURN 1";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, { "@cn": cn1 });
},
testMultiRemoveLoopSubqueryOtherCollection : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn1 });
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn2 });
var q = "FOR i IN @@cn1 LET sub = (REMOVE { _key: i._key } INTO @@cn2) RETURN 1";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2" : cn2 });
assertEqual(2010, actual.json.length);
assertEqual(2010, actual.stats.writesExecuted);
assertEqual(2010, c1.count());
assertEqual(0, c2.count());
},
testMultiRemoveLoopSubqueryOtherCollectionReturnInside : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn1 });
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn2 });
var q = "FOR i IN @@cn1 LET sub = (REMOVE { _key: i._key } INTO @@cn2 RETURN OLD._key) RETURN sub";
var actual = AQL_EXECUTE(q, { "@cn1": cn1, "@cn2" : cn2 });
assertEqual(2010, actual.json.length);
assertEqual(2010, actual.stats.writesExecuted);
assertEqual(2010, c1.count());
assertEqual(0, c2.count());
},
testMultiRemoveLoopSubquerySameCollectionIndependent : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn1 });
var q = "FOR i IN @@cn LET sub1 = (INSERT { _key: CONCAT('test', i) } INTO @@cn) LET sub2 = (REMOVE { _key: CONCAT('test', i) } INTO @@cn) RETURN 1";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, {"@cn": cn1 });
},
testMultiRemoveLoopSubquerySameCollectionIndependentReturnsInside : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i) } INTO @@cn", { "@cn" : cn1 });
var q = "FOR i IN @@cn LET sub1 = (INSERT { _key: CONCAT('test', i) } INTO @@cn RETURN NEW._key) LET sub2 = (REMOVE { _key: CONCAT('test', i) } INTO @@cn RETURN OLD._key) RETURN 1";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, {"@cn": cn1 });
},
testRemoveInSubqueryNoResult : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { value: i } INTO @@cn", { "@cn" : cn1 });
var q = "FOR doc IN @@cn SORT doc.value LET f = (REMOVE doc IN @@cn) RETURN f";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, {"@cn": cn1 });
},
testRemoveInSubqueryNoResultReturnInside : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { value: i } INTO @@cn", { "@cn" : cn1 });
var q = "FOR doc IN @@cn SORT doc.value LET f = (REMOVE doc IN @@cn RETURN OLD._key) RETURN f";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, {"@cn": cn1 });
},
testRemoveInSubqueryReturnKeys : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { value: i } INTO @@cn", { "@cn" : cn1 });
var q = "FOR doc IN @@cn SORT doc.value LET f = (REMOVE doc IN @@cn RETURN OLD.value) RETURN f";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, {"@cn": cn1 });
},
testRemoveInSubqueryReturnKeysDoc : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { value: i } INTO @@cn", { "@cn" : cn1 });
var q = "FOR doc IN @@cn SORT doc.value LET f = (REMOVE doc IN @@cn RETURN OLD) RETURN f[0].value";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, {"@cn": cn1 });
},
testInsertRemove : function () {
var q = "FOR i IN 1..2010 INSERT { value: i } INTO @@cn LET x = NEW REMOVE x._key IN @@cn";
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, q, {"@cn": cn1 });
},
testInsertRemove2 : function () {
AQL_EXECUTE("FOR i IN 1..2010 INSERT { _key: CONCAT('test', i), value: i } INTO @@cn", { "@cn" : cn1 });
assertEqual(2010, c1.count());
assertEqual(0, c2.count());
const actual = AQL_EXECUTE("FOR i IN @@cn1 INSERT { value: i } INTO @@cn2 LET x = i._key REMOVE x IN @@cn1", { "@cn1" : cn1, "@cn2": cn2 }).json;
assertEqual([ ], actual);
assertEqual(0, c1.count());
assertEqual(2010, c2.count());
},
testMultiInsert : function () {
var actual = AQL_EXECUTE("FOR i IN 1..2010 INSERT { value: i * 3, _key: CONCAT('one-', i) } INTO @@cn1 LET one = NEW._key INSERT { value: i * 5, _key: CONCAT('two-', i) } INTO @@cn2 LET two = NEW._key RETURN [ one, two ]", { "@cn1" : cn1, "@cn2": cn2 }).json;
assertEqual(2010, actual.length);
var i, seen = { };
for (i = 0; i < actual.length; ++i) {
assertTrue(typeof actual[i][0] === 'string');
assertFalse(seen.hasOwnProperty(actual[i][0]));
seen[actual[i][0]] = true;
assertFalse(seen.hasOwnProperty(actual[i][1]));
seen[actual[i][1]] = true;
}
assertEqual(2010, c1.count());
assertEqual(2010, c2.count());
for (i = 0; i < actual.length; ++i) {
assertTrue(c1.document(actual[i][0]).value % 3 === 0);
assertTrue(c2.document(actual[i][1]).value % 5 === 0);
}
},
testMultiRemove : function () {
c1.save([ { _key: "a" }, { _key:"b" }, { _key: "c" } ]);
c3.save([ { _from: cn1 + "/a", _to: cn1 + "/b", _key: "1" }, { _from: cn1 + "/a", _to: cn1 + "/b", _key: "2" } ]);
var toDelete = [ { v: "b", e: "1" }, { v: "c", e: "2" } ];
db._query(`FOR x IN @toDelete REMOVE x.v IN ${cn1} REMOVE x.e IN ${cn3}`, { toDelete }).toArray();
assertEqual(1, c1.toArray().length);
assertEqual("a", c1.toArray()[0]._key);
assertEqual([ ], c3.toArray());
},
testMultiRemove2 : function () {
AQL_EXECUTE("FOR i IN 1..2000 INSERT { _key: CONCAT('test', i) } IN @@cn1 INSERT { _key: CONCAT('test', i) } IN @@cn2", { "@cn1" : cn1, "@cn2" : cn2 });
assertEqual(2000, c1.count());
assertEqual(2000, c2.count());
AQL_EXECUTE("FOR i IN 1..2000 REMOVE { _key: CONCAT('test', i) } IN @@cn1 REMOVE { _key: CONCAT('test', i) } IN @@cn2", { "@cn1" : cn1, "@cn2" : cn2 });
assertEqual(0, c1.count());
assertEqual(0, c2.count());
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suites
////////////////////////////////////////////////////////////////////////////////
jsunity.run(ahuacatlMultiModifySuite);
return jsunity.done();