Home Manual Reference Source Test Repository

src/storage.js

import {Subject} from 'rxjs/Subject';

/**
 * Provides access to the Web storage.
 * See: https://developer.mozilla.org/en-US/docs/Web/API/Storage
 */
export class Storage {

  /**
   * Initializes a new instance of the class.
   * @param {Storage} backend The underlying data store.
   */
  constructor(backend) {

    /**
     * The underlying data store.
     * @type {Storage}
     */
    this._backend = backend;

    /**
     * The handler of "changes" events.
     * @type {Subject<KeyValueChangeRecord>}
     */
    this._onChanges = new Subject;
  }

  /**
   * The keys of this storage.
   * @type {string[]}
   */
  get keys() {
    let keys = [];
    for (let i = 0; i < this.length; i++) keys.push(this._backend.key(i));
    return keys;
  }

  /**
   * The number of entries in this storage.
   * @type {number}
   */
  get length() {
    return this._backend.length;
  }

  /**
   * The stream of "changes" events.
   * @type {Observable<KeyValueChangeRecord[]>}
   */
  get onChanges() {
    return this._onChanges.asObservable();
  }

  /**
   * Returns a new iterator that allows iterating the entries of this storage.
   */
  *[Symbol.iterator]() {
    for (let key of this.keys) yield [key, this.get(key)];
  }

  /**
   * Removes all entries from this storage.
   */
  clear() {
    let changes = this.keys.map(key => ({currentValue: null, key, previousValue: this.get(key)}));
    this._backend.clear();
    this._onChanges.next(changes);
  }

  /**
   * Gets the value associated to the specified key.
   * @param {string} key The key to seek for.
   * @param {*} defaultValue The default item value if it does not exist.
   * @return {string} The value of the storage item, or the default value if the item is not found.
   */
  get(key, defaultValue = null) {
    let value = this._backend.getItem(key);
    return typeof value == 'string' ? value : defaultValue;
  }

  /**
   * Gets the deserialized value associated to the specified key.
   * @param {string} key The key to seek for.
   * @param {*} defaultValue The default item value if it does not exist.
   * @return {*} The deserialized value of the storage item, or the default value if the item is not found.
   */
  getObject(key, defaultValue = null) {
    let value = this.get(key);
    return typeof value == 'string' ? JSON.parse(value) : defaultValue;
  }

  /**
   * Gets a value indicating whether this storage contains the specified key.
   * @param {string} key The key to seek for.
   * @return {boolean} `true` if this storage contains the specified key, otherwise `false`.
   */
  has(key) {
    return this.keys.includes(key);
  }

  /**
   * Removes the value associated to the specified key.
   * @param {string} key The key to seek for.
   */
  remove(key) {
    let previousValue = this.get(key);
    this._backend.removeItem(key);
    this._onChanges.next([{currentValue: null, key, previousValue}]);
  }

  /**
   * Associates a given value to the specified key.
   * @param {string} key The key to seek for.
   * @param {string} value The item value.
   */
  set(key, value) {
    let previousValue = this.get(key);
    this._backend.setItem(key, value);
    this._onChanges.next([{currentValue: value, key, previousValue}]);
  }

  /**
   * Serializes and associates a given value to the specified key.
   * @param {string} key The key to seek for.
   * @param {*} value The item value.
   */
  setObject(key, value) {
    this.set(key, JSON.stringify(value));
  }
}