AJ ONeal
10 years ago
9 changed files with 35 additions and 747 deletions
@ -0,0 +1,28 @@ |
|||
{ |
|||
"name": "json-storage", |
|||
"version": "2.0.1", |
|||
"homepage": "https://github.com/coolaj86/json-storage-js", |
|||
"authors": [ |
|||
"AJ ONeal <coolaj86@gmail.com>" |
|||
], |
|||
"description": "A wrapper for storage engines which use the W3C Storage API", |
|||
"main": "json-storage.js", |
|||
"keywords": [ |
|||
"dom", |
|||
"storage", |
|||
"json", |
|||
"w3c", |
|||
"localStorage", |
|||
"sessionStorage", |
|||
"globalStorage", |
|||
"Storage" |
|||
], |
|||
"license": "Apache2", |
|||
"ignore": [ |
|||
"**/.*", |
|||
"node_modules", |
|||
"bower_components", |
|||
"test", |
|||
"tests" |
|||
] |
|||
} |
@ -1,282 +0,0 @@ |
|||
(function () { |
|||
"use strict"; |
|||
|
|||
var localStorage = require('localStorage') |
|||
, JsonStorage = require('json-storage') |
|||
, jsonStorage = JsonStorage(localStorage) |
|||
, db = jsonStorage |
|||
, uuidgen = require('node-uuid') |
|||
, schemamap = {} |
|||
; |
|||
|
|||
|
|||
function create(schema) { |
|||
var models = {}; |
|||
|
|||
function createModel(lsmodel, prefix, submodels, uuid) { |
|||
//
|
|||
// New Model
|
|||
//
|
|||
function LModel(obj) { |
|||
var lmodel = this; |
|||
|
|||
// Add any already-appended submodels
|
|||
// TODO DRY this up
|
|||
submodels.forEach(function (subname) { |
|||
var sub_ids = '_' + subname + '_ids' |
|||
, subs = obj[subname] |
|||
, suuid = schemamap[subname].uuid || 'uuid'; |
|||
|
|||
// Just in case the object is already created
|
|||
if ('function' === typeof obj.__lookupGetter__(subname)) { |
|||
return; |
|||
} |
|||
|
|||
if (false === Array.isArray(subs)) { |
|||
return; |
|||
} |
|||
|
|||
obj[sub_ids] = []; |
|||
lmodel[sub_ids] = obj[sub_ids]; |
|||
|
|||
subs.forEach(function (sub) { |
|||
if (!sub[suuid]) { |
|||
sub[suuid] = uuidgen(); |
|||
} |
|||
models[subname].set(sub[suuid], sub); |
|||
lmodel[sub_ids].push(sub[suuid]); |
|||
}); |
|||
|
|||
obj[subname] = undefined; |
|||
delete obj[subname]; |
|||
}); |
|||
|
|||
// Copy object to this
|
|||
Object.keys(obj).forEach(function (k) { |
|||
lmodel[k] = obj[k]; |
|||
}); |
|||
|
|||
// create uuid if it has none
|
|||
if (undefined === obj[uuid]) { |
|||
obj[uuid] = uuidgen(); |
|||
lmodel[uuid] = obj[uuid]; |
|||
} |
|||
} |
|||
|
|||
// A simple save method
|
|||
LModel.prototype.save = function () { |
|||
lsmodel.set(this[uuid], this); |
|||
}; |
|||
|
|||
|
|||
// getters for submodels
|
|||
submodels.forEach(function (subname) { |
|||
var sub_ids = '_' + subname + '_ids'; |
|||
|
|||
LModel.prototype.__defineGetter__(subname, function () { |
|||
// not all submodels exist at "compile-time"
|
|||
var submodel = models[subname] |
|||
, lmodel = this |
|||
, subs |
|||
, suuid = schemamap[subname].uuid || 'uuid'; |
|||
|
|||
lmodel[sub_ids] = lmodel[sub_ids] || []; |
|||
|
|||
subs = submodel.some(lmodel[sub_ids]); |
|||
|
|||
// modify collection, but leave as array with forEach
|
|||
// XXX maybe create prototype with forEach
|
|||
subs.add = function (obj) { |
|||
subs.push(obj); |
|||
if (undefined === obj[suuid]) { |
|||
submodel.add(obj); |
|||
} else { |
|||
submodel.set(obj[suuid], obj); |
|||
} |
|||
lmodel[sub_ids].push(obj[suuid]); |
|||
lmodel.save(); |
|||
}; |
|||
|
|||
return subs; |
|||
}); |
|||
}); |
|||
|
|||
return LModel; |
|||
} |
|||
|
|||
|
|||
// A database abstraction
|
|||
function Model(model) { |
|||
var lsmodel = this |
|||
, prefix = model.name |
|||
, submodels = model.has_many || [] |
|||
, uuid = model.uuid || 'uuid' |
|||
, LModel = createModel(lsmodel, prefix, submodels, uuid); |
|||
|
|||
lsmodel.create = function (a, b, c) { |
|||
return new LModel(a, b, c) |
|||
}; |
|||
|
|||
|
|||
// clear
|
|||
lsmodel.clear = function () { |
|||
return db.set(prefix + '-lsm', []); |
|||
}; |
|||
|
|||
// all keys
|
|||
lsmodel.keys = function () { |
|||
return db.get(prefix + '-lsm'); |
|||
}; |
|||
|
|||
// all items
|
|||
lsmodel.all = function () { |
|||
var items = []; |
|||
lsmodel.keys().forEach(function (uuid) { |
|||
var item = lsmodel.get(uuid) |
|||
// TODO this should be a useless check
|
|||
if (null === item) { |
|||
lsmodel.remove(uuid); |
|||
return; |
|||
} |
|||
items.push(item); |
|||
}); |
|||
return items; |
|||
}; |
|||
|
|||
// TODO query accepts objects
|
|||
lsmodel.query = function (obj) { |
|||
//
|
|||
return null; |
|||
}; |
|||
|
|||
// pass in your filter function
|
|||
lsmodel.filter = function (test) { |
|||
var all = lsmodel.all(), |
|||
results = []; |
|||
|
|||
all.forEach(function (one) { |
|||
if (!test(one)) { |
|||
return; |
|||
} |
|||
results.push(one); |
|||
}); |
|||
return results; |
|||
} |
|||
|
|||
lsmodel.some = function (uuids) { |
|||
var results = []; |
|||
|
|||
uuids.forEach(function (uuid) { |
|||
var one = lsmodel.get(uuid); |
|||
// push null elements to keep array indices
|
|||
results.push(one); |
|||
}); |
|||
|
|||
return results; |
|||
} |
|||
|
|||
// TODO query object
|
|||
lsmodel.get = function (uuid) { |
|||
var item = db.get(uuid); |
|||
if (null === item) { |
|||
return null; |
|||
} |
|||
return new LModel(item); |
|||
}; |
|||
|
|||
lsmodel.set = function (uuid, val) { |
|||
var keys; |
|||
|
|||
if (null === val || undefined === val) { |
|||
return db.remove(uuid); |
|||
} |
|||
keys = db.get(prefix + '-lsm') || []; |
|||
|
|||
// add the key if it didn't exist
|
|||
if (-1 === keys.indexOf(uuid)) { |
|||
keys.push(uuid); |
|||
db.set(prefix + '-lsm', keys); |
|||
} |
|||
|
|||
submodels.forEach(function (mod) { |
|||
var children = val[mod] || []; |
|||
|
|||
// TODO decouple or create new objects
|
|||
children.forEach(function (child) { |
|||
var e; |
|||
if (null === child) { |
|||
return; |
|||
} |
|||
if ('string' === typeof child) { |
|||
return; |
|||
} |
|||
if ('string' !== typeof child.uuid) { |
|||
return; |
|||
} |
|||
// TODO other[mod].set(uuid, child);
|
|||
}); |
|||
}); |
|||
/* |
|||
console.log('\n\n val'); |
|||
console.log(val); |
|||
console.log('\n\n'); |
|||
*/ |
|||
db.set(uuid, val) |
|||
}; |
|||
|
|||
// Remove an item from the table list and the db
|
|||
lsmodel.remove = function (uuid) { |
|||
var keys = db.get(prefix + '-lsm') |
|||
, i; |
|||
|
|||
keys.forEach(function (key, j) { |
|||
if (key === uuid) { |
|||
i = j; |
|||
} |
|||
}); |
|||
|
|||
if (undefined === i) { |
|||
return; |
|||
} |
|||
db.remove(uuid); |
|||
keys.splice(i,1); |
|||
db.set(prefix + '-lsm', keys); |
|||
}; |
|||
|
|||
// Remove all objects from the table list and db
|
|||
lsmodel.clear = function () { |
|||
lsmodel.keys().forEach(function (uuid) { |
|||
db.remove(uuid); |
|||
}); |
|||
db.set(prefix + '-lsm', []); |
|||
}; |
|||
|
|||
lsmodel.add = function (val) { |
|||
var obj = lsmodel.create(val); |
|||
obj.save(); |
|||
return obj; |
|||
}; |
|||
} |
|||
|
|||
// TODO compare versions of schema
|
|||
db.set('schema-lsm', schema); |
|||
|
|||
schema.forEach(function (scheme) { |
|||
var table = scheme.name |
|||
, x = db.get(table + '-lsm') |
|||
; |
|||
|
|||
// Pre-create the "models" tableshould always have
|
|||
schemamap[scheme.name] = scheme; |
|||
if (!Array.isArray(x)) { |
|||
db.set(table + '-lsm', []); |
|||
} |
|||
|
|||
models[scheme.name] = new Model(scheme); |
|||
}); |
|||
|
|||
return models; |
|||
} |
|||
|
|||
module.exports = create; |
|||
}()); |
@ -1,20 +0,0 @@ |
|||
{ |
|||
"author": "AJ ONeal <coolaj86@gmail.com> (http://coolaj86.info)", |
|||
"name": "json-storage-model", |
|||
"description": "An abstraction for models to be stored in json-storage", |
|||
"keywords": ["ender", "model", "json-storage", "localStorage", "sessionStorage", "globalStorage", "Storage"], |
|||
"version": "0.9.1", |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git://github.com/coolaj86/json-storage-js.git" |
|||
}, |
|||
"engines": { |
|||
"node": ">= v0.2.0" |
|||
}, |
|||
"main": "index", |
|||
"dependencies": { |
|||
"json-storage": ">= 1.0.0" |
|||
, "node-uuid": ">= 0.0.0" |
|||
}, |
|||
"devDependencies": {} |
|||
} |
@ -1,247 +0,0 @@ |
|||
(function () { |
|||
"use strict"; |
|||
|
|||
var Model = require('json-storage-model') |
|||
, assert = require('assert') |
|||
, schema |
|||
, lsmAll = {} |
|||
, Returns |
|||
, Batches; |
|||
|
|||
schema = [ |
|||
{ |
|||
name: "returns", |
|||
has_many: ['batches'], |
|||
uuid: "key" |
|||
}, |
|||
{ |
|||
name: "batches", |
|||
has_many: ['products'] |
|||
}, |
|||
{ |
|||
name: "products" |
|||
} |
|||
]; |
|||
|
|||
function setup() { |
|||
lsmAll = new Model(schema); |
|||
//console.log(lsmAll);
|
|||
Returns = lsmAll.returns; |
|||
Batches = lsmAll.batches; |
|||
} |
|||
|
|||
function empty() { |
|||
assert.deepEqual([], Returns.keys()); |
|||
assert.deepEqual([], Returns.all()); |
|||
assert.deepEqual([], Returns.some([])); |
|||
assert.deepEqual([null], Returns.some(['x'])); |
|||
assert.deepEqual([null, null], Returns.some(['x','y'])); |
|||
assert.deepEqual(null, Returns.get('nada')); |
|||
Returns.clear(); |
|||
assert.deepEqual([], Returns.keys()); |
|||
assert.deepEqual([], Returns.all()); |
|||
assert.deepEqual([], Returns.some([])); |
|||
assert.deepEqual([null], Returns.some(['x'])); |
|||
assert.deepEqual([null, null], Returns.some(['x','y'])); |
|||
assert.deepEqual(null, Returns.get('nada')); |
|||
} |
|||
|
|||
function errors() { |
|||
var errcount = 0; |
|||
// TODO make throw
|
|||
try { |
|||
Returns.get(); |
|||
} catch(e) { |
|||
errcount += 1; |
|||
} |
|||
//assert.equal(1, errcount);
|
|||
console.log('skipped `throw error on get(undefined)`'); |
|||
|
|||
try { |
|||
Returns.some(); |
|||
} catch(e) { |
|||
errcount += 1; |
|||
} |
|||
assert.equal(1, errcount); |
|||
|
|||
Returns.some([]); |
|||
} |
|||
|
|||
function createWithoutKey() { |
|||
var ret = Returns.create({ |
|||
memo: "031811-IHC", |
|||
}) |
|||
, ret2; |
|||
|
|||
assert.ok(ret.key); |
|||
assert.equal("031811-IHC", ret.memo); |
|||
|
|||
ret2 = Returns.get(ret.key); |
|||
assert.equal(null, ret2); |
|||
|
|||
ret.test1 = true; |
|||
ret.save(); |
|||
|
|||
ret2 = Returns.get(ret.key); |
|||
assert.equal("031811-IHC", ret2.memo); |
|||
} |
|||
|
|||
function createWithKey() { |
|||
var ret = Returns.create({ |
|||
key: "ajs-test", |
|||
memo: "031811-IHC", |
|||
}) |
|||
, ret2; |
|||
|
|||
ret2 = Returns.get(ret.key); |
|||
assert.ok(!ret2); |
|||
|
|||
assert.equal("ajs-test", ret.key); |
|||
ret.save(); |
|||
|
|||
ret2 = Returns.get(ret.key); |
|||
assert.ok(ret2.memo); |
|||
} |
|||
|
|||
function insertRemove() { |
|||
var keys = [] |
|||
, all = [] |
|||
, ids = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
|||
, k; |
|||
|
|||
Returns.clear(); |
|||
|
|||
// add
|
|||
function populate() { |
|||
all = []; |
|||
keys = []; |
|||
ids.forEach(function (id, i) { |
|||
// this is private logic
|
|||
all.push({ key: id, _batches_ids: [] }); |
|||
keys.push(all[i].key); |
|||
Returns.create(all[i]).save(); |
|||
}); |
|||
assert.deepEqual(all, Returns.all()); |
|||
assert.deepEqual(keys, Returns.keys()); |
|||
} |
|||
|
|||
// Remove from first
|
|||
populate(); |
|||
for (k = 0; k < ids.length; k += 1) { |
|||
Returns.remove(ids[k]); |
|||
} |
|||
assert.deepEqual([], Returns.all()); |
|||
assert.deepEqual([], Returns.keys()); |
|||
|
|||
|
|||
// Remove from last
|
|||
populate(); |
|||
for (k = ids.length - 1; k >= 0; k -= 1) { |
|||
Returns.remove(ids[k]); |
|||
} |
|||
assert.deepEqual([], Returns.all()); |
|||
assert.deepEqual([], Returns.keys()); |
|||
|
|||
// Remove from middle
|
|||
populate(); |
|||
ids.sort(function () { return 0.5 - Math.random(); }); |
|||
for (k = ids.length - 1; k >= 0; k -= 1) { |
|||
Returns.remove(ids[k]); |
|||
} |
|||
assert.deepEqual([], Returns.all()); |
|||
assert.deepEqual([], Returns.keys()); |
|||
} |
|||
|
|||
// testing all, keys, some, filter
|
|||
function all() { |
|||
var keys = [], |
|||
all = [], |
|||
some, |
|||
ids = []; |
|||
|
|||
Returns.clear(); |
|||
assert.deepEqual(all, Returns.all()); |
|||
assert.deepEqual(keys, Returns.keys()); |
|||
|
|||
all.push({ key: "one", memo: "3131-mtn", _batches_ids: [] }); |
|||
keys.push(all[0].key); |
|||
Returns.create(all[0]).save(); |
|||
|
|||
all.push({ key: "two", memo: "3232-hlt", _batches_ids: [] }); |
|||
keys.push(all[1].key); |
|||
Returns.create(all[1]).save(); |
|||
|
|||
all.push({ key: "three", memo: "4123-hbc", _batches_ids: [] }); |
|||
keys.push(all[2].key); |
|||
Returns.create(all[2]).save(); |
|||
|
|||
all.push({ key: "four", memo: "4441-dtf", _batches_ids: [] }); |
|||
keys.push(all[3].key); |
|||
Returns.create(all[3]).save(); |
|||
|
|||
all.push({ key: "five", memo: "4412-abn", _batches_ids: [] }); |
|||
keys.push(all[4].key); |
|||
Returns.create(all[4]).save(); |
|||
|
|||
some = Returns.filter(function (ret) { |
|||
return /^4\d/.test(ret.memo); |
|||
}); |
|||
assert.equal(3, some.length); |
|||
|
|||
some.forEach(function (one) { |
|||
ids.push(one.key); |
|||
}); |
|||
assert.deepEqual(some, Returns.some(ids)); |
|||
|
|||
assert.deepEqual(all, Returns.all()); |
|||
assert.deepEqual(keys, Returns.keys()); |
|||
assert.deepEqual(all.slice(1,3), Returns.some(["two", "three"])); |
|||
|
|||
assert.deepEqual(keys, Returns.keys()); |
|||
|
|||
console.log('skipping not-implemented `query`'); |
|||
} |
|||
|
|||
function relate() { |
|||
var batches = [ |
|||
{ |
|||
uuid: "a", |
|||
name: "chuck", |
|||
_products_ids: [] |
|||
}, |
|||
{ |
|||
name: "daryl", |
|||
_products_ids: [] |
|||
} |
|||
] |
|||
, ret = Returns.create({}) |
|||
, batch; |
|||
|
|||
// Add relation
|
|||
ret.save(); |
|||
ret = Returns.get(ret.key); |
|||
ret.batches.add(batches[0]); |
|||
assert.deepEqual(Batches.all()[0], batches[0]); |
|||
assert.deepEqual(ret.batches[0], batches[0]); |
|||
ret.save(); |
|||
|
|||
// create with an existing relation
|
|||
ret = Returns.create({ batches: batches }); |
|||
batches[1].uuid = ret.batches[1].uuid; |
|||
|
|||
console.log('skipping assert which requires visual inspection'); |
|||
//assert.deepEqual(batches, ret.batches);
|
|||
//console.log(Batches.all());
|
|||
} |
|||
|
|||
setup(); |
|||
empty(); |
|||
errors(); |
|||
createWithoutKey(); |
|||
createWithKey(); |
|||
insertRemove(); |
|||
all(); |
|||
relate(); |
|||
|
|||
console.log("All tests passed"); |
|||
}()); |
@ -1,176 +0,0 @@ |
|||
(function () { |
|||
"use strict"; |
|||
|
|||
var Future = require('future') |
|||
, __id_ = 'id' |
|||
, nameToString = function () { |
|||
return this.name; |
|||
}; |
|||
|
|||
function RowType(table) { |
|||
var name = table.name, |
|||
columns = table.columns, |
|||
klass; |
|||
|
|||
klass = function (id, arr) { |
|||
/* |
|||
// Extending Array doesn't work very well
|
|||
|
|||
var self = this; |
|||
arr.forEach(function (item, i) { |
|||
self[i] = item; |
|||
}); |
|||
*/ |
|||
if (!(__id_ in this)) { |
|||
this[__id_] = id; |
|||
} |
|||
this.arr = arr; |
|||
}; |
|||
|
|||
// TODO make more directive-like
|
|||
// TODO create a delegates_to directive
|
|||
klass.prototype.toString = table.toString || nameToString; |
|||
|
|||
columns.forEach(function (column, i) { |
|||
klass.prototype.__defineGetter__(column, function () { |
|||
return this.arr[i]; |
|||
//return this[i];
|
|||
}); |
|||
}); |
|||
return klass; |
|||
} |
|||
|
|||
function createIndexes(tables) { |
|||
Object.keys(tables).forEach(function (name) { |
|||
var table = tables[name], |
|||
index, |
|||
krow; |
|||
|
|||
if (!table.columns) { |
|||
console.log("missing columns"); |
|||
console.log(table); |
|||
} |
|||
|
|||
table.klass = RowType(table); |
|||
|
|||
index = table.indexed = {}; |
|||
|
|||
table.rows.forEach(function (row, z) { |
|||
// TODO no need to index
|
|||
var krow = new table.klass(z, row); |
|||
//krow.id = z;
|
|||
index[krow[__id_]] = krow; |
|||
table.rows[z] = krow; |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
function createRelationships(tables) { |
|||
Object.keys(tables).forEach(function (name) { |
|||
var table = tables[name], |
|||
relationships, |
|||
relHandlers = {}; |
|||
|
|||
// TODO create a delegates_to directive
|
|||
relHandlers.belongs_to = function (relname) { |
|||
// TODO abstract name mutation
|
|||
var relation = tables[relname + 's'], |
|||
relname_s = relname + '_id'; |
|||
|
|||
table.klass.prototype.__defineGetter__(relname, function () { |
|||
var fid = this[relname_s]; |
|||
|
|||
return relation.indexed[fid]; |
|||
}); |
|||
} |
|||
|
|||
//relationships = table.relationships && table.relationships.belongs_to;
|
|||
//relationships = relationships || [];
|
|||
|
|||
relationships = table.relationships || {}; |
|||
|
|||
Object.keys(relationships).forEach(function (relType) { |
|||
if (!relHandlers[relType]) { |
|||
console.log('relationship type "' + relType + '" is not supported'); |
|||
return; |
|||
} |
|||
relationships[relType].forEach(relHandlers[relType]); |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
|
|||
function createRelate(tables) { |
|||
var future = Future() |
|||
; |
|||
|
|||
createIndexes(tables); |
|||
createRelationships(tables); |
|||
//testRelationships(tables);
|
|||
//console.log(Object.keys(data));
|
|||
|
|||
future.fulfill(null, tables); |
|||
|
|||
return future.passable(); |
|||
} |
|||
|
|||
var Future = require('future') |
|||
, Join = require('Join') |
|||
; |
|||
|
|||
function createGet(pathname, tables) { |
|||
var future = Future() |
|||
, join = Join() |
|||
, request = require('ahr2') |
|||
, db = {} |
|||
, errs = [] |
|||
; |
|||
|
|||
tables.forEach(function (tablename) { |
|||
var resource = pathname + '/' + tablename + ".json" |
|||
, req = request.get(resource) |
|||
; |
|||
|
|||
req.when(function (err, xhr, data) { |
|||
if (err) { |
|||
console.log('error tables-get'); |
|||
console.log(err); |
|||
console.log(err.message); |
|||
return; |
|||
} |
|||
|
|||
if (global.Buffer && data instanceof global.Buffer) { |
|||
data = data.toString(); |
|||
} |
|||
|
|||
// TODO need to refactor AHR and fix JSON / text handling
|
|||
try { |
|||
data = JSON.parse(data.toString()); |
|||
} catch (e) { |
|||
// ignore, it was probably already parsed
|
|||
} |
|||
// follow convention
|
|||
tablename = tablename.replace('-','_'); |
|||
db[tablename] = data; |
|||
}); |
|||
|
|||
join.add(req); |
|||
}); |
|||
|
|||
join.when(function () { |
|||
// TODO add timeout as error
|
|||
if (0 == errs.length) { |
|||
errs = null; |
|||
} |
|||
|
|||
future.fulfill(errs, db); |
|||
}); |
|||
|
|||
return future.passable(); |
|||
} |
|||
|
|||
module.exports = { |
|||
get: createGet |
|||
, relate: createRelate |
|||
}; |
|||
}()); |
@ -1,21 +0,0 @@ |
|||
{ |
|||
"author": "AJ ONeal <coolaj86@gmail.com> (http://coolaj86.info)" |
|||
, "name": "json-tables" |
|||
, "description": "An abstraction for models to be stored in json-storage" |
|||
, "keywords": ["ender", "orm", "sql", "model", "json-storage", "localStorage", "sessionStorage", "globalStorage", "Storage"] |
|||
, "version": "0.7.1" |
|||
, "repository": { |
|||
"type": "git" |
|||
, "url": "git://github.com/coolaj86/json-storage-js.git" |
|||
} |
|||
, "engines": { |
|||
"node": ">= v0.2.0" |
|||
} |
|||
, "main": "index" |
|||
, "dependencies": { |
|||
"json-storage-model": ">= 0.9.0" |
|||
, "json-storage": ">= 1.0.0" |
|||
, "node-uuid": ">= 0.0.0" |
|||
} |
|||
, "devDependencies": {} |
|||
} |
Loading…
Reference in new issue