From 5233ea544a45ff47eb033c984333819b91e3ea0a Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Thu, 23 Jun 2016 12:07:36 +0200 Subject: [PATCH 01/22] Fix exit code handling of example generator, so we actualy fail for the caller if something goes wrong. --- utils/generateExamples.js | 4 ++++ utils/generateExamples.sh | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/utils/generateExamples.js b/utils/generateExamples.js index 0e80459b75..89da0e8916 100644 --- a/utils/generateExamples.js +++ b/utils/generateExamples.js @@ -245,6 +245,10 @@ function main(argv) { } } + if (res.exit != 0) { + throw("generating examples failed!"); + } + return 0; } diff --git a/utils/generateExamples.sh b/utils/generateExamples.sh index b6a6cc7085..9f04462b59 100755 --- a/utils/generateExamples.sh +++ b/utils/generateExamples.sh @@ -39,7 +39,9 @@ ${ARANGOSH} \ -- \ "$@" -if test $? -eq 0; then +rc=$? + +if test $rc -eq 0; then echo "removing ${LOGFILE} ${DBDIR}" rm -rf ${LOGFILE} ${DBDIR} arangosh.examples.js else @@ -47,4 +49,4 @@ else cat ${LOGFILE} fi -echo Server has terminated. +exit $rc From 1d524bcad23473efb7a219b369723528fdbe0e55 Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Thu, 23 Jun 2016 12:09:09 +0200 Subject: [PATCH 02/22] one more place where exit codes should be passed up in the process pipeline. --- utils/generateSwagger.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/generateSwagger.sh b/utils/generateSwagger.sh index 0d3e3365f9..e0fe9a7536 100755 --- a/utils/generateSwagger.sh +++ b/utils/generateSwagger.sh @@ -1,6 +1,6 @@ #!/bin/bash -python \ +exec python \ `pwd`/utils/generateSwagger.py \ `pwd` \ `pwd`/js/apps/system/_admin/aardvark/APP/api-docs \ From 7496fa2c677faf0612720d0d011f902fc088e522 Mon Sep 17 00:00:00 2001 From: jsteemann Date: Thu, 23 Jun 2016 12:13:55 +0200 Subject: [PATCH 03/22] issue #1894: make list of edge collections unique in traversal --- .../Books/AQL/Graphs/Traversals.mdpp | 3 ++ arangod/Aql/TraversalNode.cpp | 31 ++++++++++++++--- js/server/tests/aql/aql-graph-traverser.js | 34 ++++++++++++++++++- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/Documentation/Books/AQL/Graphs/Traversals.mdpp b/Documentation/Books/AQL/Graphs/Traversals.mdpp index 1211e4e56a..705120baf0 100644 --- a/Documentation/Books/AQL/Graphs/Traversals.mdpp +++ b/Documentation/Books/AQL/Graphs/Traversals.mdpp @@ -160,6 +160,9 @@ FOR vertex[, edge[, path]] Instead of `GRAPH graphName` you may specify a list of edge collections. Vertex collections are determined by the edges in the edge collections. The rest of the behavior is similar to the named version. +If the same edge collection is specified multiple times, it will behave as if it +were specified only once. Specifying the same edge collection is only allowed when +the collections do not have conflicting traversal directions. !SUBSECTION Traversing in mixed directions diff --git a/arangod/Aql/TraversalNode.cpp b/arangod/Aql/TraversalNode.cpp index e5f29b7efe..6f70e64644 100644 --- a/arangod/Aql/TraversalNode.cpp +++ b/arangod/Aql/TraversalNode.cpp @@ -171,6 +171,8 @@ TraversalNode::TraversalNode(ExecutionPlan* plan, size_t id, "invalid traversal depth"); } + std::unordered_map seenCollections; + if (graph->type == NODE_TYPE_COLLECTION_LIST) { size_t edgeCollectionCount = graph->numMembers(); _graphJson = arangodb::basics::Json(arangodb::basics::Json::Array, @@ -180,16 +182,32 @@ TraversalNode::TraversalNode(ExecutionPlan* plan, size_t id, // List of edge collection names for (size_t i = 0; i < edgeCollectionCount; ++i) { auto col = graph->getMember(i); + TRI_edge_direction_e dir = TRI_EDGE_ANY; + if (col->type == NODE_TYPE_DIRECTION) { // We have a collection with special direction. - TRI_edge_direction_e dir = parseDirection(col->getMember(0)); - _directions.emplace_back(dir); + dir = parseDirection(col->getMember(0)); col = col->getMember(1); } else { - _directions.emplace_back(baseDirection); + dir = baseDirection; } - + std::string eColName = col->getString(); + + // now do some uniqueness checks for the specified collections + auto it = seenCollections.find(eColName); + if (it != seenCollections.end()) { + if ((*it).second != dir) { + std::string msg("conflicting directions specified for collection '" + + std::string(eColName)); + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID, + msg); + } + // do not re-add the same collection! + continue; + } + seenCollections.emplace(eColName, dir); + auto eColType = resolver->getCollectionTypeCluster(eColName); if (eColType != TRI_COL_TYPE_EDGE) { std::string msg("collection type invalid for collection '" + @@ -198,8 +216,10 @@ TraversalNode::TraversalNode(ExecutionPlan* plan, size_t id, THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID, msg); } + + _directions.emplace_back(dir); _graphJson.add(arangodb::basics::Json(eColName)); - _edgeColls.push_back(eColName); + _edgeColls.emplace_back(eColName); } } else { if (_edgeColls.empty()) { @@ -252,6 +272,7 @@ TraversalNode::TraversalNode(ExecutionPlan* plan, size_t id, // Parse options node } +/// @brief Internal constructor to clone the node. TraversalNode::TraversalNode( ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase, std::vector const& edgeColls, Variable const* inVariable, diff --git a/js/server/tests/aql/aql-graph-traverser.js b/js/server/tests/aql/aql-graph-traverser.js index fa19f9a555..8da08c84cd 100644 --- a/js/server/tests/aql/aql-graph-traverser.js +++ b/js/server/tests/aql/aql-graph-traverser.js @@ -2113,8 +2113,40 @@ function multiEdgeDirectionSuite () { result = db._query(item.q2, bindVars2).toArray(); assertEqual(result, item.res); }); - } + }, + testDuplicationCollections: function () { + var queries = [ + [ "FOR x IN ANY @start @@ec, INBOUND @@ec RETURN x", false ], + [ "FOR x IN ANY @start @@ec, OUTBOUND @@ec RETURN x", false ], + [ "FOR x IN ANY @start @@ec, ANY @@ec RETURN x", true ], + [ "FOR x IN INBOUND @start @@ec, INBOUND @@ec RETURN x", true ], + [ "FOR x IN INBOUND @start @@ec, OUTBOUND @@ec RETURN x", false ], + [ "FOR x IN INBOUND @start @@ec, ANY @@ec RETURN x", false ], + [ "FOR x IN OUTBOUND @start @@ec, INBOUND @@ec RETURN x", false ], + [ "FOR x IN OUTBOUND @start @@ec, OUTBOUND @@ec RETURN x", true ], + [ "FOR x IN OUTBOUND @start @@ec, ANY @@ec RETURN x", false ] + ]; + + var bindVars = { + "@ec": en, + start: vertex.A + }; + queries.forEach(function (query) { + if (query[1]) { + // should work + db._query(query[0], bindVars).toArray(); + } else { + // should fail + try { + db._query(query[0], bindVars).toArray(); + fail(); + } catch (e) { + assertEqual(e.errorNum, errors.ERROR_ARANGO_COLLECTION_TYPE_INVALID.code); + } + } + }); + } }; } From f4996c3bd5d7c626d2a056ba43b89867f060535d Mon Sep 17 00:00:00 2001 From: Simran Brucherseifer Date: Wed, 22 Jun 2016 16:01:42 +0200 Subject: [PATCH 04/22] Initial content for CommonErrors and TODOs --- Documentation/Books/AQL/CommonErrors.mdpp | 41 +++++++++++++++++++ Documentation/Books/AQL/Functions/String.mdpp | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/Documentation/Books/AQL/CommonErrors.mdpp b/Documentation/Books/AQL/CommonErrors.mdpp index 15f3f1cb14..f6e798ab4f 100644 --- a/Documentation/Books/AQL/CommonErrors.mdpp +++ b/Documentation/Books/AQL/CommonErrors.mdpp @@ -1 +1,42 @@ !CHAPTER Common Errors + +!SECTION String concatenation + +In AQL, strings must be concatenated using the [CONCAT()](Functions/String.md#concat) +function. Joining them together with the `+` operator is not supported. Especially +as JavaScript programmer it is easy to walk into this trap: + +```js +RETURN "foo" + "bar" // [ 0 ] +RETURN "foo" + 123 // [ 123 ] +RETURN "123" + 200 // [ 323 ] +``` + +The arithmetic plus operator expects numbers as operands, and will try to implicitly +cast them to numbers if they are of different type. `"foo"` and `"bar"` are casted +to `0` and then added to together (still zero). If an actual number is added, that +number will be returned (adding zero doesn't change the result). If the string is a +valid string representation of a number, then it is casted to a number. Thus, adding +`"123"` and `200` results in two numbers being added up to `323`. + +To concatenate elements (with implicit casting to string for non-string values), do: + +```js +RETURN CONCAT("foo", "bar") // [ "foobar" ] +RETURN CONCAT("foo", 123) // [ "foo123" ] +RETURN CONCAT("123", 200) // [ "123200" ] +``` + + \ No newline at end of file diff --git a/Documentation/Books/AQL/Functions/String.mdpp b/Documentation/Books/AQL/Functions/String.mdpp index 261390675d..99e342460e 100644 --- a/Documentation/Books/AQL/Functions/String.mdpp +++ b/Documentation/Books/AQL/Functions/String.mdpp @@ -64,8 +64,8 @@ CONCAT_SEPARATOR(", ", [ "foo", "bar", "baz" ]) CONCAT_SEPARATOR(", ", [ "foo", [ "b", "a", "r" ], "baz" ]) // [ "foo, b,a,r, baz" ] -/* "1-2-3-4-5" */ CONCAT_SEPARATOR("-", [1, 2, 3, null], [4, null, 5]) +// "1-2-3-4-5" ``` !SUBSECTION CONTAINS() From dfb898aa887db1d7bc604f31a1f52c672260a563 Mon Sep 17 00:00:00 2001 From: Simran Brucherseifer Date: Thu, 23 Jun 2016 12:04:28 +0200 Subject: [PATCH 05/22] Minor reformatting of docs --- .../Books/AQL/Examples/Grouping.mdpp | 104 +++--------------- Documentation/Books/Manual/Graphs/README.mdpp | 9 +- 2 files changed, 22 insertions(+), 91 deletions(-) diff --git a/Documentation/Books/AQL/Examples/Grouping.mdpp b/Documentation/Books/AQL/Examples/Grouping.mdpp index 741f033fbb..3f1519c303 100644 --- a/Documentation/Books/AQL/Examples/Grouping.mdpp +++ b/Documentation/Books/AQL/Examples/Grouping.mdpp @@ -54,39 +54,11 @@ FOR u IN users ```json [ - { - "age": 37, - "users": [ - "John", - "Sophia" - ] - }, - { - "age": 36, - "users": [ - "Fred", - "Emma" - ] - }, - { - "age": 34, - "users": [ - "Madison" - ] - }, - { - "age": 33, - "users": [ - "Chloe", - "Michael" - ] - }, - { - "age": 32, - "users": [ - "Alexander" - ] - } + { "age": 37, "users": [ "John", "Sophia" ] }, + { "age": 36, "users": [ "Fred", "Emma" ] }, + { "age": 34, "users": [ "Madison" ] }, + { "age": 33, "users": [ "Chloe", "Michael" ] }, + { "age": 32, "users": [ "Alexander" ] } ] ``` @@ -132,30 +104,12 @@ FOR u IN users ```json [ - { - "ageGroup": 35, - "gender": "f" - }, - { - "ageGroup": 35, - "gender": "m" - }, - { - "ageGroup": 30, - "gender": "f" - }, - { - "ageGroup": 30, - "gender": "m" - }, - { - "ageGroup": 25, - "gender": "f" - }, - { - "ageGroup": 25, - "gender": "m" - } + { "ageGroup": 35, "gender": "f" }, + { "ageGroup": 35, "gender": "m" }, + { "ageGroup": 30, "gender": "f" }, + { "ageGroup": 30, "gender": "m" }, + { "ageGroup": 25, "gender": "f" }, + { "ageGroup": 25, "gender": "m" } ] ``` @@ -180,36 +134,12 @@ FOR u IN users ```json [ - { - "ageGroup": 35, - "gender": "f", - "numUsers": 2 - }, - { - "ageGroup": 35, - "gender": "m", - "numUsers": 2 - }, - { - "ageGroup": 30, - "gender": "f", - "numUsers": 4 - }, - { - "ageGroup": 30, - "gender": "m", - "numUsers": 4 - }, - { - "ageGroup": 25, - "gender": "f", - "numUsers": 2 - }, - { - "ageGroup": 25, - "gender": "m", - "numUsers": 2 - } + { "ageGroup": 35, "gender": "f", "numUsers": 2 }, + { "ageGroup": 35, "gender": "m", "numUsers": 2 }, + { "ageGroup": 30, "gender": "f", "numUsers": 4 }, + { "ageGroup": 30, "gender": "m", "numUsers": 4 }, + { "ageGroup": 25, "gender": "f", "numUsers": 2 }, + { "ageGroup": 25, "gender": "m", "numUsers": 2 } ] ``` diff --git a/Documentation/Books/Manual/Graphs/README.mdpp b/Documentation/Books/Manual/Graphs/README.mdpp index 146fdb654b..f7f49fafad 100644 --- a/Documentation/Books/Manual/Graphs/README.mdpp +++ b/Documentation/Books/Manual/Graphs/README.mdpp @@ -17,19 +17,19 @@ graph databases can handle an arbitrary number of these hops over edge collectio Also edges in one edge collection may point to several vertex collections. Its common to have attributes attached to edges, i.e. a *label* naming this interconnection. Edges have a direction, with their relations `_from` and `_to` pointing *from* one document *to* another document stored in vertex collections. -In queries you can define in which directions the edge relations may be followed (`OUTBOUND`: `_from` → `_to`, `INBOUND`: `_to` → `_from`, `ANY`: `_from` ↔ `_to`). +In queries you can define in which directions the edge relations may be followed (`OUTBOUND`: `_from` → `_to`, `INBOUND`: `_from` ← `_to`, `ANY`: `_from` ↔ `_to`). !SUBSECTION Named Graphs Named graphs are completely managed by arangodb, and thus also [visible in the webinterface](../Administration/WebInterface/Graphs.md). They use the full spectrum of ArangoDBs graph features. You may access them via several interfaces. - - [AQL Graph Operations](../../AQL/Graphs/index.html) with several flavors: +- [AQL Graph Operations](../../AQL/Graphs/index.html) with several flavors: - [AQL Traversals](../../AQL/Graphs/Traversals.html) on both named and anonymous graphs - [AQL Shortest Path](../../AQL/Graphs/ShortestPath.html) on both named and anonymous graph - [The javascript General Graph implementation, as you may use it in Foxx Services](GeneralGraphs/README.md) - * [Graph Management](GeneralGraphs/Management.md); creating & manipualating graph definitions; inserting, updating and deleting vertices and edges into graphs - * [Graph Functions](GeneralGraphs/Functions.md) for working with edges and vertices, to analyze them and their relations + - [Graph Management](GeneralGraphs/Management.md); creating & manipualating graph definitions; inserting, updating and deleting vertices and edges into graphs + - [Graph Functions](GeneralGraphs/Functions.md) for working with edges and vertices, to analyze them and their relations - [the RESTful General Graph interface](../../HTTP/Gharial/index.html) used to implement graph management in client drivers !SUBSUBSECTION Manipulating collections of named graphs with regular document functions @@ -75,6 +75,7 @@ A set of persons knowing each other: The *knows* graph consists of one *vertex collection* `persons` connected via one *edge collection* `knows`. It will contain five persons *Alice*, *Bob*, *Charlie*, *Dave* and *Eve*. We will have the following directed relations: + - *Alice* knows *Bob* - *Bob* knows *Charlie* - *Bob* knows *Dave* From b7f4032696ba642beb52275601a3502ea56593c1 Mon Sep 17 00:00:00 2001 From: Simran Brucherseifer Date: Thu, 23 Jun 2016 12:19:02 +0200 Subject: [PATCH 06/22] Use JS to switch between versions and books --- Documentation/Books/AQL/HEADER.html | 11 ++++----- Documentation/Books/AQL/styles/header.js | 25 +++++++++++++++++++-- Documentation/Books/HTTP/HEADER.html | 11 ++++----- Documentation/Books/HTTP/styles/header.js | 23 ++++++++++++++++++- Documentation/Books/Manual/HEADER.html | 11 ++++----- Documentation/Books/Manual/styles/header.js | 23 ++++++++++++++++++- 6 files changed, 85 insertions(+), 19 deletions(-) diff --git a/Documentation/Books/AQL/HEADER.html b/Documentation/Books/AQL/HEADER.html index 68f47770d2..c032e7ddec 100644 --- a/Documentation/Books/AQL/HEADER.html +++ b/Documentation/Books/AQL/HEADER.html @@ -10,7 +10,8 @@ - + + @@ -25,16 +26,16 @@
  • - Manual + Manual
  • - AQL + AQL
  • - HTTP + HTTP
  • - Cookbook + Cookbook