kane-thornwyrd/borax

View on GitHub
lib/datastore.js

Summary

Maintainability
A
3 hrs
Test Coverage
'use strict';

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _immutable = require('immutable'),
    _immutable2 = _interopRequireDefault(_immutable);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // # Datastore


// Let's assume that 100 entries are enougth history...
var HISTORY_MAX_LENGTH = 100,
    _inst = void 0;
// Small static to save the singleton instance.

var Datastore = function () {
  function Datastore() {
    _classCallCheck(this, Datastore);

    // That's the heart of the beast: an array of immutables !
    this.history = [_immutable2.default.Map()];
    this.reducers = {};
    this.cbs = [];
  }

  // ## registerReducer
  // Register a reducer
  // * **@param**  {String} name of the reducer, incidentally also the name of the
  // data it will reduce from the state.
  // * **@param**  {Function} cb for the reducer.
  // * **@chainable**
  //
  // ```js
  //  require('borax').Datastore.registerReducer('foo',(state = {}, action)=>{
  //    switch(action.type){
  //      case 'START':
  //        return {start: Date.now()};
  //      case 'END':
  //        return {end: Date.now()};
  //      case 'RETRIEVED':
  //        return {data: data.message};
  //      default:
  //        return state;
  //  });
  // ```


  Datastore.prototype.registerReducer = function registerReducer(name, cb) {
    this.reducers[name] = cb;
    return this;
  };

  // ## getState
  // Browse the state history
  // * **@param**  {Number} away (optionnal) how far from the latest, default: 0
  // * **@return** {Immutable.Map}      The state requested.
  //
  // ```js
  //  let { Datastore } = require('borax');
  //
  //  let currentState = Datastore.getState();
  //
  //  let antepenultimateState = Datastore.getState(2);
  // ```


  Datastore.prototype.getState = function getState() {
    var away = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];

    return this.history[this.history.length - 1 - away];
  };

  // ## dispatch
  // Call all the reducers for them to alter the app state then forge the new one.
  //
  // Also garbage collect the history to avoid pseudo-"memory leak".
  //
  // * **@param**  {Object} action [description]
  // * **@chainable**
  //
  // ```js
  //  let { Datastore } = require('borax');
  //
  //  $.ajax('exemple.com/data.json')
  //    .then((data)=>{
  //      Datastore.dispatch(
  //        require('../actions/foo/dataRetrieved')(data)
  //      );
  //    })
  //  ;
  // ```


  Datastore.prototype.dispatch = function dispatch(action) {
    var _this = this,
        latestState = this.getState();
    // Good exemple of getState use !


    //Obviously we push a new state to the history.
    this.history.push(
    // We won't create a new state for each reducer called this way.
    latestState.withMutations(function (list) {
      for (var name in _this.reducers) {

        var latest = latestState.get(name) ? latestState.get(name).toJS() : {};

        list.set(name, _immutable2.default.Map(_extends(latest, _this.reducers[name](latestState.get(name), action))));
      }
    }));

    // Here's the primitive garbage collector.
    if (this.history.length > HISTORY_MAX_LENGTH) this.history.shift();

    return this.trigger();
  };

  // ## onNewstate
  // Register a listener to the event of a new state being created.
  //
  // * **@param**  {Function} cb to register as listener.
  // * **@return** {Number}      id from the new listener.
  //
  // ```js
  //  //@ToDo
  // ```


  Datastore.prototype.onNewstate = function onNewstate(cb) {
    var id = this.cbs.length;
    this.cbs.push(cb);
    return id;
  };

  // ## offNewstate
  // Unregister a listener.
  //
  // * **@param**  {Number}  id from the callback to remove.
  // * **@return** {Number}  new listener's array length.
  //
  // ```js
  //  //@ToDo
  // ```


  Datastore.prototype.offNewState = function offNewState(id) {
    if (this.cbs.length - 1 < id) this.cbs.splice(id, 1);
    return this.cbs.length;
  };

  /**
   * Used internally to trigger all the listeners.
   * @chainable
   */


  Datastore.prototype.trigger = function trigger() {
    var state = this.getState(),
        notify = function notify(cb) {
      return cb(state);
    };

    this.cbs.every(notify);
    return this;
  };

  return Datastore;
}();

module.exports = _inst = _inst ? _inst : new Datastore();