node-persist
Advanced tools
Comparing version 0.0.12 to 1.0.0
@@ -18,11 +18,22 @@ /* | ||
logging: true, | ||
ttl: ttl, | ||
dir: __dirname + '/store' | ||
ttl: ttl | ||
}).then(function() { | ||
if(!storage.getItem('counter')) { | ||
storage.setItemSync('counter', 0); | ||
return storage.getItem('counter'); | ||
}).then(function(counter) { | ||
if (! counter) { | ||
return storage.setItemSync('counter', 0); | ||
} | ||
console.log("counter is: " + storage.getItem('counter')); | ||
}, function(err) { | ||
return counter | ||
}).then(function() { | ||
return storage.getItem('counter'); | ||
}).then(function(counter) { | ||
console.log('counter is ' + counter); | ||
}).catch(function(err) { | ||
console.error(err); | ||
throw err; | ||
}); | ||
@@ -29,0 +40,0 @@ |
{ | ||
"name": "node-persist", | ||
"version": "0.0.12", | ||
"version": "1.0.0", | ||
"description": "Super-easy (and fast) persistent data structures in Node.js, modeled after HTML5 localStorage", | ||
@@ -5,0 +5,0 @@ "main": "./src/node-persist.js", |
@@ -23,20 +23,34 @@ # node-persist | ||
Async example | ||
```js | ||
//you must first call storage.init or storage.initSync | ||
storage.initSync(); | ||
//you must first call storage.init | ||
//you must first call storage.initSync | ||
storage.init( /* options ... */ ); | ||
//then start using it | ||
storage.setItem('name','yourname'); | ||
console.log(storage.getItem('name')); | ||
storage.setItem('name','yourname') | ||
.then(function() { | ||
var batman = { | ||
first: 'Bruce', | ||
last: 'Wayne', | ||
alias: 'Batman' | ||
}; | ||
return storage.getItem('name') | ||
}) | ||
.then(function(value) { | ||
storage.setItem('batman',batman); | ||
console.log(storage.getItem('batman').alias); | ||
console.log(value); // yourname | ||
}) | ||
``` | ||
Sync example | ||
``` | ||
//you must first call storage.initSync | ||
storage.initSync(); | ||
//then start using it | ||
storage.setItemSync('name','yourname'); | ||
console.log(storage.getItemSync('name')); // yourname | ||
``` | ||
## Run the examples: | ||
@@ -50,2 +64,16 @@ | ||
## 1.0.0 change logs | ||
Mostly non-backward changes | ||
* `storage.getItem()` now returns a promise | ||
* `storage.valuesWithKeyMatch()` no longer accepts a callback | ||
* `storage.values()` no longer accepts a callback | ||
* `storage.key()` is gone | ||
* The default `dir` is now `process.cwd() + (dir || '.node-persist/storage')`, unless you use an absolute path | ||
* added `storage.get()`, alias to `getItem()` | ||
* added `storage.set()`, alias to `setItem()` | ||
* added `storage.del()`, `storage.rm()`, as aliases to `removeItem()` | ||
* Keys, on the file system are base64 encoded with the replacement of the `/` | ||
## API Documentation | ||
@@ -83,16 +111,20 @@ | ||
#### `getItem(key, [callback])` - returns value synchronous* but may linger async call if unless ttl expired, | ||
This function will get a key from your database in memory, and return its value, or undefined if it is not present. | ||
#### `getItem(key, [callback])` - returns promise, | ||
This function will get a key from your database in memory | ||
\* you can always use it in a asynchronous mode, meaning passing a callback (because we cannot return a Promise for this one) - the callback will be executed immediately and synchronously if there is no ttl used. If you are using ttl but you are also using `options.interval` or `options.continous=false` the deletion of the expired keys will wait for either the interval to kick in or if you manually `persist` | ||
```js | ||
```js | ||
// callback | ||
storage.getItem('name', function (err, value) { | ||
// use value here after makign sure expired-ttl key deletion has occured, in that case value === undefined | ||
}); // value is also returned | ||
storage.getItem('obj').key1; | ||
storage.getItem('arr')[42]; | ||
// use value here after making sure expired-ttl key deletion has occured, in that case value === undefined | ||
}); | ||
// promise | ||
storage.getItem('obj').then(function(value) { | ||
}) | ||
``` | ||
#### `getItemSync(key)` - returns value | ||
The only synchronous part is the deletion of an expired-ttl key, if `options.ttl` is used, otherwise it behaves just like `getItem` | ||
All synchronous part along with the deletion of an expired-ttl key, if `options.ttl` is used | ||
@@ -151,10 +183,6 @@ #### `setItem(key, value, [callback])` - asynchronous*, returns Promise | ||
``` | ||
#### `values([callback])` - [DEPRECATED] synchronous, but still returns array | ||
This function is synchronous, it does not need to accept a callback, so that signature is getting deprecated. | ||
#### `values()` - returns array | ||
```js | ||
// notice this callback does not accept an error as a 1st argument, to support backward compatibility | ||
// but will be removed on next minor release | ||
storage.values(function(values) { | ||
})); | ||
var values = storage.values(); | ||
``` | ||
@@ -173,15 +201,7 @@ | ||
``` | ||
#### `valuesWithKeyMatch(match, [callback])` - [DEPRECATED] synchronous, but still returns array | ||
This function is synchronous, it does not need to accept a callback, so that signature getting deprecated | ||
#### `valuesWithKeyMatch(match)` - synchronous, returns array | ||
```js | ||
// notice this callback does not accept an error as a 1st argument, to support backward compatibility | ||
// but will be removed on next minor release | ||
storage.valuesWithKeyMatch('man', function(values) { | ||
})); | ||
var values = storage.valuesWithKeyMatch('man'); | ||
``` | ||
#### `key(n)` - [DEPRECATED] synchronous, returns string | ||
This function returns a key with index n in the database, or null if it is not present. The ordering of keys is not known to the user. It is getting deprecated because `Object.keys()` does not guarantee the order of the keys, so this functionality is fragile. | ||
#### `keys()` - synchronous, returns array | ||
@@ -188,0 +208,0 @@ |
@@ -8,7 +8,8 @@ /* | ||
path = require('path'), | ||
mkdirp = require("mkdirp"), | ||
mkdirp = require('mkdirp'), | ||
Q = require('q'), | ||
pkg = require('../package.json'), | ||
defaults = { | ||
dir: 'persist', | ||
dir: '.' + pkg.name + '/storage', | ||
stringify: JSON.stringify, | ||
@@ -37,10 +38,31 @@ parse: JSON.parse, | ||
/* | ||
* To support backward compatible callbacks, | ||
* i.e callback(data) vs callback(err, data); | ||
* replace with noop and fix args order, when ready to break backward compatibily for the following API functions | ||
* - values() | ||
* - valuesWithKeyMatch() | ||
* hint: look for 'todo-breaks-backward' in the source | ||
*/ | ||
btoa = function (string) { | ||
return new Buffer(string.toString(), 'binary').toString('base64'); | ||
}, | ||
atob = function (string) { | ||
return new Buffer(string, 'base64').toString('binary'); | ||
}, | ||
sanitize = function (string) { | ||
return btoa(string).replace(btoaPathSepRegExp, atobPathSepReplacement); | ||
}, | ||
unsanitize = function (string) { | ||
return atob(string.replace(atobPathSepReplacementRegExp, '/')); | ||
}, | ||
btoaPathSepRegExp = new RegExp(path.sep, 'g'), | ||
atobPathSepReplacement = '__SLASH__', | ||
atobPathSepReplacementRegExp = new RegExp(atobPathSepReplacement, 'g'), | ||
/* | ||
* To support backward compatible callbacks, | ||
* i.e callback(data) vs callback(err, data); | ||
* replace with noop and fix args order, when ready to break backward compatibily for the following API functions | ||
* - values() | ||
* - valuesWithKeyMatch() | ||
* hint: look for 'todo-breaks-backward' in the source | ||
*/ | ||
noopWithoutError = function() {}; | ||
@@ -159,13 +181,2 @@ | ||
key: function (n) { | ||
// todo-breaks-backward: remove this function | ||
// this is fragile, keys are not guaranteed to be in a any order, so 2 calls using the same index could return a different result | ||
// http://stackoverflow.com/a/5525820/493756, see the ECMAScript source in that answer | ||
var keys = this.keys(); | ||
if (keys.length <= n) { | ||
return null; | ||
} | ||
return keys[n]; | ||
}, | ||
keys: function () { | ||
@@ -185,22 +196,10 @@ return Object.keys(this.data); | ||
values: function(callback) { | ||
// todo-breaks-backward: remove callback option | ||
callback = isFunction(callback) ? callback : noopWithoutError; | ||
var values = this.keys().map(function(k) { | ||
values: function() { | ||
return this.keys().map(function(k) { | ||
return this.data[k]; | ||
}.bind(this)); | ||
// todo-breaks-backward: remove callback, no need, this is sync | ||
callback(values); | ||
return values; | ||
}, | ||
valuesWithKeyMatch: function(match, callback) { | ||
// todo-breaks-backward: remove callback option | ||
callback = isFunction(callback) ? callback : noopWithoutError; | ||
valuesWithKeyMatch: function(match) { | ||
match = match || /.*/; | ||
@@ -223,7 +222,9 @@ | ||
// todo-breaks-backward: remove callback, no need this is sync | ||
callback(values); | ||
return values; | ||
}, | ||
set: function () { | ||
return this.setItem(key, value, callback); | ||
}, | ||
setItem: function (key, value, callback) { | ||
@@ -286,4 +287,10 @@ callback = isFunction(callback) ? callback : noop; | ||
get: function (key, callback) { | ||
return this.getItem(key, callback); | ||
}, | ||
getItem: function (key, callback) { | ||
callback = isFunction(callback) ? callback : noop; | ||
var deferred = Q.defer(); | ||
if (this.isExpired(key)) { | ||
@@ -293,11 +300,12 @@ this.log(key + ' has expired'); | ||
callback(null, null); | ||
return; | ||
return deferred.resolve(null); | ||
} | ||
this.removeItem(key, function() { | ||
callback(null, null); | ||
return this.removeItem(key).then(function() { | ||
return null; | ||
}); | ||
} else { | ||
callback(null, this.data[key]); | ||
return this.data[key]; | ||
deferred.resolve(this.data[key]); | ||
} | ||
return deferred.promise; | ||
}, | ||
@@ -313,2 +321,10 @@ | ||
del: function (key, callback) { | ||
return this.removeItem(key, callback); | ||
}, | ||
rm: function (key, callback) { | ||
return this.removeItem(key, callback); | ||
}, | ||
removeItem: function (key, callback) { | ||
@@ -430,3 +446,4 @@ callback = isFunction(callback) ? callback : noop; | ||
var file = path.join(options.dir, key); | ||
var file = path.join(options.dir, sanitize(key)); | ||
var ttlFile; | ||
@@ -461,3 +478,3 @@ | ||
if (options.ttl) { | ||
ttlFile = path.join(options.ttlDir, key); | ||
ttlFile = path.join(options.ttlDir, sanitize(key)); | ||
mkdirp(path.dirname(ttlFile), function(err) { | ||
@@ -483,3 +500,3 @@ fs.writeFile(ttlFile, options.stringify(self.ttls[key]), options.encoding, function() { | ||
var options = this.options; | ||
var file = path.join(options.dir, key); | ||
var file = path.join(options.dir, sanitize(key)); | ||
try { | ||
@@ -496,3 +513,3 @@ mkdirp.sync(path.dirname(file)); | ||
if (options.ttl) { | ||
ttlFile = path.join(options.ttlDir, key); | ||
ttlFile = path.join(options.ttlDir, sanitize(key)); | ||
mkdirp.sync(path.dirname(ttlFile)); | ||
@@ -514,3 +531,3 @@ fs.writeFileSync(ttlFile, options.stringify(this.ttls[key])); | ||
//check to see if key has been persisted | ||
var file = path.join(options.dir, key); | ||
var file = path.join(options.dir, sanitize(key)); | ||
fs.exists(file, function (exists) { | ||
@@ -536,3 +553,3 @@ if (exists) { | ||
if (options.ttl) { | ||
var ttlFile = path.join(options.ttlDir, key); | ||
var ttlFile = path.join(options.ttlDir, sanitize(key)); | ||
fs.exists(ttlFile, function (exists) { | ||
@@ -609,3 +626,3 @@ if (exists) { | ||
if (curr[0] !== '.') { | ||
deferreds.push(parseFn(curr)); | ||
deferreds.push(parseFn(unsanitize(curr))); | ||
} | ||
@@ -653,3 +670,3 @@ } | ||
var json = fs.readFileSync(path.join(dir, curr), this.options.encoding); | ||
hash[curr] = this.parseString(json); | ||
hash[unsanitize(curr)] = this.parseString(json); | ||
} | ||
@@ -683,3 +700,3 @@ } | ||
var result; | ||
var file = path.join(dir, key); | ||
var file = path.join(dir, sanitize(key)); | ||
var options = this.options; | ||
@@ -709,3 +726,3 @@ | ||
parseFileSync: function(key, dir, hash) { | ||
var file = path.join(dir, key); | ||
var file = path.join(dir, sanitize(key)); | ||
hash[key] = fs.readFileSync(file, this.options.encoding); | ||
@@ -724,3 +741,3 @@ this.log("loaded: " + dir + "/" + key); | ||
var file = path.join(options.dir, key); | ||
var file = path.join(options.dir, sanitize(key)); | ||
if (fs.existsSync(file)) { | ||
@@ -730,3 +747,3 @@ fs.unlinkSync(file); | ||
if (options.ttl) { | ||
var ttlFile = path.join(options.ttlDir, key); | ||
var ttlFile = path.join(options.ttlDir, sanitize(key)); | ||
if (fs.existsSync(ttlFile)) { | ||
@@ -740,7 +757,6 @@ fs.unlinkSync(ttlFile); | ||
dir = path.normalize(dir); | ||
if (dir !== path.resolve(dir)) { | ||
dir = path.join(__dirname, "storage", dir || ""); | ||
this.log("Made dir absolute: " + dir); | ||
if (path.isAbsolute(dir)) { | ||
return dir; | ||
} | ||
return dir; | ||
return path.join(process.cwd(), dir); | ||
}, | ||
@@ -754,5 +770,8 @@ | ||
this.options && this.options.logging && console.log.apply(console, arguments); | ||
} | ||
}, | ||
sanitize: sanitize, | ||
unsanitize: unsanitize | ||
}; | ||
module.exports = LocalStorage; |
@@ -121,9 +121,2 @@ | ||
it("should return a key() by index", function(done) { | ||
storage.setItemSync("item2", items.item2); | ||
assert.equal(storage.key(1), Object.keys(items)[1]); | ||
storage.removeItemSync("item2"); | ||
done(); | ||
}); | ||
it("should return all keys()", function(done) { | ||
@@ -192,6 +185,7 @@ assert.deepEqual(storage.keys(), ["item1"]); | ||
it("should getItem() from cache", function(done) { | ||
var value = storage.getItem("item1"); | ||
assert.equal(value, items.item1); | ||
done(); | ||
it("should getItem().then() from cache", function(done) { | ||
storage.getItem("item1").then(function(value) { | ||
assert.equal(value, items.item1); | ||
done(); | ||
}) | ||
}); | ||
@@ -283,20 +277,19 @@ | ||
storage.initSync({ | ||
storage.init({ | ||
dir: randDir(), | ||
interval: 2000 // persist to disk every 2 seconds | ||
}); | ||
}).then(function() { | ||
var startTime = +new Date(); | ||
var startTime = +new Date(); | ||
storage.setItem("item999", 1).then(function() { | ||
// 2 seconds later, that file should be there and that promise should resolve now. | ||
var endTime = +new Date(); | ||
assert.approximately(endTime, startTime, 2500, "within 2.5s or so"); | ||
assert.equal(true, fs.existsSync(storage.options.dir + "/" + storage.sanitize("item999"))); | ||
done(); | ||
}); | ||
storage.setItem("item1", 1).then(function() { | ||
// 2 seconds later, that file should be there and that promise should resolve now. | ||
var endTime = +new Date(); | ||
assert.approximately(endTime, startTime, 2500, "within 2.5s or so"); | ||
assert.equal(true, fs.existsSync(storage.options.dir + "/item1")); | ||
done(); | ||
// check if the item1 file exists immediately, it shouldnt | ||
assert.notEqual(true, fs.existsSync(storage.options.dir + "/" + storage.sanitize("item999"))); | ||
}); | ||
// check if the item1 file exists immediately, it shouldnt | ||
assert.notEqual(true, fs.existsSync(storage.options.dir + "/item1")); | ||
}); | ||
@@ -303,0 +296,0 @@ }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1089
1
281
50180