1
0
Fork 0

Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel

This commit is contained in:
Frank Celler 2015-01-09 08:55:09 +01:00
commit 17f68a94ff
6 changed files with 220 additions and 21 deletions

View File

@ -19,7 +19,7 @@ Let's start with an example that modifies existing documents in a collection
FILTER u.status == 'not active'
UPDATE u WITH { status: 'inactive' } IN users
Note there is no need to combine a data-modification query with other
Note that there is no need to combine a data-modification query with other
AQL operations such as *FOR* and *FILTER*. For example, the following
stripped-down *update* query will work, too. It will *update* one document
(with key *foo*) in collection *users*:
@ -34,13 +34,42 @@ Now, let's copy the contents of the collection *users* into the collection
As a final example, let's find some documents in collection *users* and
remove them from collection *backup*. The link between the documents in both
collections is establish via the documents' keys:
collections is established via the documents' keys:
FOR u IN users
FILTER u.status == 'deleted'
REMOVE u IN backup
!SUBSECTION Returning documents
To return documents from a data-modification query, the `INSERT`, `REMOVE`,
`UPDATE` or `REPLACE` statement must be immediately followed by a `LET`
statement that assigns either the pseudo-value `NEW` or `OLD` to a user-defined
variable. The `LET` statement must be followed by a `RETURN` statement that
returns the variable introduced by `LET`:
FOR i IN 1..100
INSERT { value: i } IN test LET inserted = NEW RETURN inserted
FOR u IN users
FILTER u.status == 'deleted'
REMOVE u IN users LET removed = OLD RETURN removed
FOR u IN users
FILTER u.status == 'not active'
UPDATE u WITH { status: 'inactive' } IN users LET updated = NEW RETURN updated
`NEW` refers to the inserted or modified document revision, and `OLD` refers
to the document revision before update or removal. `INSERT` statements can
only refer to the `NEW` pseudo-value, and `REMOVE` operations only to `OLD`.
`UPDATE` and `REPLACE` can refer to either.
In all cases the full documents will be returned with all their attributes,
including the potentially auto-generated attributes such as `_id`, `_key`, or `_rev`
and the attributes not specified in the update expression of a partial update.
!SUBSECTION Restrictions
The name of the modified collection (*users* and *backup* in the above cases)

View File

