diff options
Diffstat (limited to 'src/DataStore.js')
| -rw-r--r-- | src/DataStore.js | 604 |
1 files changed, 303 insertions, 301 deletions
diff --git a/src/DataStore.js b/src/DataStore.js index f99e5824..7952096f 100644 --- a/src/DataStore.js +++ b/src/DataStore.js @@ -1,6 +1,4 @@ -// Copyright (C) 2009 BRAT Tech LLC - -DataStore = function(post, users, anchor) { +function DataStore(post, users, anchor) { this.post = post; this.users = users; this._cache = {$collections:[]}; @@ -8,325 +6,329 @@ DataStore = function(post, users, anchor) { this.bulkRequest = []; }; -DataStore.prototype.cache = function(document) { - if (document.constructor != Model) { - throw "Parameter must be an instance of Entity! " + toJson(document); - } - var key = document.$entity + '/' + document.$id; - var cachedDocument = this._cache[key]; - if (cachedDocument) { - Model.copyDirectFields(document, cachedDocument); - } else { - this._cache[key] = document; - cachedDocument = document; - } - return cachedDocument; -}; - -DataStore.prototype.load = function(instance, id, callback, failure) { - if (id && id !== '*') { - var self = this; - this._jsonRequest(["GET", instance.$entity + "/" + id], function(response) { - instance.$loadFrom(response); - instance.$migrate(); - var clone = instance.$$entity(instance); - self.cache(clone); - (callback||noop)(instance); - }, failure); - } - return instance; -}; - -DataStore.prototype.loadMany = function(entity, ids, callback) { - var self=this; - var list = []; - var callbackCount = 0; - foreach(ids, function(id){ - list.push(self.load(entity(), id, function(){ - callbackCount++; - if (callbackCount == ids.length) { - (callback||noop)(list); - } - })); - }); - return list; -}; +DataStore.NullEntity = extend(function(){}, { + 'all': function(){return [];}, + 'query': function(){return [];}, + 'load': function(){return {};}, + 'title': undefined +}); -DataStore.prototype.loadOrCreate = function(instance, id, callback) { - var self=this; - return this.load(instance, id, callback, function(response){ - if (response.$status_code == 404) { - instance.$id = id; - (callback||noop)(instance); +DataStore.prototype = { + cache: function(document) { + if (! document instanceof Model) { + throw "Parameter must be an instance of Entity! " + toJson(document); + } + var key = document.$entity + '/' + document.$id; + var cachedDocument = this._cache[key]; + if (cachedDocument) { + Model.copyDirectFields(document, cachedDocument); } else { - throw response; + this._cache[key] = document; + cachedDocument = document; } - }); -}; - -DataStore.prototype.loadAll = function(entity, callback) { - var self = this; - var list = []; - list.$$accept = function(doc){ - return doc.$entity == entity.title; - }; - this._cache.$collections.push(list); - this._jsonRequest(["GET", entity.title], function(response) { - var rows = response; - for ( var i = 0; i < rows.length; i++) { - var document = entity(); - document.$loadFrom(rows[i]); - list.push(self.cache(document)); + return cachedDocument; + }, + + load: function(instance, id, callback, failure) { + if (id && id !== '*') { + var self = this; + this._jsonRequest(["GET", instance.$entity + "/" + id], function(response) { + instance.$loadFrom(response); + instance.$migrate(); + var clone = instance.$$entity(instance); + self.cache(clone); + (callback||noop)(instance); + }, failure); } - (callback||noop)(list); - }); - return list; -}; - -DataStore.prototype.save = function(document, callback) { - var self = this; - var data = {}; - document.$saveTo(data); - this._jsonRequest(["POST", "", data], function(response) { - document.$loadFrom(response); - var cachedDoc = self.cache(document); - _.each(self._cache.$collections, function(collection){ - if (collection.$$accept(document)) { - angular['Array']['includeIf'](collection, cachedDoc, true); + return instance; + }, + + loadMany: function(entity, ids, callback) { + var self=this; + var list = []; + var callbackCount = 0; + foreach(ids, function(id){ + list.push(self.load(entity(), id, function(){ + callbackCount++; + if (callbackCount == ids.length) { + (callback||noop)(list); + } + })); + }); + return list; + }, + + loadOrCreate: function(instance, id, callback) { + var self=this; + return this.load(instance, id, callback, function(response){ + if (response.$status_code == 404) { + instance.$id = id; + (callback||noop)(instance); + } else { + throw response; } }); - if (document.$$anchor) { - self.anchor[document.$$anchor] = document.$id; - } - if (callback) - callback(document); - }); -}; - -DataStore.prototype.remove = function(document, callback) { - var self = this; - var data = {}; - document.$saveTo(data); - this._jsonRequest(["DELETE", "", data], function(response) { - delete self._cache[document.$entity + '/' + document.$id]; - _.each(self._cache.$collections, function(collection){ - for ( var i = 0; i < collection.length; i++) { - var item = collection[i]; - if (item.$id == document.$id) { - collection.splice(i, 1); + }, + + loadAll: function(entity, callback) { + var self = this; + var list = []; + list.$$accept = function(doc){ + return doc.$entity == entity.title; + }; + this._cache.$collections.push(list); + this._jsonRequest(["GET", entity.title], function(response) { + var rows = response; + for ( var i = 0; i < rows.length; i++) { + var document = entity(); + document.$loadFrom(rows[i]); + list.push(self.cache(document)); + } + (callback||noop)(list); + }); + return list; + }, + + save: function(document, callback) { + var self = this; + var data = {}; + document.$saveTo(data); + this._jsonRequest(["POST", "", data], function(response) { + document.$loadFrom(response); + var cachedDoc = self.cache(document); + _.each(self._cache.$collections, function(collection){ + if (collection.$$accept(document)) { + angular['Array']['includeIf'](collection, cachedDoc, true); } + }); + if (document.$$anchor) { + self.anchor[document.$$anchor] = document.$id; } + if (callback) + callback(document); }); - (callback||noop)(response); - }); -}; - -DataStore.prototype._jsonRequest = function(request, callback, failure) { - request.$$callback = callback; - request.$$failure = failure||function(response){ - throw response; - }; - this.bulkRequest.push(request); -}; - -DataStore.prototype.flush = function() { - if (this.bulkRequest.length === 0) return; - var self = this; - var bulkRequest = this.bulkRequest; - this.bulkRequest = []; - log('REQUEST:', bulkRequest); - function callback(code, bulkResponse){ - log('RESPONSE[' + code + ']: ', bulkResponse); - if(bulkResponse.$status_code == 401) { - self.users.login(function(){ - self.post(bulkRequest, callback); + }, + + remove: function(document, callback) { + var self = this; + var data = {}; + document.$saveTo(data); + this._jsonRequest(["DELETE", "", data], function(response) { + delete self._cache[document.$entity + '/' + document.$id]; + _.each(self._cache.$collections, function(collection){ + for ( var i = 0; i < collection.length; i++) { + var item = collection[i]; + if (item.$id == document.$id) { + collection.splice(i, 1); + } + } }); - } else if(bulkResponse.$status_code) { - alert(toJson(bulkResponse)); - } else { - for ( var i = 0; i < bulkResponse.length; i++) { - var response = bulkResponse[i]; - var request = bulkRequest[i]; - var responseCode = response.$status_code; - if(responseCode) { - if(responseCode == 403) { - self.users.notAuthorized(); + (callback||noop)(response); + }); + }, + + _jsonRequest: function(request, callback, failure) { + request.$$callback = callback; + request.$$failure = failure||function(response){ + throw response; + }; + this.bulkRequest.push(request); + }, + + flush: function() { + if (this.bulkRequest.length === 0) return; + var self = this; + var bulkRequest = this.bulkRequest; + this.bulkRequest = []; + log('REQUEST:', bulkRequest); + function callback(code, bulkResponse){ + log('RESPONSE[' + code + ']: ', bulkResponse); + if(bulkResponse.$status_code == 401) { + self.users.login(function(){ + self.post(bulkRequest, callback); + }); + } else if(bulkResponse.$status_code) { + alert(toJson(bulkResponse)); + } else { + for ( var i = 0; i < bulkResponse.length; i++) { + var response = bulkResponse[i]; + var request = bulkRequest[i]; + var responseCode = response.$status_code; + if(responseCode) { + if(responseCode == 403) { + self.users.notAuthorized(); + } else { + request.$$failure(response); + } } else { - request.$$failure(response); + request.$$callback(response); } - } else { - request.$$callback(response); } } } - } - this.post(bulkRequest, callback); -}; - -DataStore.prototype.saveScope = function(scope, callback) { - var saveCounter = 1; - function onSaveDone() { - saveCounter--; - if (saveCounter === 0 && callback) - callback(); - } - for(var key in scope) { - var item = scope[key]; - if (item && item.$save == Model.prototype.$save) { - saveCounter++; - item.$save(onSaveDone); - } - } - onSaveDone(); -}; - -DataStore.prototype.query = function(type, query, arg, callback){ - var self = this; - var queryList = []; - queryList.$$accept = function(doc){ - return false; - }; - this._cache.$collections.push(queryList); - var request = type.title + '/' + query + '=' + arg; - this._jsonRequest(["GET", request], function(response){ - var list = response; - for(var i = 0; i < list.length; i++) { - var document = new type().$loadFrom(list[i]); - queryList.push(self.cache(document)); + this.post(bulkRequest, callback); + }, + + saveScope: function(scope, callback) { + var saveCounter = 1; + function onSaveDone() { + saveCounter--; + if (saveCounter === 0 && callback) + callback(); } - if (callback) - callback(queryList); - }); - return queryList; -}; - -DataStore.prototype.entities = function(callback) { - var entities = []; - var self = this; - this._jsonRequest(["GET", "$entities"], function(response) { - for (var entityName in response) { - entities.push(self.entity(entityName)); + for(var key in scope) { + var item = scope[key]; + if (item && item.$save == Model.prototype.$save) { + saveCounter++; + item.$save(onSaveDone); + } } - entities.sort(function(a,b){return a.title > b.title ? 1 : -1;}); - if (callback) callback(entities); - }); - return entities; -}; - -DataStore.prototype.documentCountsByUser = function(){ - var counts = {}; - var self = this; - self.post([["GET", "$users"]], function(code, response){ - foreach(response[0], function(value, key){ - counts[key] = value; + onSaveDone(); + }, + + query: function(type, query, arg, callback){ + var self = this; + var queryList = []; + queryList.$$accept = function(doc){ + return false; + }; + this._cache.$collections.push(queryList); + var request = type.title + '/' + query + '=' + arg; + this._jsonRequest(["GET", request], function(response){ + var list = response; + for(var i = 0; i < list.length; i++) { + var document = new type().$loadFrom(list[i]); + queryList.push(self.cache(document)); + } + if (callback) + callback(queryList); }); - }); - return counts; -}; - -DataStore.prototype.userDocumentIdsByEntity = function(user){ - var ids = {}; - var self = this; - self.post([["GET", "$users/" + user]], function(code, response){ - foreach(response[0], function(value, key){ - ids[key] = value; + return queryList; + }, + + entities: function(callback) { + var entities = []; + var self = this; + this._jsonRequest(["GET", "$entities"], function(response) { + for (var entityName in response) { + entities.push(self.entity(entityName)); + } + entities.sort(function(a,b){return a.title > b.title ? 1 : -1;}); + if (callback) callback(entities); }); - }); - return ids; -}; - -DataStore.NullEntity = function(){}; -DataStore.NullEntity.all = function(){return [];}; -DataStore.NullEntity.query = function(){return [];}; -DataStore.NullEntity.load = function(){return {};}; -DataStore.NullEntity.title = undefined; - -DataStore.prototype.entity = function(name, defaults){ - if (!name) { - return DataStore.NullEntity; - } - var self = this; - var entity = function(initialState){ - return new Model(entity, initialState); - }; - // entity.name does not work as name seems to be reserved for functions - entity.title = name; - entity.$$factory = true; - entity.datastore = this; - entity.defaults = defaults || {}; - entity.load = function(id, callback){ - return self.load(entity(), id, callback); - }; - entity.loadMany = function(ids, callback){ - return self.loadMany(entity, ids, callback); - }; - entity.loadOrCreate = function(id, callback){ - return self.loadOrCreate(entity(), id, callback); - }; - entity.all = function(callback){ - return self.loadAll(entity, callback); - }; - entity.query = function(query, queryArgs, callback){ - return self.query(entity, query, queryArgs, callback); - }; - entity.properties = function(callback) { - self._jsonRequest(["GET", name + "/$properties"], callback); - }; - return entity; -}; - -DataStore.prototype.join = function(join){ - var fn = function(){ - throw "Joined entities can not be instantiated into a document."; - }; - function base(name){return name ? name.substring(0, name.indexOf('.')) : undefined;} - function next(name){return name.substring(name.indexOf('.') + 1);} - var joinOrder = _(join).chain(). - map(function($, name){ - return name;}). - sortBy(function(name){ - var path = []; - do { - if (_(path).include(name)) throw "Infinite loop in join: " + path.join(" -> "); - path.push(name); - if (!join[name]) throw _("Named entity '<%=name%>' is undefined.").template({name:name}); - name = base(join[name].on); - } while(name); - return path.length; - }). - value(); - if (_(joinOrder).select(function($){return join[$].on;}).length != joinOrder.length - 1) - throw "Exactly one entity needs to be primary."; - fn.query = function(exp, value) { - var joinedResult = []; - var baseName = base(exp); - if (baseName != joinOrder[0]) throw _("Named entity '<%=name%>' is not a primary entity.").template({name:baseName}); - var Entity = join[baseName].join; - var joinIndex = 1; - Entity.query(next(exp), value, function(result){ - var nextJoinName = joinOrder[joinIndex++]; - var nextJoin = join[nextJoinName]; - var nextJoinOn = nextJoin.on; - var joinIds = {}; - _(result).each(function(doc){ - var row = {}; - joinedResult.push(row); - row[baseName] = doc; - var id = Scope.getter(row, nextJoinOn); - joinIds[id] = id; + return entities; + }, + + documentCountsByUser: function(){ + var counts = {}; + var self = this; + self.post([["GET", "$users"]], function(code, response){ + foreach(response[0], function(value, key){ + counts[key] = value; }); - nextJoin.join.loadMany(_.toArray(joinIds), function(result){ - var byId = {}; + }); + return counts; + }, + + userDocumentIdsByEntity: function(user){ + var ids = {}; + var self = this; + self.post([["GET", "$users/" + user]], function(code, response){ + foreach(response[0], function(value, key){ + ids[key] = value; + }); + }); + return ids; + }, + + entity: function(name, defaults){ + if (!name) { + return DataStore.NullEntity; + } + var self = this; + var entity = extend(function(initialState){ + return new Model(entity, initialState); + }, { + // entity.name does not work as name seems to be reserved for functions + 'title': name, + '$$factory': true, + 'datastore': this, + 'defaults': defaults || {}, + 'load': function(id, callback){ + return self.load(entity(), id, callback); + }, + 'loadMany': function(ids, callback){ + return self.loadMany(entity, ids, callback); + }, + 'loadOrCreate': function(id, callback){ + return self.loadOrCreate(entity(), id, callback); + }, + 'all': function(callback){ + return self.loadAll(entity, callback); + }, + 'query': function(query, queryArgs, callback){ + return self.query(entity, query, queryArgs, callback); + }, + 'properties': function(callback) { + self._jsonRequest(["GET", name + "/$properties"], callback); + } + }); + return entity; + }, + + join: function(join){ + function fn(){ + throw "Joined entities can not be instantiated into a document."; + }; + function base(name){return name ? name.substring(0, name.indexOf('.')) : undefined;} + function next(name){return name.substring(name.indexOf('.') + 1);} + var joinOrder = _(join).chain(). + map(function($, name){ + return name;}). + sortBy(function(name){ + var path = []; + do { + if (_(path).include(name)) throw "Infinite loop in join: " + path.join(" -> "); + path.push(name); + if (!join[name]) throw _("Named entity '<%=name%>' is undefined.").template({name:name}); + name = base(join[name].on); + } while(name); + return path.length; + }). + value(); + if (_(joinOrder).select(function($){return join[$].on;}).length != joinOrder.length - 1) + throw "Exactly one entity needs to be primary."; + fn['query'] = function(exp, value) { + var joinedResult = []; + var baseName = base(exp); + if (baseName != joinOrder[0]) throw _("Named entity '<%=name%>' is not a primary entity.").template({name:baseName}); + var Entity = join[baseName].join; + var joinIndex = 1; + Entity['query'](next(exp), value, function(result){ + var nextJoinName = joinOrder[joinIndex++]; + var nextJoin = join[nextJoinName]; + var nextJoinOn = nextJoin.on; + var joinIds = {}; _(result).each(function(doc){ - byId[doc.$id] = doc; - }); - _(joinedResult).each(function(row){ + var row = {}; + joinedResult.push(row); + row[baseName] = doc; var id = Scope.getter(row, nextJoinOn); - row[nextJoinName] = byId[id]; + joinIds[id] = id; + }); + nextJoin.join.loadMany(_.toArray(joinIds), function(result){ + var byId = {}; + _(result).each(function(doc){ + byId[doc.$id] = doc; + }); + _(joinedResult).each(function(row){ + var id = Scope.getter(row, nextJoinOn); + row[nextJoinName] = byId[id]; + }); }); }); - }); - return joinedResult; - }; - return fn; -}; + return joinedResult; + }; + return fn; + } +};
\ No newline at end of file |
