app/assets/javascripts/kojac.js in kojac-0.9.1 vs app/assets/javascripts/kojac.js in kojac-0.11.0
- old
+ new
@@ -157,20 +157,85 @@
return aKeyValues; // assume already [key1, value, key2, value]
} else if (_.isObject(aKeyValues)) {
return _.flatten(_.pairs(aKeyValues),true); // this style : {key1: value, key2: value}
} else
return null; // unrecognised input
- }
+ },
- //public static function getTrailingId(aKey: String): int {
- // if (!aKey)
- // return 0;
- // var parts: Array = aKey.split('__')
- // if (!parts.length)
- // return 0;
- // return StringUtils.toInt(parts[parts.length-1])
- //}
+ // pass a copy aPropListFn aCopyFn when you have a complex object eg. ember class. It will not be passed on to recursive calls
+ toJsono: function(aValue,aOptions,aPropListFn,aCopyFn) {
+ if (_.isObjectStrict(aValue)) {
+ if (!aPropListFn && !aCopyFn && ("toJsono" in aValue))
+ aValue = aValue.toJsono(aOptions || {});
+ else {
+ var aDest = {};
+ aOptions = _.clone(aOptions);
+ var aProperties = aPropListFn ? aPropListFn(aValue) : aValue; // may return an array of properties, or an object to use the keys from
+ var aInclude = (aOptions && _.removeKey(aOptions,'include')); // must be an array
+ if (_.isString(aInclude))
+ aInclude = aInclude.split(',');
+ if (aInclude && aInclude.length) {
+ if (_.isArray(aProperties)) //ensure aProperties is an array to add includes
+ aProperties = _.clone(aProperties);
+ else
+ aProperties = _.keys(aProperties);
+ for (var i=0;i<aInclude.length;i++)
+ aProperties.push(aInclude[i]);
+ }
+ var aExclude = (aOptions && _.removeKey(aOptions,'exclude')); // must be an array
+ if (_.isString(aExclude))
+ aExclude = aExclude.split(',');
+ var p;
+ var v;
+ if (_.isArray(aProperties)) {
+ for (var i=0;i<aProperties.length;i++) {
+ p = aProperties[i];
+ if (aExclude && (aExclude.indexOf(p)>=0))
+ continue;
+ if (aCopyFn)
+ aCopyFn(aDest,aValue,p,aOptions);
+ else {
+ aDest[p] = Kojac.Utils.toJsono(aValue[p],aOptions);
+ }
+ }
+ } else { // properties is an object to use keys from
+ for (p in aProperties) {
+ if (aExclude && (aExclude.indexOf(p)>=0))
+ continue;
+ if (aCopyFn)
+ aCopyFn(aDest,aValue,p,aOptions);
+ else {
+ aDest[p] = Kojac.Utils.toJsono(aValue[p],aOptions);
+ }
+ }
+ }
+ aValue = aDest;
+ }
+ } else if (_.isArray(aValue)) {
+ var result = [];
+ for (var i=0; i<aValue.length; i++)
+ result.push(Kojac.Utils.toJsono(aValue[i],aOptions));
+ aValue = result;
+ } else if (_.isDate(aValue)) {
+ aValue = Kojac.interpretValueAsType(aValue,String);
+ }
+ return aValue;
+ },
+
+ // returns an id above the normal 32 bit range of rails but within the range of Javascript
+ createId: function () {
+ return _.randomIntRange(4294967296,4503599627370496); // 2**32 to 2**52 see http://stackoverflow.com/questions/9389315/cross-browser-javascript-number-precision
+ },
+
+ timestamp: function() {
+ return new Date().getTime();
+ },
+
+ resolvedPromise: function() {
+ var d = jQuery.Deferred();
+ return d.resolve.apply(d,arguments);
+ }
};
/*
* Function used to determine the data type class of the given value
* @param {*} aValue
@@ -198,10 +263,13 @@
result = Array;
break;
case 'object':
result = Object;
break;
+ case 'date':
+ result = Date;
+ break;
case 'function':
case 'class':
case 'instance':
case 'error':
result = null;
@@ -231,33 +299,21 @@
case Int:
case Number:
case Boolean:
return aValue.toString();
break;
+ case Date:
+ return moment(aValue).toISOString();
default:
case Null:
return null;
break;
}
break;
case Boolean:
-
- switch(sourceType) {
- case Null:
- default:
- return null;
- break;
- case Int:
- case Number:
- if (isNaN(aValue))
- return null;
- else
- return !!aValue;
- break;
- }
-
+ return _.toBoolean(aValue,null);
break;
case Number:
switch(sourceType) {
@@ -297,10 +353,24 @@
return Math.round(Number(aValue));
break;
}
break;
+ case Date:
+ switch(sourceType) {
+ case String:
+ return moment.utc(aValue).toDate();
+ break;
+ case Number:
+ return new Date(aValue);
+ break;
+ case Null:
+ default:
+ return null;
+ break;
+ }
+ break;
case Object:
return null;
break;
case Array:
return null;
@@ -430,11 +500,11 @@
//this.__defaults = (constructor.__defaults && _.clone(constructor.__defaults)) || {};
for (var p in prop) {
if (['__defaults','__attributes'].indexOf(p)>=0)
continue;
var propValue = prop[p];
- if (_.isArray(propValue) && propValue.length===2 && Kojac.FieldTypes.indexOf(propValue[0])>=0) { // in form property: [Type, Default Value]
+ if (_.isArray(propValue) && (propValue.length===2) && (Kojac.FieldTypes.indexOf(propValue[0])>=0)) { // in form property: [Type, Default Value]
this.__attributes[p] = propValue[0];
prop[p] = propValue[1];
} else if (Kojac.FieldTypes.indexOf(propValue) >= 0) { // field type
prop[p] = null;
this.__attributes[p] = propValue;
@@ -657,11 +727,11 @@
Kojac.Operation = Kojac.Object.extend({
request: this,
verb: null,
key: null,
value: undefined,
- results: {},
+ results: null,
result_key: null,
result: undefined,
error: null, // set with some truthy error if this operation fails
performed: false,
fromCache: null, // null means not performed, true means got from cache, false means got from server. !!! Should split this into performed and fromCache
@@ -680,10 +750,12 @@
result = undefined;
else
result = results[response_key];
results = _.omit(results,response_key); // results now excludes primary result
+ if (!this.results)
+ this.results = {};
_.extend(this.results,results); // store other results
this.result_key = final_result_key;
this.results[final_result_key] = result; // store primary result
}
}
@@ -698,12 +770,12 @@
kojac: null,
options: {},
ops: [],
handlers: null,
op: null,
- result: undefined,
- results: {},
+ //result: undefined,
+ //results: null,
error: null, // set with some truthy value if this whole request or any operation fails (will contain first error if multiple)
newOperation: function() {
var obj = new Kojac.Operation({request: this});
if (this.ops.length===0)
this.op = obj;
@@ -718,22 +790,22 @@
// {key: value} or [{key1: value},{key2: value}] or {key1: value, key2: value}
// Can give existing keys with id, and will create a clone in database with a new id
create: function(aKeyValues,aOptions) {
- var result_key = aOptions && _.removeKey(aOptions,'result_key');
- var params = aOptions && _.removeKey(aOptions,'params'); // extract specific params
- var options = aOptions ? _.extend({cacheResults: true},aOptions) : {}; // extract known options
+ var result_key = (aOptions && _.removeKey(aOptions,'result_key'));
+ var params = (aOptions && _.removeKey(aOptions,'params')); // extract specific params
+ var options = _.extend({cacheResults: true, manufacture: true},aOptions || {});
var kvArray = Kojac.Utils.toKeyValueArray(aKeyValues);
for (var i=0;i<kvArray.length-1;i+=2) {
var k = kvArray[i];
var v = kvArray[i+1];
var op = this.newOperation();
op.verb = 'CREATE';
op.options = _.clone(options);
- op.params = params && _.clone(params);
+ op.params = (params && _.clone(params));
var parts = keySplit(k);
if (parts.length >= 3)
op.key = k;
else
op.key = keyResource(k);
@@ -746,18 +818,18 @@
// !!! if aKeys is String, split on ',' into an array
// known options will be moved from aOptions to op.options; remaining keys will be put into params
read: function(aKeys,aOptions) {
var keys = Kojac.Utils.interpretKeys(aKeys);
- var result_key = aOptions && _.removeKey(aOptions,'result_key'); // extract result_key
- var params = aOptions && _.removeKey(aOptions,'params'); // extract specific params
- var options = aOptions ? _.extend({cacheResults: true},aOptions) : {}; // extract known options
+ var result_key = (aOptions && _.removeKey(aOptions,'result_key')); // extract result_key
+ var params = (aOptions && _.removeKey(aOptions,'params')); // extract specific params
+ var options = _.extend({cacheResults: true, manufacture: true},aOptions || {});
var me = this;
jQuery.each(keys,function(i,k) {
var op = me.newOperation();
op.options = _.clone(options);
- op.params = params && _.clone(params);
+ op.params = (params && _.clone(params));
op.verb = 'READ';
op.key = k;
if (i===0)
op.result_key = result_key || k;
else
@@ -770,22 +842,22 @@
aOptions = _.extend({},aOptions,{preferCache: true});
return this.read(aKeys,aOptions);
},
update: function(aKeyValues,aOptions) {
- var result_key = aOptions && _.removeKey(aOptions,'result_key');
- var options = aOptions ? _.extend({cacheResults: true},aOptions) : {}; // extract known options
- var params = aOptions && _.removeKey(aOptions,'params'); // extract specific params
+ var result_key = (aOptions && _.removeKey(aOptions,'result_key'));
+ var options = _.extend({cacheResults: true, manufacture: true},aOptions || {});
+ var params = (aOptions && _.removeKey(aOptions,'params')); // extract specific params
var first=true;
var kvArray = Kojac.Utils.toKeyValueArray(aKeyValues);
for (var i=0;i<kvArray.length-1;i+=2) {
var k = kvArray[i];
var v = kvArray[i+1];
var op = this.newOperation();
op.verb = 'UPDATE';
op.options = _.clone(options);
- op.params = params && _.clone(params);
+ op.params = (params && _.clone(params));
op.key = k;
if (first) {
op.result_key = result_key || k;
first = false;
} else
@@ -795,18 +867,18 @@
return this;
},
destroy: function(aKeys,aOptions) {
var keys = Kojac.Utils.interpretKeys(aKeys);
- var result_key = aOptions && _.removeKey(aOptions,'result_key');
- var options = aOptions ? _.extend({cacheResults: true},aOptions) : {}; // extract known options
- var params = aOptions && _.removeKey(aOptions,'params'); // extract specific params
+ var result_key = (aOptions && _.removeKey(aOptions,'result_key'));
+ var options = _.extend({cacheResults: true},aOptions || {});
+ var params = (aOptions && _.removeKey(aOptions,'params')); // extract specific params
var me = this;
jQuery.each(keys,function(i,k) {
var op = me.newOperation();
op.options = _.clone(options);
- op.params = params && _.clone(params);
+ op.params = (params && _.clone(params));
op.verb = 'DESTROY';
op.key = k;
if (i===0)
op.result_key = result_key || k;
else
@@ -817,14 +889,14 @@
execute: function(aKey,aValue,aOptions) {
var op = this.newOperation();
op.verb = 'EXECUTE';
- var params = aOptions && _.removeKey(aOptions,'params'); // extract specific params
- op.result_key = aOptions && _.removeKey(aOptions,'result_key') || aKey;
- op.options = aOptions ? _.extend({cacheResults: false},aOptions) : {}; // extract known options
- op.params = params && _.clone(params);
+ var params = (aOptions && _.removeKey(aOptions,'params')); // extract specific params
+ op.result_key = (aOptions && _.removeKey(aOptions,'result_key')) || aKey;
+ op.options = _.extend({cacheResults: false, manufacture: false},aOptions || {});
+ op.params = (params && _.clone(params));
op.key = aKey;
op.value = aValue;
return this;
},
@@ -847,57 +919,89 @@
newRequest: function() {
return new Kojac.Request({kojac: this});
},
- cacheResults: function(aRequest) {
+// var v;
+// for (var i=0;i<aRequest.ops.length;i++) {
+// var op = aRequest.ops[i];
+// if (op.error)
+// break;
+// if (op.options.cacheResults===false)
+// continue;
+// for (p in op.results) {
+// if (p==op.result_key)
+// continue;
+// v = op.results[p];
+// if (v===undefined)
+// delete this.cache[p];
+// else
+// this.cache[p] = op.results[p];
+// }
+// v = op.results[op.result_key];
+// if (v===undefined) {
+// delete this.cache[op.result_key];
+// } else {
+// this.cache[op.result_key] = v;
+// }
+// console.log('end of loop');
+// }
+
+ handleResults: function(aRequest) {
if (this.cache.beginPropertyChanges)
this.cache.beginPropertyChanges();
- for (var i=0;i<aRequest.ops.length;i++) {
- var op = aRequest.ops[i];
- if (op.error)
- break;
- if (op.options.cacheResults===false)
- continue;
- for (p in op.results) {
- if (p==op.result_key)
- continue;
- if (op.results[p]===undefined)
- delete this.cache[p];
- else
- this.cache[p] = op.results[p];
+
+ var updatedObjects = [];
+
+ try {
+ for (var i=0;i<aRequest.ops.length;i++) {
+ var op = aRequest.ops[i];
+ if (op.error)
+ break;
+
+ for (var key in op.results) {
+ var value = op.results[key];
+ if ((op.options.atomise!==false) && _.isObjectStrict(value)) {
+ var existing = this.cache.retrieve(key);
+ if (_.isObjectStrict(existing)) {
+ if (existing.beginPropertyChanges) {
+ existing.beginPropertyChanges();
+ updatedObjects.push(existing);
+ }
+ if (existing.setProperties)
+ existing.setProperties(value);
+ else
+ _.copyProperties(existing,value);
+ value = existing;
+ } else {
+ if ((op.options.manufacture!==false) && (this.objectFactory))
+ value = this.objectFactory.manufacture(value,key);
+ }
+ }
+ op.results[key] = value;
+ if (op.options.cacheResults!==false)
+ this.cache.store(key,value);
+ }
}
- if (op.results[op.result_key]===undefined)
- delete this.cache[op.result_key];
- else
- this.cache[op.result_key] = op.results[op.result_key];
+ } finally {
+ for (var i=0;i<updatedObjects.length;i++)
+ updatedObjects[i].endPropertyChanges();
}
if (this.cache.endPropertyChanges)
this.cache.endPropertyChanges();
},
- cacheHasKeys: function(aKeysArray) {
- var me = this;
- return _.all(aKeysArray,function(k){
- return k in me.cache;
- })
- },
-
- cacheValues: function(aKeysArray) {
- var me = this;
- return _.map(aKeysArray,function(k){
- return me.cache[k];
- })
- },
-
- finaliseRequest: function(aRequest) {
+ finaliseResponse: function(aRequest) {
// set convenience properties
var results = {};
- for (var i=0;i<aRequest.ops.length;i++) {
+ if (!aRequest.error) for (var i=0;i<aRequest.ops.length;i++) {
var op = aRequest.ops[i];
- if (op.error && !aRequest.error)
- aRequest.error = op.error;
+ if (op.error) {
+ if (!aRequest.error)
+ aRequest.error = op.error;
+ break;
+ }
_.extend(results,op.results);
op.result = !op.error && op.results && (op.result_key || op.key) ? op.results[op.result_key || op.key] : null;
if (i===0) {
aRequest.op = op;
}
@@ -915,41 +1019,46 @@
} else {
aRequest.kojac.dependentKeys[op.key] = dep_keys
}
}
}
- aRequest.results = results;
- aRequest.result = aRequest.op && aRequest.op.result;
+ if (aRequest.error) {
+ _.removeKey(aRequest,'results');
+ _.removeKey(aRequest,'result');
+ } else {
+ aRequest.results = results;
+ aRequest.result = (aRequest.op && aRequest.op.result);
+ }
},
performRequest: function(aRequest) {
for (var i=0;i<aRequest.ops.length;i++) {
- var op = aRequest.ops[i];
+ var op = aRequest.ops[i]
+ op.results = {};
var k = (op.result_key && (op.result_key !== op.key)) ? op.result_key : op.key;
- if (op.verb=='READ' && op.options.preferCache && (k in aRequest.kojac.cache)) { // resolve from cache
- op.results[k] = aRequest.kojac.cache[k];
+ var cacheValue = aRequest.kojac.cache.retrieve(k);
+ if ((op.verb=='READ') && op.options.preferCache && (cacheValue!==undefined)) { // resolve from cache
+ op.results[k] = cacheValue;
var dep_keys = aRequest.kojac.dependentKeys[op.key];
if (dep_keys) {
for (var i=0;i<dep_keys.length;i++) {
var dk = dep_keys[i];
// what if not in cache? perhaps dump siblings in dependentKeys and index key to cause full refresh? or refuse to remove from cache if in dependentKeys
- op.results[dk] = aRequest.kojac.cache[dk];
+ op.results[dk] = aRequest.kojac.cache.retrieve(dk);
}
}
op.result_key = k;
op.fromCache = true;
op.performed = true;
}
}
- aRequest.handlers.add(this.remoteProvider.handleAjaxRequest,null,this.remoteProvider);
- if (this.objectFactory && this.objectFactory.transformResultsToValueObjects)
- aRequest.handlers.add(this.objectFactory.transformResultsToValueObjects,null,this.objectFactory);
- if (this.cache.cacheResults)
- aRequest.handlers.add(this.cache.cacheResults,null,this.cache);
- else
- aRequest.handlers.add(this.cacheResults,null,this);
- aRequest.handlers.run(aRequest).then(this.finaliseRequest);
+ aRequest.handlers.add(this.remoteProvider.handleRequest,null,this.remoteProvider);
+
+ //if (this.objectFactory)
+ aRequest.handlers.add(this.handleResults,null,this);
+
+ aRequest.handlers.run(aRequest).always(this.finaliseResponse);
return aRequest;
},
// BEGIN User Functions
@@ -1005,10 +1114,25 @@
return this.execute(aKey,aValue,aOptions).request();
}
// END Convenience Functions
});
+Kojac.Cache = Kojac.Object.extend({
+ store: function(k,v) {
+ if (v===undefined) {
+ delete this[k];
+ return v;
+ } else {
+ return (this[k] = v);
+ }
+ },
+ retrieve: function(k) {
+ return this[k];
+ }
+});
+
+
/**
* A default RemoteProvider implementation. Your own implementation, or a subclass of this may be used instead.
* @class Kojac.RemoteProvider
* @extends Kojac.Object
*/
@@ -1016,10 +1140,11 @@
useMockFileValues: false,
mockFilePath: null,
mockReadOperationHandler: null,
serverPath: null,
+ timeout: 10000,
mockWriteOperationHandler: null,//function(aOp) {
// Ember.Logger.log(JSON.stringify(CanUtils.copyProperties({},aOp,null,['request'])));
// },
@@ -1030,27 +1155,25 @@
var jsonOp = {
verb: op.verb,
key: op.key
};
if ((op.verb==='CREATE') || (op.verb==='UPDATE') || (op.verb==='EXECUTE')) {
- if (op.value && ("toObject" in op.value))
- jsonOp.value = op.value.toObject(op.options);
- else
- jsonOp.value = op.value;
+ jsonOp.value = Kojac.Utils.toJsono(op.value,op.options);
}
- var options = op.options && _.omit(op.options,['cacheResults','preferCache']);
+ var options = (op.options && _.omit(op.options,['cacheResults','preferCache']));
if (options && !_.isEmpty(options))
jsonOp.options = options; // omit local keys
jsonOp.params = op.params;
result.push(jsonOp);
}
return result
},
- handleAjaxRequest: function(aRequest) {
+ handleRequest: function(aRequest) {
var result;
var op;
+ var me = this;
for (var i=0;i<aRequest.ops.length;i++) {
op = aRequest.ops[i];
if (op.performed)
continue;
if (op.verb==='READ' || op.verb==='EXECUTE') {
@@ -1074,20 +1197,19 @@
var server_ops = _.filterByCriteria(aRequest.ops,{performed: false});
if (!server_ops.length)
return;
if (this.useMockFileValues) {
aRequest.handlers.waitForCallNext = true;
- var me = this;
var getMockFile = function(aOp) {
var fp = me.mockFilePath+aOp.key+'.js';
var data = null;
- return jQuery.ajax({url: fp, dataType: 'json', cache: false, data: data}).done(
+ return jQuery.ajax({url: fp, dataType: 'json', cache: false, data: data, timeout: me.timeout}).done(
function( aData ) {
for (p in aData) {
if (p==='results') {
for (k in aData.results) {
- if (k===aOp.key && (aOp.result_key!=aOp.key))
+ if ((k===aOp.key) && (aOp.result_key!=aOp.key))
aOp.results[aOp.result_key] = aData.results[k];
else
aOp.results[k] = aData.results[k];
}
} else
@@ -1117,10 +1239,11 @@
version: 'KOJAC-1.0',
ops: opsJson
}
};
aRequest.handlers.waitForCallNext = true;
+ // !!! might need to include X-CSRF-Token see http://stackoverflow.com/questions/8511695/rails-render-json-session-lost?rq=1
var ajaxpars = {
type: 'POST',
data: JSON.stringify(dataToSend),
contentType: "application/json; charset=utf-8",
dataType: "json"
@@ -1129,29 +1252,187 @@
// poke results into request ops using request_op_index
aRequest.xhr = aXhr;
for (var i=0;i<server_ops.length;i++) {
var opRequest = server_ops[i]; //aRequest.ops[request_op_index[i]];
var opResult = (_.isArray(aResult.ops) && (i<aResult.ops.length) && aResult.ops[i]);
- opRequest.receiveResult(opResult);
opRequest.fromCache = false;
opRequest.performed = true;
+ if (opResult.error) {
+ opRequest.error = opResult.error;
+ aRequest.handlers.handleError(opResult.error);
+ break;
+ } else {
+ opRequest.receiveResult(opResult);
+ }
}
aRequest.handlers.callNext();
}).fail(function(aXhr,aStatus,aError){
+ aRequest.error = me.interpretXhrError(aXhr);
+ //_.removeKey(aRequest,'results');
for (var i=0;i<server_ops.length;i++) {
var opRequest = server_ops[i]; //aRequest.ops[request_op_index[i]];
opRequest.fromCache = false;
opRequest.performed = true;
+ //if (opRequest.error)
+ // _.removeKey(opRequest,'results');
}
- aRequest.error = aXhr;
- aRequest.handlers.handleError(aXhr);
+ aRequest.handlers.handleError(aRequest.error);
aRequest.handlers.callNext();
});
}
+ },
+
+ interpretXhrError: function(aXhr) {
+ var http_code = null;
+ var kind = null;
+ var message = null;
+ var debug_message = null;
+ var response = null;
+ var headers = null;
+ if (http_code = (aXhr && aXhr.status)) {
+ kind = (aXhr.statusText && aXhr.statusText.replace(' ',''));
+ message = debug_message = aXhr.statusText;
+ headers = aXhr.getAllResponseHeaders();
+ response = aXhr.responseText;
+ } else {
+ http_code = null;
+ kind = "NetworkError";
+ message = "Failed to connect. Please check network or try again";
+ debug_message = "Network connection failed";
+ }
+ return {
+ format: 'KojacError',
+ http_code: http_code, // a valid HTTP status code, or null
+ kind: kind, // CamelCase text name of error, for conditional code handling
+ message: message, // an explanation for normal humans
+ debug_message: debug_message, // an explanation for developers
+ xhr: aXhr, // the original XHR object from jQuery
+ headers: headers, // all response headers
+ response: response // the response body
+ }
}
});
+
+Kojac.LocalStorageRemoteProvider = Kojac.Object.extend({
+ operationsToJson: function(aOps) {
+ var result = [];
+ for (var i=0;i<aOps.length;i++) {
+ var op = aOps[i];
+ var jsonOp = {
+ verb: op.verb,
+ key: op.key
+ };
+ if ((op.verb==='CREATE') || (op.verb==='UPDATE') || (op.verb==='EXECUTE')) {
+ jsonOp.value = Kojac.Utils.toJsono(op.value,op.options);
+ }
+ var options = (op.options && _.omit(op.options,['cacheResults','preferCache']));
+ if (options && !_.isEmpty(options))
+ jsonOp.options = options; // omit local keys
+ jsonOp.params = op.params;
+ result.push(jsonOp);
+ }
+ return result
+ },
+
+ handleRequest: function(aRequest) {
+ var aRequestOp;
+ if (!aRequest.ops.length)
+ return;
+ var ops = this.operationsToJson(aRequest.ops);
+ var op_output;
+ var v,op,id,key,value,parts,results,result_key;
+ for (var i=0;i<ops.length;i++) {
+ op = ops[i];
+ aRequestOp = aRequest.ops[i];
+ if (op.verb=='CREATE') {
+ id = Kojac.Utils.createId();
+ key = keyJoin(op.key,id);
+ result_key = (op.result_key || key);
+ value = _.clone(op.value,true,true);
+ value.id = id;
+
+ $.jStorage.set(key,value);
+ results = {};
+ results[result_key] = value;
+ op_output = {
+ key: op.key,
+ verb: op.verb,
+ result_key: result_key,
+ results: results
+ };
+ } else if (op.verb=='READ') {
+ result_key = (op.result_key || op.key);
+ results = {};
+ parts = keySplit(op.key);
+ if (parts[1]) { // item
+ value = $.jStorage.get(op.key,Boolean);
+ if (value===Boolean)
+ value = undefined;
+ results[result_key] = value;
+ } else { // collection
+ var keys = $.jStorage.index();
+ var ids = [];
+ _.each(keys,function(k){
+ parts = keySplit(k);
+ id = parts[1];
+ if (parts[0]!=op.key || !id)
+ return;
+ ids.push(id);
+ v = $.jStorage.get(k,Boolean);
+ if (value===Boolean)
+ value = undefined;
+ results[k] = v;
+ });
+ results[result_key] = ids;
+ }
+ op_output = {
+ key: op.key,
+ verb: op.verb,
+ result_key: result_key,
+ results: results
+ };
+ } else if (op.verb=='UPDATE') {
+ value = $.jStorage.get(op.key,Boolean);
+ if (value===Boolean)
+ value = undefined;
+ result_key = (op.result_key || op.key);
+ if (_.isObjectStrict(value))
+ _.extend(value,op.value);
+ else
+ value = op.value;
+ $.jStorage.set(op.key,value);
+ results = {};
+ results[result_key] = value;
+ op_output = {
+ key: op.key,
+ verb: op.verb,
+ result_key: result_key,
+ results: results
+ };
+ } else if (op.verb=='DESTROY') {
+ $.jStorage.deleteKey(op.key);
+ result_key = (op.result_key || op.key);
+ results = {};
+ //results[result_key] = undefined;
+ op_output = {
+ key: op.key,
+ verb: op.verb,
+ result_key: result_key,
+ results: results
+ };
+ } else {
+ throw "verb not implemented";
+ }
+ aRequestOp.receiveResult(op_output);
+ aRequestOp.fromCache = false;
+ aRequestOp.performed = true;
+ }
+ }
+});
+
+
/**
* A default ObjectFactory implementation. Your own implementation, or a subclass of this may be used instead.
* @class Kojac.ObjectFactory
* @extends Kojac.Object
*/
@@ -1171,11 +1452,11 @@
classFromKey: function(aKey) {
var pair;
var re;
var newClass;
- for (var i = 0; i < this.matchers.length; i++) {
+ if (this.matchers) for (var i = 0; i < this.matchers.length; i++) {
pair = this.matchers[i];
re = pair[0];
if (!re.test(aKey))
continue;
newClass = pair[1];
@@ -1207,24 +1488,11 @@
}
} else {
var newClass = this.classFromKey(aKey);
result = me.createInstance(newClass,aObject);
}
+ console.log('END manufacture');
return result;
- },
-
- transformResultsToValueObjects: function(aRequest) {
- for (var i=0;i<aRequest.ops.length;i++) {
- var op = aRequest.ops[i];
- if (op.error)
- break;
- for (var k in op.results) {
- var v = op.results[k];
- if (!jQuery.isPlainObject(v))
- continue;
- op.results[k] = this.manufacture(v,k);
- }
- }
}
});