Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add InPredicate and tests #192

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Change Log

## [Unreleased]
### Added
- The `InPredicate`.

## [2.6.0-beta.0] - 2020-10-06
### Added
Expand Down
19 changes: 18 additions & 1 deletion addon/query/indexeddb-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import Ember from 'ember';
import FilterOperator from './filter-operator';
import Condition from 'ember-flexberry-data/query/condition';
import {
SimplePredicate,
ComplexPredicate,
Expand All @@ -13,7 +14,8 @@ import {
GeographyPredicate,
GeometryPredicate,
TruePredicate,
FalsePredicate
FalsePredicate,
InPredicate
} from './predicate';
import BaseAdapter from './base-adapter';
import JSAdapter from 'ember-flexberry-data/query/js-adapter';
Expand Down Expand Up @@ -701,6 +703,21 @@ function updateWhereClause(store, table, query) {
return table.limit(0);
}

if (predicate instanceof InPredicate) {
let predicates = [];

predicate.valueArray.forEach(value => {
let sp = new SimplePredicate(predicate.attributePath, FilterOperator.Eq, value);
predicates.push(sp);
});

let finalPredicate = new ComplexPredicate(Condition.Or, ...predicates);
let queriWithIn = query;
queriWithIn.predicate = finalPredicate;

return updateWhereClause(store, table, query);
}

if (predicate instanceof ComplexPredicate) {
let datePredicates = predicate.predicates.filter(pred => pred instanceof DatePredicate);
let jsAdapter = datePredicates.length > 0 ? new JSAdapter(Ember.getOwner(store).lookup('service:moment')) : new JSAdapter();
Expand Down
18 changes: 16 additions & 2 deletions addon/query/js-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
GeographyPredicate,
GeometryPredicate,
TruePredicate,
FalsePredicate
FalsePredicate,
InPredicate
} from './predicate';
import FilterOperator from './filter-operator';
import Condition from './condition';
Expand Down Expand Up @@ -257,7 +258,8 @@ export default class JSAdapter extends BaseAdapter {
let b6 = predicate instanceof GeometryPredicate;
let b7 = predicate instanceof TruePredicate;
let b8 = predicate instanceof FalsePredicate;
if (b1 || b2 || b3 || b4 || b7 || b8) {
let b9 = predicate instanceof InPredicate;
if (b1 || b2 || b3 || b4 || b7 || b8 || b9) {
let filterFunction = this.getAttributeFilterFunction(predicate, options);
return this.getFilterFunctionAnd([filterFunction]);
}
Expand Down Expand Up @@ -378,6 +380,18 @@ export default class JSAdapter extends BaseAdapter {
return () => false;
}

if (predicate instanceof InPredicate) {
return (i) => {
let attribute = _this.getValue(i, predicate.attributePath);
let valuesArray = predicate.valueArray;

let dataExist = !Ember.isNone(attribute) && !Ember.isNone(valuesArray);
let valueIncludes = dataExist && valuesArray.indexOf(attribute) !== -1;

return valueIncludes;
};
}

if (predicate instanceof DetailPredicate) {
let detailFilter = _this.buildFilter(predicate.predicate, options);
if (predicate.isAll) {
Expand Down
16 changes: 16 additions & 0 deletions addon/query/odata-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Ember from 'ember';
import DS from 'ember-data';

import BaseAdapter from './base-adapter';
import Condition from 'ember-flexberry-data/query/condition';
import {
SimplePredicate,
ComplexPredicate,
Expand All @@ -14,6 +15,7 @@ import {
IsOfPredicate,
TruePredicate,
FalsePredicate,
InPredicate
} from './predicate';
import FilterOperator from './filter-operator';
import Information from '../utils/information';
Expand Down Expand Up @@ -321,6 +323,20 @@ export default class ODataAdapter extends BaseAdapter {
return 'false';
}

if (predicate instanceof InPredicate) {
let separator = ` ${Condition.Or} `;

let result = predicate.valueArray
.map(i => {
let sp = new SimplePredicate(predicate.attributePath, FilterOperator.Eq, i);
return this._convertPredicateToODataFilterClause(sp, modelName, prefix, level + 1);
}).join(separator);

let lp = level > 0 ? '(' : '';
let rp = level > 0 ? ')' : '';
return lp + result + rp;
}

throw new Error(`Unknown predicate '${predicate}'`);
}

Expand Down
48 changes: 48 additions & 0 deletions addon/query/predicate.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Ember from 'ember';
import FilterOperator from './filter-operator';
import Condition from './condition';
import moment from 'moment';
Expand Down Expand Up @@ -681,6 +682,53 @@ export class FalsePredicate extends BasePredicate {
}
}

/**
* The class of in predicate.
*
* @namespace Query
* @class InPredicate
* @extends BasePredicate
* @constructor
*/
export class InPredicate extends BasePredicate {
constructor(attributePath, valueArray) {
super();

if (!attributePath) {
throw new Error('Attribute path is required for inPredicate constructor.');
}

if (!Ember.isArray(valueArray) && valueArray.length === 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!Ember.isArray(valueArray) && valueArray.length === 0) {
if (!Ember.isArray(valueArray) || valueArray.length === 0) {

throw new Error('Array of compared values is required for inPredicate constructor.');
}

this._attributePath = attributePath;
this._valueArray = valueArray;
}

/**
* The path to the attribute for predicate.
*
* @property attributePath
* @type {String}
* @public
*/
get attributePath() {
return this._attributePath;
}

/**
* Array of values, that check of attribute exist.
*
* @property valueArray
* @type {Array}
* @public
*/
get valueArray() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Может values?

return this._valueArray;
}
}

/**
* Combines specified predicates using `and` logic condition.
*
Expand Down
68 changes: 68 additions & 0 deletions tests/unit/CRUD/base/base-reading-in-predicates-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import Ember from 'ember';
import QueryBuilder from 'ember-flexberry-data/query/builder';
import { InPredicate } from 'ember-flexberry-data/query/predicate';

export default function readingComplexPredicates(store, assert) {
assert.expect(3);
let done = assert.async();

Ember.run(() => {
initTestData(store)

.then(() => {
let filterArrayValues = ['Vasya', 'SpiderMan', 'Batman'];
let ip = new InPredicate('name', filterArrayValues);

let builder = new QueryBuilder(store, 'ember-flexberry-dummy-application-user').where(ip);
return store.query('ember-flexberry-dummy-application-user', builder.build())
.then((data) => {
assert.equal(data.get('length'), 1, `Predicate "in" | Length`);
assert.ok(data.any(item => item.get('name') === 'Vasya'), `Predicate "in" | Data`);
});
})

.then(() => {
let filterArrayValues = ['CaptainAmerica', 'SpiderMan', 'Batman'];
let ip = new InPredicate('name', filterArrayValues);

let builder = new QueryBuilder(store, 'ember-flexberry-dummy-application-user').where(ip);
return store.query('ember-flexberry-dummy-application-user', builder.build())
.then((data) => {
assert.equal(data.get('length'), 0, `Predicate "out" | Length`);
});
})
.catch((e) => {
console.log(e, e.message);
throw e;
})
.finally(done);
});
}

function initTestData(store) {
return Ember.RSVP.Promise.all([
store.createRecord('ember-flexberry-dummy-application-user', {
name: 'Vasya',
eMail: '[email protected]',
karma: 4
}).save(),

store.createRecord('ember-flexberry-dummy-application-user', {
name: 'Oleg',
eMail: '[email protected]',
karma: 5
}).save(),

store.createRecord('ember-flexberry-dummy-application-user', {
name: 'Oleg',
eMail: '[email protected]',
karma: 7
}).save(),

store.createRecord('ember-flexberry-dummy-application-user', {
name: 'Andrey',
eMail: '[email protected]',
karma: 6
}).save()
]);
}
6 changes: 6 additions & 0 deletions tests/unit/CRUD/odata/odata-reading-in-predicates-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import executeTest from './execute-odata-test';
import readingInPredicates from '../base/base-reading-in-predicates-test';

executeTest('reading | predicates | in predicates', (store, assert) => {
readingInPredicates(store, assert);
});
6 changes: 6 additions & 0 deletions tests/unit/CRUD/offline/offline-reading-in-predicates-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import executeTest from './execute-offline-test';
import readingInPredicates from '../base/base-reading-in-predicates-test';

executeTest('reading | predicates | in predicates', (store, assert) => {
readingInPredicates(store, assert);
});
20 changes: 20 additions & 0 deletions tests/unit/query/in-predicate-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { module, test } from 'qunit';

import { InPredicate } from 'ember-flexberry-data/query/predicate';

module('query');

test('predicate | in | constructor', function (assert) {
assert.throws(() => new InPredicate(), Error);
assert.throws(() => new InPredicate(''), Error);
assert.throws(() => new InPredicate(null), Error);
assert.throws(() => new InPredicate(null, ''), Error);
assert.throws(() => new InPredicate('', null), Error);
assert.throws(() => new InPredicate('', ''), Error);
assert.throws(() => new InPredicate('', 2), Error);

let p = new InPredicate('City', ['Perm', 'Moscow', 'Paris']);

assert.ok(p);
assert.equal(p.attributePath, 'City');
});
34 changes: 33 additions & 1 deletion tests/unit/query/indexeddb-adapter-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
GeographyPredicate,
GeometryPredicate,
TruePredicate,
FalsePredicate
FalsePredicate,
InPredicate
} from 'ember-flexberry-data/query/predicate';
import Condition from 'ember-flexberry-data/query/condition';

Expand Down Expand Up @@ -1634,3 +1635,34 @@ test('adapter | indexeddb | geometry predicate | intersects', (assert) => {
assert.equal(result.data[2].id, 3);
});
});

test('adapter | indexeddb | in predicate', (assert) => {
let data = {
employee: [
{ id: 1, City: 'Perm' },
{ id: 2, City: 'Paris' },
{ id: 3, City: 'Bobruisk' }
]
};

let filterArrayValues = ['Perm', 'New Yourk', 'Moscow'];

let ip1 = new InPredicate('City', filterArrayValues);
let builder = new QueryBuilder(storeIndexedbAdapterTest, modelNameIndexedbAdapterTest).where(ip1);

executeTest(data, builder.build(), assert, (result) => {
assert.ok(result.data);
assert.equal(result.data.length, 1);
assert.equal(result.data[0].id, 1);
});

filterArrayValues = ['Mumbai', 'New Yourk', 'Moscow'];

ip1 = new InPredicate('City', filterArrayValues);
builder = new QueryBuilder(storeIndexedbAdapterTest, modelNameIndexedbAdapterTest).where(ip1);

executeTest(data, builder.build(), assert, (result) => {
assert.ok(result.data);
assert.equal(result.data.length, 0);
});
});
Loading