spincycle
Version:
A reactive message router and object manager that lets clients subscribe to object property changes on the server
368 lines (332 loc) • 13.7 kB
text/coffeescript
defer = require('node-promise').defer
all = require('node-promise').all
uuid = require('node-uuid')
LRU = require('lru-cache')
OStore = require('./OStore')
#GDS = require('./gds')
#Roach = require('./cockroach')
Couch = require('./CouchPersistence')
#Mongo = require('./MongoPersistence')
Rethink = require('./RethinkPersistence')
ResolveModule = require('./ResolveModule')
resolver = new ResolveModule()
debug = process.env["DEBUG"]
class DB
: 'localhost'
: LRU()
: LRU()
: ''
: (record)=>
if record and record.type and record.id
resolver.createObjectFrom(record).then (ooo) =>
OStore.updateObj(ooo)
: (_name) =>
#console.log 'getDataStore called for '+_name
name = _name or DB.dbname
DB.dbname = name
#console.log 'DB.getDataStore called name = '+name
q = defer()
if not
# = new GDS()
# = new Roach()
if not name then = new Rethink(DB.dburl, DB)
#if not name then = new Google(DB.dburl, DB)
else if name == 'couchdb' then = new Couch(DB.dburl)
#else if name == 'mongodb' then = new Mongo(DB.dburl, DB)
else if name == 'rethinkdb' then = new Rethink(DB.dburl, DB)
.connect().then (ds)=>
#console.log 'DB got back datastore for '+name
.then (meta)=>
= meta
meta.serialize()
= ds
q.resolve(ds)
else
#console.log '..resolving existing store'
q.resolve( )
return q
:(dblist) =>
q = defer()
console.log '*** createDatabases called for list of dbs...'
console.dir dblist
.then (store)=>
console.log 'DB.createDatabases got back store'
promises = []
dblist.forEach (dbname) =>
console.log 'attempting to get table for '+dbname
if not (dbname in .knownModels)
.knownModels.push dbname
.serialize()
db = store.getDbFor(dbname)
promises.push db
all(promises).then (results) =>
console.log '*DB.createDatabases all good'
dblist.forEach (dbname2) =>
q.resolve(results)
return q
:(db,_dbname)=>
# get schema
dbname = _dbname
q = defer()
#console.log 'extendSchemaIfNeeded for module "'+_dbname+'"we have the following modules named in cache:'
#for k,v of ResolveModule.modulecache
# console.log k
proto = ResolveModule.modulecache[dbname]
#console.log '+++++++++++++++++++++++++++++++++++++extendSchemaIfNeeded resolve '+dbname+' to '+proto
#console.dir proto
if not (proto and proto.model)
console.log 'found undefined prototype for '+dbname
#console.dir ResolveModule.modulecache
q.resolve()
else
db.all dbname,{skip:0,limit:10},(res)=>
if res.length > 0
#if debug then console.log 'extendSchemaIfNeeded found '+res.length+' objects after call to all()'
#if debug then console.log 'first object is '+res[0]
#if debug then console.dir res[0]
# collect missing properties from first object
o = res[res.length-1]
missing = []
lookup = {createdAt:true, modifiedAt:true, createdBy:true}
for k,v of o
lookup[k] = k
#if debug then console.log 'going through model'
#if debug then console.dir proto
proto.model.forEach (property)=>
#if debug then console.log 'checking property '+property.name+' and if it exist in lookup table -> '+lookup[property.name]
#console.dir property
if not lookup[property.name] then missing.push property
#console.log 'found '+missing.length+' missing properties on first object of '+dbname+' compared to current model : '
#console.dir missing
if missing.length > 0
.then (modelcount)=>
count = modelcount
cursor = 0
console.log 'adding '+missing.length+' missing properties to '+modelcount+' existing objects'
getThese = (where)=>
console.log 'getThese called with skip '+where
r = defer()
start = Date.now()
db.all dbname,{skip:where,limit:1000},(objs)=>
console.log 'getThese got '+objs.length+' objs'
cnt = objs.length*missing.length
objs.forEach (ro) =>
missing.forEach (mprop) =>
if not mprop.default
if mprop.array then mprop.default = []
else if mprop.hashtable then mprop.default = {}
else if mprop.type then mprop.default = ''
#ro[mprop.name] = mprop.default or ''
if ro
.then (o)=>
#console.log ' setting new property '+mprop.name+' to default value of '+mprop.default+' on object type '+ro.type+' id '+ro.id+' cnt = '+cnt
.set(ro.id, ro)
if --cnt == 0
end = Date.now()
diff = parseInt((end - start)/1000)
console.log 'extendSchemaIfNeeded done for '+res.length+' objects. runtime = '+diff+' seconds'
r.resolve()
return r
loopThrough = ()=>
#console.log 'loopThrough called cursor = '+cursor+', count = '+count
getThese(cursor).then ()=>
setTimeout(
()=>
if cursor < count
cursor += 1000
loopThrough()
,100
)
# ro.type, ro, ()=> if --count == 0 then q.resolve()
loopThrough()
else
q.resolve()
return q
:(type, id, field, def)=> .then (store)=>
#console.log 'extending '+type+' id '+id+' with new property '+field+' and default value of '+def
store.extend(type, id, field, def)
: (type, id) =>
#if debug then console.log 'DB.getFromStoreOrDb called for '+type+' id '+id
q = defer()
OStore.getObject(id, type).then (oo)=>
if oo
#console.log 'getFromStoreOrDb resolved from Ostore directly...'
q.resolve(oo)
else
.then (records) =>
#console.log 'DB.getFromStoreOrDb get returns..'
#console.dir records
if records and records[0]
record = records[0]
resolver.createObjectFrom(record).then (ooo) =>
q.resolve(ooo)
else
q.resolve(undefined)
return q
: (record) =>
q = defer()
if debug then console.log 'getOrCreateObjectByRecord called for type '+record.type+' and id '+record.id
OStore.getObject(record.id, record.type).then (oo)=>
if debug then console.log 'DB.getOrCreateObjectByRecord OStore returns '+oo
if oo
q.resolve(oo)
else
.then (res)=>
if debug then console.log 'DB.getOrCreateObjectByRecord DB load returns '+res
#if debug then console.dir res
if res and res[0]
if debug then console.log 'DB.getOrCreateObjectByRecord found existing record in DB *'
record = res[0]
resolver.createObjectFrom(record).then (ooo) =>
if debug then console.log 'DB.getOrCreateObjectByRecord createFromRecord returns '+ooo
q.resolve(ooo)
return q
: (type, pid) =>
q = defer()
if pid
.then (store)=>
store.byProviderId(type, pid).then (res) =>
q.resolve(res)
else
q.resolve(undefined)
return q
: (type, query, cb) =>
.then (store)=>
if store.all
store.all(type, query, cb)
else
console.log 'DB.all: All not implemented in underlying persistence logic'
cb []
: (type) =>
q = defer()
.then (store)=>
store.count(type).then (value)=>
q.resolve(value)
return q
: (type, property, value) =>
q = defer()
.then (store) => store.find(type, property, value).then (result) =>
#if debug then console.log 'DB.find found '+result
#if debug then console.dir result
if not result
#console.log 'DB.find type '+type+', property '+property+', value '+value+' got back '+result
else
if not typeof result.id == 'string'
console.log '----------***************** DB.find error: trying to cache found result but id is not a string!!!'
console.dir result
else
if result.length
result.forEach (re) => .set(re.id, re)
else
.set(result.id, result)
q.resolve(result)
return q
: (type, property, value) =>
q = defer()
#console.log 'DB.findMany called'
#console.dir arguments
.then (store) => store.findMany(type, property, value).then (results) =>
if debug then console.log 'DB.findMany results are..'
if debug then console.dir results
if not results or not results.length or results.length == 0
#console.log 'DB.findMany type '+type+', property '+property+', value '+value+' got back '+results
q.resolve([])
else
#console.log 'DB.findMany got back'
#console.dir results
results.forEach (result) => .set(result.id, result)
q.resolve(results)
return q
: (type, query) =>
q = defer()
.then (store)=> store.findQuery(type, query).then (results) =>
if results and results.length and results.length > 0
if debug then console.log ' DB.findQuery got back '
if debug then console.dir results
results.forEach (result) =>
#console.dir result
if result then .set(result.id, result)
q.resolve(results)
return q
: (type, query) =>
q = defer()
.then (store)=> store.filter(type, query).then (results) =>
if results and results.length and results.length > 0
if debug then console.log ' DB.filter got back '
if debug then console.dir results
results.forEach (result) =>
#console.dir result
if result then .set(result.id, result)
q.resolve(results)
return q
# search for wildcards for property as a string beginning with value..
: (type, property, value) =>
q = defer()
.then (store)=> store.search(type, property, value).then (results) =>
#console.log 'DB.search results were..'
# console.dir results
if not results
if debug then console.log 'DB.search type '+type+', property '+property+', value '+value+' got back '+results
else
results.forEach (result) => .set(result.id, result)
q.resolve(results)
return q
(type, ids) =>
if not type or not ids
console.log '********************************* DB.get called with null type or id ***********************'
console.dir arguments
xyzzy
toarr = (x)->
if !Array.isArray(x)
#if debug then console.dir x
#if debug then console.log 'result is not array, so putting it into one..'
x = [x]
return x
#if debug then console.log 'DB.get called for type "'+type+'" and ids "'+ids+'"'
if not ids.length then ids = [ids]
q = defer()
id = ids[0]
if not id
console.log 'DB.get for type '+type+' was served an empty id!'
q.resolve()
else if (typeof id == 'object')
console.log 'DB.get was served an object instead of an id!!!'
console.dir id
xyzzy
else
#console.log 'DB.get id is '+id
rv = .get id
if rv
if debug then console.log 'DB found '+id+' in lru: '+rv
if debug then console.dir rv
q.resolve(toarr(rv))
else
#console.log ' attempting to use datastore for type '+type+' and id '+id+' typeof = '+(typeof id)
.then (store)=>
#if debug then console.log 'DB.get calling datastore '+store
store.get(type, id, (result) =>
if not result
#if debug then console.log 'DB.get for type '+type+' and id '+id+' got back '+result
#if debug then console.dir result
else
result = toarr(result)
.set(id, result)
if debug then console.log 'DB.get resolving '+result
if debug then console.dir result
q.resolve(result)
)
return q
(type, obj, cb) =>
if obj
.set(obj.id, obj)
.then (store)=>
store.set type, obj, (res) ->
#if debug then console.log 'DB.set got back '+res
cb(res)
else
cb()
: (obj, cb) =>
.del obj.id
.then (store)=> store.remove obj.type, obj, (res) ->
if cb then cb(res)
module.exports = DB