diff --git a/arangod/V8Server/V8Traverser.cpp b/arangod/V8Server/V8Traverser.cpp index 36ec50ab54..84fef890d3 100644 --- a/arangod/V8Server/V8Traverser.cpp +++ b/arangod/V8Server/V8Traverser.cpp @@ -381,86 +381,51 @@ unique_ptr TRI_RunShortestPathSearch ( } vector TRI_RunNeighborsSearch ( - v8::Isolate* isolate, - TRI_vocbase_t* vocbase, - std::string const& vertexCollectionName, - std::string const& edgeCollectionName, - std::string const& startVertex, - CollectionNameResolver const* resolver, - TRI_document_collection_t* ecol, + vector& collectionInfos, NeighborsOptions& opts ) { - // Transform string ids to VertexIds - // Needs refactoring! - size_t split; - char const* str = startVertex.c_str(); vector result; - if (!TRI_ValidateDocumentIdKeyGenerator(str, &split)) { - // TODO Error Handling - return result; - } - string collectionName = startVertex.substr(0, split); - - auto coli = resolver->getCollectionStruct(collectionName); - if (coli == nullptr) { - // collection not found - throw TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND; - } if (opts.distinct) { unordered_set distinct; - if (opts.direction == "any") { - auto edges = TRI_LookupEdgesDocumentCollection(ecol, - TRI_EDGE_IN, coli->_cid, const_cast(str + split + 1)); - for (size_t j = 0; j < edges.size(); ++j) { - distinct.insert(extractFromId(edges[j])); + if (opts.direction == TRI_EDGE_IN || opts.direction == TRI_EDGE_ANY) { + TRI_edge_direction_e dir = TRI_EDGE_IN; + for (auto col : collectionInfos) { + auto edges = col->getEdges(dir, opts.start); + for (size_t j = 0; j < edges.size(); ++j) { + distinct.insert(extractFromId(edges[j])); + } } - edges = TRI_LookupEdgesDocumentCollection(ecol, - TRI_EDGE_OUT, coli->_cid, const_cast(str + split + 1)); - for (size_t j = 0; j < edges.size(); ++j) { - distinct.insert(extractToId(edges[j])); - } - } else if (opts.direction == "inbound") { - auto edges = TRI_LookupEdgesDocumentCollection(ecol, - TRI_EDGE_IN, coli->_cid, const_cast(str + split + 1)); - for (size_t j = 0; j < edges.size(); ++j) { - distinct.insert(extractFromId(edges[j])); - } - } else { - auto edges = TRI_LookupEdgesDocumentCollection(ecol, - TRI_EDGE_OUT, coli->_cid, const_cast(str + split + 1)); - for (size_t j = 0; j < edges.size(); ++j) { - distinct.insert(extractToId(edges[j])); + } + if (opts.direction == TRI_EDGE_OUT || opts.direction == TRI_EDGE_ANY) { + TRI_edge_direction_e dir = TRI_EDGE_OUT; + for (auto col : collectionInfos) { + auto edges = col->getEdges(dir, opts.start); + for (size_t j = 0; j < edges.size(); ++j) { + distinct.insert(extractToId(edges[j])); + } } } copy(distinct.begin(), distinct.end(), back_inserter(result)); } else { - if (opts.direction == "any") { - auto edges = TRI_LookupEdgesDocumentCollection(ecol, - TRI_EDGE_IN, coli->_cid, const_cast(str + split + 1)); - for (size_t j = 0; j < edges.size(); ++j) { - result.push_back(extractFromId(edges[j])); + if (opts.direction == TRI_EDGE_IN || opts.direction == TRI_EDGE_ANY) { + TRI_edge_direction_e dir = TRI_EDGE_IN; + for (auto col : collectionInfos) { + auto edges = col->getEdges(dir, opts.start); + for (size_t j = 0; j < edges.size(); ++j) { + result.push_back(extractFromId(edges[j])); + } } - edges = TRI_LookupEdgesDocumentCollection(ecol, - TRI_EDGE_OUT, coli->_cid, const_cast(str + split + 1)); - for (size_t j = 0; j < edges.size(); ++j) { - result.push_back(extractToId(edges[j])); - } - } else if (opts.direction == "inbound") { - auto edges = TRI_LookupEdgesDocumentCollection(ecol, - TRI_EDGE_IN, coli->_cid, const_cast(str + split + 1)); - for (size_t j = 0; j < edges.size(); ++j) { - result.push_back(extractFromId(edges[j])); - } - } else { - auto edges = TRI_LookupEdgesDocumentCollection(ecol, - TRI_EDGE_OUT, coli->_cid, const_cast(str + split + 1)); - for (size_t j = 0; j < edges.size(); ++j) { - result.push_back(extractToId(edges[j])); + } + if (opts.direction == TRI_EDGE_OUT || opts.direction == TRI_EDGE_ANY) { + TRI_edge_direction_e dir = TRI_EDGE_OUT; + for (auto col : collectionInfos) { + auto edges = col->getEdges(dir, opts.start); + for (size_t j = 0; j < edges.size(); ++j) { + result.push_back(extractToId(edges[j])); + } } } } - - return result; }; diff --git a/arangod/V8Server/V8Traverser.h b/arangod/V8Server/V8Traverser.h index cecb02d39e..8366ba10bf 100644 --- a/arangod/V8Server/V8Traverser.h +++ b/arangod/V8Server/V8Traverser.h @@ -44,10 +44,10 @@ struct VertexId { TRI_voc_cid_t cid; char const* key; - VertexId() : cid(0), key(nullptr) { + VertexId () : cid(0), key(nullptr) { } - VertexId( TRI_voc_cid_t cid, char const* key) + VertexId (TRI_voc_cid_t cid, char const* key) : cid(cid), key(key) { } @@ -77,7 +77,7 @@ struct VertexFilterInfo { TRI_transaction_collection_t* col; triagens::arango::ExampleMatcher* matcher; - VertexFilterInfo( + VertexFilterInfo ( triagens::arango::ExplicitTransaction* trx, TRI_transaction_collection_t* col, triagens::arango::ExampleMatcher* matcher @@ -126,7 +126,7 @@ namespace triagens { useEdgeFilter(false) { } - void addEdgeFilter( + void addEdgeFilter ( v8::Isolate* isolate, v8::Handle const& example, TRI_shaper_t* shaper, @@ -134,7 +134,7 @@ namespace triagens { std::string& errorMessage ); - void addVertexFilter( + void addVertexFilter ( v8::Isolate* isolate, v8::Handle const& example, triagens::arango::ExplicitTransaction* trx, @@ -144,20 +144,21 @@ namespace triagens { std::string& errorMessage ); - void addFinalVertex(VertexId& v); + void addFinalVertex (VertexId& v); - bool matchesEdge(EdgeId& e, TRI_doc_mptr_copy_t* edge) const; - - bool matchesVertex(VertexId& v) const; + bool matchesEdge (EdgeId& e, TRI_doc_mptr_copy_t* edge) const; + bool matchesVertex (VertexId& v) const; }; - struct NeighborsOptions { - std::string direction; - bool distinct; - NeighborsOptions() : - direction("outbound"), - distinct(false) { + struct NeighborsOptions { + TRI_edge_direction_e direction; + bool distinct; + VertexId start; + + NeighborsOptions () : + direction(TRI_EDGE_OUT), + distinct(true) { } }; @@ -292,13 +293,7 @@ std::unique_ptr TRI_RunShortestPathSearch ( //////////////////////////////////////////////////////////////////////////////// std::vector TRI_RunNeighborsSearch ( - v8::Isolate* isolate, - TRI_vocbase_t* vocbase, - std::string const& vertexCollectionName, - std::string const& edgeCollectionName, - std::string const& startVertex, - triagens::arango::CollectionNameResolver const* resolver, - TRI_document_collection_t* ecol, + std::vector& collectionInfos, triagens::basics::traverser::NeighborsOptions& opts ); diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index 8d216e3aba..2ec706526c 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -1669,7 +1669,7 @@ static ExplicitTransaction* beginTransaction( // Abort the collection and free the pointers trx->abort(); delete trx; - throw e; + throw; } return trx; } @@ -1854,7 +1854,7 @@ static void JS_QueryShortestPath (const v8::FunctionCallbackInfo& arg unordered_set vertexCollectionNames; v8ArrayToStrings(args[0], vertexCollectionNames); - // get the vertex collections + // get the edge collections if (! args[1]->IsArray()) { TRI_V8_THROW_TYPE_ERROR("expecting array for "); } @@ -2033,8 +2033,15 @@ static void JS_QueryShortestPath (const v8::FunctionCallbackInfo& arg } } - opts.start = idStringToVertexId(resolver, startVertex); - opts.end = idStringToVertexId(resolver, targetVertex); + try { + opts.start = idStringToVertexId(resolver, startVertex); + opts.end = idStringToVertexId(resolver, targetVertex); + } catch (int e) { + // Id string might have illegal collection name + trx->finish(e); + delete trx; + TRI_V8_THROW_EXCEPTION(e); + } try { path = TRI_RunShortestPathSearch( @@ -2074,54 +2081,27 @@ static v8::Handle vertexIdsToV8(v8::Isolate* isolate, CollectionNameResolver const* resolver, vector& ids, unordered_map& barriers, - bool includeData = false, - bool includeDuplicates = true) { + bool includeData = false) { v8::EscapableHandleScope scope(isolate); - v8::Handle result = v8::Object::New(isolate); + uint32_t const vn = static_cast(ids.size()); + v8::Handle vertices = v8::Array::New(isolate, static_cast(vn)); - if (includeDuplicates) { - uint32_t const vn = static_cast(ids.size()); - v8::Handle vertices = v8::Array::New(isolate, static_cast(vn)); - - if (includeData) { - for (uint32_t j = 0; j < vn; ++j) { - vertices->Set(j, vertexIdToData(isolate, resolver, trx, barriers, ids[j])); - } - } else { - for (uint32_t j = 0; j < vn; ++j) { - vertices->Set(j, vertexIdToString(isolate, resolver, ids[j])); - } + if (includeData) { + for (uint32_t j = 0; j < vn; ++j) { + vertices->Set(j, vertexIdToData(isolate, resolver, trx, barriers, ids[j])); } - result->Set(TRI_V8_STRING("vertices"), vertices); - return scope.Escape(result); } else { - // set uniqueIds(ids.begin(), ids.end()); - // TODO - auto uniqueIds = ids; - uint32_t const vn = static_cast(uniqueIds.size()); - v8::Handle vertices = v8::Array::New(isolate, static_cast(vn)); - auto iterator = uniqueIds.begin(); - if (includeData) { - for (uint32_t j = 0; j < vn; ++j) { - vertices->Set(j, vertexIdToData(isolate, resolver, trx, barriers, *iterator)); - ++iterator; - } - } else { - for (uint32_t j = 0; j < vn; ++j) { - vertices->Set(j, vertexIdToString(isolate, resolver, *iterator)); - ++iterator; - } + for (uint32_t j = 0; j < vn; ++j) { + vertices->Set(j, vertexIdToString(isolate, resolver, ids[j])); } - result->Set(TRI_V8_STRING("vertices"), vertices); - return scope.Escape(result); - } + return scope.Escape(vertices); }; //////////////////////////////////////////////////////////////////////////////// -/// @brief Executes a shortest Path Traversal +/// @brief Executes a Neighbors computation //////////////////////////////////////////////////////////////////////////////// static void JS_QueryNeighbors (const v8::FunctionCallbackInfo& args) { @@ -2129,74 +2109,88 @@ static void JS_QueryNeighbors (const v8::FunctionCallbackInfo& args) v8::HandleScope scope(isolate); if (args.Length() < 3 || args.Length() > 4) { - TRI_V8_THROW_EXCEPTION_USAGE("CPP_NEIGHBORS(, , , )"); + TRI_V8_THROW_EXCEPTION_USAGE("CPP_NEIGHBORS(, , , )"); } - TRI_vocbase_t* vocbase; - - vocbase = GetContextVocBase(isolate); - - // get the vertex collection - if (! args[0]->IsString()) { - TRI_V8_THROW_TYPE_ERROR("expecting string for "); + // get the vertex collections + if (! args[0]->IsArray()) { + TRI_V8_THROW_TYPE_ERROR("expecting array for "); } - string vertexCollectionName = TRI_ObjectToString(args[0]); + unordered_set vertexCollectionNames; + v8ArrayToStrings(args[0], vertexCollectionNames); - // get the edge collection - if (! args[1]->IsString()) { - TRI_V8_THROW_TYPE_ERROR("expecting string for "); + // get the edge collections + if (! args[1]->IsArray()) { + TRI_V8_THROW_TYPE_ERROR("expecting array for "); } - string const edgeCollectionName = TRI_ObjectToString(args[1]); + unordered_set edgeCollectionNames; + v8ArrayToStrings(args[1], edgeCollectionNames); - vocbase = GetContextVocBase(isolate); + TRI_vocbase_t* vocbase = GetContextVocBase(isolate); if (vocbase == nullptr) { TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } if (! args[2]->IsString()) { - TRI_V8_THROW_TYPE_ERROR("expecting string for "); + TRI_V8_THROW_TYPE_ERROR("expecting id for "); } string const startVertex = TRI_ObjectToString(args[2]); - - // TODO Option parsing traverser::NeighborsOptions opts; + bool includeData = false; + v8::Handle vertexExample; if (args.Length() == 4) { if (! args[3]->IsObject()) { TRI_V8_THROW_TYPE_ERROR("expecting json for "); } v8::Handle options = args[3]->ToObject(); - v8::Local keyDirection = TRI_V8_ASCII_STRING("direction"); - v8::Local keyDistinct= TRI_V8_ASCII_STRING("distinct"); + // Parse direction + v8::Local keyDirection = TRI_V8_ASCII_STRING("direction"); if (options->Has(keyDirection) ) { - opts.direction = TRI_ObjectToString(options->Get(keyDirection)); - if ( opts.direction != "outbound" - && opts.direction != "inbound" - && opts.direction != "any" - ) { + string dir = TRI_ObjectToString(options->Get(keyDirection)); + if (dir == "outbound") { + opts.direction = TRI_EDGE_OUT; + } else if (dir == "inbound") { + opts.direction = TRI_EDGE_IN; + } else if (dir == "any") { + opts.direction = TRI_EDGE_ANY; + } else { TRI_V8_THROW_TYPE_ERROR("expecting direction to be 'outbound', 'inbound' or 'any'"); } } + + // Parse use distinct + v8::Local keyDistinct= TRI_V8_ASCII_STRING("distinct"); if (options->Has(keyDistinct) ) { opts.distinct = TRI_ObjectToBoolean(options->Get(keyDistinct)); } + + // Parse includeData + v8::Local keyIncludeData = TRI_V8_ASCII_STRING("includeData"); + if (options->Has(keyIncludeData)) { + includeData = TRI_ObjectToBoolean(options->Get(keyIncludeData)); + } + } vector readCollections; vector writeCollections; V8ResolverGuard resolverGuard(vocbase); - CollectionNameResolver const* resolver = resolverGuard.getResolver(); - - readCollections.push_back(resolver->getCollectionId(vertexCollectionName)); - readCollections.push_back(resolver->getCollectionId(edgeCollectionName)); - ExplicitTransaction* trx = nullptr; int res = 0; + CollectionNameResolver const* resolver = resolverGuard.getResolver(); + + for (auto it : edgeCollectionNames) { + readCollections.push_back(resolver->getCollectionId(it)); + } + for (auto it : vertexCollectionNames) { + readCollections.push_back(resolver->getCollectionId(it)); + } unordered_map barriers; // Start the transaction @@ -2204,21 +2198,43 @@ static void JS_QueryNeighbors (const v8::FunctionCallbackInfo& args) trx = beginTransaction(vocbase, readCollections, writeCollections, resolver, barriers); } catch (int e) { + // Nothing to clean up. Throw the error to V8 TRI_V8_THROW_EXCEPTION(e); } - TRI_voc_cid_t edgeCid = resolver->getCollectionId(edgeCollectionName); - TRI_ASSERT(barriers.find(edgeCid) != barriers.end()); + vector edgeCollectionInfos; + for(auto it : edgeCollectionNames) { + auto cid = resolver->getCollectionId(it); + auto colObj = barriers.find(cid)->second.col->_collection->_collection; + edgeCollectionInfos.push_back(new EdgeCollectionInfo( + cid, + colObj, + HopWeightCalculator() + )); + } + + vector vertexCollectionInfos; + for(auto it : vertexCollectionNames) { + auto cid = resolver->getCollectionId(it); + auto colObj = barriers.find(cid)->second.col; + vertexCollectionInfos.push_back(new VertexCollectionInfo( + cid, + colObj + )); + } + + try { + opts.start = idStringToVertexId(resolver, startVertex); + } catch (int e) { + // Id string might have illegal collection name + trx->finish(e); + delete trx; + TRI_V8_THROW_EXCEPTION(e); + } vector neighbors; try { neighbors = TRI_RunNeighborsSearch( - isolate, - vocbase, - vertexCollectionName, - edgeCollectionName, - startVertex, - resolver, - barriers.find(edgeCid)->second.col->_collection->_collection, + edgeCollectionInfos, opts ); } catch (int e) { @@ -2227,7 +2243,7 @@ static void JS_QueryNeighbors (const v8::FunctionCallbackInfo& args) TRI_V8_THROW_EXCEPTION(e); } - auto result = vertexIdsToV8(isolate, trx, resolver, neighbors, barriers, true); + auto result = vertexIdsToV8(isolate, trx, resolver, neighbors, barriers, includeData); trx->finish(res); delete trx; diff --git a/js/server/modules/org/arangodb/aql.js b/js/server/modules/org/arangodb/aql.js index 5ef50bc84c..a41190615e 100644 --- a/js/server/modules/org/arangodb/aql.js +++ b/js/server/modules/org/arangodb/aql.js @@ -6490,15 +6490,17 @@ function AQL_NEIGHBORS (vertexCollection, edgeCollection, vertex, direction, - examples) { + examples, + options) { 'use strict'; vertex = TO_ID(vertex, vertexCollection); - /* + options = options || {}; + options.direction = direction; + options.examples = examples; if (examples === undefined) { - return [CPP_NEIGHBORS(vertexCollection, edgeCollection, vertex, {direction: direction})]; + return CPP_NEIGHBORS([vertexCollection], [edgeCollection], vertex, options); } - */ var edges = AQL_EDGES(edgeCollection, vertex, direction); return FILTERED_EDGES(edges, vertex, direction, examples); diff --git a/js/server/tests/aql-graph.js b/js/server/tests/aql-graph.js index 5698b4c766..267d2fc1ac 100644 --- a/js/server/tests/aql-graph.js +++ b/js/server/tests/aql-graph.js @@ -150,26 +150,38 @@ function ahuacatlQueryEdgesTestSuite () { testNeighborsAny : function () { var actual; + var v1 = "UnitTestsAhuacatlVertex/v1"; + var v2 = "UnitTestsAhuacatlVertex/v2"; + var v3 = "UnitTestsAhuacatlVertex/v3"; + var v4 = "UnitTestsAhuacatlVertex/v4"; + var v5 = "UnitTestsAhuacatlVertex/v5"; + var v6 = "UnitTestsAhuacatlVertex/v6"; + var v7 = "UnitTestsAhuacatlVertex/v7"; + var v8 = "UnitTestsAhuacatlVertex/v8"; + var theFox = "UnitTestsAhuacatlVertex/thefox"; + var queryStart = "FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, '"; + var queryEnd = "', 'any') SORT n RETURN n"; - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v1', 'any') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]"); - assertEqual(actual, [ [ "v2", "v1->v2" ], [ "v3", "v1->v3" ] ]); + actual = getQueryResults(queryStart + v1 + queryEnd); + assertEqual(actual, [ v2, v3 ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v2', 'any') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]"); - assertEqual(actual, [ [ "v1", "v1->v2" ], [ "v3", "v2->v3" ], [ "v4", "v4->v2" ] ]); + actual = getQueryResults(queryStart + v2 + queryEnd); + assertEqual(actual, [ v1, v3, v4 ]); + + // v6 and v7 are neighbors twice + actual = getQueryResults(queryStart + v3 + queryEnd); + assertEqual(actual, [ v1, v2, v4, v6, v7 ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v3', 'any') SORT n.vertex._key, n.edge.what RETURN [ n.vertex._key, n.edge.what ]"); - assertEqual(actual, [ [ "v1", "v1->v3"], [ "v2", "v2->v3" ], [ "v4", "v3->v4" ], [ "v6", "v3->v6" ], [ "v6", "v6->v3"], [ "v7", "v3->v7" ], [ "v7", "v7->v3" ] ]); - - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v8', 'any') SORT n.vertex._key RETURN n.vertex._key"); + actual = getQueryResults(queryStart + v8 + queryEnd); assertEqual(actual, [ ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v5', 'any') SORT n.vertex._key RETURN n.vertex._key"); + actual = getQueryResults(queryStart + v5 + queryEnd); assertEqual(actual, [ ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/thefox', 'any') SORT n.vertex._key RETURN n.vertex._key"); + actual = getQueryResults(queryStart + theFox + queryEnd); assertEqual(actual, [ ]); - assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "FOR e IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'thefox/thefox', 'any') SORT n.vertex._key RETURN n.vertex._key"); + assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, queryStart + "thefox/thefox" + queryEnd); }, //////////////////////////////////////////////////////////////////////////////// @@ -178,26 +190,37 @@ function ahuacatlQueryEdgesTestSuite () { testNeighborsIn : function () { var actual; + var v1 = "UnitTestsAhuacatlVertex/v1"; + var v2 = "UnitTestsAhuacatlVertex/v2"; + var v3 = "UnitTestsAhuacatlVertex/v3"; + var v4 = "UnitTestsAhuacatlVertex/v4"; + var v5 = "UnitTestsAhuacatlVertex/v5"; + var v6 = "UnitTestsAhuacatlVertex/v6"; + var v7 = "UnitTestsAhuacatlVertex/v7"; + var v8 = "UnitTestsAhuacatlVertex/v8"; + var theFox = "UnitTestsAhuacatlVertex/thefox"; + var queryStart = "FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, '"; + var queryEnd = "', 'inbound') SORT n RETURN n"; - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v1', 'inbound') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]"); + actual = getQueryResults(queryStart + v1 + queryEnd); assertEqual(actual, [ ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v2', 'inbound') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]"); - assertEqual(actual, [ [ "v1", "v1->v2" ], [ "v4", "v4->v2" ] ]); + actual = getQueryResults(queryStart + v2 + queryEnd); + assertEqual(actual, [v1, v4]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v3', 'inbound') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]"); - assertEqual(actual, [ [ "v1", "v1->v3"], [ "v2", "v2->v3" ], [ "v6", "v6->v3"], [ "v7", "v7->v3" ] ]); + actual = getQueryResults(queryStart + v3 + queryEnd); + assertEqual(actual, [v1, v2, v6, v7]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v8', 'inbound') SORT n.vertex._key RETURN n.vertex._key"); + actual = getQueryResults(queryStart + v8 + queryEnd); assertEqual(actual, [ ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v5', 'inbound') SORT n.vertex._key RETURN n.vertex._key"); + actual = getQueryResults(queryStart + v5 + queryEnd); assertEqual(actual, [ ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/thefox', 'inbound') SORT n.vertex._key RETURN n.vertex._key"); + actual = getQueryResults(queryStart + theFox + queryEnd); assertEqual(actual, [ ]); - assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "FOR e IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'thefox/thefox', 'inbound') SORT n.vertex._key RETURN n.vertex._key"); + assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, queryStart + "thefox/thefox" + queryEnd); }, //////////////////////////////////////////////////////////////////////////////// @@ -234,26 +257,37 @@ function ahuacatlQueryEdgesTestSuite () { testNeighborsOut : function () { var actual; + var v1 = "UnitTestsAhuacatlVertex/v1"; + var v2 = "UnitTestsAhuacatlVertex/v2"; + var v3 = "UnitTestsAhuacatlVertex/v3"; + var v4 = "UnitTestsAhuacatlVertex/v4"; + var v5 = "UnitTestsAhuacatlVertex/v5"; + var v6 = "UnitTestsAhuacatlVertex/v6"; + var v7 = "UnitTestsAhuacatlVertex/v7"; + var v8 = "UnitTestsAhuacatlVertex/v8"; + var theFox = "UnitTestsAhuacatlVertex/thefox"; + var queryStart = "FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, '"; + var queryEnd = "', 'outbound') SORT n RETURN n"; - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v1', 'outbound') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]"); - assertEqual(actual, [ [ "v2", "v1->v2" ], [ "v3", "v1->v3" ] ]); + actual = getQueryResults(queryStart + v1 + queryEnd); + assertEqual(actual, [ v2, v3 ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v2', 'outbound') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]"); - assertEqual(actual, [ [ "v3", "v2->v3" ] ]); + actual = getQueryResults(queryStart + v2 + queryEnd); + assertEqual(actual, [ v3 ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v3', 'outbound') SORT n.vertex._key RETURN n.vertex._key"); - assertEqual(actual, [ "v4", "v6", "v7" ]); + actual = getQueryResults(queryStart + v3 + queryEnd); + assertEqual(actual, [ v4, v6, v7 ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v8', 'outbound') SORT n.vertex._key RETURN n.vertex._key"); - assertEqual(actual, [ ]); - - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v5', 'outbound') SORT n.vertex._key RETURN n.vertex._key"); + actual = getQueryResults(queryStart + v8 + queryEnd); assertEqual(actual, [ ]); - actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/thefox', 'outbound') SORT n.vertex._key RETURN n.vertex._key"); + actual = getQueryResults(queryStart + v5 + queryEnd); assertEqual(actual, [ ]); - assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "FOR e IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'thefox/thefox', 'outbound') SORT n.vertex._key RETURN n.vertex._key"); + actual = getQueryResults(queryStart + theFox + queryEnd); + assertEqual(actual, [ ]); + + assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, queryStart + "thefox/thefox" + queryEnd); } };