Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow append to existing object; allow user-provided read/write functions #29

Merged
merged 7 commits into from
Oct 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions examples/ini.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const fs = require('fs');
const ini = require('ini');
const utils = require('../utils');
const path = require('path');
const Store = require('../');

// Will be called in context of store
function writeFile() {
console.log('writeFile');
utils.mkdir(path.dirname(this.path));
fs.writeFileSync(this.path, ini.stringify(this.data), { mode: 0o0600 });
}

// Will be called in context of store
function readParseFile() {
let data;

console.log('readParseFile');
try {
data = fs.readFileSync(this.path, 'utf-8');
} catch (e) {
console.log('readParseFile error; starting with empty data');
data = {};
}

// Parse the INI-format configuration file
return ini.parse(data);
}

const store = new Store('app', {
path: __dirname + '/data.ini',
debounce: 10,
writeFile: writeFile,
readParseFile: readParseFile
});

store.merge('section 1', { a : 'b' });
store.merge('section 1', { c : 'd' });
store.set('section 2', { e : 'f' });
console.log(store.data);

//store.unlink();
61 changes: 59 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,20 @@ class Store {

const opts = { debounce: 0, indent: 2, home: os.homedir(), name, ...options };

this.name = opts.name || (opts.path ? utils.stem(opts.path) : 'data-store')
this.name = opts.name || (opts.path ? utils.stem(opts.path) : 'data-store');
this.path = opts.path || path.join(opts.home, `${this.name}.json`);
this.indent = opts.indent;
this.debounce = opts.debounce;
this.defaults = defaults || opts.default;
this.timeouts = {};

// Allow override of read and write methods
if (typeof options.readParseFile === 'function') {
this.readParseFile = options.readParseFile;
}
if (typeof options.writeFile === 'function') {
this.writeFile = options.writeFile;
}
}

/**
Expand Down Expand Up @@ -91,6 +99,39 @@ class Store {
return this;
}

/**
* Assign `value` to `key` while retaining prior members of `value` if
* `value` is a map. If `value` is not a map, overwrites like `.set`.
*
* ```js
* store.set('a', { b: c });
* //=> {a: { b: c }}
*
* store.merge('a', { d: e });
* //=> {a: { b: c, d: e }}
*
* store.set('a', 'b');
* //=> {a: 'b'}
*
* store.merge('a', { c : 'd' });
* //=> {a: { c : 'd' }}
* ```
*
* @name .merge
* @param {String} `key`
* @param {any} `val` The value to merge to `key`. Must be a valid JSON type: String, Number, Array or Object.
* @return {Object} `Store` for chaining
* @api public
*/

merge(key, val) {
let oldVal = this.get(key);
if (oldVal && typeof oldVal === 'object' && !Array.isArray(oldVal)) {
val = Object.assign(this.get(key), val);
}
return this.set(key, val);
}

/**
* Add the given `value` to the array at `key`. Creates a new array if one
* doesn't exist, and only adds unique values to the array.
Expand Down Expand Up @@ -323,14 +364,30 @@ class Store {
utils.tryUnlink(this.path);
}

/**
* Read and parse the data from the file system store. This method should
* probably not be called directly. Unless you are familiar with the inner
* workings of the code it's recommended that you use .load() instead.
*
* ```js
* data = store.readPraseFile();
* ```
* @name .readParseFile
* @return {Object}
*/

readParseFile() {
return JSON.parse(fs.readFileSync(this.path));
}

/**
* Load the store.
* @return {Object}
*/

load() {
try {
return (this[kData] = JSON.parse(fs.readFileSync(this.path)));
return (this[kData] = this.readParseFile());
} catch (err) {
if (err.code === 'EACCES') {
err.message += '\ndata-store does not have permission to load this file\n';
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"devDependencies": {
"delete": "^1.1.0",
"gulp-format-md": "^2.0.0",
"ini": "^1.3.5",
"mocha": "^6.2.0"
},
"keywords": [
Expand Down
27 changes: 27 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,33 @@ describe('store', () => {
});
});

describe('merge', () => {
it('should allow adding to an existing map', () => {
store.merge('a', { b : 'c' });
store.merge('d', { e : 'f' });
store.set('g', { h : 'i' });
assert.equal(store.data.a.b, 'c');
assert.equal(store.data.d.e, 'f');
assert.equal(store.data.g.h, 'i');
});
derrell marked this conversation as resolved.
Show resolved Hide resolved

it('should allow overriding an existing key in an existing map', () => {
store.merge('a', { b : 'c' });
store.merge('d', { e : 'f' });
store.set('g', { h : 'i' });
store.merge('d', { e : 'j' });
assert.equal(store.data.a.b, 'c');
assert.equal(store.data.d.e, 'j');
assert.equal(store.data.g.h, 'i');
});

it('should just overwrite if merge to non-object', () => {
store.set('a', 'b');
store.merge('a', { c : 'd' });
assert.equal(store.data.a.c, 'd');
});
});

describe('union', () => {
it('should add and arrayify a new value', () => {
store.union('one', 'two');
Expand Down