documented new features

This commit is contained in:
AJ ONeal 2012-03-02 11:35:53 -07:00
parent da17e4e05f
commit 3ddf2be63d
5 changed files with 161 additions and 48 deletions

View File

@ -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,22 +65,22 @@ 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\""`:
`null`, and `"null"` both parse as `null` the "object", instead of one being the string (which would be `"\"null\""`). `null`, and `"null"` both parse as `null` the "object", instead of one being the string (which would be `"\"null\""`).
Objects containing `null`, however, parse as expected `{ "foo": null, "bar": "null" }` will parse as `foo` being `null` but `bar` being `"null"`, much unlike the value `"null"` being parsed on its own. Objects containing `null`, however, parse as expected `{ "foo": null, "bar": "null" }` will parse as `foo` being `null` but `bar` being `"null"`, much unlike the value `"null"` being parsed on its own.

View File

@ -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;
function upgradeStorage(jss, w3cs) {
var i
, key
, 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;
db.prototype.clear = function () { Store.prototype.clear = function () {
this.keysAreDirty = true; this._keysAreDirty = true;
this.keys().forEach(function (uuid) { this.keys().forEach(function (key) {
this.remove(uuid); 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) || '';
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; this._keysAreDirty = false;
return this.__keys.concat([]); 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;
}()); }());

View File

@ -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": {}
} }

View File

@ -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.");
}()); }());

View 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');
}());