UNPKG

mini-dbx

Version:

A JSON based super lightweight database!!

263 lines (235 loc) 5.01 kB
var fs = require('fs'), mu = require('mini-util'); var _lockSave = false var _needSave = {} var PATTERN_SHARP = /##?/g, /** * Compile filter string to function. * @param filter {string} */ compile = (function () { var cache = { '': function () { return true; } }; return function (filter) { filter = filter || ''; if (!cache[filter]) { filter = 'return (' + filter.replace(PATTERN_SHARP, function (sharp) { return sharp === '#' ? '__index' : '#'; }) + ');' cache[filter] = new Function('$', '__index', filter); } return cache[filter]; }; }()), /** * Create a Storage instance. * @param filename {string} */ factory = (function () { var cache = {}; return function (filename) { var instance = cache[filename]; if (!instance) { instance = cache[filename] = new Storage({ filename: filename }); } return instance; }; }()), /** * Test whether an array value matches a filter. * @param filter {string} * @param value {*} * @param index {number} * @return {boolean} */ match = function (filter, value, index) { return !!compile(filter)(value, index); }, /** * deep clone object */ clone = function (source){ if(!mu.isObject(source)){ throw new Error('invalid object , only object can be cloned !'); } var copy; try{ copy = JSON.parse(JSON.stringify(source)); }catch(e){ copy = {}; } return copy; }, // Storage constructor. Storage = mu.inherit(Object, { /** * Initializer. * @param config {Object} */ constructor: function (config) { var filename = this._filename = config.filename; if (!fs.existsSync(filename)) { fs.writeFileSync(filename, '{}'); } this._data = JSON.parse( fs.readFileSync(filename, 'utf-8')); }, /** * Save change to disk. * @param cb {function} */ _save: function (cb) { //here lock save if(!_lockSave){ _lockSave = true var filename = this._filename, data = this._data; setTimeout(() => { //console.log(filename) fs.writeFile(filename, JSON.stringify(data,null,2), function(){ _lockSave = false if(_needSave.filename){ _needSave.filename =false __save(cb) } else cb() } ); }, 50); } else{ _needSave[this._filename] = true } }, /** * Insert a new record. * @param key {string} * @param value {*} * @param [cb] {function} * @return {Object} */ insert: function (key, value, cb) { var data = this._data; if (!data[key]) { data[key] = [ value ]; } else { data[key].push(value); } this._save(function (err){ if(mu.isFunction(cb)){ cb(err,value); } }); return this; }, /** * Remove records. * @param key {string} * @param [filter] {string} * @param [cb] {function} * @return {Object} */ remove: function (key, filter, cb) { var data = this._data, arr = data[key], removed = [], i; if(mu.isFunction(filter)){ cb = filter; filter = null; } if (arr) { for (i = 0; i < arr.length; ++i) { if (match(filter, arr[i], i)) { removed.push(arr[i]); // Set to undefined first to keep indexes of other value unchanged. arr[i] = undefined; } } arr = arr.filter(function (value) { // Compact array. return value !== undefined; }); if (arr.length === 0) { // Delete empty property. delete data[key]; } else { data[key] = arr; } } this._save(function (err){ if(mu.isFunction(cb)){ cb(err,removed); } }); return this; }, /** * Select records. * @param key {string} * @param [filter] {string} * @param [cb] {function} * @return {Array} */ select: function (key, filter, cb) { var data = this._data, arr = data[key], result = [], i, len; if(mu.isFunction(filter)){ cb = filter; filter = null; } if (arr) { for (i = 0, len = arr.length; i < len; ++i) { if (match(filter, arr[i], i)) { result.push(clone(arr[i]));// deep clone } } } if(mu.isFunction(cb)){ setImmediate(function(){ cb(null,result); }); } return result; }, /** * Update records. * @param key {string} * @param value {*} * @param [filter] {string} * @param [cb] {function} * @return {Object} */ update: function (key, value, filter, cb) { var data = this._data, arr = data[key], updated = [], i, len; if(mu.isFunction(filter)){ cb = filter; filter = null; } if (arr) { for (i = 0, len = arr.length; i < len; ++i) { if (match(filter, arr[i], i)) { // arr[i] = value; arr[i] = mu.mix(arr[i],value); updated.push(arr[i]); } } } this._save(function (err){ if(mu.isFunction(cb)){ cb(err,updated); } }); return this; } }); module.exports = factory;