1
0
Fork 0

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

This commit is contained in:
Max Neunhoeffer 2015-12-08 20:11:32 +01:00
commit 5465db463d
11 changed files with 406 additions and 63 deletions

View File

@ -9,6 +9,11 @@ v2.8.0 (XXXX-XX-XX)
* fixed cluster upgrade procedure
* the AQL functions `NEAR` and `WITHIN` now have stricter validations
for their input parameters `limit`, `radius` and `distance`. They may now throw
exceptions when invalid parameters are passed that may have not led
to exceptions in previous versions.
v2.8.0-beta1 (2015-12-06)
-------------------------

View File

@ -0,0 +1,78 @@
!CHAPTER Combining Graph Traversals
!SUBSECTION Finding the start vertex via a geo query
Our first example will locate the start vertex for a graph traversal via [a geo index](../IndexHandling/Geo.md).
We use [the city graph](../Graphs/README.md#the-city-graph) and its geo indices:
![Cities Example Graph](../Graphs/cities_graph.png)
@startDocuBlockInline COMBINING_GRAPH_01_create_graph
@EXAMPLE_ARANGOSH_OUTPUT{COMBINING_GRAPH_01_create_graph}
~addIgnoreCollection("germanHighway");
~addIgnoreCollection("germanCity");
~addIgnoreCollection("frenchHighway");
~addIgnoreCollection("frenchCity");
~addIgnoreCollection("internationalHighway");
var examples = require("org/arangodb/graph-examples/example-graph.js");
var g = examples.loadGraph("routeplanner");
var bonn=[50.7340, 7.0998];
|db._query(`FOR startCity IN
| WITHIN(germanCity, @lat, @long, @radius)
| RETURN startCity`,
| {lat: bonn[0], long: bonn[1], radius: 400000}
).toArray()
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock COMBINING_GRAPH_01_create_graph
We search all german cities in a range of 400 km around the ex-capital **Bonn**: **Hambung** and **Cologne**.
We won't find **Paris** since its in the `frenchCity` collection.
@startDocuBlockInline COMBINING_GRAPH_02_combine
@EXAMPLE_ARANGOSH_OUTPUT{COMBINING_GRAPH_02_combine}
~var bonn=[50.7340, 7.0998]
|db._query(`FOR startCity IN
| WITHIN(germanCity, @lat, @long, @radius)
| FOR v, e, p IN 1..1 OUTBOUND startCity
| GRAPH 'routeplanner'
| RETURN {startcity: startCity._key, traversedCity: v}`,
|{
| lat: bonn[0],
| long: bonn[1],
| radius: 400000
} ).toArray()
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock COMBINING_GRAPH_02_combine
The geo index query returns us `startCity` (**Cologne** and **Hamburg**) which we then use as starting point for our graph traversal. For simplicity we only return their direct neighbours. We format the return result so we can see from which `startCity` the traversal came.
Alternatively we could use a `LET` statement with a subquery to group the traversals by their `startCity` efficiently:
@startDocuBlockInline COMBINING_GRAPH_03_combine_let
@EXAMPLE_ARANGOSH_OUTPUT{COMBINING_GRAPH_03_combine_let}
~var bonn=[50.7340, 7.0998];
|db._query(`FOR startCity IN
| WITHIN(germanCity, @lat, @long, @radius)
| LET oneCity = (FOR v, e, p IN 1..1 OUTBOUND startCity
| GRAPH 'routeplanner' RETURN v)
| return {startCity: startCity._key, connectedCities: oneCity}`,
|{
| lat: bonn[0],
| long: bonn[1],
| radius: 400000
} ).toArray();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock COMBINING_GRAPH_03_combine_let
Finaly we clean up again:
@startDocuBlockInline COMBINING_GRAPH_04_cleanup
@EXAMPLE_ARANGOSH_OUTPUT{COMBINING_GRAPH_04_cleanup}
~var examples = require("org/arangodb/graph-examples/example-graph.js");
examples.dropGraph("routeplanner");
~removeIgnoreCollection("germanHighway");
~removeIgnoreCollection("germanCity");
~removeIgnoreCollection("frenchHighway");
~removeIgnoreCollection("frenchCity");
~removeIgnoreCollection("internationalHighway");
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock COMBINING_GRAPH_04_cleanup

View File

@ -102,6 +102,7 @@
* [Projections and filters](AqlExamples/ProjectionsAndFilters.md)
* [Joins](AqlExamples/Join.md)
* [Grouping](AqlExamples/Grouping.md)
* [Traversals](AqlExamples/CombiningGraphTraversals.md)
* [Graphs](Graphs/README.md)
* [General Graphs](GeneralGraphs/README.md)
* [Graph Management](GeneralGraphs/Management.md)

View File

@ -26,6 +26,13 @@ FOR doc IN `OUTBOUND`
RETURN doc.`any`
```
!SUBSECTION Changed behavior
The AQL functions `NEAR` and `WITHIN` now have stricter validations
for their input parameters `limit`, `radius` and `distance`. They may now throw
exceptions when invalid parameters are passed that may have not led
to exceptions in previous versions.
!SUBSECTION Deadlock handling
@ -123,3 +130,10 @@ let response = request({
* the built-in support for CoffeeScript source files is deprecated, it will raise a warning
if you use it. Please pre-compile CoffeeScript source files.
!SECTION Client tools
arangodump will now fail by default when trying to dump edges that
refer to already dropped collections. This can be circumvented by
specifying the option `--force true` when invoking arangodump

View File

@ -0,0 +1,32 @@
arangosh&gt; <span class="hljs-keyword">var</span> examples = <span class="hljs-built_in">require</span>(<span class="hljs-string">"org/arangodb/graph-examples/example-graph.js"</span>);
arangosh&gt; <span class="hljs-keyword">var</span> g = examples.loadGraph(<span class="hljs-string">"routeplanner"</span>);
arangosh&gt; <span class="hljs-keyword">var</span> bonn=[<span class="hljs-number">50.7340</span>, <span class="hljs-number">7.0998</span>];
arangosh&gt; db._query(<span class="hljs-string">`FOR startCity IN
........&gt; WITHIN(germanCity, @lat, @long, @radius)
........&gt; RETURN startCity`</span>,
........&gt; {lat: bonn[<span class="hljs-number">0</span>], long: bonn[<span class="hljs-number">1</span>], radius: <span class="hljs-number">400000</span>}
........&gt; ).toArray()
[
{
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">false</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">1000000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">50.9364</span>,
<span class="hljs-number">6.9528</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"germanCity/Cologne"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"24341039"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Cologne"</span>
},
{
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">false</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">1000000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">53.5653</span>,
<span class="hljs-number">10.0014</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"germanCity/Hamburg"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"24537647"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Hamburg"</span>
}
]

View File

@ -0,0 +1,82 @@
arangosh&gt; db._query(<span class="hljs-string">`FOR startCity IN
........&gt; WITHIN(germanCity, @lat, @long, @radius)
........&gt; FOR v, e, p IN 1..1 OUTBOUND startCity
........&gt; GRAPH 'routeplanner'
........&gt; RETURN {startcity: startCity._key, traversedCity: v}`</span>,
........&gt; {
........&gt; lat: bonn[<span class="hljs-number">0</span>],
........&gt; long: bonn[<span class="hljs-number">1</span>],
........&gt; radius: <span class="hljs-number">400000</span>
........&gt; } ).toArray()
[
{
<span class="hljs-string">"startcity"</span> : <span class="hljs-string">"Cologne"</span>,
<span class="hljs-string">"traversedCity"</span> : {
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">false</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">80000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">45.76</span>,
<span class="hljs-number">4.84</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"frenchCity/Lyon"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"25061935"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Lyon"</span>
}
},
{
<span class="hljs-string">"startcity"</span> : <span class="hljs-string">"Cologne"</span>,
<span class="hljs-string">"traversedCity"</span> : {
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">true</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">4000000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">48.8567</span>,
<span class="hljs-number">2.3508</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"frenchCity/Paris"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"25258543"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Paris"</span>
}
},
{
<span class="hljs-string">"startcity"</span> : <span class="hljs-string">"Hamburg"</span>,
<span class="hljs-string">"traversedCity"</span> : {
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">true</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">4000000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">48.8567</span>,
<span class="hljs-number">2.3508</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"frenchCity/Paris"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"25258543"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Paris"</span>
}
},
{
<span class="hljs-string">"startcity"</span> : <span class="hljs-string">"Hamburg"</span>,
<span class="hljs-string">"traversedCity"</span> : {
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">false</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">80000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">45.76</span>,
<span class="hljs-number">4.84</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"frenchCity/Lyon"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"25061935"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Lyon"</span>
}
},
{
<span class="hljs-string">"startcity"</span> : <span class="hljs-string">"Hamburg"</span>,
<span class="hljs-string">"traversedCity"</span> : {
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">false</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">1000000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">50.9364</span>,
<span class="hljs-number">6.9528</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"germanCity/Cologne"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"24341039"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Cologne"</span>
}
}
]

View File

@ -0,0 +1,77 @@
arangosh&gt; db._query(<span class="hljs-string">`FOR startCity IN
........&gt; WITHIN(germanCity, @lat, @long, @radius)
........&gt; LET oneCity = (FOR v, e, p IN 1..1 OUTBOUND startCity
........&gt; GRAPH 'routeplanner' RETURN v)
........&gt; return {startCity: startCity._key, connectedCities: oneCity}`</span>,
........&gt; {
........&gt; lat: bonn[<span class="hljs-number">0</span>],
........&gt; long: bonn[<span class="hljs-number">1</span>],
........&gt; radius: <span class="hljs-number">400000</span>
........&gt; } ).toArray();
[
{
<span class="hljs-string">"startCity"</span> : <span class="hljs-string">"Cologne"</span>,
<span class="hljs-string">"connectedCities"</span> : [
{
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">false</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">80000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">45.76</span>,
<span class="hljs-number">4.84</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"frenchCity/Lyon"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"25061935"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Lyon"</span>
},
{
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">true</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">4000000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">48.8567</span>,
<span class="hljs-number">2.3508</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"frenchCity/Paris"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"25258543"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Paris"</span>
}
]
},
{
<span class="hljs-string">"startCity"</span> : <span class="hljs-string">"Hamburg"</span>,
<span class="hljs-string">"connectedCities"</span> : [
{
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">true</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">4000000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">48.8567</span>,
<span class="hljs-number">2.3508</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"frenchCity/Paris"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"25258543"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Paris"</span>
},
{
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">false</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">80000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">45.76</span>,
<span class="hljs-number">4.84</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"frenchCity/Lyon"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"25061935"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Lyon"</span>
},
{
<span class="hljs-string">"isCapital"</span> : <span class="hljs-literal">false</span>,
<span class="hljs-string">"population"</span> : <span class="hljs-number">1000000</span>,
<span class="hljs-string">"loc"</span> : [
<span class="hljs-number">50.9364</span>,
<span class="hljs-number">6.9528</span>
],
<span class="hljs-string">"_id"</span> : <span class="hljs-string">"germanCity/Cologne"</span>,
<span class="hljs-string">"_rev"</span> : <span class="hljs-string">"24341039"</span>,
<span class="hljs-string">"_key"</span> : <span class="hljs-string">"Cologne"</span>
}
]
}
]

View File

@ -0,0 +1,2 @@
arangosh&gt; examples.dropGraph(<span class="hljs-string">"routeplanner"</span>);
<span class="hljs-literal">true</span>

View File

@ -3029,6 +3029,7 @@ static Json getDocumentByIdentifier (triagens::arango::AqlTransaction* trx,
std::string const& collectionName,
std::string const& identifier) {
std::vector<std::string> parts = triagens::basics::StringUtils::split(identifier, "/");
TRI_doc_mptr_copy_t mptr;
if (parts.size() == 1) {
int res = trx->readSingle(collection, &mptr, parts[0]);
@ -3059,24 +3060,37 @@ static Json getDocumentByIdentifier (triagens::arango::AqlTransaction* trx,
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Helper function to get a document by it's _id
/// @brief Helper function to get a document by its _id
/// This function will lazy read-lock the collection.
/// this function will not throw if the document or the collection cannot be
/// found
////////////////////////////////////////////////////////////////////////////////
static Json getDocumentByIdentifier (triagens::arango::AqlTransaction* trx,
CollectionNameResolver const* resolver,
std::string& identifier) {
std::string const& identifier) {
std::vector<std::string> parts = triagens::basics::StringUtils::split(identifier, "/");
if (parts.size() != 2) {
return Json(Json::Null);
}
std::string collectionName = parts[0];
TRI_transaction_collection_t* collection = nullptr;
TRI_voc_cid_t cid = 0;
RegisterCollectionInTransaction(trx, collectionName, cid, collection);
try {
RegisterCollectionInTransaction(trx, collectionName, cid, collection);
}
catch (triagens::basics::Exception const& ex) {
// don't throw if collection is not found
if (ex.code() == TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) {
return Json(Json::Null);
}
throw ex;
}
TRI_doc_mptr_copy_t mptr;
int res = trx->readSingle(collection, &mptr, parts[1]);
if (res != TRI_ERROR_NO_ERROR) {
return Json(Json::Null);
}
@ -3087,8 +3101,7 @@ static Json getDocumentByIdentifier (triagens::arango::AqlTransaction* trx,
cid,
&mptr
);
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief function Document
@ -3144,15 +3157,32 @@ AqlValue Functions::Document (triagens::aql::Query* query,
TRI_transaction_collection_t* collection = nullptr;
TRI_voc_cid_t cid;
RegisterCollectionInTransaction(trx, collectionName, cid, collection);
bool notFound = false;
try {
RegisterCollectionInTransaction(trx, collectionName, cid, collection);
}
catch (triagens::basics::Exception const& ex) {
// don't throw if collection is not found
if (ex.code() != TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND) {
throw ex;
}
notFound = true;
}
Json id = ExtractFunctionParameter(trx, parameters, 1, false);
if (id.isString()) {
if (notFound) {
return AqlValue(new Json(Json::Null));
}
std::string identifier = triagens::basics::JsonHelper::getStringValue(id.json(), "");
Json result = getDocumentByIdentifier(trx, resolver, collection, cid, collectionName, identifier);
return AqlValue(new Json(TRI_UNKNOWN_MEM_ZONE, result.steal()));
}
else if (id.isArray()) {
if (notFound) {
return AqlValue(new Json(Json::Array));
}
size_t const n = id.size();
Json result(Json::Array, n);
for (size_t i = 0; i < n; ++i) {

View File

@ -693,20 +693,27 @@ function INDEX (collection, indexTypes) {
/// @brief get access to a collection
////////////////////////////////////////////////////////////////////////////////
function COLLECTION (name) {
function COLLECTION (name, func) {
'use strict';
if (typeof name !== 'string') {
THROW(null, INTERNAL.errors.ERROR_INTERNAL);
THROW(func, INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, func);
}
var c;
if (name.substring(0, 1) === '_') {
// system collections need to be accessed slightly differently as they
// are not returned by the propertyGetter of db
return INTERNAL.db._collection(name);
c = INTERNAL.db._collection(name);
}
else {
c = INTERNAL.db[name];
}
return INTERNAL.db[name];
if (c === null || c === undefined) {
THROW(func, INTERNAL.errors.ERROR_ARANGO_COLLECTION_NOT_FOUND, String(name));
}
return c;
}
////////////////////////////////////////////////////////////////////////////////
@ -1311,7 +1318,7 @@ function AQL_DOCUMENT (collection, id) {
}
if (TYPEWEIGHT(id) === TYPEWEIGHT_ARRAY) {
var c = COLLECTION(collection);
var c = COLLECTION(collection, "DOCUMENT");
var result = [ ], i;
for (i = 0; i < id.length; ++i) {
@ -1325,7 +1332,7 @@ function AQL_DOCUMENT (collection, id) {
}
try {
return COLLECTION(collection).document(id);
return COLLECTION(collection, "DOCUMENT").document(id);
}
catch (e2) {
return null;
@ -1336,16 +1343,16 @@ function AQL_DOCUMENT (collection, id) {
/// @brief get all documents from the specified collection
////////////////////////////////////////////////////////////////////////////////
function GET_DOCUMENTS (collection) {
function GET_DOCUMENTS (collection, func) {
'use strict';
WARN(null, INTERNAL.errors.ERROR_QUERY_COLLECTION_USED_IN_EXPRESSION, AQL_TO_STRING(collection));
if (isCoordinator) {
return COLLECTION(collection).all().toArray();
return COLLECTION(collection, func).all().toArray();
}
return COLLECTION(collection).ALL(0, null).documents;
return COLLECTION(collection, func).ALL(0, null).documents;
}
////////////////////////////////////////////////////////////////////////////////
@ -3928,27 +3935,30 @@ function AQL_NEAR (collection, latitude, longitude, limit, distanceAttribute) {
limit = 100;
}
else {
if (TYPEWEIGHT(limit) !== TYPEWEIGHT_NUMBER) {
THROW("NEAR", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
}
limit = AQL_TO_NUMBER(limit);
}
var weight = TYPEWEIGHT(distanceAttribute);
if (weight !== TYPEWEIGHT_NULL && weight !== TYPEWEIGHT_STRING) {
WARN("NEAR", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
THROW("NEAR", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
}
if (isCoordinator) {
var query = COLLECTION(collection).near(latitude, longitude);
var query = COLLECTION(collection, "NEAR").near(latitude, longitude);
query._distance = distanceAttribute;
return query.limit(limit).toArray();
}
var idx = INDEX(COLLECTION(collection), [ "geo1", "geo2" ]);
var idx = INDEX(COLLECTION(collection, "NEAR"), [ "geo1", "geo2" ]);
if (idx === null) {
THROW("NEAR", INTERNAL.errors.ERROR_QUERY_GEO_INDEX_MISSING, collection);
}
var result = COLLECTION(collection).NEAR(idx.id, latitude, longitude, limit);
var result = COLLECTION(collection, "NEAR").NEAR(idx.id, latitude, longitude, limit);
if (distanceAttribute === null || distanceAttribute === undefined) {
return result.documents;
@ -3976,22 +3986,28 @@ function AQL_WITHIN (collection, latitude, longitude, radius, distanceAttribute)
var weight = TYPEWEIGHT(distanceAttribute);
if (weight !== TYPEWEIGHT_NULL && weight !== TYPEWEIGHT_STRING) {
WARN("WITHIN", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
THROW("WITHIN", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
}
weight = TYPEWEIGHT(radius);
if (weight !== TYPEWEIGHT_NULL && weight !== TYPEWEIGHT_NUMBER) {
THROW("WITHIN", INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH);
}
radius = AQL_TO_NUMBER(radius);
if (isCoordinator) {
var query = COLLECTION(collection).within(latitude, longitude, radius);
var query = COLLECTION(collection, "WITHIN").within(latitude, longitude, radius);
query._distance = distanceAttribute;
return query.toArray();
}
var idx = INDEX(COLLECTION(collection), [ "geo1", "geo2" ]);
var idx = INDEX(COLLECTION(collection, "WITHIN"), [ "geo1", "geo2" ]);
if (idx === null) {
THROW("WITHIN", INTERNAL.errors.ERROR_QUERY_GEO_INDEX_MISSING, collection);
}
var result = COLLECTION(collection).WITHIN(idx.id, latitude, longitude, radius);
var result = COLLECTION(collection, "WITHIN").WITHIN(idx.id, latitude, longitude, radius);
if (distanceAttribute === null || distanceAttribute === undefined) {
return result.documents;
@ -4023,7 +4039,7 @@ function AQL_WITHIN_RECTANGLE (collection, latitude1, longitude1, latitude2, lon
return null;
}
return COLLECTION(collection).withinRectangle(latitude1, longitude1, latitude2, longitude2).toArray();
return COLLECTION(collection, "WITHIN_RECTANGLE").withinRectangle(latitude1, longitude1, latitude2, longitude2).toArray();
}
////////////////////////////////////////////////////////////////////////////////
@ -4105,7 +4121,7 @@ function AQL_IS_IN_POLYGON (points, latitude, longitude) {
function AQL_FULLTEXT (collection, attribute, query, limit) {
'use strict';
var idx = INDEX_FULLTEXT(COLLECTION(collection), attribute);
var idx = INDEX_FULLTEXT(COLLECTION(collection, "FULLTEXT"), attribute);
if (idx === null) {
THROW("FULLTEXT", INTERNAL.errors.ERROR_QUERY_FULLTEXT_INDEX_MISSING, collection);
@ -4113,12 +4129,12 @@ function AQL_FULLTEXT (collection, attribute, query, limit) {
if (isCoordinator) {
if (limit !== undefined && limit !== null && limit > 0) {
return COLLECTION(collection).fulltext(attribute, query, idx).limit(limit).toArray();
return COLLECTION(collection, "FULLTEXT").fulltext(attribute, query, idx).limit(limit).toArray();
}
return COLLECTION(collection).fulltext(attribute, query, idx).toArray();
return COLLECTION(collection, "FULLTEXT").fulltext(attribute, query, idx).toArray();
}
return COLLECTION(collection).FULLTEXT(idx, query, limit).documents;
return COLLECTION(collection, "FULLTEXT").FULLTEXT(idx, query, limit).documents;
}
// -----------------------------------------------------------------------------
@ -5486,7 +5502,7 @@ function AQL_PATHS (vertices, edgeCollection, direction, options) {
}
var searchAttributes = {
edgeCollection : COLLECTION(edgeCollection),
edgeCollection : COLLECTION(edgeCollection, "PATHS"),
minLength : minLength,
maxLength : maxLength,
direction : searchDirection,
@ -5612,7 +5628,7 @@ function AQL_GRAPH_PATHS (graphName, options) {
return null;
}
if (edgeCollections.indexOf(def.collection) === -1) {
edgeCollections.push(COLLECTION(def.collection));
edgeCollections.push(COLLECTION(def.collection, "GRAPH_PATHS"));
}
});
@ -5633,7 +5649,7 @@ function AQL_GRAPH_PATHS (graphName, options) {
followCycles : followCycles
};
var vertices = GET_DOCUMENTS(startCollection);
var vertices = GET_DOCUMENTS(startCollection, "GRAPH_PATHS");
var n = vertices.length, i, j;
for (i = 0; i < n; ++i) {
var vertex = vertices[i];
@ -6018,11 +6034,11 @@ function FILTER_RESTRICTION (list, restrictionList) {
/// @brief get all document _ids matching the given examples
////////////////////////////////////////////////////////////////////////////////
function DOCUMENT_IDS_BY_EXAMPLE (collectionList, example) {
function DOCUMENT_IDS_BY_EXAMPLE (func, collectionList, example) {
var res = [ ];
if (example === "null" || example === null || ! example) {
collectionList.forEach(function (c) {
res = res.concat(COLLECTION(c).toArray().map(function(t) { return t._id; }));
res = res.concat(COLLECTION(c, func).toArray().map(function(t) { return t._id; }));
});
return res;
}
@ -6045,7 +6061,7 @@ function DOCUMENT_IDS_BY_EXAMPLE (collectionList, example) {
});
collectionList.forEach(function (c) {
tmp.forEach(function (e) {
res = res.concat(COLLECTION(c).byExample(e).toArray().map(function(t) {
res = res.concat(COLLECTION(c, func).byExample(e).toArray().map(function(t) {
return t._id;
}));
});
@ -6057,11 +6073,11 @@ function DOCUMENT_IDS_BY_EXAMPLE (collectionList, example) {
/// @brief getAllDocsByExample
////////////////////////////////////////////////////////////////////////////////
function DOCUMENTS_BY_EXAMPLE (collectionList, example) {
function DOCUMENTS_BY_EXAMPLE (func, collectionList, example) {
var res = [ ];
if (example === "null" || example === null || ! example) {
collectionList.forEach(function (c) {
res = res.concat(COLLECTION(c).toArray());
res = res.concat(COLLECTION(c, func).toArray());
});
return res;
}
@ -6082,7 +6098,7 @@ function DOCUMENTS_BY_EXAMPLE (collectionList, example) {
});
collectionList.forEach(function (c) {
tmp.forEach(function (e) {
res = res.concat(COLLECTION(c).byExample(e).toArray());
res = res.concat(COLLECTION(c, func).byExample(e).toArray());
});
});
return res;
@ -6152,7 +6168,7 @@ function RESOLVE_GRAPH_TO_FROM_VERTICES (graphname, options, funcname) {
if (options.includeOrphans) {
collections.fromCollections = collections.fromCollections.concat(collections.orphanCollections);
}
return DOCUMENTS_BY_EXAMPLE(
return DOCUMENTS_BY_EXAMPLE(funcname,
collections.fromCollections.filter(removeDuplicates), options.fromVertexExample
);
}
@ -6168,7 +6184,7 @@ function RESOLVE_GRAPH_TO_TO_VERTICES (graphname, options, funcname) {
return self.indexOf(elem) === pos;
};
return DOCUMENTS_BY_EXAMPLE(
return DOCUMENTS_BY_EXAMPLE(funcname,
collections.toCollection.filter(removeDuplicates), options.toVertexExample
);
}
@ -6188,7 +6204,7 @@ function RESOLVE_GRAPH_START_VERTICES (graphName, options, funcname) {
var removeDuplicates = function(elem, pos, self) {
return self.indexOf(elem) === pos;
};
return DOCUMENTS_BY_EXAMPLE(
return DOCUMENTS_BY_EXAMPLE(funcname,
collections.fromCollections.filter(removeDuplicates), options.fromVertexExample
);
}
@ -6211,13 +6227,13 @@ function RESOLVE_GRAPH_TO_DOCUMENTS (graphname, options, funcname) {
};
var result = {
fromVertices : DOCUMENTS_BY_EXAMPLE(
fromVertices : DOCUMENTS_BY_EXAMPLE(funcname,
collections.fromCollections.filter(removeDuplicates), options.fromVertexExample
),
toVertices : DOCUMENTS_BY_EXAMPLE(
toVertices : DOCUMENTS_BY_EXAMPLE(funcname,
collections.toCollection.filter(removeDuplicates), options.toVertexExample
),
edges : DOCUMENTS_BY_EXAMPLE(
edges : DOCUMENTS_BY_EXAMPLE(funcname,
collections.edgeCollections.filter(removeDuplicates), options.edgeExamples
),
edgeCollections : collections.edgeCollections,
@ -6367,7 +6383,7 @@ function AQL_SHORTEST_PATH (vertexCollection,
) {
params = SHORTEST_PATH_PARAMS(params);
var a = TRAVERSAL_FUNC("SHORTEST_PATH",
TRAVERSAL.collectionDatasourceFactory(COLLECTION(edgeCollection)),
TRAVERSAL.collectionDatasourceFactory(COLLECTION(edgeCollection, "SHORTEST_PATH")),
TO_ID(startVertex, vertexCollection),
TO_ID(endVertex, vertexCollection),
direction,
@ -6900,14 +6916,14 @@ function AQL_GRAPH_SHORTEST_PATH (graphName,
let startVertices;
if (options.hasOwnProperty("startVertexCollectionRestriction")
&& Array.isArray(options.startVertexCollectionRestriction)) {
startVertices = DOCUMENT_IDS_BY_EXAMPLE(options.startVertexCollectionRestriction, startVertexExample);
startVertices = DOCUMENT_IDS_BY_EXAMPLE("GRAPH_SHORTEST_PATH", options.startVertexCollectionRestriction, startVertexExample);
}
else if (options.hasOwnProperty("startVertexCollectionRestriction")
&& typeof options.startVertexCollectionRestriction === 'string') {
startVertices = DOCUMENT_IDS_BY_EXAMPLE([ options.startVertexCollectionRestriction ], startVertexExample);
startVertices = DOCUMENT_IDS_BY_EXAMPLE("GRAPH_SHORTEST_PATH", [ options.startVertexCollectionRestriction ], startVertexExample);
}
else {
startVertices = DOCUMENT_IDS_BY_EXAMPLE(vertexCollections, startVertexExample);
startVertices = DOCUMENT_IDS_BY_EXAMPLE("GRAPH_SHORTEST_PATH", vertexCollections, startVertexExample);
}
if (startVertices.length === 0) {
return [];
@ -6916,14 +6932,14 @@ function AQL_GRAPH_SHORTEST_PATH (graphName,
let endVertices;
if (options.hasOwnProperty("endVertexCollectionRestriction")
&& Array.isArray(options.endVertexCollectionRestriction)) {
endVertices = DOCUMENT_IDS_BY_EXAMPLE(options.endVertexCollectionRestriction, endVertexExample);
endVertices = DOCUMENT_IDS_BY_EXAMPLE("GRAPH_SHORTEST_PATH", options.endVertexCollectionRestriction, endVertexExample);
}
else if (options.hasOwnProperty("endVertexCollectionRestriction")
&& typeof options.endVertexCollectionRestriction === 'string') {
endVertices = DOCUMENT_IDS_BY_EXAMPLE([ options.endVertexCollectionRestriction ], endVertexExample);
endVertices = DOCUMENT_IDS_BY_EXAMPLE("GRAPH_SHORTEST_PATH", [ options.endVertexCollectionRestriction ], endVertexExample);
}
else {
endVertices = DOCUMENT_IDS_BY_EXAMPLE(vertexCollections, endVertexExample);
endVertices = DOCUMENT_IDS_BY_EXAMPLE("GRAPH_SHORTEST_PATH", vertexCollections, endVertexExample);
}
if (endVertices.length === 0) {
return [];
@ -6971,7 +6987,7 @@ function AQL_TRAVERSAL (vertexCollection,
params = TRAVERSAL_PARAMS(params);
return TRAVERSAL_FUNC("TRAVERSAL",
TRAVERSAL.collectionDatasourceFactory(COLLECTION(edgeCollection)),
TRAVERSAL.collectionDatasourceFactory(COLLECTION(edgeCollection, "TRAVERSAL")),
TO_ID(startVertex, vertexCollection),
undefined,
direction,
@ -7148,7 +7164,7 @@ function AQL_TRAVERSAL_TREE (vertexCollection,
}
var result = TRAVERSAL_FUNC("TRAVERSAL_TREE",
TRAVERSAL.collectionDatasourceFactory(COLLECTION(edgeCollection)),
TRAVERSAL.collectionDatasourceFactory(COLLECTION(edgeCollection, "TRAVERSAL_TREE")),
TO_ID(startVertex, vertexCollection),
undefined,
direction,
@ -7327,7 +7343,7 @@ function AQL_EDGES (edgeCollection,
options) {
'use strict';
var c = COLLECTION(edgeCollection), result;
var c = COLLECTION(edgeCollection, "EDGES"), result;
// validate arguments
if (direction === "outbound") {
@ -7704,7 +7720,7 @@ function AQL_GRAPH_NEIGHBORS (graphName,
}
}
let vertexCollections = graph._vertexCollections().map(function (c) { return c.name();});
let startVertices = DOCUMENT_IDS_BY_EXAMPLE(vertexCollections, vertexExample);
let startVertices = DOCUMENT_IDS_BY_EXAMPLE("GRAPH_NEIGHBORS", vertexCollections, vertexExample);
if (startVertices.length === 0) {
return [];
}
@ -8044,13 +8060,13 @@ function AQL_GRAPH_COMMON_NEIGHBORS (graphName,
let graph = graphModule._graph(graphName);
let vertexCollections = graph._vertexCollections().map(function (c) { return c.name();});
let vertices1 = DOCUMENT_IDS_BY_EXAMPLE(vertexCollections, vertex1Examples);
let vertices1 = DOCUMENT_IDS_BY_EXAMPLE("GRAPH_COMMON_NEIGHBORS", vertexCollections, vertex1Examples);
let vertices2;
if (vertex1Examples === vertex2Examples) {
vertices2 = vertices1;
}
else {
vertices2 = DOCUMENT_IDS_BY_EXAMPLE(vertexCollections, vertex2Examples);
vertices2 = DOCUMENT_IDS_BY_EXAMPLE("GRAPH_COMMON_NEIGHBORS", vertexCollections, vertex2Examples);
}
// Use ES6 Map. Higher performance then Object.
let tmpNeighborsLeft = new Map();
@ -8846,7 +8862,7 @@ function AQL_GRAPH_ABSOLUTE_BETWEENNESS (graphName, options) {
options.includeData = false;
let graph = graphModule._graph(graphName);
let vertexCollections = graph._vertexCollections().map(function (c) { return c.name();});
let vertexIds = DOCUMENT_IDS_BY_EXAMPLE(vertexCollections, {});
let vertexIds = DOCUMENT_IDS_BY_EXAMPLE("GRAPH_ABSOLUTE_BETWEENNESS", vertexCollections, {});
let result = {};
let distanceMap = AQL_GRAPH_SHORTEST_PATH(graphName, vertexIds , vertexIds, options);
for (let k = 0; k < vertexIds.length; k++) {

View File

@ -229,6 +229,17 @@ function ahuacatlGeoTestSuite () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN NEAR(\"" + locationsNon.name() + "\", 0, 0, 10, true)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid WITHIN arguments count
////////////////////////////////////////////////////////////////////////////////
testInvalidWithinArgument : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locationsNon.name() + "\", 0, 0, \"foo\")");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locationsNon.name() + "\", 0, 0, true)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locationsNon.name() + "\", 0, 0, 0, true)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locationsNon.name() + "\", 0, 0, 0, [ ])");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid collection parameter
////////////////////////////////////////////////////////////////////////////////
@ -241,12 +252,7 @@ function ahuacatlGeoTestSuite () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(true, 0, 0, 10)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN([ ], 0, 0, 10)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN({ }, 0, 0, 10)");
if (cluster.isCluster()) {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(@name, 0, 0, 10)", { name: "foobarbazcoll" });
}
else {
assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "RETURN WITHIN(@name, 0, 0, 10)", { name: "foobarbazcoll" });
}
assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "RETURN WITHIN(@name, 0, 0, 10)", { name: "foobarbazcoll" });
assertQueryError(errors.ERROR_QUERY_BIND_PARAMETER_MISSING.code, "RETURN WITHIN(@name, 0, 0, 10)");
}