1
0
Fork 0

Merge branch 'devel' of https://github.com/arangodb/arangodb into devel

This commit is contained in:
Frank Celler 2016-10-20 13:15:07 +02:00
commit 0883c49cd2
18 changed files with 344 additions and 69 deletions

View File

@ -15,6 +15,9 @@ devel
* fixed issue #2075 * fixed issue #2075
* added AQL function `DISTANCE` to calculate the distance between two arbitrary
coordinates (haversine formula)
* rewrote scheduler and dispatcher based on boost::asio * rewrote scheduler and dispatcher based on boost::asio
parameters changed: parameters changed:
@ -36,39 +39,44 @@ devel
* fixed issue #2071 * fixed issue #2071
make the AQL query optimizer inject filter condition expressions referred to by variables during filter condition aggregation. make the AQL query optimizer inject filter condition expressions referred to
for example, in the following query by variables during filter condition aggregation.
For example, in the following query
FOR doc IN collection FOR doc IN collection
LET cond1 = (doc.value == 1) LET cond1 = (doc.value == 1)
LET cond2 = (doc.value == 2) LET cond2 = (doc.value == 2)
FILTER cond1 || cond2 FILTER cond1 || cond2
RETURN { doc, cond1, cond2 } RETURN { doc, cond1, cond2 }
the optimizer will now inject the conditions for `cond1` and `cond2` into the filter condition `cond1 || cond2`, expanding it to the optimizer will now inject the conditions for `cond1` and `cond2` into the filter
`(doc.value == 1) || (doc.value == 2)` and making these conditions available for index searching. condition `cond1 || cond2`, expanding it to `(doc.value == 1) || (doc.value == 2)`
and making these conditions available for index searching.
note that the optimizer previously already injected some conditions into other conditions, but only if the variable that defined Note that the optimizer previously already injected some conditions into other
the condition was not used elsewhere. for example, the filter condition in the query conditions, but only if the variable that defined the condition was not used
elsewhere. For example, the filter condition in the query
FOR doc IN collection FOR doc IN collection
LET cond = (doc.value == 1) LET cond = (doc.value == 1)
FILTER cond FILTER cond
RETURN { doc } RETURN { doc }
already got optimized before because `cond` was only used once in the query and the optimizer decided to inject it into the already got optimized before because `cond` was only used once in the query and
place where it was used. the optimizer decided to inject it into the place where it was used.
this only worked for variables that were referred to once in the query. when a variable was used multiple times, the condition This only worked for variables that were referred to once in the query.
was not injected as in the following query When a variable was used multiple times, the condition was not injected as
in the following query:
FOR doc IN collection FOR doc IN collection
LET cond = (doc.value == 1) LET cond = (doc.value == 1)
FILTER cond FILTER cond
RETURN { doc, cond } RETURN { doc, cond }
the fix for #2070 now will enable this optimization so that the query can use an index on `doc.value` if available.
The fix for #2070 now will enable this optimization so that the query can
use an index on `doc.value` if available.
* changed behavior of AQL array comparison operators for empty arrays: * changed behavior of AQL array comparison operators for empty arrays:
* `ALL` and `ANY` now always return `false` when the left-hand operand is an * `ALL` and `ANY` now always return `false` when the left-hand operand is an
empty array. The behavior for non-empty arrays does not change: empty array. The behavior for non-empty arrays does not change:

View File

@ -70,9 +70,35 @@ There is no guaranteed order in which the documents are returned.
!SECTION Geo utility functions !SECTION Geo utility functions
The following helper functions do **not use any geo index**. It is advisable to use The following helper functions do **not use any geo index**. On large datasets,
them in combination with index-accelerated geo functions to limit the number of it is advisable to use them in combination with index-accelerated geo functions
calls to the non-accelerated functions because of their computational costs. to limit the number of calls to these non-accelerated functions because of their
computational costs.
!SUBSECTION DISTANCE()
`DISTANCE(latitude1, longitude1, latitude2, longitude2) → distance`
Calculate the distance between two arbitrary coordinates in meters (as birds
would fly). The value is computed using the haversine formula, which is based
on a spherical Earth model. It's fast to compute and is accurate to around 0.3%,
which is sufficient for most use cases such as location-aware services.
- **latitude1** (number): the latitude portion of the first coordinate
- **longitude1** (number): the longitude portion of the first coordinate
- **latitude2** (number): the latitude portion of the second coordinate
- **longitude2** (number): the longitude portion of the second coordinate
- returns **distance** (number): the distance between both coordinates in meters
```js
// Distance between Brandenburg Gate (Berlin) and ArangoDB headquarters (Cologne)
DISTANCE(52.5163, 13.3777, 50.9322, 6.94) // 476918.89688380965 (~477km)
// Sort a small number of documents based on distance to Central Park (New York)
FOR doc IN documentSubset // e.g. documents returned by a traversal
SORT DISTANCE(doc.latitude, doc.longitude, 40.78, -73.97)
RETURN doc
```
!SUBSECTION IS_IN_POLYGON() !SUBSECTION IS_IN_POLYGON()

