From ed32dd0a9b0ecdf25a31a2eccfc93c5d80c10de5 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Wed, 12 Jun 2013 16:06:47 +0200 Subject: [PATCH] Started documentation of Traversals. Expander example not yet working --- .../ImplementorManual/HttpTraversals.md | 23 +- js/actions/api-traversal.js | 566 +++++++++++++++++- 2 files changed, 543 insertions(+), 46 deletions(-) diff --git a/Documentation/ImplementorManual/HttpTraversals.md b/Documentation/ImplementorManual/HttpTraversals.md index 1a0ebb2600..d741ceb05c 100644 --- a/Documentation/ImplementorManual/HttpTraversals.md +++ b/Documentation/ImplementorManual/HttpTraversals.md @@ -7,22 +7,17 @@ HTTP Interface for Traversals {#HttpTraversals} Traverals {#HttpTraversalsIntro} ================================ -TODO: FIXME -ArangoDB's transactions are executed on the server. Transactions can be -initiated by clients by sending the transaction description for execution to +ArangoDB's graph traversals are executed on the server. Traversals can be +initiated by clients by sending the traversal description for execution to the server. -Transactions in ArangoDB do not offer seperate `BEGIN`, `COMMIT` and `ROLLBACK` -operations as they are available in many other database products. -Instead, ArangoDB transactions are described by a Javascript function, and the -code inside the Javascript function will then be executed transactionally. -At the end of the function, the transaction is automatically committed, and all -changes done by the transaction will be persisted. If an exception is thrown -during transaction execution, all operations performed in the transaction are -rolled back. - -For a more detailed description of how transactions work in ArangoDB please -refer to @ref Transactions. +Traversals in ArangoDB are used to walk over a graph +stored in one edge collection. It can easily be described +which edges of the graph should be followed and which actions +should be performed on each visited vertex. +Furthermore the ordering of visiting the nodes can be +specified, for instance depth-first or breadth-first search +are offered. Executing Traversals via HTTP {#HttpTraversalsHttp} ======================================================= diff --git a/js/actions/api-traversal.js b/js/actions/api-traversal.js index 76e13fab06..dcedb469e1 100644 --- a/js/actions/api-traversal.js +++ b/js/actions/api-traversal.js @@ -87,49 +87,551 @@ function validateArg (value, map) { /// /// @RESTBODYPARAM{body,string,required} /// -/// TODO: -/// startVertex: id of the startVertex, e.g. "users/foo", mandatory -/// edgeCollection: name of the collection that contains the edges, mandatory -/// filter: body (JavaScript code) of custom filter function, optional +/// @RESTDESCRIPTION +/// Starts a traversal starting from a given vertex and following. +/// edges contained in a given edgeCollection. The request must +/// contain the following attributes. +/// +/// - `startVertex`: id of the startVertex, e.g. `"users/foo"`. +/// +/// - `edgeCollection`: name of the collection that contains the edges. +/// +/// - `filter` (optional, default is to include all nodes): +/// body (JavaScript code) of custom filter function /// function signature: (config, vertex, path) -> mixed -/// can return either undefined (=include), 'exclude', 'prune' or an array of these -/// if no filter is specified, all nodes will be included -/// minDepth: optional minDepth filter value (will be ANDed with any existing filters) -/// maxDepth: optional maxDepth filter value (will be ANDed with any existing filters) -/// visitor: body (JavaScript) code of custom visitor function, optional +/// can return four different string values: +/// - `"exclude"` -> this vertex will not be visited. +/// - `"prune"` -> the edges of this vertex will not be followed. +/// - `""` or `undefined` -> visit the vertex and follow it's edges. +/// - `Array` -> containing any combination of the above. +/// If there is at least one `"exclude"` or `"prune"` respectivly +/// is contained, it's effect will occur. +/// - `minDepth` (optional, ANDed with any existing filters): visits only nodes in at least the given depth +/// - `maxDepth` (optional, ANDed with any existing filters): visits only nodes in at most the given depth +/// - `visitor` (optional): body (JavaScript) code of custom visitor function /// function signature: (config, result, vertex, path) -> void /// visitor function can do anything, but its return value is ignored. To -/// populate a result, use the "result" variable by reference -/// example: "result.visited++; result.myVertices.push(vertex);" -/// direction: direction for traversal, optional -/// if set, must be either "outbound", "inbound", or "any" -/// if not set, the "expander" attribute must be specified -/// init: body (JavaScript) code of custom result initialisation function, optional +/// populate a result, use the `result` variable by reference +/// - `direction` (optional): direction for traversal +/// - *if set*, must be either `"outbound"`, `"inbound"`, or `"any"` +/// - *if not set*, the `expander` attribute must be specified +/// - `init` (optional): body (JavaScript) code of custom result initialisation function /// function signature: (config, result) -> void /// initialise any values in result with what is required -/// example: "result.visited = 0; result.myVertices = [ ];" -/// expander: body (JavaScript) code of custom expander function, optional -/// must be set if "direction" attribute is not set +/// - `expander` (optional): body (JavaScript) code of custom expander function +/// *must* be set if `direction` attribute is *not* set /// function signature: (config, vertex, path) -> array -/// expander must return an array of the connections for "vertex" -/// each connection is an object with the attributes "edge" and "vertex" -/// example: "expander": "var connections = [ ]; config.edgeCollection.outEdges(vertex).forEach(function (e) { connections.push({ vertex: e._to, edge: e }); }); return connections;" -/// strategy: traversal strategy, optional -/// can be "depthfirst" or "breadthfirst" -/// order: traversal order, optional -/// can be "preorder" or "postorder" -/// itemOrder: item iteration order, optional -/// can be "forward" or "backward" -/// uniqueness: specifies uniqueness for vertices and edges visited, optional -/// if set, must be an object like this: "uniqueness": { "vertices": "none"|"global"|path", "edges": "none"|"global"|"path" } +/// expander must return an array of the connections for `vertex` +/// each connection is an object with the attributes `edge` and `vertex` +/// - `strategy` (optional): traversal strategy +/// can be `"depthfirst"` or `"breadthfirst"` +/// - `order` (optional): traversal order +/// can be `"preorder"` or `"postorder"` +/// - `itemOrder` (optional): item iteration order +/// can be `"forward"` or `"backward"` +/// - `uniqueness` (optional): specifies uniqueness for vertices and edges visited +/// if set, must be an object like this: +/// `"uniqueness": {"vertices": "none"|"global"|path", "edges": "none"|"global"|"path"}` /// -/// the "result" object will be returned by the traversal +/// +/// If the Traversal is successfully executed `HTTP 200` will be returned. +/// Additionally the `result` object will be returned by the traversal. +/// +/// For successful traversals, the returned JSON object has the +/// following properties: +/// +/// - `error`: boolean flag to indicate if an error occurred (`false` +/// in this case) +/// +/// - `code`: the HTTP status code +/// +/// - `result`: the return value of the traversal +/// +/// If the traversal specification is either missing or malformed, the server +/// will respond with `HTTP 400`. +/// +/// The body of the response will then contain a JSON object with additional error +/// details. The object has the following attributes: +/// +/// - `error`: boolean flag to indicate that an error occurred (`true` in this case) +/// +/// - `code`: the HTTP status code +/// +/// - `errorNum`: the server error number +/// +/// - `errorMessage`: a descriptive error message /// /// example: /// POST {"edgeCollection": "e", "expander": "var connections = [ ]; config.edgeCollection.outEdges(vertex).forEach(function (e) { connections.push({ vertex: e._to, edge: e }); }); return connections;", "startVertex" : "v/jan", "filter": "return undefined;", "minDepth": 0 } /// -/// @RESTDESCRIPTION -/// TODO +/// @RESTRETURNCODES +/// +/// @RESTRETURNCODE{200} +/// If the traversal is fully executed +/// `HTTP 200` will be returned. +/// +/// @RESTRETURNCODE{400} +/// If the traversal specification is either missing or malformed, the server +/// will respond with `HTTP 400`. +/// +/// @EXAMPLES +/// +/// In the following examples the underlying graph 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` +/// - `Eve` knows `Alice` +/// - `Eve` knows `Bob` +/// +/// The starting vertex will always be Alice. +/// +/// Follow only outbound edges: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalOutbound} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "outbound"}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Follow only inbound edges: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalInbound} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "inbound"}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Follow any direction of edges: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalAny} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "any"}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Excluding `Charlie` and `Bob`: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalFilterExclude} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "outbound", '; +/// body += '"filter" : "if (vertex.name === \\"Bob\\" || '; +/// body += 'vertex.name === \\"Charlie\\") {'; +/// body += 'return \\"exclude\\";' +/// body += '}' +/// body += 'return;"}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Do not follow edges from `Bob`: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalFilterPrune} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "outbound", '; +/// body += '"filter" : "if (vertex.name === \\"Bob\\") {'; +/// body += 'return \\"prune\\";' +/// body += '}' +/// body += 'return;"}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Visit only nodes in a depth of at least 2: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalMinDepth} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "outbound", '; +/// body += '"minDepth" : 2}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Visit only nodes in a depth of at most 1: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalMaxDepth} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "outbound", '; +/// body += '"maxDepth" : 1}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Count all visited nodes and return a list of nodes only: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalVisitorCountAndList} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "outbound", '; +/// body += '"init" : "result.visited = 0; result.myVertices = [ ];", '; +/// body += '"visitor" : "result.visited++; result.myVertices.push(vertex);"}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Expand only inbound edges of `Alice` and outbound edges of `Eve`: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalVisitorExpander} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"expander" : '; +/// body += '"var connections = [ ];'; +/// body += 'if (vertex.name === \\"Alice\\") {'; +/// body += 'config.edgeCollection.inEdges(vertex).forEach(function (e) {'; +/// body += 'connections.push({ vertex: db.document(e._from), edge: e });'; +/// body += '});'; +/// body += '}'; +/// body += 'if (vertex.name === \\"Eve\\") {'; +/// body += 'config.edgeCollection.outEdges(vertex).forEach(function (e) {'; +/// body += 'connections.push({ vertex: db.document(e._to), edge: e });'; +/// body += '});'; +/// body += '}'; +/// body += 'return connections;"}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Follow the `depthfirst` strategy: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalDepthFirst} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "any", '; +/// body += '"strategy" : "depthfirst"}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Using `postorder` ordering: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalPostorder} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "any", '; +/// body += '"order" : "postorder"}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Using `backward` item-ordering: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalBackwardItemOrder} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "any", '; +/// body += '"itemOrder" : "backward"}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Edges should only be included once globally, +/// but nodes are included every time they are visited: +/// +/// @EXAMPLE_ARANGOSH_RUN{RestTraversalEdgeUniqueness} +/// var cv = "persons"; +/// var ce = "knows"; +/// db._drop(cv); +/// db._drop(ce); +/// var users = db._create(cv); +/// var knows = db._createEdgeCollection(ce); +/// var a = users.save({name: "Alice"})._id; +/// var b = users.save({name: "Bob"})._id; +/// var c = users.save({name: "Charlie"})._id; +/// var d = users.save({name: "Dave"})._id; +/// var e = users.save({name: "Eve"})._id; +/// knows.save(a, b, {}); +/// knows.save(b, c, {}); +/// knows.save(b, d, {}); +/// knows.save(e, a, {}); +/// knows.save(e, b, {}); +/// var url = "/_api/traversal"; +/// var body = '{ "startVertex": "' + a + '", '; +/// body += '"edgeCollection" : "' + knows.name() + '", '; +/// body += '"direction" : "any", '; +/// body += '"uniqueness" : {"vertices": "none", "edges": "global"}}'; +/// +/// var response = logCurlRequest('POST', url, body); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// db._drop(cv); +/// db._drop(ce); +/// @END_EXAMPLE_ARANGOSH_RUN //////////////////////////////////////////////////////////////////////////////// function post_api_traversal(req, res) {