Created
October 13, 2010 16:11
-
-
Save sfoster/624360 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dojo.provide("myns.data.FeedStore"); | |
dojo.require("dojox.data.ServiceStore"); | |
dojo.require("dojox.rpc.Service"); | |
dojo.declare("myns.data.FeedStore", dojox.data.ServiceStore, { | |
// summary: | |
// Flexible, extensible store for normalizing read-only JSON feed data | |
service: null, | |
// baseParams: Object | |
// Any properties which should always be included with store queries | |
baseParams: null, | |
feedId: "", | |
// idAttribute: String? | |
// the item property which is a unique identifier for each item | |
idAttribute: "id", | |
// itemsProperty: String | |
// the property in the result object which contains all the result items | |
itemsProperty: "items", | |
// totalProperty: String? | |
// the property in the result object which indicates the total number of items, | |
// used when result is a page or slice of a large dataset | |
totalProperty: 'totalCount', | |
// labelAttribute: String? | |
// the item property which should be used when an item label is called for | |
labelAttribute: "title", | |
// itemPropertyMapping: Object | |
// A key:dotpath mapping used by getValue to associate a item attribute with the values' location in the item data structure | |
itemPropertyMapping: {}, | |
// estimateCountFactor: Number | |
// This parameter is used by the ServiceStore to estimate the total count. See dojox.data.ServiceStore for more details | |
estimateCountFactor: 2, | |
// knownTotal: Boolean | |
// Flag that indicates if the total number of records is known (e.g. by the service) | |
knownTotal: false, | |
constructor: function() { | |
this.baseParams = { feedId: this.feedId }; | |
// look to a static defaultService property if no service param was provided | |
if(!this.service) { | |
var service = dojo.getObject(this.declaredClass + ".defaultService"); | |
if(typeof service == "function") { | |
this.service = service; | |
} | |
} | |
}, | |
fetch: function(/* object */ request){ | |
// mix in some of the request properties into our query | |
// TODO: is there a mechanism for this in ServiceStore? | |
var query = {}; | |
if("count" in request) { | |
query.count = request.count; | |
} | |
if("start" in request) { | |
query.start = request.start; | |
} | |
request.query = dojo.delegate(query, request.query || {}); | |
return this.inherited(arguments); | |
}, | |
preprocessResult: function(result) { | |
// summary: | |
// Optionally manipulate service response before passing on to fetch handlers | |
// default is to pass thru | |
return result; | |
}, | |
_processResults : function(results, deferred, depth){ | |
// summary: | |
// Override ServiceStore's _processResults to pick up resultCount from results | |
// and to make recursion into item properties conditional | |
// this should return an object with the items as an array and the total count of | |
// items (maybe more than currently in the result set). | |
// for example: | |
// | {totalCount:10, items: [{id:1},{id:2}]} | |
depth = depth || 0; | |
// index the results, assigning ids as necessary | |
if(results && typeof results == 'object'){ | |
var id = results.__id; | |
if(!id){// if it hasn't been assigned yet | |
if(this.idAttribute){ | |
// use the defined id if available | |
id = results[this.idAttribute]; | |
}else{ | |
id = this._currentId++; | |
} | |
if(id !== undefined){ | |
var existingObj = this._index[id]; | |
if(existingObj){ | |
for(var j in existingObj){ | |
delete existingObj[j]; // clear it so we can mixin | |
} | |
results = dojo.mixin(existingObj,results); | |
} | |
results.__id = id; | |
this._index[id] = results; | |
} | |
} | |
if(this.isHeirarchical) { | |
// console.log("_processResults recursing into heirarchical result data"); | |
// only recurse if necessary | |
for(var i in results){ | |
results[i] = this._processResults(results[i], deferred, depth+1).items; | |
} | |
} | |
var count = results[this.itemsProperty].length; | |
} | |
var response = { | |
totalCount: (this.totalProperty in results) ? | |
// use the provided total when there is one | |
results[this.totalProperty] : | |
// does this look like a paged result? | |
deferred.request.count == count ? | |
// use a guestimated count as we don't know the total | |
(deferred.request.start || 0) + count * this.estimateCountFactor | |
: | |
// ..or just use the item count | |
count, | |
items: depth? results : results[this.itemsProperty] | |
}; | |
// set a flag to indicate if the total number of results (of | |
// which this result may be a subset) is known | |
// this heuristic will be mostly correct most times, | |
// but to be sure, set a totalProperty in the response | |
console.log("_processResults for: ", deferred.request.query.feedId); | |
this.knownTotal = (this.totalProperty in results) || (deferred.request.count && deferred.request.count !== count); | |
console.log("setting knownTotal: ", this.knownTotal, (this.totalProperty in results), count); | |
return response; | |
}, | |
_doQuery: function(args){ | |
var query= typeof args.queryStr == 'string' ? args.queryStr : args.query; | |
var serviceDfd = this.service(query); | |
var dfd = new dojo.Deferred(); | |
serviceDfd.addErrback(function(){ | |
dfd.errback.apply(dfd, arguments); | |
}); | |
serviceDfd.addCallback(this, function(result){ | |
arguments[0] = this.preprocessResult(result); | |
dfd.callback.apply(dfd, arguments); | |
}); | |
return dfd; | |
}, | |
getValue: function(/*Object*/ item, /*String*/property, /*value?*/defaultValue){ | |
// summary: | |
// Gets the value of an item's 'property' | |
// | |
// item: | |
// The item to get the value from | |
// property: | |
// property to look up value for | |
// defaultValue: | |
// the default value | |
var value = void(0), // undefined | |
attrData = this.itemPropertyMapping, | |
dotpath = property in attrData ? attrData[property].mapping : null; | |
if(dotpath) { | |
// use the mapping to lookup the property value in the item | |
value = dojo.getObject(dotpath, false, item); | |
} else { | |
// fallback to a plain property look up | |
value = item[property]; | |
} | |
if(attrData.format) { | |
value = attrData.format(value, property, attrData); | |
} | |
// TODO: lazy-loaded value access not tested | |
return typeof value !== "undefined" ? | |
value : // return the plain value since it was found; | |
(item._loadObject ? // property was not found, maybe because the item is not loaded, we will try to load it synchronously so we can get the property | |
(dojox.rpc._sync = true) && arguments.callee.call(this,dojox.data.ServiceStore.prototype.loadItem({item:item}) || {}, property, defaultValue) : // load the item and run getValue again | |
defaultValue);// not in item -> return default value | |
} | |
}); | |
myns.data.FeedStore.defaultService = null; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment