feat: Refactor to ResourceFilteringStore service

This commit is contained in:
Susmitha Girumala committed 2021-11-01 20:23:26 -04:00
1 parent 8c4a076367
commit 82636e3ee9
6 files changed
+83 -106

No files matched your search

@@ -1,68 +0,0 @@
import Store from '@ember-data/store';
class FilterQuery {
_config;
constructor(config) {
this._config = config;
}
get query() {
const filters = this._buildFilters(this._config);
return this._joinFilters(filters, { inclusive: false });
}
/**
* Iterate through filter config to generate array of filter strings
* @param {object} config
*/
_buildFilters(config) {
let filters = [];
for (const key in config) {
filters.push(this._generateQuery(`/item/${key}`, config[`${key}`]));
}
return filters;
}
/**
* For a single filter, build filter query
* @param {string} selector
* @param {*} values
*/
_generateQuery(selector, values) {
// TODO: Check for value type
const filters = values.map((value) => `"${selector}" == "${value}"`);
return this._joinFilters(filters, { inclusive: true });
}
/**
* Combine filter strings
* @param {array} filters
* @param {object} inclusive
*/
_joinFilters(filters, { inclusive }) {
return filters.join(inclusive ? ' or ' : ' and ');
}
}
export default class FilterableStoreService extends Store {
/**
* Filterable store queries using IDs
* Usage:
* // Filter for a user in sessions
* this.store.filterByIds('session', { scope_id, recursive: true }, { user: ['u_0987654321']})
* // Filter for status in pending or terminated state and for a session id
* this.store.filterByIds('session', { scope_id },
* { status: ['pending', 'terminated' ], target: ['s_U5EoFe4Jba']}
* )
* // To remove filters
* this.store.filterByIds('session', { scope_id })
* @param {string} modelName
* @param {object} queryOptions
* @param {string} filterQuery
*/
filterByIds(modelName, queryOptions, filterOptions) {
const filterQuery = new FilterQuery(filterOptions);
// Apply filters, if available
if (filterQuery.query) queryOptions.filter = filterQuery;
return this.query(modelName, queryOptions);
}
}
@@ -0,0 +1,53 @@
import Service from '@ember/service';
import { inject as service } from '@ember/service';
class ResourceFilters {
buildQuery(resourceFilters) {
const filters = this._buildFilters(resourceFilters);
return this._joinFilters(filters, { inclusive: false });
}
/**
* Iterate through filter config to generate array of filter strings
* @param {object} config
*/
_buildFilters(config) {
let filters = [];
for (const key in config) {
filters.push(this._generateQuery(`/item/${key}`, config[`${key}`]));
}
return filters;
}
/**
* For a single filter, build filter query
* @param {string} selector
* @param {*} values
*/
_generateQuery(selector, values) {
// Coerce single string filters into an array for easy mapping
if (!Array.isArray(values)) values = [values];
const filters = values.map((value) => `"${selector}" == "${value}"`);
return this._joinFilters(filters, { inclusive: true });
}
/**
* Combine filter strings
* @param {array} filters
* @param {object} inclusive
*/
_joinFilters(filters, { inclusive }) {
return filters.join(inclusive ? ' or ' : ' and ');
}
}
export default class ResourceFilteringStoreService extends Service {
@service store;
queryBy(modelName, resourceParams, resourceFilters) {
const filterQuery = new ResourceFilters().buildQuery(resourceFilters);
// Apply filters to store query when available
if (filterQuery) resourceParams.filter = filterQuery;
return this.store.query(modelName, resourceParams);
}
}
@@ -1 +0,0 @@
export { default } from 'api/services/filterable-store';
@@ -0,0 +1 @@
export { default } from 'api/services/resource-filtering-store';
@@ -1,37 +0,0 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { Response } from 'miragejs';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
module('Unit | Service | filterable-store', function (hooks) {
setupTest(hooks);
setupMirage(hooks);
let store;
hooks.beforeEach(function () {
store = this.owner.lookup('service:filterable-store');
store.createRecord('session', {
id: 'i_1234567890',
scope: {
id: '123',
},
});
});
test('it supports query filtering', function (assert) {
this.server.get('/v1/sessions?scope_id=123', () => {
new Response({});
});
store.filterByIds('session', { scope_id: '123' });
assert.ok(store);
});
test('it supports single attribute filters', function (assert) {
assert.ok(store);
});
test('it supports multiple attribute filters', function (assert) {
assert.ok(store);
});
});
@@ -0,0 +1,29 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Service | resource-filtering-store', function (hooks) {
setupTest(hooks);
let service, store;
hooks.beforeEach(function () {
service = this.owner.lookup('service:resource-filtering-store');
store = this.owner.lookup('service:store');
store.createRecord('session', {
id: 's_1',
scope: {
id: '123',
},
});
});
// TODO: Replace this with your real tests.
test('it exists', function (assert) {
assert.ok(service);
});
// TODO: Is it possible to capture mirage API requests in this test?
// test('it supports query filters', function (assert) {
// const models = service.queryBy('session', {}, { scope_id: '123' });
// assert.ok(service);
// });
});