Source: meta-data/file-storage.js

/**
 *
 * Copyright 2015 Randal L Kamradt Sr.
 *
 * File Storage.
 * @module meta-data/file-storage
 */
var fs = require('fs');
/**
 * A file store API.
 * @param  {Object} models   The models description
 * @param  {string} fileName The file to use as a store
 * @return {Object}          The API Object
 */
module.exports = function(model, fileName) {
  return {
    '_model': model,
    '_key': model.getKey(),
    '_fileStore': fileName,
    '_data': [],
    '_readData': function(done) {
      var self = this;
      fs.exists(this._fileStore, function(exists) {
        if(!exists) {
          self._data = []; // no file; assume empty
          done();
        } else {
          fs.readFile(self._fileStore, function(err, data) {
            if(err) {
              done(err);
            } else {
              self._data = JSON.parse(data);
              done();
            }
          });
        }
      });
    },
    '_writeData': function(done, result) {
      var data = JSON.stringify(this._data);
      fs.writeFile(this._fileStore, data, function(err) {
        if(err) {
          done(err);
        } else {
          done(null, result);
        }
      });
    },
    /**
     * load an array of data into a store
     * @param  {Array}   d    The data to load
     * @param  {Function} done The callback when done
     */
    'load': function(d, done) {
      var self = this;
      this._readData(function(err) {
        if(err) {
          done(err);
        }
        self._data = self._data.concat(d);
        self._writeData(done);
      });
    },
    /**
     * add an item to the store
     * @param  {Object}   data    The item to store
     * @param  {Function} done The callback when done
     */
    'add': function(data, done) {
      var self = this;
      this._readData(function(err) {
        if(err) {
          done(err);
        }
        self._data.push(data);
        var ret = self._data.length;
        self._writeData(done, ret);
      });
    },
    /**
     * update an item in the store
     * @param  {Object}   data    The item to store
     * @param  {Function} done The callback when done
     */
    'update': function(data, done) {
      if(!this._key) {
        done('no key found for metadata');
        return;
      }
      var keyValue = data[this._key.getName()];
      var self = this;
      this._readData(function(err) {
        if(err) {
          done(err);
        }
        var ix = -1; // if not found return null
        for(var i = 0; i < self._data.length; i++) {
          if(self._data[i][self._key.getName()] === keyValue) {
            ix = i;
            break;
          }
        }
        if(ix === -1) {
          self._data.push(data);
        } else {
          self._data[ix] = data;
        }
        self._writeData(done);
      });
    },
    /**
     * return the entire store as an Array
     * @param  {Function} done The callback when done
     */
    'findAll': function(done) {
      var self = this;
      this._readData(function(err) {
        if(err) {
          done(err);
        }
        var ret = self._data.concat([]); // make a shallow copy
        self._writeData(done, ret);
      });
    },
    /**
     * return an item by id
     * @param  {String}   key  The key value
     * @param  {Function} done The callback when done
     */
    'find': function(key, done) {
      if(!this._key) {
        done('no key found for metadata');
        return;
      }
      var self = this;
      this._readData(function(err) {
        if(err) {
          done(err);
        }
        var ret = null; // if not found return null
        for(var i = 0; i < self._data.length; i++) {
          if(self._data[i][self._key.getName()] === key) {
            ret = self._data[i];
            break;
          }
        }
        self._writeData(done, ret);
      });
    },
    /**
     * Remove an item by key
     * @param  {String}   key  The key value
     * @param  {Function} done The callback when done
     */
    'remove': function(key, done) {
      if(!this._key) {
        done('no key found for metadata');
        return;
      }
      var self = this;
      this._readData(function(err) {
        if(err) {
          done(err);
        }
        var ret = null; // if not found, do nothing and return null
        for(var i = 0; i < self._data.length; i++) {
          if(self._data[i][self._key.getName()] === key) {
            ret = self._data.splice(i, 1)[0];
            break;
          }
        }
        self._writeData(done, ret);
      });
    }
  };
};