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')
, JsonStorage = require('json-storage')
, db = JsonStorage(localStorage, 'my-app-prefix')
, store = JsonStorage.create(localStorage, 'my-widget-namespace')
, myValue = {
foo: "bar"
, baz: "quux"
}
;
db.set('myKey', myValue);
myValue = db.get('myKey');
store.set('myKey', myValue);
myValue = store.get('myKey');
API
===
* JsonStorage(DOMStorage, 'application-prefix') // optional prefix
* get(key)
* set(key, value)
* remove(key)
* clear()
* keys()
* size()
* `create(DOMStorage, namespace)`
* `DOMStorage` should be globalStorage, sessionStorage, or localStorage
* `namespace` is optional string which allows multiple non-conflicting storage containers
* `get(key)`
* `set(key, value)`
* `remove(key)`
* `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
===
@ -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.
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.
Note that both values that exist as `null` and values that don't exist at all will return `null`.
db.set('existing-key', null);
null === db.get('existing-key');
null === db.get('non-existant-key');
store.set('existing-key', null);
null === store.get('existing-key');
null === store.get('non-existant-key');
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\""`).
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 () {
"use strict";
var db;
var Store
, delim = ':'
;
function Stringify(obj) {
var str;
@ -23,57 +25,122 @@
return obj;
}
function JsonStorage(w3cStorage) {
this.db = w3cStorage;
this.keysAreDirty = true;
function escapeRegExp(str) {
return str.replace(/[-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
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 () {
this.keysAreDirty = true;
this.keys().forEach(function (uuid) {
this.remove(uuid);
Store.prototype.clear = function () {
this._keysAreDirty = true;
this.keys().forEach(function (key) {
this.remove(key);
}, this);
};
db.prototype.remove = function (uuid) {
this.keysAreDirty = true;
this.db.removeItem(uuid);
Store.prototype.remove = function (key) {
this._keysAreDirty = true;
this._store.removeItem(key + this._namespace);
};
db.prototype.get = function (uuid) {
return Parse(this.db.getItem(uuid));
Store.prototype.get = function (key) {
return Parse(this._store.getItem(key + this._namespace));
};
db.prototype.set = function (uuid, val) {
this.keysAreDirty = true;
return this.db.setItem(uuid, Stringify(val));
Store.prototype.set = function (key, val) {
this._keysAreDirty = true;
return this._store.setItem(key + this._namespace, Stringify(val));
};
db.prototype.keys = function () {
Store.prototype.keys = function () {
var i
, key
, delimAt
;
if (!this.keysAreDirty) {
return this.__keys.concat([]);
if (!this._keysAreDirty) {
return this._keys.concat([]);
}
this.__keys = [];
for (i = 0; i < this.db.length; i += 1) {
this.__keys.push(this.db.key(i));
this._keys = [];
for (i = 0; i < this._store.length; i += 1) {
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 () {
return this.db.length;
Store.prototype.size = function () {
return this._store.length;
};
function create(w3cStorage) {
return new JsonStorage(w3cStorage);
Store.prototype.toJSON = function () {
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",
"description": "A wrapper for storage engines which use the W3C Storage API",
"keywords": ["ender", "localStorage", "sessionStorage", "globalStorage", "Storage"],
"version": "1.0.1",
"version": "1.1.0",
"repository": {
"type": "git",
"url": "git://github.com/coolaj86/json-storage-js.git"
@ -12,6 +12,7 @@
"node": ">= v0.2.0"
},
"main": "index",
"browserDependencies": {},
"dependencies": {},
"devDependencies": {}
}

View File

@ -8,7 +8,7 @@
;
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();
assert.equal(null, db.get('x'));
@ -23,5 +23,9 @@
db.clear();
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.");
}());

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