chore: 🤖 add storage service with support for memory and local

This commit is contained in:
Randall Morey committed 2020-05-13 15:47:38 -04:00
1 parent 0230299aa2
commit 7f2e195fd8
5 files changed
+174 -1

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
import Service from '@ember/service';
import { getOwner } from '@ember/application';
import { get } from '@ember/object';
/**
* A dead simple memory storage class used by `StorageService` when it
* is configued for memory-only.
*/
class MemoryStorage {
/**
* Internal storage object.
* @type {object}
* @private
*/
#storage = {};
/**
* Gets a value from storage.
* @param {string} key
* @return {any}
*/
getItem(key) {
return this.#storage[key];
}
/**
* Sets a value to storage.
* @param {string} key
*/
setItem(key, value) {
this.#storage[key] = value;
}
/**
* Removes a value from storage.
* @param {string} key
*/
removeItem(key) {
delete this.#storage[key];
}
}
/**
* The storage service provides a simple way to persist data in the browser.
* Most of the time localStorage is used. Appplications may specify in-memory
* storage via the config, for example:
*
* ENV.storage = {
* memory: true
* };
*
* @example
* import Route from '@ember/routing/route';
* import { inject as service } from '@ember/service';
* export default class ApplicationRoute extends Route {
* @service storage;
* afterModel() {
* this.storage.setItem('key', 'value');
* }
* }
*/
export default class StorageService extends Service {
/**
* @type {MemoryStorage}
* @private
*/
#memoryStorage = new MemoryStorage();
/**
* Gets the underlying storage mechanism.
* @return {Storage}
*/
get storage() {
// Get the application config to determine if memory storage is enabled
const config = getOwner(this).resolveRegistration('config:environment');
const inMemory = get(config, 'storage.memory');
// Get the global context object (window) via service lookup,
// because just reaching for a global is icky
const globalContext = getOwner(this).lookup('service:-document')
.documentElement.parentNode.defaultView;
// If memory storage enabled, return the memory storage instance,
// otherwise return localStorage.
return inMemory ? this.#memoryStorage : globalContext.localStorage;
}
/**
* Returns the storage namespace, which is the applications `modulePrefix`.
* @return {string}
*/
get namespace() {
const config = getOwner(this).resolveRegistration('config:environment');
return config.modulePrefix;
}
/**
* Returns a fully qualified key from the passed string. A fully qualified
* key includes the namespace.
* @param {string} key
* @return {string} fully qualified key
*/
qualifiedKey(key) {
return `${this.namespace}:${key}`;
}
/**
* Gets a value from storage.
* @param {string} key
* @return {any}
*/
getItem(key) {
return this.storage.getItem(this.qualifiedKey(key));
}
/**
* Sets a value to storage.
* @param {string} key
*/
setItem(key, value) {
this.storage.setItem(this.qualifiedKey(key), value);
}
/**
* Removes a value from storage.
* @param {string} key
*/
removeItem(key) {
this.storage.removeItem(this.qualifiedKey(key));
}
}
+1
View File
@@ -0,0 +1 @@
export { default } from 'api/services/storage';
@@ -3,8 +3,9 @@ import { inject as service } from '@ember/service';
export default class ApplicationRoute extends Route {
@service scope;
@service storage;
afterModel() {
//console.log(this.scope);
//console.log(this.storage);
}
}
@@ -41,6 +41,10 @@ module.exports = function (environment) {
ENV.APP.rootElement = '#ember-testing';
ENV.APP.autoboot = false;
ENV.storage = {
memory: true,
};
}
if (environment === 'production') {
@@ -0,0 +1,38 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Service | storage', function (hooks) {
setupTest(hooks);
test('it can persist values', function (assert) {
assert.expect(1);
const service = this.owner.lookup('service:storage');
service.setItem('foo', 'bar');
assert.equal(service.getItem('foo'), 'bar');
});
test('it can remove persisted values', function (assert) {
assert.expect(2);
const service = this.owner.lookup('service:storage');
service.setItem('foo', 'bar');
assert.equal(service.getItem('foo'), 'bar');
service.removeItem('foo');
assert.notOk(service.getItem('foo'));
});
// NOTE: the following tests are order-dependent, so may be invalidated
// if we switch to random test ordering
test("it's in-memory storage is implicitly refreshed for every test case", function (assert) {
assert.expect(1);
const service = this.owner.lookup('service:storage');
service.setItem('foo', 'bar');
assert.equal(service.getItem('foo'), 'bar');
});
test("it's in-memory storage is implicitly refreshed for every test case", function (assert) {
assert.expect(1);
const service = this.owner.lookup('service:storage');
assert.notOk(service.getItem('foo'));
});
});