1
0
Fork 0
arangodb/tests/js/server/aql/aql-queries-geo.js

1284 lines
53 KiB
JavaScript

/*jshint globalstrict:false, strict:false, maxlen: 500 */
/*global assertEqual */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, geo queries
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens 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 triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var db = require("@arangodb").db;
var errors = require("@arangodb").errors;
var helper = require("@arangodb/aql-helper");
var getQueryResults = helper.getQueryResults;
var assertQueryError = helper.assertQueryError;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function ahuacatlLegacyGeoTestSuite () {
var locations = null;
var locationsNon = null;
function runQuery (query) {
var result = getQueryResults(query);
result = result.map(function(row) {
var r;
if (row !== null && typeof row === 'object') {
for (r in row) {
if (row.hasOwnProperty(r)) {
var value = row[r];
if (typeof(value) === "number") {
if (value !== parseFloat(parseInt(value))) {
row[r] = Number(value).toFixed(5);
}
}
}
}
}
return row;
});
return result;
}
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
var lat, lon;
db._drop("UnitTestsAhuacatlLocations");
db._drop("UnitTestsAhuacatlLocationsNon");
locations = db._create("UnitTestsAhuacatlLocations");
for (lat = -40; lat <= 40; ++lat) {
for (lon = -40; lon <= 40; ++lon) {
locations.save({"latitude" : lat, "longitude" : lon });
}
}
locations.ensureGeoIndex("latitude", "longitude");
//locations without index
locationsNon = db._create("UnitTestsAhuacatlLocationsNon");
for (lat = -40; lat <= 40; ++lat) {
for (lon = -40; lon <= 40; ++lon) {
locationsNon.save({"latitude" : lat, "longitude" : lon });
}
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
db._drop("UnitTestsAhuacatlLocations");
db._drop("UnitTestsAhuacatlLocationsNon");
},
testLegacyNearInvalidCoordinate : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_GEO_VALUE.code, "RETURN NEAR(" + locations.name() + ", 1000, 1000, 10)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test near function
////////////////////////////////////////////////////////////////////////////////
testLegacyNear1 : function () {
var expected = [ { "distance" : "111194.92664", "latitude" : -1, "longitude" : 0 }, { "distance" : "111194.92664", "latitude" : 0, "longitude" : -1 }, { "distance" : "111194.92664", "latitude" : 0, "longitude" : 1 }, { "distance" : "111194.92664", "latitude" : 1, "longitude" : 0 }, { "distance" : 0, "latitude" : 0, "longitude" : 0 } ];
var actual = runQuery("FOR x IN NEAR(" + locations.name() + ", 0, 0, 5, \"distance\") SORT x.distance DESC, x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test near function
////////////////////////////////////////////////////////////////////////////////
testLegacyNear2 : function () {
var expected = [ { "latitude" : -10, "longitude" : 24 }, { "latitude" : -10, "longitude" : 25 }, { "latitude" : -10, "longitude" : 26 } ];
var actual = runQuery("FOR x IN NEAR(" + locations.name() + ", -10, 25, 3) SORT x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test near function
////////////////////////////////////////////////////////////////////////////////
testLegacyNear3 : function () {
var expected = [ { "distance" : "14891044.54146", "latitude" : 40, "longitude" : -40 },
{ "distance" : "14853029.30724", "latitude" : 40, "longitude" : -39 },
{ "distance" : "14815001.47646", "latitude" : 40, "longitude" : -38 } ];
var query = "FOR x IN NEAR(" + locations.name() + ", -70, 70, 10000, \"distance\") " +
"SORT x.distance DESC LIMIT 3 RETURN x";
var actual = runQuery(query);
assertEqual(expected, actual);
expected = [ { "distance" : "4487652.12954", "latitude" : -37, "longitude" : 26 },
{ "distance" : "4485565.93668", "latitude" : -39, "longitude" : 20 },
{ "distance" : "4484371.86154", "latitude" : -38, "longitude" : 23 } ];
query = "FOR x IN NEAR(" + locations.name() + ", -70, 70, 100, \"distance\") "+
"SORT x.distance DESC LIMIT 3 RETURN x";
actual = runQuery(query);
assertEqual(expected, actual);
//until changed null will result in the default value of 100
//expected = [ { "distance" : "14891044.54146", "latitude" : 40, "longitude" : -40 },
// { "distance" : "14853029.30724", "latitude" : 40, "longitude" : -39 },
// { "distance" : "14815001.47646", "latitude" : 40, "longitude" : -38 } ];
query = "FOR x IN NEAR(" + locations.name() + ", -70, 70, null, \"distance\") "+
"SORT x.distance DESC LIMIT 3 RETURN x";
actual = runQuery(query);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test near function
////////////////////////////////////////////////////////////////////////////////
testLegacyNear4 : function () {
var expected = [ {"latitude" : -40, "longitude" : 40 }, { "latitude" : -40, "longitude" : 39 }, { "latitude" : -40, "longitude" : 38 } ];
var actual = runQuery("FOR x IN NEAR(" + locations.name() + ", -70, 70, null) SORT x.latitude, x.longitude DESC LIMIT 3 RETURN x");
assertEqual(expected, actual);
expected = [ { "latitude" : -40, "longitude" : 40 }, { "latitude" : -40, "longitude" : 39 } ];
actual = runQuery("FOR x IN NEAR(" + locations.name() + ", -70, 70, 2) SORT x.latitude, x.longitude DESC LIMIT 3 RETURN x");
assertEqual(expected, actual);
},
testLegacyWithinInvalidCoordinate : function () {
assertQueryError(errors.ERROR_QUERY_INVALID_GEO_VALUE.code, "RETURN WITHIN(" + locations.name() + ", 1000, 1000, 100000)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test within function
////////////////////////////////////////////////////////////////////////////////
testLegacyWithin1 : function () {
var expected = [ { "distance" : 0, "latitude" : 0, "longitude" : 0 } ];
var actual = runQuery("FOR x IN WITHIN(" + locations.name() + ", 0, 0, 10000, \"distance\") SORT x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test within function
////////////////////////////////////////////////////////////////////////////////
testLegacyWithin2 : function () {
var expected = [ { "distance" : "111194.92664", "latitude" : -1, "longitude" : 0 }, { "distance" : "111194.92664", "latitude" : 0, "longitude" : -1 }, { "distance" : 0, "latitude" : 0, "longitude" : 0 }, { "distance" : "111194.92664", "latitude" : 0, "longitude" : 1 }, { "distance" : "111194.92664", "latitude" : 1, "longitude" : 0 } ];
var actual = runQuery("FOR x IN WITHIN(" + locations.name() + ", 0, 0, 150000, \"distance\") SORT x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test within function
////////////////////////////////////////////////////////////////////////////////
testLegacyWithin3 : function () {
var expected = [ { "latitude" : -10, "longitude" : 25 } ];
var actual = runQuery("FOR x IN WITHIN(" + locations.name() + ", -10, 25, 10000) SORT x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test within function
////////////////////////////////////////////////////////////////////////////////
testLegacyWithin4 : function () {
var expected = [
{ "latitude" : -11, "longitude" : 25 },
{ "latitude" : -10, "longitude" : 24 },
{ "latitude" : -10, "longitude" : 25 },
{ "latitude" : -10, "longitude" : 26 },
{ "latitude" : -9, "longitude" : 25 }
];
var actual = runQuery("FOR x IN WITHIN(" + locations.name() + ", -10, 25, 150000) SORT x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test within function
////////////////////////////////////////////////////////////////////////////////
testLegacyWithin5 : function () {
var expected = [ ];
var actual = runQuery("FOR x IN WITHIN(" + locations.name() + ", -90, 90, 10000) SORT x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test without geo index available
////////////////////////////////////////////////////////////////////////////////
testLegacyNonIndexed : function () {
assertQueryError(errors.ERROR_QUERY_GEO_INDEX_MISSING.code, "RETURN NEAR(" + locationsNon.name() + ", 0, 0, 10)");
assertQueryError(errors.ERROR_QUERY_GEO_INDEX_MISSING.code, "RETURN WITHIN(" + locationsNon.name() + ", 0, 0, 10)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid NEAR arguments count
////////////////////////////////////////////////////////////////////////////////
testLegacyInvalidNearArgument : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN NEAR(\"" + locations.name() + "\", 0, 0, \"foo\")");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN NEAR(\"" + locations.name() + "\", 0, 0, true)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN NEAR(\"" + locations.name() + "\", 0, 0, 10, true)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid WITHIN arguments count
////////////////////////////////////////////////////////////////////////////////
testLegacyInvalidWithinArgument : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locations.name() + "\", 0, 0, \"foo\")");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locations.name() + "\", 0, 0, true)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locations.name() + "\", 0, 0, 0, true)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locations.name() + "\", 0, 0, 0, [ ])");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid collection parameter
////////////////////////////////////////////////////////////////////////////////
testLegacyInvalidCollectionArgument : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(1234, 0, 0, 10)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(false, 0, 0, 10)");
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)");
assertQueryError(errors.ERROR_ARANGO_DATA_SOURCE_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)");
}
};
}
function legacyGeoTestSuite() {
var locations = null;
var locationsNon = null;
function runQuery(query) {
var result = getQueryResults(query);
result = result.map(function (row) {
var r;
if (row !== null && typeof row === 'object') {
for (r in row) {
if (row.hasOwnProperty(r)) {
var value = row[r];
if (typeof (value) === "number") {
if (value !== parseFloat(parseInt(value))) {
row[r] = Number(value).toFixed(5);
}
}
}
}
}
return row;
});
return result;
}
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp: function () {
var lat, lon;
db._drop("UnitTestsAhuacatlLocations");
db._drop("UnitTestsAhuacatlLocationsNon");
locations = db._create("UnitTestsAhuacatlLocations");
for (lat = -40; lat <= 40; ++lat) {
for (lon = -40; lon <= 40; ++lon) {
locations.save({ "latitude": lat, "longitude": lon });
}
}
locations.ensureIndex({ type: "geo", fields: ["latitude", "longitude"] });
locationsNon = db._create("UnitTestsAhuacatlLocationsNon");
for (lat = -40; lat <= 40; ++lat) {
for (lon = -40; lon <= 40; ++lon) {
locationsNon.save({ "latitude": lat, "longitude": lon });
}
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown: function () {
db._drop("UnitTestsAhuacatlLocations");
db._drop("UnitTestsAhuacatlLocationsNon");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test near function
////////////////////////////////////////////////////////////////////////////////
testNear1: function () {
var expected = [{ "distance": "111194.92664", "latitude": -1, "longitude": 0 },
{ "distance": "111194.92664", "latitude": 0, "longitude": -1 },
{ "distance": "111194.92664", "latitude": 0, "longitude": 1 },
{ "distance": "111194.92664", "latitude": 1, "longitude": 0 },
{ "distance": 0, "latitude": 0, "longitude": 0 }];
var actual = runQuery("FOR x IN NEAR(" + locations.name() + ", 0, 0, 5) " +
"LET d = DISTANCE(0,0,x.latitude,x.longitude) " +
"SORT d DESC, x.latitude, x.longitude RETURN MERGE(x, {distance:d})");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test near function
////////////////////////////////////////////////////////////////////////////////
testNear2: function () {
var expected = [{ "latitude": -10, "longitude": 24 }, { "latitude": -10, "longitude": 25 }, { "latitude": -10, "longitude": 26 }];
var actual = runQuery("FOR x IN NEAR(" + locations.name() + ", -10, 25, 3) SORT x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test near function
////////////////////////////////////////////////////////////////////////////////
testNear3: function () {
var expected = [{ "distance": "14891044.54146", "latitude": 40, "longitude": -40 },
{ "distance": "14853029.30724", "latitude": 40, "longitude": -39 },
{ "distance": "14815001.47646", "latitude": 40, "longitude": -38 }];
var actual = runQuery("FOR x IN NEAR(" + locations.name() + ", -70, 70, 10000) " +
"LET d = DISTANCE(-70,70,x.latitude,x.longitude) " +
"SORT d DESC LIMIT 3 RETURN MERGE(x, {distance:d})");
assertEqual(expected, actual);
expected = [{ "distance": "4487652.12954", "latitude": -37, "longitude": 26 },
{ "distance": "4485565.93668", "latitude": -39, "longitude": 20 },
{ "distance": "4484371.86154", "latitude": -38, "longitude": 23 }];
actual = runQuery("FOR x IN NEAR(" + locations.name() + ", -70, 70, 100) " +
"LET d = DISTANCE(-70,70,x.latitude,x.longitude) " +
"SORT d DESC LIMIT 3 RETURN MERGE(x, {distance:d})");
assertEqual(expected, actual);
//until changed null will result in the default value of 100
//expected = [{ "distance": "14891044.54146", "latitude": 40, "longitude": -40 },
// { "distance": "14853029.30724", "latitude": 40, "longitude": -39 },
// { "distance": "14815001.47646", "latitude": 40, "longitude": -38 }];
actual = runQuery("FOR x IN NEAR(" + locations.name() + ", -70, 70, null) " +
"LET d = DISTANCE(-70,70,x.latitude,x.longitude) " +
"SORT d DESC LIMIT 3 RETURN MERGE(x, {distance:d})");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test near function
////////////////////////////////////////////////////////////////////////////////
testNear4: function () {
var expected = [{ "latitude": -40, "longitude": 40 }, { "latitude": -40, "longitude": 39 }, { "latitude": -40, "longitude": 38 }];
var actual = runQuery("FOR x IN NEAR(" + locations.name() + ", -70, 70, null) SORT x.latitude, x.longitude DESC LIMIT 3 RETURN x");
assertEqual(expected, actual);
expected = [{ "latitude": -40, "longitude": 40 }, { "latitude": -40, "longitude": 39 }];
actual = runQuery("FOR x IN NEAR(" + locations.name() + ", -70, 70, 2) SORT x.latitude, x.longitude DESC LIMIT 3 RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test within function
////////////////////////////////////////////////////////////////////////////////
testWithin1: function () {
var expected = [{ "distance": 0, "latitude": 0, "longitude": 0 }];
var actual = runQuery("FOR x IN WITHIN(" + locations.name() + ", 0, 0, 10000) " +
"LET d = DISTANCE(0,0,x.latitude,x.longitude) " +
"SORT x.latitude, x.longitude RETURN MERGE(x, {distance:d})");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test within function
////////////////////////////////////////////////////////////////////////////////
testWithin2: function () {
var expected = [{ "distance": "111194.92664", "latitude": -1, "longitude": 0 }, { "distance": "111194.92664", "latitude": 0, "longitude": -1 }, { "distance": 0, "latitude": 0, "longitude": 0 }, { "distance": "111194.92664", "latitude": 0, "longitude": 1 }, { "distance": "111194.92664", "latitude": 1, "longitude": 0 }];
var actual = runQuery("FOR x IN WITHIN(" + locations.name() + ", 0, 0, 150000) " +
"LET d = DISTANCE(0,0,x.latitude,x.longitude) " +
"SORT x.latitude, x.longitude RETURN MERGE(x, {distance:d})");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test within function
////////////////////////////////////////////////////////////////////////////////
testWithin3: function () {
var expected = [{ "latitude": -10, "longitude": 25 }];
var actual = runQuery("FOR x IN WITHIN(" + locations.name() + ", -10, 25, 10000) SORT x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test within function
////////////////////////////////////////////////////////////////////////////////
testWithin4: function () {
var expected = [
{ "latitude": -11, "longitude": 25 },
{ "latitude": -10, "longitude": 24 },
{ "latitude": -10, "longitude": 25 },
{ "latitude": -10, "longitude": 26 },
{ "latitude": -9, "longitude": 25 }
];
var actual = runQuery("FOR x IN WITHIN(" + locations.name() + ", -10, 25, 150000) SORT x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test within function
////////////////////////////////////////////////////////////////////////////////
testWithin5: function () {
var expected = [];
var actual = runQuery("FOR x IN WITHIN(" + locations.name() + ", -90, 90, 10000) SORT x.latitude, x.longitude RETURN x");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test without geo index available
////////////////////////////////////////////////////////////////////////////////
testNonIndexed: function () {
assertQueryError(errors.ERROR_QUERY_GEO_INDEX_MISSING.code, "RETURN NEAR(" + locationsNon.name() + ", 0, 0, 10)");
assertQueryError(errors.ERROR_QUERY_GEO_INDEX_MISSING.code, "RETURN WITHIN(" + locationsNon.name() + ", 0, 0, 10)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid NEAR arguments count
////////////////////////////////////////////////////////////////////////////////
testInvalidNearArgument: function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN NEAR(\"" + locations.name() + "\", 0, 0, \"foo\")");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN NEAR(\"" + locations.name() + "\", 0, 0, true)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN NEAR(\"" + locations.name() + "\", 0, 0, 10, true)");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid WITHIN arguments count
////////////////////////////////////////////////////////////////////////////////
testInvalidWithinArgument: function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locations.name() + "\", 0, 0, \"foo\")");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locations.name() + "\", 0, 0, true)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locations.name() + "\", 0, 0, 0, true)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(\"" + locations.name() + "\", 0, 0, 0, [ ])");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid collection parameter
////////////////////////////////////////////////////////////////////////////////
testInvalidCollectionArgument: function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(1234, 0, 0, 10)");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, "RETURN WITHIN(false, 0, 0, 10)");
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)");
assertQueryError(errors.ERROR_ARANGO_DATA_SOURCE_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)");
}
};
}
function pointsTestSuite() {
// Test queries with index usage and without
function runQuery(query) {
let result1 = getQueryResults(query.string, query.bindVars || {}, false);
let result2 = getQueryResults(query.string, query.bindVars || {}, false,
{ optimizer: { rules: ["-all"] } });
// due to bad experiences with interchange-adjacent-enumerations
let result3 = getQueryResults(query.string, query.bindVars || {}, false,
{ optimizer: { rules: ["-interchange-adjacent-enumerations"] } });
assertEqual(query.expected, result1, query.string);
assertEqual(query.expected, result2, query.string);
assertEqual(query.expected, result3, "Breaks with 'interchange-adjacent-enumerations': " + query.string);
}
let locations;
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp: function () {
var lat, lon;
db._drop("UnitTestsPointsTestSuite");
locations = db._create("UnitTestsPointsTestSuite");
for (lat = -40; lat <= 40; ++lat) {
for (lon = -40; lon <= 40; ++lon) {
locations.save({ "lat": lat, "lng": lon });
}
}
locations.ensureIndex({ type: "geo", fields: ["lat", "lng"]});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown: function () {
db._drop("UnitTestsPointsTestSuite");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple circle on sphere
////////////////////////////////////////////////////////////////////////////////
testContainsCircle1: function () {
runQuery({
string: "FOR x IN @@cc FILTER DISTANCE(-10, 25, x.lat, x.lng) <= 10000 RETURN x",
bindVars: {
"@cc": locations.name(),
},
expected: [{ "lat": -10, "lng": 25 }]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple circle on sphere
////////////////////////////////////////////////////////////////////////////////
testContainsCircle2: function () {
runQuery({
string: "FOR x IN @@cc FILTER DISTANCE(-10, 25, x.lat, x.lng) <= 150000 SORT x.lat, x.lng RETURN x",
bindVars: {
"@cc": locations.name(),
},
expected: [
{ "lat": -11, "lng": 25 },
{ "lat": -10, "lng": 24 },
{ "lat": -10, "lng": 25 },
{ "lat": -10, "lng": 26 },
{ "lat": -9, "lng": 25 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple circle on sphere
////////////////////////////////////////////////////////////////////////////////
testContainsCircle3: function () {
runQuery({
string: "FOR x IN @@cc FILTER DISTANCE(-90, -90, x.lat, x.lng) <= 10000 SORT x.lat, x.lng RETURN x",
bindVars: {
"@cc": locations.name(),
},
expected: []
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple circle on sphere
////////////////////////////////////////////////////////////////////////////////
testContainsCircle4: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_DISTANCE([25, -10], [x.lng, x.lat]) <= 10000 RETURN x",
bindVars: {
"@cc": locations.name(),
},
expected: [{ "lat": -10, "lng": 25 }]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple circle on sphere
////////////////////////////////////////////////////////////////////////////////
testContainsCircle5: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_DISTANCE([25, -10], [x.lng, x.lat]) <= 150000 SORT x.lat, x.lng RETURN x",
bindVars: {
"@cc": locations.name(),
},
expected: [
{ "lat": -11, "lng": 25 },
{ "lat": -10, "lng": 24 },
{ "lat": -10, "lng": 25 },
{ "lat": -10, "lng": 26 },
{ "lat": -9, "lng": 25 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple circle on sphere
////////////////////////////////////////////////////////////////////////////////
testContainsCircle6: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_DISTANCE([-90, -90], [x.lng, x.lat]) <= 10000 SORT x.lat, x.lng RETURN x",
bindVars: {
"@cc": locations.name(),
},
expected: []
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple annulus on sphere (a donut)
////////////////////////////////////////////////////////////////////////////////
testContainsAnnulus1: function () {
runQuery({
string: `FOR x IN @@cc
FILTER DISTANCE(-10, 25, x.lat, x.lng) <= 150000
FILTER DISTANCE(-10, 25, x.lat, x.lng) > 108500
SORT x.lat, x.lng RETURN x`,
bindVars: {
"@cc": locations.name(),
},
expected: [
{ "lat": -11, "lng": 25 },
{ "lat": -10, "lng": 24 },
{ "lat": -10, "lng": 26 },
{ "lat": -9, "lng": 25 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple annulus on sphere (a donut)
////////////////////////////////////////////////////////////////////////////////
testContainsAnnulus2: function () {
runQuery({
string: `FOR x IN @@cc
FILTER DISTANCE(-10, 25, x.lat, x.lng) <= 150000
FILTER DISTANCE(-10, 25, x.lat, x.lng) > 109545
SORT x.lat, x.lng RETURN x`,
bindVars: {
"@cc": locations.name(),
},
expected: [
{ "lat": -11, "lng": 25 },
{ "lat": -9, "lng": 25 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple annulus on sphere (a donut)
////////////////////////////////////////////////////////////////////////////////
testContainsAnnulus3: function () {
runQuery({
string: `FOR x IN @@cc
FILTER GEO_DISTANCE([25, -10], [x.lng, x.lat]) <= 150000
FILTER GEO_DISTANCE([25, -10], [x.lng, x.lat]) > 108500
SORT x.lat, x.lng RETURN x`,
bindVars: {
"@cc": locations.name(),
},
expected: [
{ "lat": -11, "lng": 25 },
{ "lat": -10, "lng": 24 },
{ "lat": -10, "lng": 26 },
{ "lat": -9, "lng": 25 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple annulus on a sphere (a donut)
////////////////////////////////////////////////////////////////////////////////
testContainsAnnulus4: function () {
runQuery({
string: `FOR x IN @@cc
FILTER GEO_DISTANCE([25, -10], [x.lng, x.lat]) <= 150000
FILTER GEO_DISTANCE([25, -10], [x.lng, x.lat]) > 109545
SORT x.lat, x.lng RETURN x`,
bindVars: {
"@cc": locations.name(),
},
expected: [
{ "lat": -11, "lng": 25 },
{ "lat": -9, "lng": 25 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple annulus on sphere (a donut) using refernces
////////////////////////////////////////////////////////////////////////////////
testContainsAnnulus5: function () {
runQuery({
string: `LET lat = -10
LET lng = 25
FOR x IN @@cc
FILTER DISTANCE(lat, lng, x.lat, x.lng) <= 150000
FILTER DISTANCE(lat, lng, x.lat, x.lng) > 109545
SORT x.lat, x.lng RETURN x`,
bindVars: {
"@cc": locations.name(),
},
expected: [
{ "lat": -11, "lng": 25 },
{ "lat": -9, "lng": 25 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple annulus on a sphere (a donut) using reference
////////////////////////////////////////////////////////////////////////////////
testContainsAnnulus6: function () {
runQuery({
string: `LET latLng = [25, -10]
FOR x IN @@cc
FILTER GEO_DISTANCE(latLng, [x.lng, x.lat]) <= 150000
FILTER GEO_DISTANCE(latLng, [x.lng, x.lat]) > 109545
SORT x.lat, x.lng RETURN x`,
bindVars: {
"@cc": locations.name(),
},
expected: [
{ "lat": -11, "lng": 25 },
{ "lat": -9, "lng": 25 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple annulus on a sphere (a donut) with nested FOR loops
////////////////////////////////////////////////////////////////////////////////
testContainsAnnulus7: function () {
runQuery({
string: `LET coords = [[25, -10], [150, 70]]
FOR latLng IN coords
FOR x IN @@cc
FILTER GEO_DISTANCE(latLng, [x.lng, x.lat]) <= 150000
FILTER GEO_DISTANCE(latLng, [x.lng, x.lat]) > 109545
SORT x.lat, x.lng RETURN x`,
bindVars: {
"@cc": locations.name(),
},
expected: [
{ "lat": -11, "lng": 25 },
{ "lat": -9, "lng": 25 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test containment with a polygon
////////////////////////////////////////////////////////////////////////////////
testContainsPolygon: function () {
const polygon = {
"type": "Polygon",
"coordinates": [[[-11.5, 23.5], [-6, 26], [-10.5, 26.1], [-11.5, 23.5]]]
};
runQuery({
string: `FOR x IN @@cc
FILTER GEO_CONTAINS(@poly, [x.lng, x.lat])
SORT x.lat, x.lng RETURN x`,
bindVars: {
"@cc": locations.name(),
"poly": polygon
},
expected: [
{ "lat": 24, "lng": -11 },
{ "lat": 25, "lng": -10 },
{ "lat": 25, "lng": -9 },
{ "lat": 26, "lng": -10 },
{ "lat": 26, "lng": -9 },
{ "lat": 26, "lng": -8 },
{ "lat": 26, "lng": -7 },
{ "lat": 26, "lng": -6 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test containment in a nested FOR loop
////////////////////////////////////////////////////////////////////////////////
testContainsPolygonNested: function () {
const polygon1 = [[[-11.5, 12.5], [-11.5, 13.5], [-10.5, 13.5], [-10.5, 12.5], [-11.5, 12.5]]];
const polygon2 = [[[11.5, -12.5], [11.5, -13.5], [10.5, -13.5], [10.5, -12.5], [11.5, -12.5]]];
runQuery({
string: `
FOR poly IN [GEO_POLYGON(@poly1), GEO_POLYGON(@poly2)]
FOR doc IN @@cc
FILTER GEO_CONTAINS(poly, [doc.lng, doc.lat])
SORT doc.lat, doc.lng
RETURN doc
`,
bindVars: {
"@cc": locations.name(),
"poly1": polygon1,
"poly2": polygon2
},
expected: [
{ "lat": -13, "lng": 11 },
{ "lat": 13, "lng": -11 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test intersection with a polygon
////////////////////////////////////////////////////////////////////////////////
testIntersectsPolygon: function () {
const polygon = {
"type": "Polygon",
"coordinates": [[[-11.5, 23.5], [-6, 26], [-10.5, 26.1], [-11.5, 23.5]]]
};
runQuery({
string: `FOR x IN @@cc
FILTER GEO_INTERSECTS(@poly, [x.lng, x.lat])
SORT x.lat, x.lng RETURN x`,
bindVars: {
"@cc": locations.name(),
"poly": polygon
},
expected: [
{ "lat": 24, "lng": -11 },
{ "lat": 25, "lng": -10 },
{ "lat": 25, "lng": -9 },
{ "lat": 26, "lng": -10 },
{ "lat": 26, "lng": -9 },
{ "lat": 26, "lng": -8 },
{ "lat": 26, "lng": -7 },
{ "lat": 26, "lng": -6 }
]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test intersection in a nested FOR loop
////////////////////////////////////////////////////////////////////////////////
testIntersectsPolygonNested: function () {
const polygon1 = [[[-11.5, 12.5], [-11.5, 13.5], [-10.5, 13.5], [-10.5, 12.5], [-11.5, 12.5]]];
const polygon2 = [[[11.5, -12.5], [11.5, -13.5], [10.5, -13.5], [10.5, -12.5], [11.5, -12.5]]];
runQuery({
string: `
FOR poly IN [GEO_POLYGON(@poly1), GEO_POLYGON(@poly2)]
FOR doc IN @@cc
FILTER GEO_INTERSECTS(poly, [doc.lng, doc.lat])
SORT doc.lat, doc.lng
RETURN doc
`,
bindVars: {
"@cc": locations.name(),
"poly1": polygon1,
"poly2": polygon2
},
expected: [
{ "lat": -13, "lng": 11 },
{ "lat": 13, "lng": -11 }
]
});
}
};
}
const internal = require('internal');
////////////////////////////////////////////////////////////////////////////////
/// @brief Querys on a collection of GeoJson objects
////////////////////////////////////////////////////////////////////////////////
function geoJsonTestSuite() {
let locations;
// Test queries with index usage and without
function runQuery(query) {
var result1 = getQueryResults(query.string, query.bindVars || {}, false);
var result2 = getQueryResults(query.string, query.bindVars || {}, false,
{ optimizer: { rules: ["-all"] } });
let expected = query.expected.slice().sort();
assertEqual(expected, result1.sort(), query.string);
assertEqual(expected, result2.sort(), query.string);
}
// GeoJSON test data, located over Borneo, Sumatra and malaysia
// Mostly from the spec: http://geojson.org/geojson-spec.html.
let indonesia = [
{ "type": "Polygon", "coordinates": [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]] },
{ "type": "LineString", "coordinates": [[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]] },
{ "type": "Point", "coordinates": [102.0, 0.5] },
{ "type": "MultiPolygon", "coordinates": [
[[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],
[[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],
[[100.2, 0.2], [100.2, 0.8], [100.8, 0.8], [100.8, 0.2], [100.2, 0.2]]]]
}];
let indonesiaKeys = [];
// EMEA region
let emea = [ // TODO implement multi-polygon
/*{ "type": "MultiPolygon", "coordinates": [ [[[40, 40], [20, 45], [45, 30], [40, 40]]],
[[[20, 35], [10, 30], [10, 10], [30, 5], [45, 20], [20, 35]], [[30, 20], [20, 15], [20, 25], [30, 20]]]] }*/
{ "type": "Polygon", "coordinates": [[[35, 10], [45, 45], [15, 40], [10, 20], [35, 10]], [[20, 30], [35, 35], [30, 20], [20, 30]]] },
{ "type": "LineString", "coordinates": [[25, 10], [10, 30], [25, 40]] },
{ "type": "MultiLineString", "coordinates": [[[10, 10], [20, 20], [10, 40]], [[40, 40], [30, 30], [40, 20], [30, 10]]] },
{ "type": "MultiPoint", "coordinates": [[10, 40], [40, 30], [20, 20], [30, 10]] }
];
let emeaKeys = [];
let rectEmea1 = { "type": "Polygon", "coordinates": [[[2, 4], [26, 4], [26, 49], [2, 49], [2, 4]]] };
let rectEmea2 = { "type": "Polygon", "coordinates": [[[35, 42], [49, 42], [49, 50], [35, 51], [35, 42]]] };
let rectEmea3 = { "type": "Polygon", "coordinates": [[[35, 42], [49, 42], [49, 50], [35, 50], [35, 42]]] };
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp: function () {
var lat, lon;
db._drop("UnitTestsGeoJsonTestSuite");
locations = db._create("UnitTestsGeoJsonTestSuite");
locations.ensureIndex({ type: "geo", fields: ["geometry"], geoJson: true});
indonesiaKeys = indonesia.map(doc => locations.save({ geometry: doc })._key);
emeaKeys = emea.map(doc => locations.save({ geometry: doc })._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown: function () {
db._drop("UnitTestsGeoJsonTestSuite");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple circle on sphere
////////////////////////////////////////////////////////////////////////////////
testJsonContainsCircle1: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_DISTANCE(GEO_POINT(102, 0), x.geometry) <= 450000 RETURN x._key",
bindVars: {
"@cc": locations.name(),
},
expected: indonesiaKeys
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple circle on sphere (without circle edge included)
////////////////////////////////////////////////////////////////////////////////
testJsonContainsCircle2: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_DISTANCE(GEO_POINT(101, 0), x.geometry) < 283439.318405 RETURN x._key",
bindVars: {
"@cc": locations.name(),
},
expected: [indonesiaKeys[0], indonesiaKeys[2], indonesiaKeys[3]]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple circle on sphere
////////////////////////////////////////////////////////////////////////////////
testJsonContainsCircle3: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_DISTANCE(GEO_POINT(101, 0), x.geometry) <= 100000 RETURN x._key",
bindVars: {
"@cc": locations.name(),
},
expected: indonesiaKeys.slice(0, 1)
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test simple circle on sphere
////////////////////////////////////////////////////////////////////////////////
testJsonContainsCircle4: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_DISTANCE(GEO_POINT(101, 0), x.geometry) <= 100000 RETURN x._key",
bindVars: {
"@cc": locations.name(),
},
expected: indonesiaKeys.slice(0, 1)
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test polygon contains
////////////////////////////////////////////////////////////////////////////////
testJsonContainsPolygon1: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_CONTAINS(GEO_POLYGON(@poly), x.geometry) RETURN x._key",
bindVars: {
"@cc": locations.name(),
"poly": rectEmea1.coordinates
},
expected: [emeaKeys[1]]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test polygon contains
////////////////////////////////////////////////////////////////////////////////
testJsonContainsPolygon2: function () {
runQuery({
string: `LET poly = GEO_POLYGON(@coords)
FOR x IN @@cc
FILTER GEO_CONTAINS(poly, x.geometry)
RETURN x._key`,
bindVars: {
"@cc": locations.name(),
"coords": rectEmea1.coordinates
},
expected: [emeaKeys[1]]
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test polygon intersection
////////////////////////////////////////////////////////////////////////////////
testJsonIntersectsPolygon1: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_INTERSECTS(GEO_POLYGON(@poly), x.geometry) RETURN x._key",
bindVars: {
"@cc": locations.name(),
"poly": rectEmea1.coordinates
},
expected: emeaKeys
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test polygon intersection
////////////////////////////////////////////////////////////////////////////////
testJsonIntersectsPolygon2: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_INTERSECTS(GEO_POLYGON(@poly), x.geometry) RETURN x._key",
bindVars: {
"@cc": locations.name(),
"poly": rectEmea2.coordinates
},
expected: emeaKeys.slice(0, 1)
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test polygon intersection
////////////////////////////////////////////////////////////////////////////////
testJsonIntersectsPolygon3: function () {
runQuery({
string: "FOR x IN @@cc FILTER GEO_INTERSECTS(GEO_POLYGON(@poly), x.geometry) RETURN x._key",
bindVars: {
"@cc": locations.name(),
"poly": rectEmea3.coordinates
},
expected: emeaKeys.slice(0, 1)
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test polygon intersection using a reference
////////////////////////////////////////////////////////////////////////////////
testJsonIntersectsPolygon4: function () {
runQuery({
string: `LET poly = GEO_POLYGON(@coords)
FOR x IN @@cc
FILTER GEO_INTERSECTS(poly, x.geometry)
RETURN x._key`,
bindVars: {
"@cc": locations.name(),
"coords": rectEmea3.coordinates
},
expected: emeaKeys.slice(0, 1)
});
}
};
}
function geoFunctionsTestSuite() {
function runQuery(query) {
var result1 = getQueryResults(query.string, query.bindVars || {}, false);
var result2 = getQueryResults(query.string, query.bindVars || {}, false,
{ optimizer: { rules: ["-all"] } });
let expected = query.expected.slice().sort();
assertEqual(expected, result1.sort(), query.string);
assertEqual(expected, result2.sort(), query.string);
}
let locations;
return {
testContainsPolygon1: function () {
// simple triangle
let triangle = {type:"Polygon", coordinates:[[[0,0], [1,0], [0,1], [0,0]]]};
let valid = [[0.01, 0.01], [0.01, 0.99], [0.99, 0.01], [0.49, 0.49]];
const query = "RETURN GEO_CONTAINS(@polygon, @cc)";
valid.forEach(c => {
assertEqual(getQueryResults(query, {"polygon": triangle, "cc": c}), [true]);
});
assertEqual(getQueryResults(query, {"polygon": triangle, "cc": [1.0, 1.0]}), [false]);
},
testContainsPolygon2: function () {
// polygon with nested rings
let polygon = {type:"Polygon", coordinates:[[[-1,-1], [2,-1], [2,2], [-1,2], [-1,-1]],
[[0,0], [1,0], [1,1], [0,1], [0,0]]]};
let valid = [[-0.99, -0.99], [1.99, -0.99], [1.99, 1.99], [-0.99, 1.99],
[-0.5, 0.5], [0.5, 1.5], [1.5, -0.5], [0.5, -0.5]];
const query = "RETURN GEO_CONTAINS(@polygon, @cc)";
valid.forEach(c => {
assertEqual(getQueryResults(query, {"polygon": polygon, "cc": c}), [true]);
});
assertEqual(getQueryResults(query, {"polygon": polygon, "cc": [0.5, 0.5]}), [false]);
assertEqual(getQueryResults(query, {"polygon": polygon, "cc": [3.0, 3.0]}), [false]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
testContainsMultiPolygon: function () {
let multipoly = {"type": "MultiPolygon", "coordinates": [[[[0,0], [1,0], [0,1], [0,0]]],[[[2,2], [3,2], [2,3], [2,2]]]] };
let valid = [[0.01, 0.01], [0.01, 0.99], [0.99, 0.01], [0.49, 0.49],
[2.01, 2.01], [2.01, 2.99], [2.99, 2.01], [2.49, 2.49]];
const query = "RETURN GEO_CONTAINS(@polygon, @cc)";
valid.forEach(c => {
assertEqual(getQueryResults(query, {"polygon": multipoly, "cc": c}), [true]);
});
assertEqual(getQueryResults(query, {"polygon": multipoly, "cc": [1.0, 1.0]}), [false]);
assertEqual(getQueryResults(query, {"polygon": multipoly, "cc": [3.0, 3.0]}), [false]);
},
testIntersectsPolygon1: function () {
// polygon with nested rings
let polygon = {type:"Polygon", coordinates:[[[-1,-1], [2,-1], [2,2], [-1,2], [-1,-1]],
[[0,0], [1,0], [1,1], [0,1], [0,0]]]};
let valid = [[-0.99, -0.99], [1.99, -0.99], [1.99, 1.99], [-0.99, 1.99],
[-0.5, 0.5], [0.5, 1.5], [1.5, -0.5], [0.5, -0.5]];
const query = "RETURN GEO_INTERSECTS(@polygon, @cc)";
valid.forEach(c => {
assertEqual(getQueryResults(query, {"polygon": polygon, "cc": c}), [true]);
});
assertEqual(getQueryResults(query, {"polygon": polygon, "cc": [0.5, 0.5]}), [false]);
assertEqual(getQueryResults(query, {"polygon": polygon, "cc": [3.0, 3.0]}), [false]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
testIntersectsMultiPolygon1: function () {
let multipoly = {"type": "MultiPolygon", "coordinates": [[[[0,0], [1,0], [0,1], [0,0]]],[[[2,2], [3,2], [2,3], [2,2]]]] };
let valid = [[0.01, 0.01], [0.01, 0.99], [0.99, 0.01], [0.49, 0.49],
[2.01, 2.01], [2.01, 2.99], [2.99, 2.01], [2.49, 2.49]];
const query = "RETURN GEO_INTERSECTS(@polygon, @cc)";
valid.forEach(c => {
assertEqual(getQueryResults(query, {"polygon": multipoly, "cc": c}), [true]);
});
assertEqual(getQueryResults(query, {"polygon": multipoly, "cc": [1.0, 1.0]}), [false]);
assertEqual(getQueryResults(query, {"polygon": multipoly, "cc": [3.0, 3.0]}), [false]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
testIntersectsMultiPolygon2: function () {
let multipoly = {"type": "MultiPolygon", "coordinates": [[[[0,0], [1,0], [0,1], [0,0]]],[[[2,2], [3,2], [2,3], [2,2]]]] };
let valid = [{"type": "Polygon","coordinates": [[[2.5,2],[3,2.0],[3,2.5],[2.5,2.5],[2.5,2]]]},
{"type": "LineString","coordinates": [[2,2.5],[2.5,3.0]]},
{"type": "LineString","coordinates": [[-0,0.5],[0.5,1],[0.5,-0.5]]}];
const query = "RETURN GEO_INTERSECTS(@polygon, @other)";
valid.forEach(c => {
assertEqual(getQueryResults(query, {"polygon": multipoly, "other": c}), [true]);
});
assertEqual(getQueryResults(query, {"polygon": multipoly, "other": {"type": "LineString","coordinates": [[2.5,1],[3,0.05]]}}), [false]);
},
};
}
jsunity.run(ahuacatlLegacyGeoTestSuite);
jsunity.run(legacyGeoTestSuite);
jsunity.run(pointsTestSuite);
jsunity.run(geoJsonTestSuite);
jsunity.run(geoFunctionsTestSuite);
return jsunity.done();