From 3f3213d6c25e256597014d86d29f8d3f838c9c11 Mon Sep 17 00:00:00 2001 From: Kamran Fardanesh Date: Thu, 2 Mar 2017 20:44:01 -0500 Subject: [PATCH 1/2] added directory support An initial start to add directory support, looking to get help/advice from community to make code more robust. Added capability to prefix key with directory for get, set, has, remove (i.e. "testfolder/foo" will get, set, has, or remove foo under the testfolder directory). Also extended functions getAll, keys, clear* to allow optional directory parameter (i.e. "testfolder" will getAll, keys or clear* under the testfolder directory. getMany is tricky and needs some work. *Currently clear removes the directory passed to function. **All current test cases pass with exception of utils test function since directory is different --- lib/storage.js | 45 +++++++++++++++++++++++++++++++++++---------- lib/utils.js | 20 ++++++++++++++++---- tests/utils.spec.js | 10 +++++----- 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/lib/storage.js b/lib/storage.js index aed7588..a664b8f 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -63,6 +63,7 @@ const utils = require('./utils'); * console.log(data); * }); */ + // WORKING exports.get = function(key, callback) { async.waterfall([ async.asyncify(_.partial(utils.getFileName, key)), @@ -121,7 +122,7 @@ exports.getMany = function(keys, callback) { if (error) { return callback(error); } - + // console.log(data) return callback(null, _.set(reducer, key, data)); }); }, callback); @@ -146,9 +147,14 @@ exports.getMany = function(keys, callback) { * console.log(data); * }); */ -exports.getAll = function(callback) { + // WORKING +exports.getAll = function(directory, callback) { + if(arguments.length === 1){ + callback = directory; + directory = ""; + } async.waterfall([ - exports.keys, + _.partial(exports.keys, directory), function(keys, callback) { async.reduce(keys, {}, function(reducer, key, callback) { async.waterfall([ @@ -178,6 +184,7 @@ exports.getAll = function(callback) { * if (error) throw error; * }); */ + // WORKING exports.set = function(key, json, callback) { async.waterfall([ async.asyncify(_.partial(utils.getFileName, key)), @@ -220,6 +227,7 @@ exports.set = function(key, json, callback) { * } * }); */ + // WORKING exports.has = function(key, callback) { async.waterfall([ async.asyncify(_.partial(utils.getFileName, key)), @@ -245,9 +253,14 @@ exports.has = function(key, callback) { * } * }); */ -exports.keys = function(callback) { + // WORKING +exports.keys = function(directory, callback) { + if(arguments.length === 1){ + callback = directory; + directory = ""; + } async.waterfall([ - async.asyncify(utils.getUserDataPath), + async.asyncify(_.partial(utils.getUserDataPath, directory)), function(userDataPath, callback) { mkdirp(userDataPath, function(error) { return callback(error, userDataPath); @@ -255,9 +268,12 @@ exports.keys = function(callback) { }, fs.readdir, function(keys, callback) { - callback(null, _.map(keys, function(key) { - return path.basename(key, '.json'); - })); + callback(null, keys.filter(function(key){ + return path.extname(key) !== ""; + }).map(function(key) { + return path.basename(key, '.json'); + } + )); } ], callback); }; @@ -281,6 +297,7 @@ exports.keys = function(callback) { * if (error) throw error; * }); */ + // WORKING exports.remove = function(key, callback) { async.waterfall([ async.asyncify(_.partial(utils.getFileName, key)), @@ -302,8 +319,16 @@ exports.remove = function(key, callback) { * if (error) throw error; * }); */ -exports.clear = function(callback) { - const userData = utils.getUserDataPath(); + // WORKING +exports.clear = function(directory, callback) { + if(arguments.length === 1){ + callback = directory; + directory = ""; + } + const userData = utils.getUserDataPath(directory); const jsonFiles = path.join(userData, '*.json'); rimraf(jsonFiles, callback); + if(directory !== ""){ + rimraf(userData, callback); + } }; diff --git a/lib/utils.js b/lib/utils.js index 6425628..bb56f94 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -29,6 +29,17 @@ const path = require('path'); const electron = require('electron'); const app = electron.app || electron.remote.app; +function getDirectory(directory){ + const directoryArray = directory.split(path.posix.sep); + let newDirectory = ""; + for(var dir of directoryArray){ + if(dir !== ".."){ + newDirectory += dir + "/"; + } + } + return newDirectory; +} + /** * @summary Get user data directory path * @function @@ -39,8 +50,8 @@ const app = electron.app || electron.remote.app; * let userDataPath = utils.getUserDataPath(); * console.log(userDataPath); */ -exports.getUserDataPath = function() { - return path.join(app.getPath('userData'), 'storage'); +exports.getUserDataPath = function(directory = "") { + return path.join(app.getPath('userData'), 'storage', getDirectory(directory)); }; /** @@ -72,6 +83,7 @@ exports.getFileName = function(key) { // reserved characters in Windows filenames. // See: https://en.wikipedia.org/wiki/Filename#Reserved%5Fcharacters%5Fand%5Fwords const escapedFileName = encodeURIComponent(keyFileName); - - return path.join(exports.getUserDataPath(), escapedFileName); + + // console.log(path.join(exports.getUserDataPath(), newDirectory, escapedFileName)); + return path.join(exports.getUserDataPath(), getDirectory(path.dirname(key)) , escapedFileName); }; diff --git a/tests/utils.spec.js b/tests/utils.spec.js index 7838640..0b55a48 100644 --- a/tests/utils.spec.js +++ b/tests/utils.spec.js @@ -38,11 +38,11 @@ describe('Utils', function() { m.chai.expect(path.isAbsolute(utils.getUserDataPath())).to.be.true; }); - it('should equal the dirname of the path returned by getFileName()', function() { - const fileName = utils.getFileName('foo'); - const userDataPath = utils.getUserDataPath(); - m.chai.expect(path.dirname(fileName)).to.equal(userDataPath); - }); + // it('should equal the dirname of the path returned by getFileName()', function() { + // const fileName = utils.getFileName('foo'); + // const userDataPath = utils.getUserDataPath(); + // m.chai.expect(path.dirname(fileName)).to.equal(userDataPath); + // }); }); From bfb46bb97d4c3ce6fa2ee497539e74c32c4a3af1 Mon Sep 17 00:00:00 2001 From: Kamran Fardanesh Date: Mon, 6 Mar 2017 22:31:21 -0500 Subject: [PATCH 2/2] user can now set a dataPath or working directory --- lib/storage.js | 74 ++++++++++++++++++++++++++++----------------- lib/utils.js | 35 +++++++++++++++++---- tests/utils.spec.js | 10 +++--- 3 files changed, 80 insertions(+), 39 deletions(-) diff --git a/lib/storage.js b/lib/storage.js index a664b8f..b37c920 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -37,6 +37,46 @@ const mkdirp = require('mkdirp'); const path = require('path'); const utils = require('./utils'); +/** + * @summary Set data path + * @function + * @public + * + * @description + * Pass the directory you want to call the functions from. + * If no directory is passed, returns to default 'storage' + * + * @param {String} directory - directory + * + * @example + * const storage = require('electron-json-storage'); + * + * storage.setDataPath('foo'); + */ +exports.setDataPath = function(dir = ""){ + utils.setUserDataPath(dir); +}; + +/** + * @summary Get data path + * @function + * @public + * + * @description + * Returns the current directory being used. + * + * @param {String} directory - directory + * + * @example + * const storage = require('electron-json-storage'); + * + * let dataPath = storage.getDataPath(); + * console.log(dataPath); + */ +exports.getDataPath = function(){ + return utils.getUserDataPath(); +}; + /** * @summary Read user data * @function @@ -63,7 +103,6 @@ const utils = require('./utils'); * console.log(data); * }); */ - // WORKING exports.get = function(key, callback) { async.waterfall([ async.asyncify(_.partial(utils.getFileName, key)), @@ -147,14 +186,9 @@ exports.getMany = function(keys, callback) { * console.log(data); * }); */ - // WORKING -exports.getAll = function(directory, callback) { - if(arguments.length === 1){ - callback = directory; - directory = ""; - } +exports.getAll = function(callback) { async.waterfall([ - _.partial(exports.keys, directory), + exports.keys, function(keys, callback) { async.reduce(keys, {}, function(reducer, key, callback) { async.waterfall([ @@ -184,7 +218,6 @@ exports.getAll = function(directory, callback) { * if (error) throw error; * }); */ - // WORKING exports.set = function(key, json, callback) { async.waterfall([ async.asyncify(_.partial(utils.getFileName, key)), @@ -227,7 +260,6 @@ exports.set = function(key, json, callback) { * } * }); */ - // WORKING exports.has = function(key, callback) { async.waterfall([ async.asyncify(_.partial(utils.getFileName, key)), @@ -253,14 +285,9 @@ exports.has = function(key, callback) { * } * }); */ - // WORKING -exports.keys = function(directory, callback) { - if(arguments.length === 1){ - callback = directory; - directory = ""; - } +exports.keys = function(callback) { async.waterfall([ - async.asyncify(_.partial(utils.getUserDataPath, directory)), + async.asyncify(utils.getUserDataPath), function(userDataPath, callback) { mkdirp(userDataPath, function(error) { return callback(error, userDataPath); @@ -297,7 +324,6 @@ exports.keys = function(directory, callback) { * if (error) throw error; * }); */ - // WORKING exports.remove = function(key, callback) { async.waterfall([ async.asyncify(_.partial(utils.getFileName, key)), @@ -319,16 +345,8 @@ exports.remove = function(key, callback) { * if (error) throw error; * }); */ - // WORKING -exports.clear = function(directory, callback) { - if(arguments.length === 1){ - callback = directory; - directory = ""; - } - const userData = utils.getUserDataPath(directory); +exports.clear = function(callback) { + const userData = utils.getUserDataPath(); const jsonFiles = path.join(userData, '*.json'); rimraf(jsonFiles, callback); - if(directory !== ""){ - rimraf(userData, callback); - } }; diff --git a/lib/utils.js b/lib/utils.js index bb56f94..f3145b3 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -29,6 +29,17 @@ const path = require('path'); const electron = require('electron'); const app = electron.app || electron.remote.app; +// define the defaultDataPath and current directory +const defaultBasePath = 'storage'; +let currentDirectory = ''; + +/** + * @summary Parse directory to avoid parent directories + * @function + * @private + * + * @returns {Strings} parsed user data path without parent directories + */ function getDirectory(directory){ const directoryArray = directory.split(path.posix.sep); let newDirectory = ""; @@ -41,17 +52,30 @@ function getDirectory(directory){ } /** - * @summary Get user data directory path + * @summary Set default user data directory path + * @function + * @public + * + * @example + * utils.getUserDataPath('newDirectory'); + */ +exports.setUserDataPath = function(directory) { + currentDirectory = getDirectory(directory); +}; + +/** + * @summary Get default user data directory path * @function * @public * * @returns {Strings} user data path * + * @example * let userDataPath = utils.getUserDataPath(); * console.log(userDataPath); */ -exports.getUserDataPath = function(directory = "") { - return path.join(app.getPath('userData'), 'storage', getDirectory(directory)); +exports.getUserDataPath = function() { + return path.join(app.getPath('userData'), defaultBasePath, currentDirectory); }; /** @@ -83,7 +107,6 @@ exports.getFileName = function(key) { // reserved characters in Windows filenames. // See: https://en.wikipedia.org/wiki/Filename#Reserved%5Fcharacters%5Fand%5Fwords const escapedFileName = encodeURIComponent(keyFileName); - - // console.log(path.join(exports.getUserDataPath(), newDirectory, escapedFileName)); - return path.join(exports.getUserDataPath(), getDirectory(path.dirname(key)) , escapedFileName); + + return path.join(exports.getUserDataPath(), escapedFileName); }; diff --git a/tests/utils.spec.js b/tests/utils.spec.js index 0b55a48..7838640 100644 --- a/tests/utils.spec.js +++ b/tests/utils.spec.js @@ -38,11 +38,11 @@ describe('Utils', function() { m.chai.expect(path.isAbsolute(utils.getUserDataPath())).to.be.true; }); - // it('should equal the dirname of the path returned by getFileName()', function() { - // const fileName = utils.getFileName('foo'); - // const userDataPath = utils.getUserDataPath(); - // m.chai.expect(path.dirname(fileName)).to.equal(userDataPath); - // }); + it('should equal the dirname of the path returned by getFileName()', function() { + const fileName = utils.getFileName('foo'); + const userDataPath = utils.getUserDataPath(); + m.chai.expect(path.dirname(fileName)).to.equal(userDataPath); + }); });