View File

@ -135,11 +135,46 @@ string *text*. Positions start at 0.
is not contained in *text*, -1 is returned. is not contained in *text*, -1 is returned.
```js ```js
FIND_LAST("foobarbaz", "ba"), // 6 FIND_LAST("foobarbaz", "ba") // 6
FIND_LAST("foobarbaz", "ba", 7), // -1 FIND_LAST("foobarbaz", "ba", 7) // -1
FIND_LAST("foobarbaz", "ba", 0, 4) // 3 FIND_LAST("foobarbaz", "ba", 0, 4) // 3
``` ```
!SUBSECTION JSON_PARSE()
`JSON_PARSE(text) → value`
Return an AQL value described by the JSON-encoded input string.
- **text** (string): the string to parse as JSON
- returns **value** (mixed): the value corresponding to the given JSON text.
For input values that are no valid JSON strings, the function will return *null*.
```js
JSON_PARSE("123") // 123
JSON_PARSE("[ true, false, 2 ]") // [ true, false, 2 ]
JSON_PARSE("\\\"abc\\\"") // "abc"
JSON_PARSE("{\\\"a\\\": 1}") // { a : 1 }
JSON_PARSE("abc") // null
```
!SUBSECTION JSON_STRINGIFY()
`JSON_STRINGIFY(value) → text`
Return a JSON string representation of the input value.
- **value** (mixed): the value to convert to a JSON string
- returns **text** (string): the JSON string representing *value*.
For input values that cannot be converted to JSON, the function
will return *null*.
```js
JSON_STRINGIFY("1") // "1"
JSON_STRINGIFY("abc") // "\"abc\""
JSON_STRINGIFY("[1, 2, 3]") // "[1,2,3]"
```
!SUBSECTION LEFT() !SUBSECTION LEFT()
`LEFT(value, length) → substring` `LEFT(value, length) → substring`
@ -160,7 +195,6 @@ LEFT("foobar", 10) // "foobar"
`LENGTH(str) → length` `LENGTH(str) → length`
Determine the character length of a string. Determine the character length of a string.
- **str** (string): a string. If a number is passed, it will be casted to string first. - **str** (string): a string. If a number is passed, it will be casted to string first.

View File