@ -186,7 +186,11 @@ repeated computations of the same value at multiple parts of a query.
```
FOR u IN users
LET numRecommendations = LENGTH(u.recommendations)
RETURN { "user" : u, "numRecommendations" : numRecommendations, "isPowerUser" : numRecommendations >= 10 }
RETURN {
"user" : u,
"numRecommendations" : numRecommendations,
"isPowerUser" : numRecommendations >= 10
}
```
In the above example, the computation of the number of recommendations is
@ -446,20 +450,22 @@ do not need to be identical to the ones produced by a preceding *FOR* statement:
```
FOR i IN 1..1000
REMOVE { _key: CONCAT('test', TO_STRING(i)) } IN users
REMOVE { _key: CONCAT('test', i) } IN users
FOR u IN users
FILTER u.active == false
REMOVE { _key: u._key } IN backup
```
!SUBSUBSECTION Setting query options
*options* can be used to suppress query errors that may occur when trying to
remove non-existing documents. For example, the following query will fail if one
of the to-be-deleted documents does not exist:
```
FOR i IN 1..1000
REMOVE { _key: CONCAT('test', TO_STRING(i)) } IN users
REMOVE { _key: CONCAT('test', i) } IN users
```
By specifying the *ignoreErrors* query option, these errors can be suppressed so
@ -467,7 +473,7 @@ the query completes:
```
FOR i IN 1..1000
REMOVE { _key: CONCAT('test', TO_STRING(i)) } IN users OPTIONS { ignoreErrors: true }
REMOVE { _key: CONCAT('test', i) } IN users OPTIONS { ignoreErrors: true }
```
To make sure data has been written to disk when a query returns, there is the *waitForSync*
@ -475,7 +481,26 @@ query option:
```
FOR i IN 1..1000
REMOVE { _key: CONCAT('test', TO_STRING(i)) } IN users OPTIONS { waitForSync: true }
REMOVE { _key: CONCAT('test', i) } IN users OPTIONS { waitForSync: true }
```
!SUBSUBSECTION Returning the removed documents
The removed documents can also be returned by the query. In this case, the `REMOVE`
statement must be directly followed by a special `LET` statement and a `RETURN`
statement. The `LET` statement is limited to assigning the pseudo-value `OLD`
to a variable, and the `RETURN` statement is limited to returning this variable:
```
REMOVE key-expression IN collection options LET variable-name = OLD RETURN variable-name
```
Following is an example using a variable named `removed` to return the removed
documents:
```
FOR u IN users
REMOVE u IN users LET removed = OLD RETURN removed
```
!SUBSECTION UPDATE
@ -535,19 +560,21 @@ to the ones produced by a preceding *FOR* statement:
```
FOR i IN 1..1000
UPDATE CONCAT('test', TO_STRING(i)) WITH { foobar: true } IN users
UPDATE CONCAT('test', i) WITH { foobar: true } IN users
FOR u IN users
FILTER u.active == false
UPDATE u WITH { status: 'inactive' } IN backup
```
!SUBSUBSECTION Setting query options
*options* can be used to suppress query errors that may occur when trying to
update non-existing documents or violating unique key constraints:
```
FOR i IN 1..1000
UPDATE { _key: CONCAT('test', TO_STRING(i)) } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
UPDATE { _key: CONCAT('test', i) } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
```
An update operation will only update the attributes specified in *document* and
@ -603,6 +630,42 @@ FOR u IN users
UPDATE u WITH { foobar: true } IN users OPTIONS { waitForSync: true }
```
!SUBSUBSECTION Returning the modified documents
The modified documents can also be returned by the query. In this case, the `UPDATE`
statement must be directly followed by a special `LET` statement and a `RETURN`
statement. The `LET` statement is limited to assigning either the pseudo-value `OLD`
or `NEW` to a variable, and the `RETURN` statement is limited to returning this variable.
The `OLD` pseudo-value refers to the document revisions before the update, and `NEW`
refers to document revisions after the update.
```
UPDATE document IN collection options LET variable-name = OLD RETURN variable-name
UPDATE document IN collection options LET variable-name = NEW RETURN variable-name
UPDATE key-expression WITH document IN collection options LET variable-name = OLD RETURN variable-name
UPDATE key-expression WITH document IN collection options LET variable-name = NEW RETURN variable-name
```
Following is an example using a variable named `previous` to return the original
documents before modification:
```
FOR u IN users
UPDATE u WITH { value: "test" } LET previous = OLD RETURN previous
```
The following query uses the `NEW` pseudo-value to return the updated
documents:
```
FOR u IN users
UPDATE u WITH { value: "test" } LET updated = NEW RETURN updated
```
In both cases, the returned documents will contain all attributes, even
those not specified in the update expression.
!SUBSECTION REPLACE
The *REPLACE* keyword can be used to completely replace documents in a collection. On a
@ -666,19 +729,21 @@ to the ones produced by a preceding *FOR* statement:
```
FOR i IN 1..1000
REPLACE CONCAT('test', TO_STRING(i)) WITH { foobar: true } IN users
REPLACE CONCAT('test', i) WITH { foobar: true } IN users
FOR u IN users
FILTER u.active == false
REPLACE u WITH { status: 'inactive', name: u.name } IN backup
```
!SUBSUBSECTION Setting query options
*options* can be used to suppress query errors that may occur when trying to
replace non-existing documents or when violating unique key constraints:
```
FOR i IN 1..1000
REPLACE { _key: CONCAT('test', TO_STRING(i)) } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
REPLACE { _key: CONCAT('test', i) } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
```
To make sure data are durable when a replace query returns, there is the *waitForSync*
@ -686,9 +751,45 @@ query option:
```
FOR i IN 1..1000
REPLACE { _key: CONCAT('test', TO_STRING(i)) } WITH { foobar: true } IN users OPTIONS { waitForSync: true }
REPLACE { _key: CONCAT('test', i) } WITH { foobar: true } IN users OPTIONS { waitForSync: true }
```
!SUBSUBSECTION Returning the modified documents
The modified documents can also be returned by the query. In this case, the `REPLACE`
statement must be directly followed by a special `LET` statement and a `RETURN`
statement. The `LET` statement is limited to assigning either the pseudo-value `OLD`
or `NEW` to a variable, and the `RETURN` statement is limited to returning this variable.
The `OLD` pseudo-value refers to the document revisions before the update, and `NEW`
refers to document revisions after the update.
```
REPLACE document IN collection options LET variable-name = OLD RETURN variable-name
REPLACE document IN collection options LET variable-name = NEW RETURN variable-name
REPLACE key-expression WITH document IN collection options LET variable-name = OLD RETURN variable-name
REPLACE key-expression WITH document IN collection options LET variable-name = NEW RETURN variable-name
```
Following is an example using a variable named `previous` to return the original
documents before modification:
```
FOR u IN users
REPLACE u WITH { value: "test" } LET previous = OLD RETURN previous
```
The following query uses the `NEW` pseudo-value to return the replaced
documents:
```
FOR u IN users
REPLACE u WITH { value: "test" } LET replaced = NEW RETURN replaced
```
In both cases, the returned documents will contain all attributes, even
those not specified in the replace expression.
!SUBSECTION INSERT
The *INSERT* keyword can be used to insert new documents into a collection. On a
@ -728,12 +829,14 @@ FOR u IN users
INSERT { _from: u._id, _to: p._id } IN recommendations
```
!SUBSUBSECTION Setting query options
*options* can be used to suppress query errors that may occur when violating unique
key constraints:
```
FOR i IN 1..1000
INSERT { _key: CONCAT('test', TO_STRING(i)), name: "test" } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
INSERT { _key: CONCAT('test', i), name: "test" } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
```
To make sure data are durable when an insert query returns, there is the *waitForSync*
@ -741,5 +844,27 @@ query option:
```
FOR i IN 1..1000
INSERT { _key: CONCAT('test', TO_STRING(i)), name: "test" } WITH { foobar: true } IN users OPTIONS { waitForSync: true }
INSERT { _key: CONCAT('test', i), name: "test" } WITH { foobar: true } IN users OPTIONS { waitForSync: true }
```
!SUBSUBSECTION Returning the inserted documents
The inserted documents can also be returned by the query. In this case, the `INSERT`
statement must be directly followed by a special `LET` statement and a `RETURN`
statement. The `LET` statement is limited to assigning the pseudo-value `NEW`
to a variable, and the `RETURN` statement is limited to returning this variable:
```
INSERT document IN collection options LET variable-name = OLD RETURN variable-name
```
Following is an example using a variable named `inserted` to return the inserted
documents:
```
FOR i IN 1..100
INSERT { value: i } LET inserted = NEW RETURN inserted
```
The returned documents will contain all attributes, even those auto-generated by
the database (e.g. `_id`, `_key`, `_rev`, `_from`, and `_to`).

