documented new features
This commit is contained in:
parent
da17e4e05f
commit
3ddf2be63d
43
README.md
43
README.md
@ -21,26 +21,39 @@ Made fo for Node.JS and Ender.JS (browser-side).
|
|||||||
|
|
||||||
var localStorage = require('localStorage')
|
var localStorage = require('localStorage')
|
||||||
, JsonStorage = require('json-storage')
|
, JsonStorage = require('json-storage')
|
||||||
, db = JsonStorage(localStorage, 'my-app-prefix')
|
, store = JsonStorage.create(localStorage, 'my-widget-namespace')
|
||||||
, myValue = {
|
, myValue = {
|
||||||
foo: "bar"
|
foo: "bar"
|
||||||
, baz: "quux"
|
, baz: "quux"
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
db.set('myKey', myValue);
|
store.set('myKey', myValue);
|
||||||
myValue = db.get('myKey');
|
myValue = store.get('myKey');
|
||||||
|
|
||||||
API
|
API
|
||||||
===
|
===
|
||||||
|
|
||||||
* JsonStorage(DOMStorage, 'application-prefix') // optional prefix
|
* `create(DOMStorage, namespace)`
|
||||||
* get(key)
|
* `DOMStorage` should be globalStorage, sessionStorage, or localStorage
|
||||||
* set(key, value)
|
* `namespace` is optional string which allows multiple non-conflicting storage containers
|
||||||
* remove(key)
|
* `get(key)`
|
||||||
* clear()
|
* `set(key, value)`
|
||||||
* keys()
|
* `remove(key)`
|
||||||
* size()
|
* `clear()`
|
||||||
|
* `keys()`
|
||||||
|
* `size()`
|
||||||
|
* `toJSON()`
|
||||||
|
* `JSON.stringify(store)`
|
||||||
|
|
||||||
|
Upgrading from localStorage and 1.0.x to 1.1.x
|
||||||
|
===
|
||||||
|
|
||||||
|
1.1.x automatically attempts to upgrade your DOMStorage to use namespaces in backwards-compatible way.
|
||||||
|
|
||||||
|
However, you can prevent this behaviour:
|
||||||
|
|
||||||
|
localStorage.getItem('_json-storage-namespaced_', true);
|
||||||
|
|
||||||
null vs undefined in JSON
|
null vs undefined in JSON
|
||||||
===
|
===
|
||||||
@ -52,18 +65,18 @@ they're simply to inform you of a few 'gotchas' inherent in JSON / DOMStorage co
|
|||||||
If they do, you're probably doing something wrong in the first place.
|
If they do, you're probably doing something wrong in the first place.
|
||||||
|
|
||||||
|
|
||||||
It is not valid to set `undefined` in JSON. So setting a key to `undefined` will remove it from the db.
|
It is not valid to set `undefined` in JSON. So setting a key to `undefined` will remove it from the store.
|
||||||
|
|
||||||
This means that `db.set('x')` is the same as `db.remove('x')`.
|
This means that `store.set('x')` is the same as `store.remove('x')`.
|
||||||
|
|
||||||
To save `undefined`, use `null` instead.
|
To save `undefined`, use `null` instead.
|
||||||
|
|
||||||
|
|
||||||
Note that both values that exist as `null` and values that don't exist at all will return `null`.
|
Note that both values that exist as `null` and values that don't exist at all will return `null`.
|
||||||
|
|
||||||
db.set('existing-key', null);
|
store.set('existing-key', null);
|
||||||
null === db.get('existing-key');
|
null === store.get('existing-key');
|
||||||
null === db.get('non-existant-key');
|
null === store.get('non-existant-key');
|
||||||
|
|
||||||
|
|
||||||
The special case of `null` as `"null"`, aka `"\"null\""`:
|
The special case of `null` as `"null"`, aka `"\"null\""`:
|
||||||
|
129
lib/index.js
129
lib/index.js
@ -1,7 +1,9 @@
|
|||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var db;
|
var Store
|
||||||
|
, delim = ':'
|
||||||
|
;
|
||||||
|
|
||||||
function Stringify(obj) {
|
function Stringify(obj) {
|
||||||
var str;
|
var str;
|
||||||
@ -23,57 +25,122 @@
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
function JsonStorage(w3cStorage) {
|
function escapeRegExp(str) {
|
||||||
this.db = w3cStorage;
|
return str.replace(/[-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||||
this.keysAreDirty = true;
|
|
||||||
}
|
}
|
||||||
db = JsonStorage;
|
|
||||||
|
|
||||||
db.prototype.clear = function () {
|
function upgradeStorage(jss, w3cs) {
|
||||||
this.keysAreDirty = true;
|
var i
|
||||||
this.keys().forEach(function (uuid) {
|
, key
|
||||||
this.remove(uuid);
|
, val
|
||||||
|
, json = {}
|
||||||
|
;
|
||||||
|
|
||||||
|
if (jss._store.getItem('_json-storage-namespaced_', true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can't modify the db while were reading or
|
||||||
|
// the keys will shift all over the place
|
||||||
|
for (i = 0; i < w3cs.length; i += 1) {
|
||||||
|
key = w3cs.key(i);
|
||||||
|
val = w3cs.getItem(key);
|
||||||
|
json[key] = val;
|
||||||
|
}
|
||||||
|
w3cs.clear();
|
||||||
|
|
||||||
|
Object.keys(json).forEach(function (key) {
|
||||||
|
jss.set(key, json[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
jss._store.setItem('_json-storage-namespaced_', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function JsonStorage(w3cStorage, namespace) {
|
||||||
|
// called without new or create
|
||||||
|
// global will be undefined
|
||||||
|
if (!this) {
|
||||||
|
return new JsonStorage(w3cStorage, namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we didn't always add at least the delimeter
|
||||||
|
// then if a keyname with the delim, it would be more
|
||||||
|
// complicated to figure it out
|
||||||
|
this._namespace = delim;
|
||||||
|
this._namespace += (namespace || 'jss');
|
||||||
|
|
||||||
|
this._store = w3cStorage;
|
||||||
|
this._keysAreDirty = true;
|
||||||
|
if (!this._store.getItem('_json-storage-namespaced_')) {
|
||||||
|
upgradeStorage(this, w3cStorage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Store = JsonStorage;
|
||||||
|
|
||||||
|
Store.prototype.clear = function () {
|
||||||
|
this._keysAreDirty = true;
|
||||||
|
this.keys().forEach(function (key) {
|
||||||
|
this.remove(key);
|
||||||
}, this);
|
}, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
db.prototype.remove = function (uuid) {
|
Store.prototype.remove = function (key) {
|
||||||
this.keysAreDirty = true;
|
this._keysAreDirty = true;
|
||||||
this.db.removeItem(uuid);
|
this._store.removeItem(key + this._namespace);
|
||||||
};
|
};
|
||||||
|
|
||||||
db.prototype.get = function (uuid) {
|
Store.prototype.get = function (key) {
|
||||||
return Parse(this.db.getItem(uuid));
|
return Parse(this._store.getItem(key + this._namespace));
|
||||||
};
|
};
|
||||||
|
|
||||||
db.prototype.set = function (uuid, val) {
|
Store.prototype.set = function (key, val) {
|
||||||
this.keysAreDirty = true;
|
this._keysAreDirty = true;
|
||||||
return this.db.setItem(uuid, Stringify(val));
|
return this._store.setItem(key + this._namespace, Stringify(val));
|
||||||
};
|
};
|
||||||
|
|
||||||
db.prototype.keys = function () {
|
Store.prototype.keys = function () {
|
||||||
var i
|
var i
|
||||||
|
, key
|
||||||
|
, delimAt
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!this.keysAreDirty) {
|
if (!this._keysAreDirty) {
|
||||||
return this.__keys.concat([]);
|
return this._keys.concat([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.__keys = [];
|
this._keys = [];
|
||||||
for (i = 0; i < this.db.length; i += 1) {
|
for (i = 0; i < this._store.length; i += 1) {
|
||||||
this.__keys.push(this.db.key(i));
|
key = this._store.key(i) || '';
|
||||||
}
|
|
||||||
this.keysAreDirty = false;
|
|
||||||
|
|
||||||
return this.__keys.concat([]);
|
delimAt = key.lastIndexOf(this._namespace);
|
||||||
|
// test if this key belongs to this widget
|
||||||
|
if (-1 !== delimAt) {
|
||||||
|
this._keys.push(key.substr(0, delimAt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._keysAreDirty = false;
|
||||||
|
|
||||||
|
return this._keys.concat([]);
|
||||||
};
|
};
|
||||||
|
|
||||||
db.prototype.size = function () {
|
Store.prototype.size = function () {
|
||||||
return this.db.length;
|
return this._store.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
function create(w3cStorage) {
|
Store.prototype.toJSON = function () {
|
||||||
return new JsonStorage(w3cStorage);
|
var json = {}
|
||||||
|
;
|
||||||
|
|
||||||
|
this._keys.forEach(function (key) {
|
||||||
|
json[key] = this.get(key);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
return json;
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.create = function (w3cStorage, namespace) {
|
||||||
|
return new JsonStorage(w3cStorage, namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = create;
|
module.exports = Store;
|
||||||
}());
|
}());
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "json-storage",
|
"name": "json-storage",
|
||||||
"description": "A wrapper for storage engines which use the W3C Storage API",
|
"description": "A wrapper for storage engines which use the W3C Storage API",
|
||||||
"keywords": ["ender", "localStorage", "sessionStorage", "globalStorage", "Storage"],
|
"keywords": ["ender", "localStorage", "sessionStorage", "globalStorage", "Storage"],
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/coolaj86/json-storage-js.git"
|
"url": "git://github.com/coolaj86/json-storage-js.git"
|
||||||
@ -12,6 +12,7 @@
|
|||||||
"node": ">= v0.2.0"
|
"node": ">= v0.2.0"
|
||||||
},
|
},
|
||||||
"main": "index",
|
"main": "index",
|
||||||
|
"browserDependencies": {},
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {}
|
"devDependencies": {}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
;
|
;
|
||||||
|
|
||||||
assert.equal(null, db.get('x'));
|
assert.equal(null, db.get('x'));
|
||||||
assert.deepEqual([], db.keys());
|
assert.deepEqual([], db.keys(), 'found keys in empty db: ' + JSON.stringify(db.keys()));
|
||||||
db.clear();
|
db.clear();
|
||||||
assert.equal(null, db.get('x'));
|
assert.equal(null, db.get('x'));
|
||||||
|
|
||||||
@ -23,5 +23,9 @@
|
|||||||
db.clear();
|
db.clear();
|
||||||
assert.deepEqual([], db.keys());
|
assert.deepEqual([], db.keys());
|
||||||
|
|
||||||
|
db.set('a', 'b');
|
||||||
|
assert.deepEqual(['a'], db.keys());
|
||||||
|
assert.deepEqual({ 'a': 'b' }, db.toJSON());
|
||||||
|
|
||||||
console.log("Done! All tests pass.");
|
console.log("Done! All tests pass.");
|
||||||
}());
|
}());
|
||||||
|
28
test/two-stores-can-have-same-keys.js
Normal file
28
test/two-stores-can-have-same-keys.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var localStorage = require('localStorage')
|
||||||
|
, jsonStorage = require('../lib/')
|
||||||
|
, assert = require('assert')
|
||||||
|
, store0 = jsonStorage.create(localStorage, '0')
|
||||||
|
, store1 = jsonStorage.create(localStorage, '1')
|
||||||
|
;
|
||||||
|
|
||||||
|
store0.set('foo', 'bar');
|
||||||
|
store1.set('foo', 'baz');
|
||||||
|
|
||||||
|
assert.strictEqual('bar', store0.get('foo'));
|
||||||
|
assert.strictEqual('baz', store1.get('foo'));
|
||||||
|
|
||||||
|
store0.remove('foo');
|
||||||
|
|
||||||
|
assert.strictEqual(null, store0.get('foo'));
|
||||||
|
assert.strictEqual('baz', store1.get('foo'), 'after removing a value from store1, store0 lost it as well');
|
||||||
|
|
||||||
|
store0.clear();
|
||||||
|
|
||||||
|
assert.strictEqual(null, store0.get('foo'));
|
||||||
|
assert.strictEqual('baz', store1.get('foo'), 'after clearing store0, store1 lost values');
|
||||||
|
|
||||||
|
console.log('[PASS] no assertions failed');
|
||||||
|
}());
|
Loading…
x
Reference in New Issue
Block a user