@ -78,26 +78,57 @@ As ArangoDB supports MVCC (Multiple Version Concurrency Control),
documents can exist in more than one documents can exist in more than one
revision. The document revision is the MVCC token used to specify revision. The document revision is the MVCC token used to specify
a particular revision of a document (identified by its `_id`). a particular revision of a document (identified by its `_id`).
It is a string value currently It is a string value that contained (up to ArangoDB 3.0)
containing an integer number and is unique within the list of document an integer number and is unique within the list of document
revisions for a single document. Document revisions can be used to revisions for a single document.
conditionally query, update, replace or delete documents in the database. In In ArangoDB >= 3.1 the _rev strings
order to find a particular revision of a document, you need the document are in fact time stamps. They use the local clock of the DBserver that
handle or key, and the document revision. actually writes the document and have millisecond accuracy.
Actually, a "Hybrid Logical Clock" is used (for
this concept see
[this paper](http://www.cse.buffalo.edu/tech-reports/2014-04.pdf)).
Within one shard it is guaranteed that two different document revisions
have a different _rev string, even if they are written in the same
millisecond, and that these stamps are ascending.
Note however that different servers in your cluster might have a clock
skew, and therefore between different shards or even between different
collections the time stamps are not guaranteed to be comparable.
The Hybrid Logical Clock feature does one thing to address this
issue: Whenever a message is sent from some server A in your cluster to
another one B, it is ensured that any timestamp taken on B after the
message has arrived is greater than any timestamp taken on A before the
message was sent. This ensures that if there is some "causality" between
events on different servers, time stamps increase from cause to effect.
A direct consequence of this is that sometimes a server has to take
timestamps that seem to come from the future of its own clock. It will
however still produce ever increasing timestamps. If the clock skew is
small, then your timestamps will relatively accurately describe the time
when the document revision was actually written.
ArangoDB uses 64bit unsigned integer values to maintain ArangoDB uses 64bit unsigned integer values to maintain
document revisions internally. When returning document revisions to document revisions internally. At this stage we intentionally do not
document the exact format of the revision values. When returning
document revisions to
clients, ArangoDB will put them into a string to ensure the revision clients, ArangoDB will put them into a string to ensure the revision
is not clipped by clients that do not support big integers. Clients is not clipped by clients that do not support big integers. Clients
should treat the revision returned by ArangoDB as an opaque string should treat the revision returned by ArangoDB as an opaque string
when they store or use it locally. This will allow ArangoDB to change when they store or use it locally. This will allow ArangoDB to change
the format of revisions later if this should be required. Clients can the format of revisions later if this should be required (as has happened
with 3.1 with the Hybrid Logical Clock). Clients can
use revisions to perform simple equality/non-equality comparisons use revisions to perform simple equality/non-equality comparisons
(e.g. to check whether a document has changed or not), but they should (e.g. to check whether a document has changed or not), but they should
not use revision ids to perform greater/less than comparisons with them not use revision ids to perform greater/less than comparisons with them
to check if a document revision is older than one another, even if this to check if a document revision is older than one another, even if this
might work for some cases. might work for some cases.
Document revisions can be used to
conditionally query, update, replace or delete documents in the database. In
order to find a particular revision of a document, you need the document
handle or key, and the document revision.
!SUBSECTION Multiple Documents in a single Command !SUBSECTION Multiple Documents in a single Command

View File

@ -4,6 +4,21 @@ The following list shows in detail which features have been added or improved in
ArangoDB 3.1. ArangoDB 3.1 also contains several bugfixes that are not listed ArangoDB 3.1. ArangoDB 3.1 also contains several bugfixes that are not listed
here. here.
!SECTION Data format
The format of the revision values stored in the `_rev` attribute of documents
has been changed in 3.1. Up to 3.0 they were strings containing largish decimal numbers. With 3.1, revision values are still strings, but are actually encoded time stamps of the creation date of the revision of the document. The time stamps are acquired using a hybrid logical clock (HLC) on the DBserver that holds the
revision (for the concept of a hybrid logical clock see
[this paper](http://www.cse.buffalo.edu/tech-reports/2014-04.pdf)).
See [this manual section](../DataModeling/Documents/DocumentAddress.html#document-revision) for details.
ArangoDB >= 3.1 can ArangoDB 3.0 database directories and will simply continue
to use the old `_rev` attribute values. New revisions will be written with
the new time stamps.
It is highly recommended to backup all your data before loading a database
directory that was written by ArangoDB <= 3.0 into an ArangoDB >= 3.1.
!SECTION Communication Layer !SECTION Communication Layer
ArangoDB up to 3.0 used [libev](http://software.schmorp.de/pkg/libev.html) for ArangoDB up to 3.0 used [libev](http://software.schmorp.de/pkg/libev.html) for

View File

@ -2,6 +2,7 @@
!SECTION Whats New !SECTION Whats New
- [Whats New in 3.1](NewFeatures31.md)
- [Whats New in 3.0](NewFeatures30.md) - [Whats New in 3.0](NewFeatures30.md)
- [Whats New in 2.8](NewFeatures28.md) - [Whats New in 2.8](NewFeatures28.md)
- [Whats New in 2.7](NewFeatures27.md) - [Whats New in 2.7](NewFeatures27.md)
@ -17,6 +18,7 @@
Also see [Upgrading](../Administration/Upgrading/README.md) in the Also see [Upgrading](../Administration/Upgrading/README.md) in the
Administration chapter. Administration chapter.
- [Incompatible changes in 3.1](UpgradingChanges31.md)
- [Incompatible changes in 3.0](UpgradingChanges30.md) - [Incompatible changes in 3.0](UpgradingChanges30.md)
- [Incompatible changes in 2.8](UpgradingChanges28.md) - [Incompatible changes in 2.8](UpgradingChanges28.md)
- [Incompatible changes in 2.7](UpgradingChanges27.md) - [Incompatible changes in 2.7](UpgradingChanges27.md)

View File

@ -51,7 +51,22 @@ meta-data files ("parameter.json"). Files containing the `maximalSize` attribute
will still be picked up correctly for not-yet adjusted collections. will still be picked up correctly for not-yet adjusted collections.
The format of the revision values stored in the `_rev` attribute of documents The format of the revision values stored in the `_rev` attribute of documents
has been changed in 3.1. Revision values are stored as hybrid logical clock values. has been changed in 3.1. Up to 3.0 they were strings containing largish decimal numbers. With 3.1, revision values are still strings, but are actually encoded time stamps of the creation date of the revision of the document. The time stamps are acquired using a hybrid logical clock (HLC) on the DBserver that holds the
revision (for the concept of a hybrid logical clock see
[this paper](http://www.cse.buffalo.edu/tech-reports/2014-04.pdf)).
See [this manual section](../DataModeling/Documents/DocumentAddress.html#document-revision) for details.
ArangoDB >= 3.1 can ArangoDB 3.0 database directories and will simply continue
to use the old `_rev` attribute values. New revisions will be written with
the new time stamps.
It is highly recommended to backup all your data before loading a database
directory that was written by ArangoDB <= 3.0 into an ArangoDB >= 3.1.
To change all your old `_rev` attributes into new style time stamps you
have to use `arangodump` to dump all data out (using ArangoDB 3.0), and
use `arangorestore` into the new ArangoDB 3.1, which is the safest
way to upgrade.
!SECTION HTTP API changes !SECTION HTTP API changes

View File

@ -55,9 +55,9 @@ On success an object with the following attributes is returned:
generating keys and supplying own key values in the *_key* attribute generating keys and supplying own key values in the *_key* attribute
of documents is considered an error. of documents is considered an error.
**Note**: some other collection properties, such as *type*, *isVolatile*, **Note**: except for *waitForSync*, *journalSize* and *name*, collection
*numberOfShards* or *shardKeys* cannot be changed once a collection is properties **cannot be changed** once a collection is created. To rename
created. a collection, the rename endpoint must be used.
@RESTRETURNCODES @RESTRETURNCODES

View File

@ -109,7 +109,8 @@ DistributeNode::DistributeNode(ExecutionPlan* plan,
_varId(base.get("varId").getNumericValue<VariableId>()), _varId(base.get("varId").getNumericValue<VariableId>()),
_alternativeVarId(base.get("alternativeVarId").getNumericValue<VariableId>()), _alternativeVarId(base.get("alternativeVarId").getNumericValue<VariableId>()),
_createKeys(base.get("createKeys").getBoolean()), _createKeys(base.get("createKeys").getBoolean()),
_allowKeyConversionToObject(base.get("allowKeyConversionToObject").getBoolean()) {} _allowKeyConversionToObject(base.get("allowKeyConversionToObject").getBoolean()),
_allowSpecifiedKeys(false) {}
/// @brief toVelocyPack, for DistributedNode /// @brief toVelocyPack, for DistributedNode
void DistributeNode::toVelocyPackHelper(VPackBuilder& nodes, void DistributeNode::toVelocyPackHelper(VPackBuilder& nodes,

View File

@ -1304,17 +1304,6 @@ static void JS_GetCurrentResponse(
TRI_V8_TRY_CATCH_END TRI_V8_TRY_CATCH_END
} }
static void JS_IsEnterprise(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
#ifndef USE_ENTERPRISE
TRI_V8_RETURN(v8::False(isolate));
#else
TRI_V8_RETURN(v8::True(isolate));
#endif
TRI_V8_TRY_CATCH_END
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief stores the V8 actions function inside the global variable /// @brief stores the V8 actions function inside the global variable
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1345,9 +1334,6 @@ void TRI_InitV8Actions(v8::Isolate* isolate, v8::Handle<v8::Context> context) {
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_AddGlobalFunctionVocbase(isolate, context,
TRI_V8_ASCII_STRING("SYS_REQUEST_PARTS"), TRI_V8_ASCII_STRING("SYS_REQUEST_PARTS"),
JS_RequestParts, true); JS_RequestParts, true);
TRI_AddGlobalFunctionVocbase(isolate, context,
TRI_V8_ASCII_STRING("SYS_IS_ENTERPRISE"),
JS_IsEnterprise);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -2732,6 +2732,18 @@ void TRI_V8ReloadRouting(v8::Isolate* isolate) {
TRI_V8_ASCII_STRING("reload routing"), false); TRI_V8_ASCII_STRING("reload routing"), false);
} }
static void JS_IsEnterprise(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
#ifndef USE_ENTERPRISE
TRI_V8_RETURN(v8::False(isolate));
#else
TRI_V8_RETURN(v8::True(isolate));
#endif
TRI_V8_TRY_CATCH_END
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief creates a TRI_vocbase_t global context /// @brief creates a TRI_vocbase_t global context
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -2919,6 +2931,10 @@ void TRI_InitV8VocBridge(v8::Isolate* isolate, v8::Handle<v8::Context> context,
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_AddGlobalFunctionVocbase(isolate, context,
TRI_V8_ASCII_STRING("TRUSTED_PROXIES"), TRI_V8_ASCII_STRING("TRUSTED_PROXIES"),
JS_TrustedProxies, true); JS_TrustedProxies, true);
TRI_AddGlobalFunctionVocbase(isolate, context,
TRI_V8_ASCII_STRING("SYS_IS_ENTERPRISE"),
JS_IsEnterprise);
// ............................................................................. // .............................................................................
// create global variables // create global variables
// ............................................................................. // .............................................................................

View File

@ -5,7 +5,7 @@
<div class="navlogo"> <div class="navlogo">
<a class="logo big" href="#"><img id="ArangoDBLogo" class="arangodbLogo" src="img/arangodb-edition-optimized.svg"/></a> <a class="logo big" href="#"><img id="ArangoDBLogo" class="arangodbLogo" src="img/arangodb-edition-optimized.svg"/></a>
<a class="logo small" href="#"><img class="arangodbLogo" src="img/arangodb_logo_small.png"/></a> <a class="logo small" href="#"><img class="arangodbLogo" src="img/arangodb_logo_small.png"/></a>
<a class="version"><span>VERSION: </span><span id="currentVersion"></span></a> <a class="version"><span id="currentVersion"></span></a>
</div> </div>
<!-- <div id="progressPlaceholderIcon"></div> --> <!-- <div id="progressPlaceholderIcon"></div> -->
<div class="statmenu" id="statisticBar"> <div class="statmenu" id="statisticBar">

View File

@ -139,7 +139,7 @@
window.versionHelper.fromString(data.version); window.versionHelper.fromString(data.version);
$('.navbar #currentVersion').html( $('.navbar #currentVersion').html(
' ' + data.version.substr(0, 7) + '<i class="fa fa-exclamation-circle"></i>' data.version.substr(0, 7) + '<i class="fa fa-exclamation-circle"></i>'
); );
window.parseVersions = function (json) { window.parseVersions = function (json) {

View File

@ -455,24 +455,35 @@
}); });
_.each(obj.vertices, function (node) { _.each(obj.vertices, function (node) {
vertices[node._id] = { if (node !== null) {
id: node._id, vertices[node._id] = {
label: node._key, id: node._id,
// size: 0.3, label: node._key,
color: color, size: 0.3,
x: Math.random(), color: color,
y: Math.random() x: Math.random(),
}; y: Math.random()
};
}
}); });
} }
}); });
var nodeIds = [];
_.each(vertices, function (node) { _.each(vertices, function (node) {
returnObj.nodes.push(node); returnObj.nodes.push(node);
nodeIds.push(node.id);
}); });
_.each(edges, function (edge) { _.each(edges, function (edge) {
returnObj.edges.push(edge); if (nodeIds.includes(edge.source) && nodeIds.includes(edge.target)) {
returnObj.edges.push(edge);
}
/* how to handle not correct data?
else {
console.log('target to from is missing');
}
*/
}); });
} else if (type === 'array') { } else if (type === 'array') {
_.each(data, function (edge) { _.each(data, function (edge) {

View File

@ -257,7 +257,7 @@
position: fixed; position: fixed;
right: 0; right: 0;
text-align: center; text-align: center;
top: 120px; top: 135px;
width: 100%; width: 100%;
span { span {

View File

@ -3579,7 +3579,7 @@ testFuncs.endpoints = function(options) {
return { return {
status: true, status: true,
skipped: true, skipped: true,
} };
} else { } else {
let instanceInfo = startInstance('tcp', Object.assign(options, {useReconnect: true}), { let instanceInfo = startInstance('tcp', Object.assign(options, {useReconnect: true}), {
'server.endpoint': endpoint, 'server.endpoint': endpoint,

View File

@ -1,4 +1,4 @@
/* global describe, it, beforeEach, afterEach*/ /* global db, describe, it, beforeEach, afterEach*/
'use strict'; 'use strict';
// ////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,130 @@
/*jshint globalstrict:false, strict:false, maxlen: 500 */
/*global AQL_EXECUTE, assertEqual */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, geo queries
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Simran Brucherseifer
/// @author Copyright 2016, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var internal = require("internal");
var errors = internal.errors;
var db = require("@arangodb").db;
var helper = require("@arangodb/aql-helper");
var assertQueryError = helper.assertQueryError;
var assertQueryWarningAndNull = helper.assertQueryWarningAndNull;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function distanceSuite () {
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief test DISTANCE function
////////////////////////////////////////////////////////////////////////////////
testDistance1 : function () {
var co1 = { lat: 52.5163, lon: 13.3777, _key: "BrandenburgGate" };
var co2 = { lat: 50.9322, lon: 6.94, _key: "ArangoHQ" };
var query = "DISTANCE(" + co1.lat + "," + co1.lon + "," + co2.lat + "," + co2.lon + ")";
var expected = [ 476918.89688380965 ]; // Vincenty's formula: 477.47 km
var actual = AQL_EXECUTE("RETURN " + query).json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(" + query + ")").json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(V8(" + query + "))").json;
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test DISTANCE function
////////////////////////////////////////////////////////////////////////////////
testDistance2 : function () {
var co1 = { lat: 40.78, lon: -73.97, _key: "CentralPark" };
var co2 = { lat: 34.05, lon: -118.25, _key: "LosAngeles" };
var query = "DISTANCE(" + co1.lat + "," + co1.lon + "," + co2.lat + "," + co2.lon + ")";
var expected = [ 3938926.7382122413 ]; // Vincenty's formula: 3943.29 km
var actual = AQL_EXECUTE("RETURN " + query).json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(" + query + ")").json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(V8(" + query + "))").json;
assertEqual(expected, actual); },
////////////////////////////////////////////////////////////////////////////////
/// @brief test DISTANCE function
////////////////////////////////////////////////////////////////////////////////
testDistance3 : function () {
var co1 = { lat: 0, lon: 0, _key: "zeroPoint" };
var co2 = { lat: 0, lon: 180, _key: "otherSideOfGLobe" };
var query = "DISTANCE(" + co1.lat + "," + co1.lon + "," + co2.lat + "," + co2.lon + ")";
var expected = [ 20015086.79602057 ]; // Half of equatorial circumference (WGS 84): 20037.5085 km
var actual = AQL_EXECUTE("RETURN " + query).json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(" + query + ")").json;
assertEqual(expected, actual);
actual = AQL_EXECUTE("RETURN NOOPT(V8(" + query + "))").json;
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid DISTANCE arguments
////////////////////////////////////////////////////////////////////////////////
testDistanceInvalid : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN DISTANCE()");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN DISTANCE( 0 )");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN DISTANCE( 0, 0 )");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN DISTANCE( 0, 0, 0 )");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN DISTANCE( 0, 0, 0, 0, 0 )");
assertQueryWarningAndNull(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN DISTANCE( 0, 0, 0, \"foo\" )");
assertQueryWarningAndNull(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN DISTANCE( 0, 0, 0, [ 1, 2, 3 ] )");
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsunity.run(distanceSuite);
return jsunity.done();