View File

@ -167,7 +167,7 @@ is available that describes how to compile ArangoDB from source on Ubuntu.
Verify that your system contains
* the GNU C/C++ compilers "gcc" and "g++" and the standard C/C++ libraries, with support
for C++11. You will need version gcc number 4.8.1 or higher. For "clang" and "clang++",
for C++11. You will need version gcc 4.8.1 or higher. For "clang" and "clang++",
you will need at least version 3.4.
* the GNU autotools (autoconf, automake)
* GNU make
@ -278,8 +278,12 @@ the code.
This option activates additional code in the server that intentionally makes the
server crash or misbehave (e.g. by pretending the system ran out of memory). This
option is useful to test the recovery after a crash and also several edge cases.
option is useful for writing tests.
`--enable-v8-debug`
Builds a debug version of the V8 library. This is useful only when working on the
V8 integration inside ArangoDB.
!SUBSECTION Compiling Go

View File

@ -99,6 +99,39 @@ statement and move the random iteration into the appropriate `EnumerateCollectio
This is usually more efficient than individually enumerating and sorting.
!SUBSECTION Data-modification queries returning documents
`INSERT`, `REMOVE`, `UPDATE` or `REPLACE` queries now can optionally return
the documents inserted, removed, updated, or replaced. This is helpful for tracking
the auto-generated attributes (e.g. `_key`, `_rev`) created by an `INSERT` and in
a lot of other situations.
In order to return documents from a data-modification query, the statement must
immediately be immediately followed by a `LET` statement that assigns either the
pseudo-value `NEW` or `OLD` to a variable. This `LET` statement must be followed
by a `RETURN` statement that returns the variable introduced by `LET`:
FOR i IN 1..100
INSERT { value: i } IN test LET inserted = NEW RETURN inserted
FOR u IN users
FILTER u.status == 'deleted'
REMOVE u IN users LET removed = OLD RETURN removed
FOR u IN users
FILTER u.status == 'not active'
UPDATE u WITH { status: 'inactive' } IN users LET updated = NEW RETURN updated
`NEW` refers to the inserted or modified document revision, and `OLD` refers
to the document revision before update or removal. `INSERT` statements can
only refer to the `NEW` pseudo-value, and `REMOVE` operations only to `OLD`.
`UPDATE` and `REPLACE` can refer to either.
In all cases the full documents will be returned with all their attributes,
including the potentially auto-generated attributes such as `_id`, `_key`, or `_rev`
and the attributes not specified in the update expression of a partial update.
!SUBSECTION Language improvements
!SUBSUBSECTION `COUNT` clause

View File

@ -109,7 +109,7 @@ bool Parser::configureWriteQuery (QueryType type,
case AQL_QUERY_REMOVE:
if (newOld != nullptr) {
if (! TRI_CaseEqualString(newOld, "OLD")) {
_query->registerError(TRI_ERROR_QUERY_PARSE, "OLD expected");
_query->registerError(TRI_ERROR_QUERY_PARSE, "remove operations can only refer to 'OLD' value");
return false;
}
}
@ -118,7 +118,7 @@ bool Parser::configureWriteQuery (QueryType type,
case AQL_QUERY_INSERT:
if (newOld != nullptr) {
if (! TRI_CaseEqualString(newOld, "NEW")) {
_query->registerError(TRI_ERROR_QUERY_PARSE, "NEW expected");
_query->registerError(TRI_ERROR_QUERY_PARSE, "insert operations can only refer to 'NEW' value");
return false;
}
}
@ -128,7 +128,7 @@ bool Parser::configureWriteQuery (QueryType type,
case AQL_QUERY_REPLACE:
if (newOld != nullptr) {
if (! TRI_CaseEqualString(newOld, "OLD") && ! TRI_CaseEqualString(newOld, "NEW")) {
_query->registerError(TRI_ERROR_QUERY_PARSE, "NEW or OLD expected");
_query->registerError(TRI_ERROR_QUERY_PARSE, "update/replace operations can only refer to 'NEW' or 'OLD' values");
return false;
}
}
@ -137,7 +137,7 @@ bool Parser::configureWriteQuery (QueryType type,
if (varInto != nullptr && varReturn != nullptr) {
if (! TRI_CaseEqualString(varInto, varReturn)) {
_query->registerError(TRI_ERROR_QUERY_PARSE, "invalid variable used in data-modification operation");
_query->registerError(TRI_ERROR_QUERY_PARSE, "invalid variable used in data-modification operation return value");
return false;
}
}

View File

@ -91,7 +91,7 @@ var validateDeleteGone = function (collection, results) {
assertEqual(collection.document(results[index]._key), {});
fail();
}
catch(e) {
catch (e) {
assertTrue(e.errorNum !== undefined, "unexpected error format while calling checking for deleted entry");
assertEqual(errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code, e.errorNum, "unexpected error code (" + e.errorMessage + "): ");
}
@ -264,6 +264,14 @@ function ahuacatlModifySuite () {
assertQueryError(errors.ERROR_QUERY_PARSE.code, "UPDATE 'abc' WITH { } IN @@cn LET updated = NEW RETURN foo", { "@cn": cn1 });
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test variable names
////////////////////////////////////////////////////////////////////////////////
testInvalidVariableNames3 : function () {
assertQueryError(errors.ERROR_QUERY_PARSE.code, "FOR i IN 1..1 UPDATE 'abc' WITH { } IN @@cn LET updated = NEW RETURN i", { "@cn": cn1 });
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test empty results
////////////////////////////////////////////////////////////////////////////////