Skip to content

Instantly share code, notes, and snippets.

@tomasgreen
Last active August 29, 2015 14:16
Show Gist options
  • Save tomasgreen/aabb28becbdc6d7a36ab to your computer and use it in GitHub Desktop.
Save tomasgreen/aabb28becbdc6d7a36ab to your computer and use it in GitHub Desktop.
Simple json database
'use strict';
/**
* Author: Tomas Green
* License: MIT
*/
/*
Using the database:
var db = require('./jsondb')('./path/to/json/file.json');
db.store.test = [1,2,3];
db.write();
var dataToSend = json.stringify(db.store.test);
*/
var fs = require('fs');
var db = (function (storePath) {
var _this = this,
writeQueue = [],
writing = false,
reading = false,
rwConflict = 0,
rwConflictMax = 1000,
lastWrite = new Date();
function load(data) {
try {
_this.store = JSON.parse(data);
return true;
} catch (err) {
console.error('parsing json failed', err);
return false;
}
}
function queue(callback) {
writeQueue.push(callback);
resolve(writeFile);
}
function dequeue() {
writeQueue.splice(0, 1);
resolve(writeFile);
}
function resolve(func) {
if (rwConflict == rwConflictMax) {
console.error(storePath + ': resolving read-write conflict failed, maximum number of retries exeeded');
return;
}
if (reading || writing) {
setTimeout(function () {
resolve(func);
console.info(storePath + ': resolving read-write conflict...');
rwConflict++;
}, 1000);
return;
} else {
rwConflict = 0;
func();
}
}
function writeFile() {
if (writeQueue.length === 0) return;
var callback = writeQueue[0];
try {
writing = true;
var string = JSON.stringify(_this.store, undefined, '\t');
fs.writeFile(storePath, string, function (err) {
if (err) {
callback(false, err);
console.error('cannot write to ' + storePath, err);
} else callback(true);
writing = false;
lastWrite = new Date();
dequeue();
});
} catch (err) {
writing = false;
callback(false, err);
dequeue();
console.error(storePath + ': converting json to string failed');
}
}
function readFile() {
reading = true;
fs.readFile(storePath, function (error, data) {
if (error) {
console.error(storePath + ': reload failed', error);
} else if (!data) {
console.error(storePath + ': reload failed, no data');
} else if (load(data)) {
console.info(storePath + ': finished reloading data');
}
reading = false;
});
}
if (fs.existsSync(storePath)) {
var data = fs.readFileSync(storePath, 'utf8');
if (load(data)) {
console.info('finished loading data from ' + storePath);
}
} else {
console.error(storePath + ' does not exist, bailing out...');
return undefined;
}
fs.watchFile(storePath, function (curr, prev) {
if (curr.mtime < lastWrite) return;
console.warn(storePath + ' was updated by another application. reloading...');
resolve(readFile);
});
_this.write = function () {
if (arguments[0]) queue(arguments[0]);
else queue(function (success, err) {
if (success) console.info('writing to ' + storePath + ' succeded');
else console.error('writing to ' + storePath + ' failed');
});
};
return _this;
});
module = module.exports = function (storePath) {
return new db(storePath);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment