From 4bebe7c5bbcb7be92a45ea3255336964cd487bc6 Mon Sep 17 00:00:00 2001 From: leoleopon Date: Wed, 18 Aug 2021 17:46:47 +0500 Subject: [PATCH 1/5] Add SpatialPredicate supertype in predicates. --- addon/query/indexeddb-adapter.js | 12 +-- addon/query/js-adapter.js | 21 ++--- addon/query/odata-adapter.js | 20 ++--- addon/query/predicate.js | 137 ++++++++++++++++++++----------- 4 files changed, 106 insertions(+), 84 deletions(-) diff --git a/addon/query/indexeddb-adapter.js b/addon/query/indexeddb-adapter.js index e7befaeb..0ced26f3 100644 --- a/addon/query/indexeddb-adapter.js +++ b/addon/query/indexeddb-adapter.js @@ -10,8 +10,7 @@ import { StringPredicate, DetailPredicate, DatePredicate, - GeographyPredicate, - GeometryPredicate, + SpatialPredicate, TruePredicate, FalsePredicate } from './predicate'; @@ -610,13 +609,8 @@ function updateWhereClause(store, table, query) { } } - if (predicate instanceof GeographyPredicate) { - Ember.warn('GeographyPredicate is not supported in indexedDB-adapter'); - return table; - } - - if (predicate instanceof GeometryPredicate) { - Ember.warn('GeometryPredicate is not supported in indexedDB-adapter'); + if (predicate instanceof SpatialPredicate) { + Ember.warn('SpatialPredicate subtypes are not supported in indexedDB-adapter'); return table; } diff --git a/addon/query/js-adapter.js b/addon/query/js-adapter.js index 686a7e9d..b73b201a 100644 --- a/addon/query/js-adapter.js +++ b/addon/query/js-adapter.js @@ -6,8 +6,7 @@ import { StringPredicate, DetailPredicate, DatePredicate, - GeographyPredicate, - GeometryPredicate, + SpatialPredicate, TruePredicate, FalsePredicate } from './predicate'; @@ -253,24 +252,16 @@ export default class JSAdapter extends BaseAdapter { let b2 = predicate instanceof StringPredicate; let b3 = predicate instanceof DetailPredicate; let b4 = predicate instanceof DatePredicate; - let b5 = predicate instanceof GeographyPredicate; - let b6 = predicate instanceof GeometryPredicate; - let b7 = predicate instanceof TruePredicate; - let b8 = predicate instanceof FalsePredicate; - if (b1 || b2 || b3 || b4 || b7 || b8) { + let b5 = predicate instanceof SpatialPredicate; + let b6 = predicate instanceof TruePredicate; + let b7 = predicate instanceof FalsePredicate; + if (b1 || b2 || b3 || b4 || b6 || b7) { let filterFunction = this.getAttributeFilterFunction(predicate, options); return this.getFilterFunctionAnd([filterFunction]); } if (b5) { - Ember.warn('GeographyPredicate is not supported in js-adapter'); - return function (data) { - return data; - }; - } - - if (b6) { - Ember.warn('GeometryPredicate is not supported in js-adapter'); + Ember.warn('SpatialPredicate subtypes are not supported in js-adapter'); return function (data) { return data; }; diff --git a/addon/query/odata-adapter.js b/addon/query/odata-adapter.js index 43a4c663..b20235ad 100644 --- a/addon/query/odata-adapter.js +++ b/addon/query/odata-adapter.js @@ -8,8 +8,7 @@ import { StringPredicate, DetailPredicate, DatePredicate, - GeographyPredicate, - GeometryPredicate, + SpatialPredicate, NotPredicate, IsOfPredicate, TruePredicate, @@ -268,22 +267,17 @@ export default class ODataAdapter extends BaseAdapter { return `isof(${expression},'${namespace}.${className}')`; } - if (predicate instanceof GeographyPredicate) { + if (predicate instanceof SpatialPredicate) { let attribute = this._getODataAttributeName(modelName, predicate.attributePath); if (prefix) { attribute = `${prefix}/${attribute}`; } - return `geo.intersects(geography1=${attribute},geography2=geography'${predicate.intersectsValue}')`; - } - - if (predicate instanceof GeometryPredicate) { - let attribute = this._getODataAttributeName(modelName, predicate.attributePath); - if (prefix) { - attribute = `${prefix}/${attribute}`; - } - - return `geom.intersects(geometry1=${attribute},geometry2=geometry'${predicate.intersectsValue}')`; + let ns = predicate.spatialNamespace; + let tp = predicate.spatialType; + let fn = predicate.spatialFunction; + let vl = predicate.spatialValue; + return `${ns}.${fn}(${tp}1=${attribute},${tp}2=${tp}'${vl}')`; } if (predicate instanceof DetailPredicate) { diff --git a/addon/query/predicate.js b/addon/query/predicate.js index 80266e73..3bd744fd 100644 --- a/addon/query/predicate.js +++ b/addon/query/predicate.js @@ -293,25 +293,26 @@ export class StringPredicate extends BasePredicate { } /** - * The predicate class for geography attributes. + * The base class of logical predicate for spatial attributes. * * @namespace Query - * @class GeographyPredicate + * @class SpatialPredicate * @extends BasePredicate * * @param {String} attributePath The path to the attribute for predicate. * @constructor */ -export class GeographyPredicate extends BasePredicate { +export class SpatialPredicate extends BasePredicate { constructor(attributePath) { super(); if (!attributePath) { - throw new Error('Attribute path is required for GeographyPredicate constructor.'); + throw new Error('Attribute path is required for SpatialPredicate constructor.'); } this._attributePath = attributePath; - this._intersectsValue = null; + this._function = null; + this._value = null; } /** @@ -326,85 +327,127 @@ export class GeographyPredicate extends BasePredicate { } /** - * The geography value that has to intersect with the attribute. + * The spatial function to call. * - * @property intersectsValue + * @property spatialFunction * @type {String} * @public */ - get intersectsValue() { - return this._intersectsValue; + get spatialFunction() { + return this._function; } /** - * Sets the value that the attribute has to contain. + * The spatial value that has to be the second argument of the spatial function, + * assuming the attribute is the first argument. + * + * @property spatialValue + * @type {String} + * @public + */ + get spatialValue() { + return this._value; + } + + /** + * The spatial type namespace. + * + * @property spatialNamespace + * @type {String} + * @public + */ + get spatialNamespace() { + throw this._getAbstractPropertyError('spatialNamespace'); + } + + /** + * The spatial type. + * + * @property spatialType + * @type {String} + * @public + */ + get spatialType() { + throw this._getAbstractPropertyError('spatialType'); + } + + /** + * Sets the spatial type value that has to intersect with the attribute. * * @method contains - * @param {String} geography The geography value that has to intersect with the attribute. - * @return {Query.StringPredicate} Returns this instance. + * @param {String} value The spatial type value that has to intersect with the attribute. + * @return {Query.SpatialPredicate} Returns this instance. * @chainable */ - intersects(geography) { - this._intersectsValue = geography; + intersects(value) { + this._function = 'intersects'; + this._value = value; return this; } + + _getAbstractPropertyError(property) { + return new Error(`The ${property} property must be overridden in the SpatialPredicate subtypes.`); + } } /** - * The predicate class for geometry attributes. + * The predicate class for geography attributes. * * @namespace Query - * @class GeometryPredicate - * @extends BasePredicate - * - * @param {String} attributePath The path to the attribute for predicate. - * @constructor + * @class GeographyPredicate + * @extends SpatialPredicate */ -export class GeometryPredicate extends BasePredicate { - constructor(attributePath) { - super(); - - if (!attributePath) { - throw new Error('Attribute path is required for GeometryPredicate constructor.'); - } - - this._attributePath = attributePath; - this._intersectsValue = null; +export class GeographyPredicate extends SpatialPredicate { + /** + * The geography type namespace. + * + * @property spatialNamespace + * @type {String} + * @public + */ + get spatialNamespace() { + return 'geo'; } /** - * The path to the attribute for predicate. + * The geography type. * - * @property attributePath + * @property spatialType * @type {String} * @public */ - get attributePath() { - return this._attributePath; + get spatialType() { + return 'geography'; } +} - /** - * The geometry value that has to intersect with the attribute. +/** + * The predicate class for geometry attributes. + * + * @namespace Query + * @class GeometryPredicate + * @extends SpatialPredicate + */ +export class GeometryPredicate extends SpatialPredicate { /** + * The geometry type namespace. * - * @property intersectsValue + * @property spatialNamespace * @type {String} * @public */ - get intersectsValue() { - return this._intersectsValue; + get spatialNamespace() { + return 'geom'; } /** - * Sets the value that the attribute has to contain. + * The geometry type. * - * @method contains - * @param {String} geometry The geometry value that has to intersect with the attribute. - * @return {Query.StringPredicate} Returns this instance. - * @chainable + * @property spatialType + * @type {String} + * @public */ - intersects(geometry) { - this._intersectsValue = geometry; - return this; + get spatialType() { + return 'geometry'; } } From 478b74685fb91eee6420ab46a56930483bc6138b Mon Sep 17 00:00:00 2001 From: leoleopon Date: Fri, 20 Aug 2021 17:51:34 +0500 Subject: [PATCH 2/5] Rename geometry-predicate.js to geometry-predicate-test.js in tests/unit/query/ . --- .../query/{geometry-predicate.js => geometry-predicate-test.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/unit/query/{geometry-predicate.js => geometry-predicate-test.js} (100%) diff --git a/tests/unit/query/geometry-predicate.js b/tests/unit/query/geometry-predicate-test.js similarity index 100% rename from tests/unit/query/geometry-predicate.js rename to tests/unit/query/geometry-predicate-test.js From ac4a8114ba016e606022966729b89c2695b1e9b4 Mon Sep 17 00:00:00 2001 From: leoleopon Date: Thu, 26 Aug 2021 14:46:37 +0500 Subject: [PATCH 3/5] Use hash to store the SpatialPredicate subtype instance metadata. --- addon/query/odata-adapter.js | 6 +++--- addon/query/predicate.js | 33 +++++++++++++++++---------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/addon/query/odata-adapter.js b/addon/query/odata-adapter.js index b20235ad..7f9db725 100644 --- a/addon/query/odata-adapter.js +++ b/addon/query/odata-adapter.js @@ -274,10 +274,10 @@ export default class ODataAdapter extends BaseAdapter { } let ns = predicate.spatialNamespace; - let tp = predicate.spatialType; let fn = predicate.spatialFunction; - let vl = predicate.spatialValue; - return `${ns}.${fn}(${tp}1=${attribute},${tp}2=${tp}'${vl}')`; + let tp = predicate.spatialType; + let sp = predicate.spatial; + return `${ns}.${fn}(${tp}1=${attribute},${tp}2=${tp}'${sp}')`; } if (predicate instanceof DetailPredicate) { diff --git a/addon/query/predicate.js b/addon/query/predicate.js index 3bd744fd..2d91dbf1 100644 --- a/addon/query/predicate.js +++ b/addon/query/predicate.js @@ -311,8 +311,7 @@ export class SpatialPredicate extends BasePredicate { } this._attributePath = attributePath; - this._function = null; - this._value = null; + this._options = null; } /** @@ -327,26 +326,26 @@ export class SpatialPredicate extends BasePredicate { } /** - * The spatial function to call. + * The spatial type value that has to be the second argument of the spatial function, + * assuming the attribute is the first argument. * - * @property spatialFunction + * @property spatial * @type {String} * @public */ - get spatialFunction() { - return this._function; + get spatial() { + return this._options.spatial; } /** - * The spatial value that has to be the second argument of the spatial function, - * assuming the attribute is the first argument. + * The spatial function to call. * - * @property spatialValue + * @property spatialFunction * @type {String} * @public */ - get spatialValue() { - return this._value; + get spatialFunction() { + return this._function; } /** @@ -372,16 +371,18 @@ export class SpatialPredicate extends BasePredicate { } /** - * Sets the spatial type value that has to intersect with the attribute. + * Sets the spatial predicate metadata that has to be used on build the intersection condition with the attribute. * - * @method contains - * @param {String} value The spatial type value that has to intersect with the attribute. + * @method intesects + * @param {String} spatial The spatial type value that has to intersect with the attribute. * @return {Query.SpatialPredicate} Returns this instance. * @chainable */ - intersects(value) { + intersects(spatial) { this._function = 'intersects'; - this._value = value; + this._options = { + spatial: spatial, + } return this; } From acc7965ddb9d91599305c935680b814979962f9e Mon Sep 17 00:00:00 2001 From: leoleopon Date: Thu, 26 Aug 2021 15:37:34 +0500 Subject: [PATCH 4/5] Add supported SpatialPredicate spatial functions check in ODataAdapter. --- addon/query/odata-adapter.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/addon/query/odata-adapter.js b/addon/query/odata-adapter.js index 7f9db725..814fbeaf 100644 --- a/addon/query/odata-adapter.js +++ b/addon/query/odata-adapter.js @@ -277,7 +277,13 @@ export default class ODataAdapter extends BaseAdapter { let fn = predicate.spatialFunction; let tp = predicate.spatialType; let sp = predicate.spatial; - return `${ns}.${fn}(${tp}1=${attribute},${tp}2=${tp}'${sp}')`; + + switch (fn) { + case 'intersects': + return `${ns}.${fn}(${tp}1=${attribute},${tp}2=${tp}'${sp}')`; + } + + throw new Error(`Unsupported '${fn}' spatial function.`); } if (predicate instanceof DetailPredicate) { From 414c2c764ed1ccc1db27a9e72a9b4a0a3b02d169 Mon Sep 17 00:00:00 2001 From: leoleopon Date: Sat, 28 Aug 2021 00:38:09 +0500 Subject: [PATCH 5/5] Add SpatialPredicate distance() method with implementation for ODataAdapter. --- CHANGELOG.md | 5 + addon/query/odata-adapter.js | 8 +- addon/query/predicate.js | 42 ++++++ tests/unit/query/indexeddb-adapter-test.js | 44 ++++++ tests/unit/query/js-adapter-test.js | 44 +++++- tests/unit/query/odata-adapter-test.js | 164 +++++++++++++++++++-- 6 files changed, 288 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a61d5f48..8ea9a134 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log ## [Unreleased] +### Added +- The `distance` method for the `SpatialPredicate` predicate with implementation for the `ODataAdapter` adapter. + +### Changed +- The `GeographyPredicate` and `GeometryPredicate` predicates are the `SpatialPredicate` predicate subtypes. ## [2.6.0] - 2021-07-02 ### Added diff --git a/addon/query/odata-adapter.js b/addon/query/odata-adapter.js index 814fbeaf..7b116b8d 100644 --- a/addon/query/odata-adapter.js +++ b/addon/query/odata-adapter.js @@ -278,9 +278,15 @@ export default class ODataAdapter extends BaseAdapter { let tp = predicate.spatialType; let sp = predicate.spatial; + let expression = `${ns}.${fn}(${tp}1=${attribute},${tp}2=${tp}'${sp}')`; switch (fn) { + case 'distance': { + let operator = this._getODataFilterOperator(predicate.operator); + let value = predicate.value; + return `${expression} ${operator} ${value}`; + } case 'intersects': - return `${ns}.${fn}(${tp}1=${attribute},${tp}2=${tp}'${sp}')`; + return expression; } throw new Error(`Unsupported '${fn}' spatial function.`); diff --git a/addon/query/predicate.js b/addon/query/predicate.js index 2d91dbf1..b6cfd4e1 100644 --- a/addon/query/predicate.js +++ b/addon/query/predicate.js @@ -325,6 +325,17 @@ export class SpatialPredicate extends BasePredicate { return this._attributePath; } + /** + * The filter operator. + * + * @property operator + * @type Query.FilterOperator + * @public + */ + get operator() { + return this._options.operator; + } + /** * The spatial type value that has to be the second argument of the spatial function, * assuming the attribute is the first argument. @@ -370,6 +381,37 @@ export class SpatialPredicate extends BasePredicate { throw this._getAbstractPropertyError('spatialType'); } + /** + * The value for filtering. + * + * @property value + * @type String|Number + * @public + */ + get value() { + return this._options.value; + } + + /** + * Sets the spatial predicate metadata that has to be used on build the distance condition with the attribute. + * + * @method distance + * @param {String} spatial The spatial type value that has to have a distance from the attribute. + * @param operator {Query.FilterOperator|String} The filter operator. + * @param value {String|Number} The value for filtering. + * @return {Query.SpatialPredicate} Returns this instance. + * @chainable + */ + distance(spatial, operator, value) { + this._function = 'distance'; + this._options = { + spatial: spatial, + operator: FilterOperator.tryCreate(operator), + value: value, + } + return this; + } + /** * Sets the spatial predicate metadata that has to be used on build the intersection condition with the attribute. * diff --git a/tests/unit/query/indexeddb-adapter-test.js b/tests/unit/query/indexeddb-adapter-test.js index 49295f3e..4f0f6e0c 100644 --- a/tests/unit/query/indexeddb-adapter-test.js +++ b/tests/unit/query/indexeddb-adapter-test.js @@ -1639,6 +1639,28 @@ function getJoinsPerformanceTestData(count, assert) { return data; } +test('adapter | indexeddb | geography predicate | distance', (assert) => { + let data = { + employee: [ + { id: 1, Coordinates: 'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' }, + { id: 2, Coordinates: 'SRID=12346;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' }, + { id: 3, Coordinates: 'SRID=12347;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' } + ] + }; + + let gp = new GeographyPredicate('Coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0); + let builder = new QueryBuilder(storeIndexedbAdapterTest, modelNameIndexedbAdapterTest).where(gp); + + executeTest(data, builder.build(), assert, (result) => { + assert.ok(result.data); + assert.equal(result.data.length, 3); + assert.equal(result.data[0].id, 1); + assert.equal(result.data[1].id, 2); + assert.equal(result.data[2].id, 3); + }); +}); + test('adapter | indexeddb | geography predicate | intersects', (assert) => { let data = { employee: [ @@ -1661,6 +1683,28 @@ test('adapter | indexeddb | geography predicate | intersects', (assert) => { }); }); +test('adapter | indexeddb | geometry predicate | distance', (assert) => { + let data = { + employee: [ + { id: 1, Coordinates: 'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' }, + { id: 2, Coordinates: 'SRID=12346;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' }, + { id: 3, Coordinates: 'SRID=12347;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' } + ] + }; + + let gp = new GeometryPredicate('Coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0); + let builder = new QueryBuilder(storeIndexedbAdapterTest, modelNameIndexedbAdapterTest).where(gp); + + executeTest(data, builder.build(), assert, (result) => { + assert.ok(result.data); + assert.equal(result.data.length, 3); + assert.equal(result.data[0].id, 1); + assert.equal(result.data[1].id, 2); + assert.equal(result.data[2].id, 3); + }); +}); + test('adapter | indexeddb | geometry predicate | intersects', (assert) => { let data = { employee: [ diff --git a/tests/unit/query/js-adapter-test.js b/tests/unit/query/js-adapter-test.js index e3521a46..60094143 100644 --- a/tests/unit/query/js-adapter-test.js +++ b/tests/unit/query/js-adapter-test.js @@ -526,6 +526,26 @@ test('adapter | js | skip-top', (assert) => { assert.equal(result[0].Name, 'B'); }); +test('adapter | js | geography predicate | distance', (assert) => { + const data = [ + { id: 1, Coordinates: 'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' }, + { id: 2, Coordinates: 'SRID=12346;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' }, + { id: 3, Coordinates: 'SRID=12347;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' } + ]; + + let sp1 = new GeographyPredicate('Coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0); + let builder = new QueryBuilder(store, 'employee').where(sp1); + let filter = adapter.buildFunc(builder.build()); + + let result = filter(data); + assert.ok(result); + assert.equal(result.length, 3); + assert.equal(result[0].id, 1); + assert.equal(result[1].id, 2); + assert.equal(result[2].id, 3); +}); + test('adapter | js | geography predicate | intersects', (assert) => { const data = [ { id: 1, Coordinates: 'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' }, @@ -534,7 +554,27 @@ test('adapter | js | geography predicate | intersects', (assert) => { ]; let sp1 = new GeographyPredicate('Coordinates'). - intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'); + intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'); + let builder = new QueryBuilder(store, 'employee').where(sp1); + let filter = adapter.buildFunc(builder.build()); + + let result = filter(data); + assert.ok(result); + assert.equal(result.length, 3); + assert.equal(result[0].id, 1); + assert.equal(result[1].id, 2); + assert.equal(result[2].id, 3); +}); + +test('adapter | js | geometry predicate | distance', (assert) => { + const data = [ + { id: 1, Coordinates: 'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' }, + { id: 2, Coordinates: 'SRID=12346;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' }, + { id: 3, Coordinates: 'SRID=12347;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))' } + ]; + + let sp1 = new GeometryPredicate('Coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0); let builder = new QueryBuilder(store, 'employee').where(sp1); let filter = adapter.buildFunc(builder.build()); @@ -554,7 +594,7 @@ test('adapter | js | geometry predicate | intersects', (assert) => { ]; let sp1 = new GeometryPredicate('Coordinates'). - intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'); + intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'); let builder = new QueryBuilder(store, 'employee').where(sp1); let filter = adapter.buildFunc(builder.build()); diff --git a/tests/unit/query/odata-adapter-test.js b/tests/unit/query/odata-adapter-test.js index cf291282..1adbceb7 100644 --- a/tests/unit/query/odata-adapter-test.js +++ b/tests/unit/query/odata-adapter-test.js @@ -495,7 +495,20 @@ test('adapter | odata | select | master fields', function (assert) { ); }); -test('adapter | odata | geography predicate | intersect', function (assert) { +test('adapter | odata | geography predicate | distance', function (assert) { + // Arrange. + let gp = new GeographyPredicate('coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0); + + // Act. + let builder = new QueryBuilder(store, 'customer').where(gp); + + // Act && Assert. + runTest(assert, builder, 'Customers', `$filter=geo.distance(geography1=Coordinates,geography2=geography'SRID=12345;` + + `POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))') eq 0&$select=CustomerID`); +}); + +test('adapter | odata | geography predicate | intersects', function (assert) { // Arrange. let gp = new GeographyPredicate('coordinates'). intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'); @@ -508,7 +521,21 @@ test('adapter | odata | geography predicate | intersect', function (assert) { `POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))')&$select=CustomerID`); }); -test('adapter | odata | geography predicate | inside complex', function (assert) { +test('adapter | odata | geography predicate | inside complex | distance', function (assert) { + // Arrange. + let gp = new GeographyPredicate('coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0); + let sp = new SimplePredicate('firstName', FilterOperator.Eq, 'Vasya'); + + // Act. + let builder = new QueryBuilder(store, 'customer').where(gp.and(sp)); + + // Act && Assert. + runTest(assert, builder, 'Customers', `$filter=geo.distance(geography1=Coordinates,geography2=geography'SRID=12345;` + + `POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))') eq 0 and FirstName eq 'Vasya'&$select=CustomerID`); +}); + +test('adapter | odata | geography predicate | inside complex | intersects', function (assert) { // Arrange. let gp = new GeographyPredicate('coordinates'). intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'); @@ -522,10 +549,23 @@ test('adapter | odata | geography predicate | inside complex', function (assert) `POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))') and FirstName eq 'Vasya'&$select=CustomerID`); }); -test('adapter | odata | detail predicate | all | with geography predicate', function (assert) { +test('adapter | odata | detail predicate | all | with geography predicate | distance ', function (assert) { + // Arrange. + let dp = new DetailPredicate('userVotes').all(new GeographyPredicate('applicationUser.coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0)); + + // Act. + let builder = new QueryBuilder(store, 'ember-flexberry-dummy-comment').where(dp); + + // Act && Assert. + runTest(assert, builder, 'EmberFlexberryDummyComments', `$filter=UserVotes/all(f:geo.distance(geography1=f/ApplicationUser/Coordinates,` + + `geography2=geography'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))') eq 0)&$select=__PrimaryKey`); +}); + +test('adapter | odata | detail predicate | all | with geography predicate | intersects ', function (assert) { // Arrange. let dp = new DetailPredicate('userVotes').all(new GeographyPredicate('applicationUser.coordinates'). - intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))')); + intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))')); // Act. let builder = new QueryBuilder(store, 'ember-flexberry-dummy-comment').where(dp); @@ -535,20 +575,46 @@ test('adapter | odata | detail predicate | all | with geography predicate', func `geography2=geography'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'))&$select=__PrimaryKey`); }); -test('adapter | odata | detail predicate | any | with geography predicate', function (assert) { +test('adapter | odata | detail predicate | any | with geography predicate | distance', function (assert) { + // Arrange. + let dp = new DetailPredicate('userVotes').any(new GeographyPredicate('applicationUser.coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0)); + + // Act. + let builder = new QueryBuilder(store, 'ember-flexberry-dummy-comment').where(dp); + + // Act && Assert. + runTest(assert, builder, 'EmberFlexberryDummyComments', `$filter=UserVotes/any(f:geo.distance(geography1=f/ApplicationUser/Coordinates,` + + `geography2=geography'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))') eq 0)&$select=__PrimaryKey`); +}); + +test('adapter | odata | detail predicate | any | with geography predicate | intersects', function (assert) { // Arrange. let dp = new DetailPredicate('userVotes').any(new GeographyPredicate('applicationUser.coordinates'). - intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))')); + intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))')); // Act. let builder = new QueryBuilder(store, 'ember-flexberry-dummy-comment').where(dp); // Act && Assert. runTest(assert, builder, 'EmberFlexberryDummyComments', `$filter=UserVotes/any(f:geo.intersects(geography1=f/ApplicationUser/Coordinates,` + - `geography2=geography'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'))&$select=__PrimaryKey`); + `geography2=geography'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'))&$select=__PrimaryKey`); +}); + +test('adapter | odata | geometry predicate | distance', function (assert) { + // Arrange. + let gp = new GeometryPredicate('coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0); + + // Act. + let builder = new QueryBuilder(store, 'customer').where(gp); + + // Act && Assert. + runTest(assert, builder, 'Customers', `$filter=geom.distance(geometry1=Coordinates,geometry2=geometry'SRID=12345;` + + `POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))') eq 0&$select=CustomerID`); }); -test('adapter | odata | geometry predicate | intersect', function (assert) { +test('adapter | odata | geometry predicate | intersects', function (assert) { // Arrange. let gp = new GeometryPredicate('coordinates'). intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'); @@ -561,7 +627,21 @@ test('adapter | odata | geometry predicate | intersect', function (assert) { `POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))')&$select=CustomerID`); }); -test('adapter | odata | geometry predicate | inside complex', function (assert) { +test('adapter | odata | geometry predicate | inside complex | distance', function (assert) { + // Arrange. + let gp = new GeometryPredicate('coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0); + let sp = new SimplePredicate('firstName', FilterOperator.Eq, 'Vasya'); + + // Act. + let builder = new QueryBuilder(store, 'customer').where(gp.and(sp)); + + // Act && Assert. + runTest(assert, builder, 'Customers', `$filter=geom.distance(geometry1=Coordinates,geometry2=geometry'SRID=12345;` + + `POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))') eq 0 and FirstName eq 'Vasya'&$select=CustomerID`); +}); + +test('adapter | odata | geometry predicate | inside complex | intersects', function (assert) { // Arrange. let gp = new GeometryPredicate('coordinates'). intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'); @@ -575,10 +655,23 @@ test('adapter | odata | geometry predicate | inside complex', function (assert) `POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))') and FirstName eq 'Vasya'&$select=CustomerID`); }); -test('adapter | odata | detail predicate | all | with geometry predicate', function (assert) { +test('adapter | odata | detail predicate | all | with geometry predicate | distance', function (assert) { + // Arrange. + let dp = new DetailPredicate('userVotes').all(new GeometryPredicate('applicationUser.coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0)); + + // Act. + let builder = new QueryBuilder(store, 'ember-flexberry-dummy-comment').where(dp); + + // Act && Assert. + runTest(assert, builder, 'EmberFlexberryDummyComments', `$filter=UserVotes/all(f:geom.distance(geometry1=f/ApplicationUser/Coordinates,` + + `geometry2=geometry'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))') eq 0)&$select=__PrimaryKey`); +}); + +test('adapter | odata | detail predicate | all | with geometry predicate | intersects', function (assert) { // Arrange. let dp = new DetailPredicate('userVotes').all(new GeometryPredicate('applicationUser.coordinates'). - intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))')); + intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))')); // Act. let builder = new QueryBuilder(store, 'ember-flexberry-dummy-comment').where(dp); @@ -588,17 +681,30 @@ test('adapter | odata | detail predicate | all | with geometry predicate', funct `geometry2=geometry'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'))&$select=__PrimaryKey`); }); -test('adapter | odata | detail predicate | any | with geometry predicate', function (assert) { +test('adapter | odata | detail predicate | any | with geometry predicate | distance', function (assert) { + // Arrange. + let dp = new DetailPredicate('userVotes').any(new GeometryPredicate('applicationUser.coordinates'). + distance('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))', FilterOperator.Eq, 0)); + + // Act. + let builder = new QueryBuilder(store, 'ember-flexberry-dummy-comment').where(dp); + + // Act && Assert. + runTest(assert, builder, 'EmberFlexberryDummyComments', `$filter=UserVotes/any(f:geom.distance(geometry1=f/ApplicationUser/Coordinates,` + + `geometry2=geometry'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))') eq 0)&$select=__PrimaryKey`); +}); + +test('adapter | odata | detail predicate | any | with geometry predicate | intersects', function (assert) { // Arrange. let dp = new DetailPredicate('userVotes').any(new GeometryPredicate('applicationUser.coordinates'). - intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))')); + intersects('SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))')); // Act. let builder = new QueryBuilder(store, 'ember-flexberry-dummy-comment').where(dp); // Act && Assert. runTest(assert, builder, 'EmberFlexberryDummyComments', `$filter=UserVotes/any(f:geom.intersects(geometry1=f/ApplicationUser/Coordinates,` + - `geometry2=geometry'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'))&$select=__PrimaryKey`); + `geometry2=geometry'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'))&$select=__PrimaryKey`); }); test('adapter | odata | not predicate | with simple predicate', function (assert) { @@ -627,7 +733,20 @@ test('adapter | odata | not predicate | with complex predicate', function (asser runTest(assert, builder, 'Customers', `$filter=not(FirstName eq 'Vasya' or FirstName eq 'Petya')&$select=CustomerID`); }); -test('adapter | odata | not predicate | with geography predicate', function (assert) { +test('adapter | odata | not predicate | with geography predicate | distance', function (assert) { + // Arrange. + const POLYGON = 'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'; + let innerPredicate = new GeographyPredicate('coordinates').distance(POLYGON, FilterOperator.Eq, 0); + let np = new NotPredicate(innerPredicate); + + // Act. + let builder = new QueryBuilder(store, 'customer').where(np); + + // Act && Assert. + runTest(assert, builder, 'Customers', `$filter=not(geo.distance(geography1=Coordinates,geography2=geography'${POLYGON}') eq 0)&$select=CustomerID`); +}); + +test('adapter | odata | not predicate | with geography predicate | intersects', function (assert) { // Arrange. const POLYGON = 'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'; let innerPredicate = new GeographyPredicate('coordinates').intersects(POLYGON); @@ -640,7 +759,20 @@ test('adapter | odata | not predicate | with geography predicate', function (ass runTest(assert, builder, 'Customers', `$filter=not(geo.intersects(geography1=Coordinates,geography2=geography'${POLYGON}'))&$select=CustomerID`); }); -test('adapter | odata | not predicate | with geometry predicate', function (assert) { +test('adapter | odata | not predicate | with geometry predicate | distance', function (assert) { + // Arrange. + const POLYGON = 'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'; + let innerPredicate = new GeometryPredicate('coordinates').distance(POLYGON, FilterOperator.Eq, 0); + let np = new NotPredicate(innerPredicate); + + // Act. + let builder = new QueryBuilder(store, 'customer').where(np); + + // Act && Assert. + runTest(assert, builder, 'Customers', `$filter=not(geom.distance(geometry1=Coordinates,geometry2=geometry'${POLYGON}') eq 0)&$select=CustomerID`); +}); + +test('adapter | odata | not predicate | with geometry predicate | intersects', function (assert) { // Arrange. const POLYGON = 'SRID=12345;POLYGON((-127.89734578345 45.234534534,-127.89734578345 45.234534534))'; let innerPredicate = new GeometryPredicate('coordinates').intersects(POLYGON);