angular-data
Advanced tools
Comparing version 0.9.0 to 0.10.0-beta.1
@@ -1,4 +0,26 @@ | ||
##### 0.9.0 - xx May 2014 | ||
##### 0.10.0-beta.1 - 28 June 2014 | ||
###### Breaking API changes | ||
- #76 - Queries and filtering. See [TRANSITION.md](https://github.com/jmdobry/angular-data/blob/master/TRANSITION.md). | ||
- #82 - Simplify error handling. Reduced size of angular-data.min.js by 4kb. | ||
- #42 - Relations/Associations. `DS.inject` now looks for relations and injects them as well. | ||
###### Backwards compatible API changes | ||
- #17 - Where predicates should be able to handle OR, not just AND | ||
- #23 - Computed Properties | ||
- #78 - Added optional callback to `bindOne` and `bindAll` | ||
- #79 - `ejectAll` should clear matching completed queries | ||
- #83 - Implement `DS.loadRelations(resourceName, instance(Id), relations[, options])` | ||
- #84 - idAttribute of a resource can be a computed property | ||
##### 0.9.1 - 30 May 2014 | ||
###### Backwards compatible bug fixes | ||
- #68 - Async methods should honor methods on a resource definition. | ||
- #69 - Failed requests should throw an error, not just return it | ||
- #70 - Make `params` and `params.query` optional | ||
##### 0.9.0 - 22 May 2014 | ||
###### Breaking API changes | ||
- #61 - Make custom serializers/deserializers more valuable | ||
@@ -5,0 +27,0 @@ - #59, #62 - Make queryTransform() consistent with the rest of the API |
/** | ||
* @author Jason Dobry <jason.dobry@gmail.com> | ||
* @file angular-data.min.js | ||
* @version 0.9.0 - Homepage <http://angular-data.codetrain.io/> | ||
* @version 0.10.0-beta.1 - Homepage <http://angular-data.pseudobry.com/> | ||
* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/> | ||
@@ -10,3 +10,3 @@ * @license MIT <https://github.com/jmdobry/angular-data/blob/master/LICENSE> | ||
*/ | ||
require=function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({QYwGEY:[function(a,b,c){(function(){!function(a){"use strict";function b(){function a(a){"splice"===a[0].type&&"splice"===a[1].type&&(b=!0)}if("function"!=typeof Object.observe||"function"!=typeof Array.observe)return!1;var b=!1,c=[0];return Array.observe(c,a),c[1]=1,c.length=0,Object.deliverChangeRecords(a),b}function c(a){return a===Object(a)}function d(a){for(var b=0;s>b&&a.check();)a.report(),b++}function e(a){for(var b in a)return!1;return!0}function f(a){return e(a.added)&&e(a.removed)&&e(a.changed)}function g(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var f in a)f in b||(c[f]=a[f]);return Array.isArray(a)&&a.length!==b.length&&(e.length=a.length),{added:c,removed:d,changed:e}}function h(a,b){var c=b||(Array.isArray(a)?[]:{});for(var d in a)c[d]=a[d];return Array.isArray(a)&&(c.length=a.length),c}function i(a,b,c,d){if(this.closed=!1,this.object=a,this.callback=b,this.target=c,this.token=d,this.reporting=!0,n){var e=this;this.boundInternalCallback=function(a){e.internalCallback(a)}}j(this),this.connect(),this.sync(!0)}function j(a){u&&(t.push(a),i._allObserversCount++)}function k(a,b,c,d){i.call(this,a,b,c,d)}function l(a){this.arr=[],this.callback=a,this.isObserved=!0}function m(a,b,c){for(var d={},e={},f=0;f<b.length;f++){var g=b[f];z[g.type]?(g.name in c||(c[g.name]=g.oldValue),"updated"!=g.type&&("new"!=g.type?g.name in d?(delete d[g.name],delete c[g.name]):e[g.name]=!0:g.name in e?delete e[g.name]:d[g.name]=!0)):(console.error("Unknown changeRecord type: "+g.type),console.error(g))}for(var h in d)d[h]=a[h];for(var h in e)e[h]=void 0;var i={};for(var h in c)if(!(h in d||h in e)){var j=a[h];c[h]!==j&&(i[h]=j)}return{added:d,removed:e,changed:i}}var n=b(),o=!1;try{var p=new Function("","return true;");o=p()}catch(q){}var r=(a.Number.isNaN||function(b){return"number"==typeof b&&a.isNaN(b)},"__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c}),s=1e3;i.prototype={internalCallback:function(a){this.closed||this.reporting&&this.check(a)&&(this.report(),this.testingResults&&(this.testingResults.anyChanged=!0))},close:function(){this.closed||(this.object&&"function"==typeof this.object.unobserved&&this.object.unobserved(),this.disconnect(),this.object=void 0,this.closed=!0)},deliver:function(a){this.closed||(n?(this.testingResults=a,Object.deliverChangeRecords(this.boundInternalCallback),this.testingResults=void 0):d(this))},report:function(){this.reporting&&(this.sync(!1),this.reportArgs.push(this.token),this.invokeCallback(this.reportArgs),this.reportArgs=void 0)},invokeCallback:function(a){try{this.callback.apply(this.target,a)}catch(b){i._errorThrownDuringCallback=!0,console.error("Exception caught during observer callback: "+b)}},reset:function(){this.closed||(n&&(this.reporting=!1,Object.deliverChangeRecords(this.boundInternalCallback),this.reporting=!0),this.sync(!0))}};var t,u=!n||a.forceCollectObservers;i._allObserversCount=0,u&&(t=[]);var v=!1,w="function"==typeof Object.deliverAllChangeRecords;a.Platform=a.Platform||{},a.Platform.performMicrotaskCheckpoint=function(){if(!v){if(w)return void Object.deliverAllChangeRecords();if(u){v=!0;var a=0,b={};do{a++;var c=t;t=[],b.anyChanged=!1;for(var d=0;d<c.length;d++){var e=c[d];e.closed||(n?e.deliver(b):e.check()&&(b.anyChanged=!0,e.report()),t.push(e))}}while(s>a&&b.anyChanged);i._allObserversCount=t.length,v=!1}}},u&&(a.Platform.clearObservers=function(){t=[]}),k.prototype=r({__proto__:i.prototype,connect:function(){n&&Object.observe(this.object,this.boundInternalCallback)},sync:function(){n||(this.oldObject=h(this.object))},check:function(a){var b,c;if(n){if(!a)return!1;c={},b=m(this.object,a,c)}else c=this.oldObject,b=g(this.object,this.oldObject);return f(b)?!1:(this.reportArgs=[b.added||{},b.removed||{},b.changed||{}],this.reportArgs.push(function(a){return c[a]}),!0)},disconnect:function(){n?this.object&&Object.unobserve(this.object,this.boundInternalCallback):this.oldObject=void 0}});var x=Object.getPrototypeOf({}),y=Object.getPrototypeOf([]);l.prototype={reset:function(){this.isObserved=!this.isObserved},observe:function(a){if(c(a)&&a!==x&&a!==y){var b=this.arr.indexOf(a);b>=0&&this.arr[b+1]===this.isObserved||(0>b&&(b=this.arr.length,this.arr[b]=a,Object.observe(a,this.callback)),this.arr[b+1]=this.isObserved,this.observe(Object.getPrototypeOf(a)))}},cleanup:function(){for(var a=0,b=0,c=this.isObserved;b<this.arr.length;){var d=this.arr[b];this.arr[b+1]==c?(b>a&&(this.arr[a]=d,this.arr[a+1]=c),a+=2):Object.unobserve(d,this.callback),b+=2}this.arr.length=a}};var z={"new":!0,updated:!0,deleted:!0};a.Observer=i,a.Observer.hasObjectObserve=n,a.ObjectObserver=k}((c.Number={isNaN:window.isNaN})?c:c)}).call(this,"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],observejs:[function(a,b){b.exports=a("QYwGEY")},{}],3:[function(a,b){function c(a,b){return-1!==d(a,b)}var d=a("./indexOf");b.exports=c},{"./indexOf":6}],4:[function(a,b){function c(a,b,c){b=d(b,c);var e=[];if(null==a)return e;for(var f,g=-1,h=a.length;++g<h;)f=a[g],b(f,g,a)&&e.push(f);return e}var d=a("../function/makeIterator_");b.exports=c},{"../function/makeIterator_":12}],5:[function(a,b){function c(a,b,c){if(null!=a)for(var d=-1,e=a.length;++d<e&&b.call(c,a[d],d,a)!==!1;);}b.exports=c},{}],6:[function(a,b){function c(a,b,c){if(c=c||0,null==a)return-1;for(var d=a.length,e=0>c?d+c:c;d>e;){if(a[e]===b)return e;e++}return-1}b.exports=c},{}],7:[function(a,b){function c(a){return null!=a&&""!==a}function d(a,b){return b=b||"",e(a,c).join(b)}var e=a("./filter");b.exports=d},{"./filter":4}],8:[function(a,b){function c(a,b,c){var d=a.length;b=null==b?0:0>b?Math.max(d+b,0):Math.min(b,d),c=null==c?d:0>c?Math.max(d+c,0):Math.min(c,d);for(var e=[];c>b;)e.push(a[b++]);return e}b.exports=c},{}],9:[function(a,b){function c(a,b){if(null==a)return[];if(a.length<2)return a;null==b&&(b=d);var f,g,h;return f=~~(a.length/2),g=c(a.slice(0,f),b),h=c(a.slice(f,a.length),b),e(g,h,b)}function d(a,b){return b>a?-1:a>b?1:0}function e(a,b,c){for(var d=[];a.length&&b.length;)d.push(c(a[0],b[0])<=0?a.shift():b.shift());return a.length&&d.push.apply(d,a),b.length&&d.push.apply(d,b),d}b.exports=c},{}],10:[function(a,b){function c(a,b){var c={};if(null==a)return c;var e,f=-1,g=a.length;if(d(b))for(;++f<g;)e=a[f],c[b(e)]=e;else for(;++f<g;)e=a[f],c[e[b]]=e;return c}var d=a("../lang/isFunction");b.exports=c},{"../lang/isFunction":16}],11:[function(a,b){function c(a){return a}b.exports=c},{}],12:[function(a,b){function c(a,b){if(null==a)return d;switch(typeof a){case"function":return"undefined"!=typeof b?function(c,d,e){return a.call(b,c,d,e)}:a;case"object":return function(b){return f(b,a)};case"string":case"number":return e(a)}}var d=a("./identity"),e=a("./prop"),f=a("../object/deepMatches");b.exports=c},{"../object/deepMatches":21,"./identity":11,"./prop":13}],13:[function(a,b){function c(a){return function(b){return b[a]}}b.exports=c},{}],14:[function(a,b){var c=a("./isKind"),d=Array.isArray||function(a){return c(a,"Array")};b.exports=d},{"./isKind":17}],15:[function(a,b){function c(a){if(null==a)return!1;if("string"==typeof a||e(a))return!a.length;if("object"==typeof a||"function"==typeof a){var b=!0;return d(a,function(){return b=!1,!1}),b}return!1}var d=a("../object/forOwn"),e=a("./isArray");b.exports=c},{"../object/forOwn":24,"./isArray":14}],16:[function(a,b){function c(a){return d(a,"Function")}var d=a("./isKind");b.exports=c},{"./isKind":17}],17:[function(a,b){function c(a,b){return d(a)===b}var d=a("./kindOf");b.exports=c},{"./kindOf":19}],18:[function(a,b){function c(a){return!!a&&"object"==typeof a&&a.constructor===Object}b.exports=c},{}],19:[function(a,b){function c(a){return null===a?"Null":a===d?"Undefined":e.exec(f.call(a))[1]}var d,e=/^\[object (.*)\]$/,f=Object.prototype.toString;b.exports=c},{}],20:[function(a,b){function c(a){return null==a?"":a.toString()}b.exports=c},{}],21:[function(a,b){function c(a,b){for(var c=-1,d=a.length;++c<d;)if(f(a[c],b))return!0;return!1}function d(a,b){for(var d=-1,e=b.length;++d<e;)if(!c(a,b[d]))return!1;return!0}function e(a,b){var c=!0;return g(b,function(b,d){return f(a[d],b)?void 0:c=!1}),c}function f(a,b){return a&&"object"==typeof a?h(a)&&h(b)?d(a,b):e(a,b):a===b}var g=a("./forOwn"),h=a("../lang/isArray");b.exports=f},{"../lang/isArray":14,"./forOwn":24}],22:[function(a,b){function c(a){for(var b,c=0,f=arguments.length;++c<f;)b=arguments[c],b&&e(b,d,a);return a}function d(a,b){var d=this[b];f(a)&&f(d)?c(d,a):this[b]=a}var e=a("./forOwn"),f=a("../lang/isPlainObject");b.exports=c},{"../lang/isPlainObject":18,"./forOwn":24}],23:[function(a,b){function c(){g=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],f=!0;for(var a in{toString:null})f=!1}function d(a,b,d){var i,j=0;null==f&&c();for(i in a)if(e(b,a,i,d)===!1)break;if(f)for(var k=a.constructor,l=!!k&&a===k.prototype;(i=g[j++])&&("constructor"===i&&(l||!h(a,i))||a[i]===Object.prototype[i]||e(b,a,i,d)!==!1););}function e(a,b,c,d){return a.call(d,b[c],c,b)}var f,g,h=a("./hasOwn");b.exports=d},{"./hasOwn":25}],24:[function(a,b){function c(a,b,c){e(a,function(e,f){return d(a,f)?b.call(c,a[f],f,a):void 0})}var d=a("./hasOwn"),e=a("./forIn");b.exports=c},{"./forIn":23,"./hasOwn":25}],25:[function(a,b){function c(a,b){return Object.prototype.hasOwnProperty.call(a,b)}b.exports=c},{}],26:[function(a,b){function c(a,b){return b?(d(b.split("."),function(b){a[b]||(a[b]={}),a=a[b]}),a):a}var d=a("../array/forEach");b.exports=c},{"../array/forEach":5}],27:[function(a,b){function c(a){for(var b,c="string"!=typeof arguments[1]?arguments[1]:d(arguments,1),e={},f=0;b=c[f++];)e[b]=a[b];return e}var d=a("../array/slice");b.exports=c},{"../array/slice":8}],28:[function(a,b){function c(a,b,c){var e=/^(.+)\.(.+)$/.exec(b);e?d(a,e[1])[e[2]]=c:a[b]=c}var d=a("./namespace");b.exports=c},{"./namespace":26}],29:[function(a,b){function c(){var a=d(e(arguments),"/");return a.replace(/([^:\/]|^)\/{2,}/g,"$1/")}var d=a("../array/join"),e=a("../array/slice");b.exports=c},{"../array/join":7,"../array/slice":8}],30:[function(a,b){function c(a){return a=d(a),a.toUpperCase()}var d=a("../lang/toString");b.exports=c},{"../lang/toString":20}],31:[function(a,b){function c(){var a=this.defaults={queryTransform:function(a,b){return b}};this.$get=["$http","$log","DSUtils",function(b,c,d){function e(a){var d=(new Date).getTime();return b(a).then(function(a){return c.debug(a.config.method+" request:"+a.config.url+" Time taken: "+((new Date).getTime()-d)+"ms",arguments),a})}function f(a,b){return b=b||{},e(d.deepMixIn(b,{url:a,method:"GET"}))}function g(a,b,c){return c=c||{},e(d.deepMixIn(c,{url:a,data:b,method:"POST"}))}function h(a,b,c){return c=c||{},e(d.deepMixIn(c,{url:a,data:b,method:"PUT"}))}function i(a,b){return b=b||{},this.HTTP(d.deepMixIn(b,{url:a,method:"DELETE"}))}function j(a,b,c){return c=c||{},this.POST(d.makePath(c.baseUrl||a.baseUrl,a.endpoint),b,c)}function k(a,b,c){return c=c||{},this.DEL(d.makePath(c.baseUrl||a.baseUrl,a.endpoint,b),c)}function l(b,c,e){return e=e||{},e.params=e.params||{},c&&(c.query=c.query?a.queryTransform(b.name,c.query):c.query,d.deepMixIn(e.params,c)),this.DEL(d.makePath(e.baseUrl||b.baseUrl,b.endpoint),e)}function m(a,b,c){return c=c||{},this.GET(d.makePath(c.baseUrl||a.baseUrl,a.endpoint,b),c)}function n(b,c,e){return e=e||{},e.params=e.params||{},c&&(c.query=c.query?a.queryTransform(b.name,c.query):c.query,d.deepMixIn(e.params,c)),this.GET(d.makePath(e.baseUrl||b.baseUrl,b.endpoint),e)}function o(a,b,c,e){return e=e||{},this.PUT(d.makePath(e.baseUrl||a.baseUrl,a.endpoint,b),c,e)}function p(b,c,e,f){return f=f||{},f.params=f.params||{},e&&(e.query=e.query?a.queryTransform(b.name,e.query):e.query,d.deepMixIn(f.params,e)),this.PUT(d.makePath(f.baseUrl||b.baseUrl,b.endpoint),c,f)}return{defaults:a,HTTP:e,GET:f,POST:g,PUT:h,DEL:i,find:m,findAll:n,create:j,update:o,updateAll:p,destroy:k,destroyAll:l}}]}b.exports=c},{}],32:[function(a,b){function c(){this.$get=["$q","DSUtils",function(a,b){function c(b){var c=a.defer();try{var d=localStorage.getItem(b);c.resolve(d?angular.fromJson(d):void 0)}catch(e){c.reject(e)}return c.promise}function d(c,d){var e=a.defer();try{var f=localStorage.getItem(c);f?(f=angular.fromJson(f),b.deepMixIn(f,d),e.resolve(localStorage.setItem(c,angular.toJson(f)))):e.resolve(localStorage.setItem(c,angular.toJson(d)))}catch(g){e.reject(g)}return e.promise}function e(b){var c=a.defer();try{c.resolve(localStorage.removeItem(b))}catch(d){c.reject(d)}return c.promise}function f(a,c,d){return d=d||{},e(b.makePath(d.baseUrl||a.baseUrl,a.endpoint,c),d)}function g(a,d,e){return e=e||{},c(b.makePath(e.baseUrl||a.baseUrl,a.endpoint,d),e)}function h(a,e,f,g){return g=g||{},d(b.makePath(g.baseUrl||a.baseUrl,a.endpoint,e),f,g).then(function(){return c(b.makePath(g.baseUrl||a.baseUrl,a.endpoint,e))})}return{find:g,findAll:function(){throw new Error("Not supported!")},create:function(){throw new Error("Not supported!")},update:h,updateAll:function(){throw new Error("Not supported!")},destroy:f,destroyAll:function(){throw new Error("Not supported!")}}}]}b.exports=c},{}],33:[function(a,b){function c(a,b,c){var e=this.$q.defer(),f=e.promise;if(c=c||{},this.definitions[a])if(this.utils.isObject(b))try{var g=this.definitions[a],h=this.store[a],i=this;f=f.then(function(b){return i.$q.promisify(g.beforeValidate)(a,b)}).then(function(b){return i.$q.promisify(g.validate)(a,b)}).then(function(b){return i.$q.promisify(g.afterValidate)(a,b)}).then(function(b){return i.$q.promisify(g.beforeCreate)(a,b)}).then(function(b){return i.adapters[c.adapter||g.defaultAdapter].create(g,g.serialize(a,b),c)}).then(function(b){return i.$q.promisify(g.afterCreate)(a,g.deserialize(a,b))}).then(function(a){var b=i.inject(g.name,a),c=b[g.idAttribute];return h.previousAttributes[c]=i.utils.deepMixIn({},b),h.saved[c]=i.utils.updateTimestamp(h.saved[c]),i.get(g.name,c)}),e.resolve(b)}catch(j){e.reject(new this.errors.UnhandledError(j))}else e.reject(new this.errors.IllegalArgumentError(d+"attrs: Must be an object!",{attrs:{actual:typeof b,expected:"object"}}));else e.reject(new this.errors.RuntimeError(d+a+" is not a registered resource!"));return f}var d="DS.create(resourceName, attrs[, options]): ";b.exports=c},{}],34:[function(a,b){function c(a,b,c){var e=this.$q.defer(),f=e.promise;if(c=c||{},this.definitions[a])if(this.utils.isString(b)||this.utils.isNumber(b)){var g=this.get(a,b);if(g){var h=this.definitions[a],i=(this.store[a],this);f=f.then(function(b){return i.$q.promisify(h.beforeDestroy)(a,b)}).then(function(){return i.adapters[c.adapter||h.defaultAdapter].destroy(h,b,c)}).then(function(){return i.$q.promisify(h.afterDestroy)(a,g)}).then(function(){return i.eject(a,b),b}),e.resolve(g)}else e.reject(new this.errors.RuntimeError(d+'id: "'+b+'" not found!'))}else e.reject(new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}}));else e.reject(new this.errors.RuntimeError(d+a+" is not a registered resource!"));return f}var d="DS.destroy(resourceName, id): ";b.exports=c},{}],35:[function(a,b){function c(a,b,c){var e=this.$q.defer(),f=e.promise,g=this;if(c=c||{},this.definitions[a])if(this.utils.isObject(b))if(this.utils.isObject(c))try{var h=this.definitions[a];f=f.then(function(){return g.adapters[c.adapter||h.defaultAdapter].destroyAll(h,b,c)}).then(function(){return g.ejectAll(a,b)}),e.resolve()}catch(i){e.reject(new this.errors.UnhandledError(i))}else e.reject(new this.errors.IllegalArgumentError(d+"options: Must be an object!"));else e.reject(new this.errors.IllegalArgumentError(d+"params: Must be an object!"));else e.reject(new this.errors.RuntimeError(d+a+" is not a registered resource!"));return f}var d="DS.destroyAll(resourceName, params[, options]): ";b.exports=c},{}],36:[function(a,b){function c(a,b,c){var e=this.$q.defer(),f=e.promise;if(c=c||{},this.definitions[a])if(this.utils.isString(b)||this.utils.isNumber(b))if(this.utils.isObject(c)){c.cacheResponse="cacheResponse"in c?!!c.cacheResponse:!0;try{var g=this.definitions[a],h=this.store[a],i=this;if(c.bypassCache&&delete h.completedQueries[b],!(b in h.completedQueries))return b in h.pendingQueries||(f=h.pendingQueries[b]=i.adapters[c.adapter||g.defaultAdapter].find(g,b,c).then(function(d){var e=g.deserialize(a,d);return c.cacheResponse?(delete h.pendingQueries[b],h.completedQueries[b]=(new Date).getTime(),i.inject(a,e)):e},function(a){return delete h.pendingQueries[b],a})),h.pendingQueries[b];e.resolve(i.get(a,b))}catch(j){e.reject(j)}}else e.reject(new this.errors.IllegalArgumentError(d+"options: Must be an object!",{options:{actual:typeof c,expected:"object"}}));else e.reject(new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}}));else e.reject(new this.errors.RuntimeError(d+a+" is not a registered resource!"));return f}var d="DS.find(resourceName, id[, options]): ";b.exports=c},{}],37:[function(a,b){function c(a,b,c,d){var e=this.store[c];return b=b||[],delete e.pendingQueries[d],e.completedQueries[d]=(new Date).getTime(),this.inject(c,b),e.collectionModified=a.updateTimestamp(e.collectionModified),b}function d(a,b,d,e){var f=this.definitions[b],g=this.store[b],h=this,i=a.toJson(d);return e.bypassCache&&delete g.completedQueries[i],i in g.completedQueries?this.filter(b,d,e):(i in g.pendingQueries||(g.pendingQueries[i]=h.adapters[e.adapter||f.defaultAdapter].findAll(f,d,e).then(function(d){var g=f.deserialize(b,d);if(!e.cacheResponse)return g;try{return c.apply(h,[a,g,b,i])}catch(j){throw new h.errors.UnhandledError(j)}},function(a){return delete g.pendingQueries[i],a})),g.pendingQueries[i])}function e(a,b,c){var e=this.$q.defer(),g=e.promise,h=this;if(c=c||{},this.definitions[a])if(this.utils.isObject(b))if(this.utils.isObject(c)){c.cacheResponse="cacheResponse"in c?!!c.cacheResponse:!0;try{g=g.then(function(){return d.apply(h,[h.utils,a,b,c])}),e.resolve()}catch(i){e.reject(new this.errors.UnhandledError(i))}}else e.reject(new this.errors.IllegalArgumentError(f+"options: Must be an object!"));else e.reject(new this.errors.IllegalArgumentError(f+"params: Must be an object!"));else e.reject(new this.errors.RuntimeError(f+a+" is not a registered resource!"));return g}var f="DS.findAll(resourceName, params[, options]): ";b.exports=e},{}],38:[function(a,b){b.exports={create:a("./create"),destroy:a("./destroy"),destroyAll:a("./destroyAll"),find:a("./find"),findAll:a("./findAll"),refresh:a("./refresh"),save:a("./save"),update:a("./update"),updateAll:a("./updateAll")}},{"./create":33,"./destroy":34,"./destroyAll":35,"./find":36,"./findAll":37,"./refresh":39,"./save":40,"./update":41,"./updateAll":42}],39:[function(a,b){function c(a,b,c){if(c=c||{},this.definitions[a]){if(this.utils.isString(b)||this.utils.isNumber(b)){if(this.utils.isObject(c))return c.bypassCache=!0,this.get(a,b)?this.find(a,b,c):!1;throw new this.errors.IllegalArgumentError(d+"options: Must be an object!",{options:{actual:typeof c,expected:"object"}})}throw new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}})}throw new this.errors.RuntimeError(d+a+" is not a registered resource!")}var d="DS.refresh(resourceName, id[, options]): ";b.exports=c},{}],40:[function(a,b){function c(a,b,c){var e=this.$q.defer(),f=e.promise;if(c=c||{},this.definitions[a])if(this.utils.isString(b)||this.utils.isNumber(b))if(this.utils.isObject(c)){var g=this.get(a,b);if(g){var h=this.definitions[a],i=this.store[a],j=this;f=f.then(function(b){return j.$q.promisify(h.beforeValidate)(a,b)}).then(function(b){return j.$q.promisify(h.validate)(a,b)}).then(function(b){return j.$q.promisify(h.afterValidate)(a,b)}).then(function(b){return j.$q.promisify(h.beforeUpdate)(a,b)}).then(function(d){if(c.changesOnly){i.observers[b].deliver();var e=[],f=j.changes(a,b);for(var g in f.added)e.push(g);for(g in f.changed)e.push(g);if(f=j.utils.pick(d,e),j.utils.isEmpty(f))return d;d=f}return j.adapters[c.adapter||h.defaultAdapter].update(h,b,h.serialize(a,d),c)}).then(function(b){return j.$q.promisify(h.afterUpdate)(a,h.deserialize(a,b))}).then(function(d){return j.inject(h.name,d,c),i.previousAttributes[b]=j.utils.deepMixIn({},d),i.saved[b]=j.utils.updateTimestamp(i.saved[b]),j.get(a,b)}),e.resolve(g)}else e.reject(new this.errors.RuntimeError(d+'id: "'+b+'" not found!'))}else e.reject(new this.errors.IllegalArgumentError(d+"options: Must be an object!",{options:{actual:typeof c,expected:"object"}}));else e.reject(new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}}));else e.reject(new this.errors.RuntimeError(d+a+" is not a registered resource!"));return f}var d="DS.save(resourceName, id[, options]): ";b.exports=c},{}],41:[function(a,b){function c(a,b,c,e){var f=this.$q.defer(),g=f.promise;if(e=e||{},this.definitions[a])if(this.utils.isString(b)||this.utils.isNumber(b))if(this.utils.isObject(c))if(this.utils.isObject(e)){var h=this.definitions[a],i=this.store[a],j=this;e.cacheResponse="cacheResponse"in e?!!e.cacheResponse:!0,g=g.then(function(b){return j.$q.promisify(h.beforeValidate)(a,b)}).then(function(b){return j.$q.promisify(h.validate)(a,b)}).then(function(b){return j.$q.promisify(h.afterValidate)(a,b)}).then(function(b){return j.$q.promisify(h.beforeUpdate)(a,b)}).then(function(c){return j.adapters[e.adapter||h.defaultAdapter].update(h,b,h.serialize(a,c),e)}).then(function(b){return j.$q.promisify(h.afterUpdate)(a,h.deserialize(a,b))}).then(function(a){if(e.cacheResponse){var b=j.inject(h.name,a,e),c=b[h.idAttribute];return i.previousAttributes[c]=j.utils.deepMixIn({},b),i.saved[c]=j.utils.updateTimestamp(i.saved[c]),j.get(h.name,c)}return a}),f.resolve(c)}else f.reject(new this.errors.IllegalArgumentError(d+"options: Must be an object!"));else f.reject(new this.errors.IllegalArgumentError(d+"attrs: Must be an object!"));else f.reject(new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!"));else f.reject(new this.errors.RuntimeError(d+a+" is not a registered resource!"));return g}var d="DS.update(resourceName, id, attrs[, options]): ";b.exports=c},{}],42:[function(a,b){function c(a,b,c,e){var f=this.$q.defer(),g=f.promise;if(e=e||{},this.definitions[a])if(this.utils.isObject(b))if(this.utils.isObject(c))if(this.utils.isObject(e)){var h=this.definitions[a],i=(this.store[a],this);e.cacheResponse="cacheResponse"in e?!!e.cacheResponse:!0,g=g.then(function(b){return i.$q.promisify(h.beforeValidate)(a,b)}).then(function(b){return i.$q.promisify(h.validate)(a,b)}).then(function(b){return i.$q.promisify(h.afterValidate)(a,b)}).then(function(b){return i.$q.promisify(h.beforeUpdate)(a,b)}).then(function(b){return i.adapters[e.adapter||h.defaultAdapter].updateAll(h,h.serialize(a,b),c,e)}).then(function(b){return i.$q.promisify(h.afterUpdate)(a,h.deserialize(a,b))}).then(function(a){return e.cacheResponse?i.inject(h.name,a,e):a}),f.resolve(b)}else f.reject(new this.errors.IllegalArgumentError(d+"options: Must be an object!"));else f.reject(new this.errors.IllegalArgumentError(d+"params: Must be an object!"));else f.reject(new this.errors.IllegalArgumentError(d+"attrs: Must be an object!"));else f.reject(new this.errors.RuntimeError(d+a+" is not a registered resource!"));return g}var d="DS.updateAll(resourceName, attrs, params[, options]): ";b.exports=c},{}],43:[function(a,b){function c(a,b,c){c(null,b)}function d(){}function e(){var b=this.defaults=new d;this.$get=["$rootScope","$log","$q","DSHttpAdapter","DSLocalStorageAdapter","DSUtils","DSErrors",function(c,d,e,f,g,h,i){var j,k=a("./sync_methods"),l=a("./async_methods");try{j=angular.injector(["angular-data.DSCacheFactory"]).get("DSCacheFactory")}catch(m){d.warn(m),d.warn("DSCacheFactory is unavailable. Resorting to the lesser capabilities of $cacheFactory."),j=angular.injector(["ng"]).get("$cacheFactory")}var n={$rootScope:c,$log:d,$q:e,cacheFactory:j,defaults:b,store:{},definitions:{},adapters:{DSHttpAdapter:f,DSLocalStorageAdapter:g},errors:i,utils:h};h.deepFreeze(k),h.deepFreeze(l),h.deepMixIn(n,k),h.deepMixIn(n,l),h.deepFreeze(n.errors),h.deepFreeze(n.utils);var o=c.$new();return o.$watch(function(){return(new Date).getTime()/100|0},function(){n.digest()}),n}]}var f=a("../utils")[0]();d.prototype.idAttribute="id",d.prototype.defaultAdapter="DSHttpAdapter",d.prototype.filter=function(a,b,c){var d=!0;return f.forOwn(b,function(a,b){f.isString(a)?a={"===":a}:f.isNumber(a)&&(a={"==":a}),"=="in a?d=d&&c[b]==a["=="]:"==="in a?d=d&&c[b]===a["==="]:"!="in a?d=d&&c[b]!=a["!="]:">"in a?d=d&&c[b]>a[">"]:">="in a?d=d&&c[b]>=a[">="]:"<"in a?d=d&&c[b]<a["<"]:"<="in a?d=d&&c[b]<=a["<="]:"in"in a&&(d=d&&f.contains(a["in"],c[b]))}),d},d.prototype.baseUrl="",d.prototype.endpoint="",d.prototype.beforeValidate=c,d.prototype.validate=c,d.prototype.afterValidate=c,d.prototype.beforeCreate=c,d.prototype.afterCreate=c,d.prototype.beforeUpdate=c,d.prototype.afterUpdate=c,d.prototype.beforeDestroy=c,d.prototype.afterDestroy=c,d.prototype.beforeInject=function(a,b){return b},d.prototype.afterInject=function(a,b){return b},d.prototype.serialize=function(a,b){return b},d.prototype.deserialize=function(a,b){return b.data},b.exports=e},{"../utils":"K0yknU","./async_methods":38,"./sync_methods":54}],44:[function(a,b){function c(a,b,c,e){if(!this.utils.isObject(a))throw new this.errors.IllegalArgumentError(d+"scope: Must be an object!");if(!this.utils.isString(b))throw new this.errors.IllegalArgumentError(d+"expr: Must be a string!");if(!this.definitions[c])throw new this.errors.RuntimeError(d+c+" is not a registered resource!");if(!this.utils.isObject(e))throw new this.errors.IllegalArgumentError(d+"params: Must be an object!");var f=this;try{return a.$watch(function(){return f.lastModified(c)},function(){f.utils.set(a,b,f.filter(c,e))})}catch(g){throw new this.errors.UnhandledError(g)}}var d="DS.bindAll(scope, expr, resourceName, params): ";b.exports=c},{}],45:[function(a,b){function c(a,b,c,e){if(!this.utils.isObject(a))throw new this.errors.IllegalArgumentError(d+"scope: Must be an object!");if(!this.utils.isString(b))throw new this.errors.IllegalArgumentError(d+"expr: Must be a string!");if(!this.definitions[c])throw new this.errors.RuntimeError(d+c+" is not a registered resource!");if(!this.utils.isString(e)&&!this.utils.isNumber(e))throw new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!");var f=this;try{return a.$watch(function(){return f.lastModified(c,e)},function(){f.utils.set(a,b,f.get(c,e))})}catch(g){throw new this.errors.UnhandledError(g)}}var d="DS.bindOne(scope, expr, resourceName, id): ";b.exports=c},{}],46:[function(a,b){function c(a,b){if(!this.definitions[a])throw new this.errors.RuntimeError(d+a+" is not a registered resource!");if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}});try{var c=this.get(a,b);if(c)return this.store[a].observers[b].deliver(),this.utils.diffObjectFromOldObject(c,this.store[a].previousAttributes[b])}catch(e){throw new this.errors.UnhandledError(e)}}var d="DS.changes(resourceName, id): ";b.exports=c},{}],47:[function(require,module,exports){function Resource(a,b){a.deepMixIn(this,b),this.endpoint="endpoint"in b?b.endpoint:this.name}function defineResource(definition){if(this.utils.isString(definition)&&(definition={name:definition}),!this.utils.isObject(definition))throw new this.errors.IllegalArgumentError(errorPrefix+"definition: Must be an object!",{definition:{actual:typeof definition,expected:"object"}});if(!this.utils.isString(definition.name))throw new this.errors.IllegalArgumentError(errorPrefix+"definition.name: Must be a string!",{definition:{name:{actual:typeof definition.name,expected:"string"}}});if(definition.idAttribute&&!this.utils.isString(definition.idAttribute))throw new this.errors.IllegalArgumentError(errorPrefix+"definition.idAttribute: Must be a string!",{definition:{idAttribute:{actual:typeof definition.idAttribute,expected:"string"}}});if(definition.endpoint&&!this.utils.isString(definition.endpoint))throw new this.errors.IllegalArgumentError(errorPrefix+"definition.endpoint: Must be a string!",{definition:{endpoint:{actual:typeof definition.endpoint,expected:"string"}}});if(this.store[definition.name])throw new this.errors.RuntimeError(errorPrefix+definition.name+" is already registered!");try{Resource.prototype=this.defaults,this.definitions[definition.name]=new Resource(this.utils,definition);var _this=this,def=this.definitions[definition.name],cache=this.cacheFactory("DS."+def.name,{maxAge:def.maxAge||null,recycleFreq:def.recycleFreq||1e3,cacheFlushInterval:def.cacheFlushInterval||null,deleteOnExpire:def.deleteOnExpire||"none",onExpire:function(a){_this.eject(def.name,a)},capacity:Number.MAX_VALUE,storageMode:"memory",storageImpl:null,disabled:!1,storagePrefix:"DS."+def.name});def.methods&&(def.class=definition.name[0].toUpperCase()+definition.name.substring(1),eval("function "+def.class+"() {}"),def[def.class]=eval(def.class),this.utils.deepMixIn(def[def.class].prototype,def.methods)),this.store[def.name]={collection:[],completedQueries:{},pendingQueries:{},index:cache,modified:{},saved:{},previousAttributes:{},observers:{},collectionModified:0}}catch(err){throw delete this.definitions[definition.name],delete this.store[definition.name],new this.errors.UnhandledError(err)}}var errorPrefix="DS.defineResource(definition): ";module.exports=defineResource},{}],48:[function(a,b){function c(){try{this.$rootScope.$$phase?d.Platform.performMicrotaskCheckpoint():this.$rootScope.$apply(function(){d.Platform.performMicrotaskCheckpoint()})}catch(a){throw new this.errors.UnhandledError(a)}}var d=a("observejs");b.exports=c},{observejs:"QYwGEY"}],49:[function(a,b){function c(a,b,c){for(var d=!1,e=0;e<b.collection.length;e++)if(b.collection[e][a.idAttribute]==c){d=!0;break}d&&(b.collection.splice(e,1),b.observers[c].close(),delete b.observers[c],b.index.remove(c),delete b.previousAttributes[c],delete b.modified[c],delete b.saved[c])}function d(a,b){if(!this.definitions[a])throw new this.errors.RuntimeError(e+a+" is not a registered resource!");if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IllegalArgumentError(e+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}});var d=this.store[a],f=this;try{this.$rootScope.$$phase?(c(f.definitions[a],d,b),d.collectionModified=f.utils.updateTimestamp(d.collectionModified)):this.$rootScope.$apply(function(){c(f.definitions[a],d,b),d.collectionModified=f.utils.updateTimestamp(d.collectionModified)}),delete this.store[a].completedQueries[b]}catch(g){throw new this.errors.UnhandledError(g)}}var e="DS.eject(resourceName, id): ";b.exports=d},{}],50:[function(a,b){function c(a,b,c){for(var d=this.utils.toJson(c),e=this.filter(a.name,c),f=0;f<e.length;f++)this.eject(a.name,e[f][a.idAttribute]);delete b.completedQueries[d]}function d(a,b){if(b=b||{},!this.definitions[a])throw new this.errors.RuntimeError(e+a+" is not a registered resource!");if(!this.utils.isObject(b))throw new this.errors.IllegalArgumentError(e+"params: Must be an object!",{params:{actual:typeof b,expected:"object"}});var d=this.store[a],f=this; | ||
try{this.$rootScope.$$phase?(c.apply(f,[f.definitions[a],d,b]),d.collectionModified=this.utils.updateTimestamp(d.collectionModified)):this.$rootScope.$apply(function(){c.apply(f,[f.definitions[a],d,b]),d.collectionModified=f.utils.updateTimestamp(d.collectionModified)})}catch(g){throw new this.errors.UnhandledError(g)}}var e="DS.ejectAll(resourceName[, params]): ";b.exports=d},{}],51:[function(a,b){function c(a,b,c){if(c=c||{},!this.definitions[a])throw new this.errors.RuntimeError(d+a+" is not a registered resource!");if(!this.utils.isObject(b))throw new this.errors.IllegalArgumentError(d+"params: Must be an object!",{params:{actual:typeof b,expected:"object"}});if(!this.utils.isObject(c))throw new this.errors.IllegalArgumentError(d+"options: Must be an object!",{options:{actual:typeof c,expected:"object"}});try{var e=this.definitions[a],f=this.store[a],g=this;b.query=b.query||{};var h=this.utils.toJson(b);h in f.completedQueries||!c.loadFromServer||f.pendingQueries[h]||this.findAll(a,b,c);var i=this.utils.filter(f.collection,function(c){var f=!0,h=b.query.where;if(h){if(!g.utils.isObject(h))throw new g.errors.IllegalArgumentError(d+"params.query.where: Must be an object!",{params:{query:{where:{actual:typeof b.query.where,expected:"object"}}}});f=e.filter(a,h,c)}return f});if(b.query.orderBy){if(this.utils.isString(b.query.orderBy)&&(b.query.orderBy=[[b.query.orderBy,"ASC"]]),!this.utils.isArray(b.query.orderBy))throw new this.errors.IllegalArgumentError(d+"params.query.orderBy: Must be a string or an array!",{params:{query:{orderBy:{actual:typeof b.query.orderBy,expected:"string|array"}}}});for(var j=0;j<b.query.orderBy.length;j++){if(this.utils.isString(b.query.orderBy[j]))b.query.orderBy[j]=[b.query.orderBy[j],"ASC"];else if(!this.utils.isArray(b.query.orderBy[j]))throw new this.errors.IllegalArgumentError(d+"params.query.orderBy["+j+"]: Must be a string or an array!",{params:{query:{"orderBy[i]":{actual:typeof b.query.orderBy[j],expected:"string|array"}}}});i=this.utils.sort(i,function(a,c){var d=a[b.query.orderBy[j][0]],e=c[b.query.orderBy[j][0]];return g.utils.isString(d)&&(d=g.utils.upperCase(d)),g.utils.isString(e)&&(e=g.utils.upperCase(e)),"DESC"===b.query.orderBy[j][1]?d>e?-1:e>d?1:0:e>d?-1:d>e?1:0})}}return this.utils.isNumber(b.query.limit)&&this.utils.isNumber(b.query.skip)?i=this.utils.slice(i,b.query.skip,Math.min(i.length,b.query.skip+b.query.limit)):this.utils.isNumber(b.query.limit)?i=this.utils.slice(i,0,Math.min(i.length,b.query.limit)):this.utils.isNumber(b.query.skip)&&(i=b.query.skip<i.length?this.utils.slice(i,b.query.skip):[]),i}catch(k){throw k instanceof this.errors.IllegalArgumentError?k:new this.errors.UnhandledError(k)}}var d="DS.filter(resourceName, params[, options]): ";b.exports=c},{}],52:[function(a,b){function c(a,b,c){if(c=c||{},!this.definitions[a])throw new this.errors.RuntimeError(d+a+" is not a registered resource!");if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}});if(!this.utils.isObject(c))throw new this.errors.IllegalArgumentError(d+"options: Must be an object!",{options:{actual:typeof c,expected:"object"}});try{var e=this.store[a].index.get(b);return!e&&c.loadFromServer&&this.find(a,b).then(null,function(a){throw a}),e}catch(f){throw new this.errors.UnhandledError(f)}}var d="DS.get(resourceName, id[, options]): ";b.exports=c},{}],53:[function(a,b){function c(a,b){return!(a.isEmpty(b.added)&&a.isEmpty(b.removed)&&a.isEmpty(b.changed))}function d(a,b){if(!this.definitions[a])throw new this.errors.RuntimeError(e+a+" is not a registered resource!");if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IllegalArgumentError(e+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}});try{return this.get(a,b)?c(this.utils,this.changes(a,b)):!1}catch(d){throw new this.errors.UnhandledError(d)}}var e="DS.hasChanges(resourceName, id): ";b.exports=d},{}],54:[function(a,b){b.exports={defineResource:a("./defineResource"),bindOne:a("./bindOne"),bindAll:a("./bindAll"),eject:a("./eject"),ejectAll:a("./ejectAll"),filter:a("./filter"),get:a("./get"),inject:a("./inject"),lastModified:a("./lastModified"),lastSaved:a("./lastSaved"),digest:a("./digest"),changes:a("./changes"),previous:a("./previous"),hasChanges:a("./hasChanges")}},{"./bindAll":44,"./bindOne":45,"./changes":46,"./defineResource":47,"./digest":48,"./eject":49,"./ejectAll":50,"./filter":51,"./get":52,"./hasChanges":53,"./inject":55,"./lastModified":56,"./lastSaved":57,"./previous":58}],55:[function(a,b){function c(a,b,d){function g(c,d,e,f){try{var g=f(a.idAttribute);b.modified[g]=h.utils.updateTimestamp(b.modified[g]),b.collectionModified=h.utils.updateTimestamp(b.collectionModified),a.idAttribute in e&&i.error("Doh! You just changed the primary key of an object! I don't know how to handle this yet, so your data for the \""+a.name+'" resource is now in an undefined (probably broken) state.')}catch(j){throw new h.errors.UnhandledError(j)}}var h=this,i=h.$log;if(h.utils.isArray(d))for(var j=0;j<d.length;j++)c.call(h,a,b,d[j]);else{if(!(a.idAttribute in d))throw new h.errors.RuntimeError(f+"attrs: Must contain the property specified by `idAttribute`!");try{a.beforeInject(a.name,d);var k=d[a.idAttribute],l=this.get(a.name,k);l?(h.utils.deepMixIn(l,d),"function"==typeof b.index.touch?b.index.touch(k):b.index.put(k,b.index.get(k)),b.observers[k].deliver()):(l=a.class?d instanceof a[a.class]?d:new a[a.class]:{},b.previousAttributes[k]={},h.utils.deepMixIn(l,d),h.utils.deepMixIn(b.previousAttributes[k],d),b.collection.push(l),b.observers[k]=new e.ObjectObserver(l,g),b.index.put(k,l),g({},{},{},function(){return k})),b.saved[k]=h.utils.updateTimestamp(b.saved[k]),a.afterInject(a.name,l)}catch(m){i.error(m),i.error("inject failed!",a.name,d)}}}function d(a,b,d){if(d=d||{},!this.definitions[a])throw new this.errors.RuntimeError(f+a+" is not a registered resource!");if(!this.utils.isObject(b)&&!this.utils.isArray(b))throw new this.errors.IllegalArgumentError(f+"attrs: Must be an object or an array!",{attrs:{actual:typeof b,expected:"object|array"}});if(!this.utils.isObject(d))throw new this.errors.IllegalArgumentError(f+"options: Must be an object!",{options:{actual:typeof d,expected:"object"}});var e=this.definitions[a],g=this.store[a],h=this;try{return this.$rootScope.$$phase?c.apply(h,[e,g,b]):this.$rootScope.$apply(function(){c.apply(h,[e,g,b])}),h.utils.isArray(b)?b:this.get(a,b[e.idAttribute])}catch(i){throw i instanceof this.errors.RuntimeError?i:new this.errors.UnhandledError(i)}}var e=a("observejs"),f="DS.inject(resourceName, attrs[, options]): ";b.exports=d},{observejs:"QYwGEY"}],56:[function(a,b){function c(a,b){if(!this.definitions[a])throw new this.errors.RuntimeError(d+a+" is not a registered resource!");if(b&&!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}});try{return b?(b in this.store[a].modified||(this.store[a].modified[b]=0),this.store[a].modified[b]):this.store[a].collectionModified}catch(c){throw new this.errors.UnhandledError(c)}}var d="DS.lastModified(resourceName[, id]): ";b.exports=c},{}],57:[function(a,b){function c(a,b){if(!this.definitions[a])throw new this.errors.RuntimeError(d+a+" is not a registered resource!");if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}});try{return b in this.store[a].saved||(this.store[a].saved[b]=0),this.store[a].saved[b]}catch(c){throw new this.errors.UnhandledError(c)}}var d="DS.lastSaved(resourceName[, id]): ";b.exports=c},{}],58:[function(a,b){function c(a,b){if(!this.definitions[a])throw new this.errors.RuntimeError(d+a+" is not a registered resource!");if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IllegalArgumentError(d+"id: Must be a string or a number!",{id:{actual:typeof b,expected:"string|number"}});try{return angular.copy(this.store[a].previousAttributes[b])}catch(c){throw new this.errors.UnhandledError(c)}}var d="DS.previous(resourceName, id): ";b.exports=c},{}],errors:[function(a,b){b.exports=a("XIsZmp")},{}],XIsZmp:[function(a,b){function c(a){Error.call(this),"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),a=a||{},this.type=this.constructor.name,this.originalError=a,this.message="UnhandledError: This is an uncaught exception. Please consider submitting an issue at https://github.com/jmdobry/angular-data/issues.\n\nOriginal Uncaught Exception:\n"+(a.stack?a.stack.toString():a.stack),this.stack=this.message}function d(a,b){Error.call(this),"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.type=this.constructor.name,this.errors=b||{},this.message=a||"Illegal Argument!"}function e(a,b){Error.call(this),"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.type=this.constructor.name,this.errors=b||{},this.message=a||"RuntimeError Error!"}c.prototype=Object.create(Error.prototype),c.prototype.constructor=c,d.prototype=Object.create(Error.prototype),d.prototype.constructor=d,e.prototype=Object.create(Error.prototype),e.prototype.constructor=e,b.exports=[function(){return{UnhandledError:c,IllegalArgumentError:d,RuntimeError:e}}]},{}],61:[function(a){!function(b,c){"use strict";c.module("angular-data.DS",["ng"]).factory("DSUtils",a("./utils")).factory("DSErrors",a("./errors")).provider("DSHttpAdapter",a("./adapters/http")).provider("DSLocalStorageAdapter",a("./adapters/localStorage")).provider("DS",a("./datastore")).config(["$provide",function(a){a.decorator("$q",["$delegate",function(a){return a.promisify=function(a,b){var c=this;return function(){var d=c.defer(),e=Array.prototype.slice.apply(arguments);e.push(function(a,b){a?d.reject(a):d.resolve(b)});try{a.apply(b||this,e)}catch(f){d.reject(f)}return d.promise}},a}])}])}(window,window.angular)},{"./adapters/http":31,"./adapters/localStorage":32,"./datastore":43,"./errors":"XIsZmp","./utils":"K0yknU"}],K0yknU:[function(a,b){b.exports=[function(){return{isString:angular.isString,isArray:angular.isArray,isObject:angular.isObject,isNumber:angular.isNumber,isFunction:angular.isFunction,isEmpty:a("mout/lang/isEmpty"),toJson:angular.toJson,makePath:a("mout/string/makePath"),upperCase:a("mout/string/upperCase"),deepMixIn:a("mout/object/deepMixIn"),forOwn:a("mout/object/forOwn"),pick:a("mout/object/pick"),set:a("mout/object/set"),contains:a("mout/array/contains"),filter:a("mout/array/filter"),toLookup:a("mout/array/toLookup"),slice:a("mout/array/slice"),sort:a("mout/array/sort"),updateTimestamp:function(a){var b="function"==typeof Date.now?Date.now():(new Date).getTime();return a&&a>=b?a+1:b},deepFreeze:function b(a){if("function"==typeof Object.freeze){var c,d;Object.freeze(a);for(d in a)c=a[d],a.hasOwnProperty(d)&&"object"==typeof c&&!Object.isFrozen(c)&&b(c)}},diffObjectFromOldObject:function(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var h in a)h in b||(c[h]=a[h]);return{added:c,removed:d,changed:e}}}}]},{"mout/array/contains":3,"mout/array/filter":4,"mout/array/slice":8,"mout/array/sort":9,"mout/array/toLookup":10,"mout/lang/isEmpty":15,"mout/object/deepMixIn":22,"mout/object/forOwn":24,"mout/object/pick":27,"mout/object/set":28,"mout/string/makePath":29,"mout/string/upperCase":30}],utils:[function(a,b){b.exports=a("K0yknU")},{}]},{},[61]); | ||
!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){(function(){!function(a){"use strict";function b(){function a(a){"splice"===a[0].type&&"splice"===a[1].type&&(b=!0)}if("function"!=typeof Object.observe||"function"!=typeof Array.observe)return!1;var b=!1,c=[0];return Array.observe(c,a),c[1]=1,c.length=0,Object.deliverChangeRecords(a),b}function c(a){return a===Object(a)}function d(a){for(var b=0;s>b&&a.check();)a.report(),b++}function e(a){for(var b in a)return!1;return!0}function f(a){return e(a.added)&&e(a.removed)&&e(a.changed)}function g(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var f in a)f in b||(c[f]=a[f]);return Array.isArray(a)&&a.length!==b.length&&(e.length=a.length),{added:c,removed:d,changed:e}}function h(a,b){var c=b||(Array.isArray(a)?[]:{});for(var d in a)c[d]=a[d];return Array.isArray(a)&&(c.length=a.length),c}function i(a,b,c,d){if(this.closed=!1,this.object=a,this.callback=b,this.target=c,this.token=d,this.reporting=!0,n){var e=this;this.boundInternalCallback=function(a){e.internalCallback(a)}}j(this),this.connect(),this.sync(!0)}function j(a){u&&(t.push(a),i._allObserversCount++)}function k(a,b,c,d){i.call(this,a,b,c,d)}function l(a){this.arr=[],this.callback=a,this.isObserved=!0}function m(a,b,c){for(var d={},e={},f=0;f<b.length;f++){var g=b[f];z[g.type]?(g.name in c||(c[g.name]=g.oldValue),"updated"!=g.type&&("new"!=g.type?g.name in d?(delete d[g.name],delete c[g.name]):e[g.name]=!0:g.name in e?delete e[g.name]:d[g.name]=!0)):(console.error("Unknown changeRecord type: "+g.type),console.error(g))}for(var h in d)d[h]=a[h];for(var h in e)e[h]=void 0;var i={};for(var h in c)if(!(h in d||h in e)){var j=a[h];c[h]!==j&&(i[h]=j)}return{added:d,removed:e,changed:i}}var n=b(),o=!1;try{var p=new Function("","return true;");o=p()}catch(q){}var r=(a.Number.isNaN||function(b){return"number"==typeof b&&a.isNaN(b)},"__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c}),s=1e3;i.prototype={internalCallback:function(a){this.closed||this.reporting&&this.check(a)&&(this.report(),this.testingResults&&(this.testingResults.anyChanged=!0))},close:function(){this.closed||(this.object&&"function"==typeof this.object.unobserved&&this.object.unobserved(),this.disconnect(),this.object=void 0,this.closed=!0)},deliver:function(a){this.closed||(n?(this.testingResults=a,Object.deliverChangeRecords(this.boundInternalCallback),this.testingResults=void 0):d(this))},report:function(){this.reporting&&(this.sync(!1),this.reportArgs.push(this.token),this.invokeCallback(this.reportArgs),this.reportArgs=void 0)},invokeCallback:function(a){try{this.callback.apply(this.target,a)}catch(b){i._errorThrownDuringCallback=!0,console.error("Exception caught during observer callback: "+b)}},reset:function(){this.closed||(n&&(this.reporting=!1,Object.deliverChangeRecords(this.boundInternalCallback),this.reporting=!0),this.sync(!0))}};var t,u=!n||a.forceCollectObservers;i._allObserversCount=0,u&&(t=[]);var v=!1,w="function"==typeof Object.deliverAllChangeRecords;a.Platform=a.Platform||{},a.Platform.performMicrotaskCheckpoint=function(){if(!v){if(w)return void Object.deliverAllChangeRecords();if(u){v=!0;var a=0,b={};do{a++;var c=t;t=[],b.anyChanged=!1;for(var d=0;d<c.length;d++){var e=c[d];e.closed||(n?e.deliver(b):e.check()&&(b.anyChanged=!0,e.report()),t.push(e))}}while(s>a&&b.anyChanged);i._allObserversCount=t.length,v=!1}}},u&&(a.Platform.clearObservers=function(){t=[]}),k.prototype=r({__proto__:i.prototype,connect:function(){n&&Object.observe(this.object,this.boundInternalCallback)},sync:function(){n||(this.oldObject=h(this.object))},check:function(a){var b,c;if(n){if(!a)return!1;c={},b=m(this.object,a,c)}else c=this.oldObject,b=g(this.object,this.oldObject);return f(b)?!1:(this.reportArgs=[b.added||{},b.removed||{},b.changed||{}],this.reportArgs.push(function(a){return c[a]}),!0)},disconnect:function(){n?this.object&&Object.unobserve(this.object,this.boundInternalCallback):this.oldObject=void 0}});var x=Object.getPrototypeOf({}),y=Object.getPrototypeOf([]);l.prototype={reset:function(){this.isObserved=!this.isObserved},observe:function(a){if(c(a)&&a!==x&&a!==y){var b=this.arr.indexOf(a);b>=0&&this.arr[b+1]===this.isObserved||(0>b&&(b=this.arr.length,this.arr[b]=a,Object.observe(a,this.callback)),this.arr[b+1]=this.isObserved,this.observe(Object.getPrototypeOf(a)))}},cleanup:function(){for(var a=0,b=0,c=this.isObserved;b<this.arr.length;){var d=this.arr[b];this.arr[b+1]==c?(b>a&&(this.arr[a]=d,this.arr[a+1]=c),a+=2):Object.unobserve(d,this.callback),b+=2}this.arr.length=a}};var z={"new":!0,updated:!0,deleted:!0};a.Observer=i,a.Observer.hasObjectObserve=n,a.ObjectObserver=k}((c.Number={isNaN:window.isNaN})?c:c)}).call(this,"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],2:[function(a,b){function c(a,b){return-1!==d(a,b)}var d=a("./indexOf");b.exports=c},{"./indexOf":5}],3:[function(a,b){function c(a,b,c){b=d(b,c);var e=[];if(null==a)return e;for(var f,g=-1,h=a.length;++g<h;)f=a[g],b(f,g,a)&&e.push(f);return e}var d=a("../function/makeIterator_");b.exports=c},{"../function/makeIterator_":11}],4:[function(a,b){function c(a,b,c){if(null!=a)for(var d=-1,e=a.length;++d<e&&b.call(c,a[d],d,a)!==!1;);}b.exports=c},{}],5:[function(a,b){function c(a,b,c){if(c=c||0,null==a)return-1;for(var d=a.length,e=0>c?d+c:c;d>e;){if(a[e]===b)return e;e++}return-1}b.exports=c},{}],6:[function(a,b){function c(a){return null!=a&&""!==a}function d(a,b){return b=b||"",e(a,c).join(b)}var e=a("./filter");b.exports=d},{"./filter":3}],7:[function(a,b){function c(a,b,c){var d=a.length;b=null==b?0:0>b?Math.max(d+b,0):Math.min(b,d),c=null==c?d:0>c?Math.max(d+c,0):Math.min(c,d);for(var e=[];c>b;)e.push(a[b++]);return e}b.exports=c},{}],8:[function(a,b){function c(a,b){if(null==a)return[];if(a.length<2)return a;null==b&&(b=d);var f,g,h;return f=~~(a.length/2),g=c(a.slice(0,f),b),h=c(a.slice(f,a.length),b),e(g,h,b)}function d(a,b){return b>a?-1:a>b?1:0}function e(a,b,c){for(var d=[];a.length&&b.length;)d.push(c(a[0],b[0])<=0?a.shift():b.shift());return a.length&&d.push.apply(d,a),b.length&&d.push.apply(d,b),d}b.exports=c},{}],9:[function(a,b){function c(a,b){var c={};if(null==a)return c;var e,f=-1,g=a.length;if(d(b))for(;++f<g;)e=a[f],c[b(e)]=e;else for(;++f<g;)e=a[f],c[e[b]]=e;return c}var d=a("../lang/isFunction");b.exports=c},{"../lang/isFunction":15}],10:[function(a,b){function c(a){return a}b.exports=c},{}],11:[function(a,b){function c(a,b){if(null==a)return d;switch(typeof a){case"function":return"undefined"!=typeof b?function(c,d,e){return a.call(b,c,d,e)}:a;case"object":return function(b){return f(b,a)};case"string":case"number":return e(a)}}var d=a("./identity"),e=a("./prop"),f=a("../object/deepMatches");b.exports=c},{"../object/deepMatches":20,"./identity":10,"./prop":12}],12:[function(a,b){function c(a){return function(b){return b[a]}}b.exports=c},{}],13:[function(a,b){var c=a("./isKind"),d=Array.isArray||function(a){return c(a,"Array")};b.exports=d},{"./isKind":16}],14:[function(a,b){function c(a){if(null==a)return!1;if("string"==typeof a||e(a))return!a.length;if("object"==typeof a||"function"==typeof a){var b=!0;return d(a,function(){return b=!1,!1}),b}return!1}var d=a("../object/forOwn"),e=a("./isArray");b.exports=c},{"../object/forOwn":23,"./isArray":13}],15:[function(a,b){function c(a){return d(a,"Function")}var d=a("./isKind");b.exports=c},{"./isKind":16}],16:[function(a,b){function c(a,b){return d(a)===b}var d=a("./kindOf");b.exports=c},{"./kindOf":18}],17:[function(a,b){function c(a){return!!a&&"object"==typeof a&&a.constructor===Object}b.exports=c},{}],18:[function(a,b){function c(a){return null===a?"Null":a===d?"Undefined":e.exec(f.call(a))[1]}var d,e=/^\[object (.*)\]$/,f=Object.prototype.toString;b.exports=c},{}],19:[function(a,b){function c(a){return null==a?"":a.toString()}b.exports=c},{}],20:[function(a,b){function c(a,b){for(var c=-1,d=a.length;++c<d;)if(f(a[c],b))return!0;return!1}function d(a,b){for(var d=-1,e=b.length;++d<e;)if(!c(a,b[d]))return!1;return!0}function e(a,b){var c=!0;return g(b,function(b,d){return f(a[d],b)?void 0:c=!1}),c}function f(a,b){return a&&"object"==typeof a?h(a)&&h(b)?d(a,b):e(a,b):a===b}var g=a("./forOwn"),h=a("../lang/isArray");b.exports=f},{"../lang/isArray":13,"./forOwn":23}],21:[function(a,b){function c(a){for(var b,c=0,f=arguments.length;++c<f;)b=arguments[c],b&&e(b,d,a);return a}function d(a,b){var d=this[b];f(a)&&f(d)?c(d,a):this[b]=a}var e=a("./forOwn"),f=a("../lang/isPlainObject");b.exports=c},{"../lang/isPlainObject":17,"./forOwn":23}],22:[function(a,b){function c(){g=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],f=!0;for(var a in{toString:null})f=!1}function d(a,b,d){var i,j=0;null==f&&c();for(i in a)if(e(b,a,i,d)===!1)break;if(f)for(var k=a.constructor,l=!!k&&a===k.prototype;(i=g[j++])&&("constructor"===i&&(l||!h(a,i))||a[i]===Object.prototype[i]||e(b,a,i,d)!==!1););}function e(a,b,c,d){return a.call(d,b[c],c,b)}var f,g,h=a("./hasOwn");b.exports=d},{"./hasOwn":24}],23:[function(a,b){function c(a,b,c){e(a,function(e,f){return d(a,f)?b.call(c,a[f],f,a):void 0})}var d=a("./hasOwn"),e=a("./forIn");b.exports=c},{"./forIn":22,"./hasOwn":24}],24:[function(a,b){function c(a,b){return Object.prototype.hasOwnProperty.call(a,b)}b.exports=c},{}],25:[function(a,b){function c(a,b){return b?(d(b.split("."),function(b){a[b]||(a[b]={}),a=a[b]}),a):a}var d=a("../array/forEach");b.exports=c},{"../array/forEach":4}],26:[function(a,b){function c(a){for(var b,c="string"!=typeof arguments[1]?arguments[1]:d(arguments,1),e={},f=0;b=c[f++];)e[b]=a[b];return e}var d=a("../array/slice");b.exports=c},{"../array/slice":7}],27:[function(a,b){function c(a,b,c){var e=/^(.+)\.(.+)$/.exec(b);e?d(a,e[1])[e[2]]=c:a[b]=c}var d=a("./namespace");b.exports=c},{"./namespace":25}],28:[function(a,b){function c(){var a=d(e(arguments),"/");return a.replace(/([^:\/]|^)\/{2,}/g,"$1/")}var d=a("../array/join"),e=a("../array/slice");b.exports=c},{"../array/join":6,"../array/slice":7}],29:[function(a,b){function c(a){return a=d(a),a.toUpperCase()}var d=a("../lang/toString");b.exports=c},{"../lang/toString":19}],30:[function(a,b){function c(){var a=this.defaults={queryTransform:function(a,b){return b}};this.$get=["$http","$log","DSUtils",function(b,c,d){function e(a){var d=(new Date).getTime();return b(a).then(function(a){return c.debug(a.config.method+" request:"+a.config.url+" Time taken: "+((new Date).getTime()-d)+"ms",arguments),a})}function f(a,b){return b=b||{},e(d.deepMixIn(b,{url:a,method:"GET"}))}function g(a,b,c){return c=c||{},e(d.deepMixIn(c,{url:a,data:b,method:"POST"}))}function h(a,b,c){return c=c||{},e(d.deepMixIn(c,{url:a,data:b,method:"PUT"}))}function i(a,b){return b=b||{},this.HTTP(d.deepMixIn(b,{url:a,method:"DELETE"}))}function j(a,b,c){return c=c||{},this.POST(d.makePath(c.baseUrl||a.baseUrl,a.endpoint),b,c)}function k(a,b,c){return c=c||{},this.DEL(d.makePath(c.baseUrl||a.baseUrl,a.endpoint,b),c)}function l(b,c,e){return e=e||{},e.params=e.params||{},c&&(c=a.queryTransform(b.name,c),d.deepMixIn(e.params,c)),this.DEL(d.makePath(e.baseUrl||b.baseUrl,b.endpoint),e)}function m(a,b,c){return c=c||{},this.GET(d.makePath(c.baseUrl||a.baseUrl,a.endpoint,b),c)}function n(b,c,e){return e=e||{},e.params=e.params||{},c&&(c=a.queryTransform(b.name,c),d.deepMixIn(e.params,c)),this.GET(d.makePath(e.baseUrl||b.baseUrl,b.endpoint),e)}function o(a,b,c,e){return e=e||{},this.PUT(d.makePath(e.baseUrl||a.baseUrl,a.endpoint,b),c,e)}function p(b,c,e,f){return f=f||{},f.params=f.params||{},e&&(e=a.queryTransform(b.name,e),d.deepMixIn(f.params,e)),this.PUT(d.makePath(f.baseUrl||b.baseUrl,b.endpoint),c,f)}return{defaults:a,HTTP:e,GET:f,POST:g,PUT:h,DEL:i,find:m,findAll:n,create:j,update:o,updateAll:p,destroy:k,destroyAll:l}}]}b.exports=c},{}],31:[function(a,b){function c(){this.$get=["$q","DSUtils",function(a,b){function c(b){var c=a.defer();try{var d=localStorage.getItem(b);c.resolve(d?angular.fromJson(d):void 0)}catch(e){c.reject(e)}return c.promise}function d(c,d){var e=a.defer();try{var f=localStorage.getItem(c);f?(f=angular.fromJson(f),b.deepMixIn(f,d),e.resolve(localStorage.setItem(c,angular.toJson(f)))):e.resolve(localStorage.setItem(c,angular.toJson(d)))}catch(g){e.reject(g)}return e.promise}function e(b){var c=a.defer();try{c.resolve(localStorage.removeItem(b))}catch(d){c.reject(d)}return c.promise}function f(a,c,d){return d=d||{},e(b.makePath(d.baseUrl||a.baseUrl,a.endpoint,c),d)}function g(a,d,e){return e=e||{},c(b.makePath(e.baseUrl||a.baseUrl,a.endpoint,d),e)}function h(a,e,f,g){return g=g||{},d(b.makePath(g.baseUrl||a.baseUrl,a.endpoint,e),f,g).then(function(){return c(b.makePath(g.baseUrl||a.baseUrl,a.endpoint,e))})}return{find:g,findAll:function(){throw new Error("Not supported!")},create:function(){throw new Error("Not supported!")},update:h,updateAll:function(){throw new Error("Not supported!")},destroy:f,destroyAll:function(){throw new Error("Not supported!")}}}]}b.exports=c},{}],32:[function(a,b){function c(a,b,c){var e=this.$q.defer(),f=e.promise;try{if(c=c||{},!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isObject(b))throw new this.errors.IA(d+"attrs: Must be an object!");var g=this.definitions[a],h=this.store[a],i=this;f=f.then(function(b){return i.$q.promisify(g.beforeValidate)(a,b)}).then(function(b){return i.$q.promisify(g.validate)(a,b)}).then(function(b){return i.$q.promisify(g.afterValidate)(a,b)}).then(function(b){return i.$q.promisify(g.beforeCreate)(a,b)}).then(function(b){return i.adapters[c.adapter||g.defaultAdapter].create(g,g.serialize(a,b),c)}).then(function(b){return i.$q.promisify(g.afterCreate)(a,g.deserialize(a,b))}).then(function(a){var b=i.inject(g.name,a),c=b[g.idAttribute];return h.previousAttributes[c]=i.utils.deepMixIn({},b),h.saved[c]=i.utils.updateTimestamp(h.saved[c]),i.get(g.name,c)}),e.resolve(b)}catch(j){e.reject(j)}return f}var d="DS.create(resourceName, attrs[, options]): ";b.exports=c},{}],33:[function(a,b){function c(a,b,c){var e=this.$q.defer(),f=e.promise;try{if(c=c||{},!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IA(d+"id: Must be a string or a number!");var g=this.get(a,b);if(!g)throw new this.errors.R(d+'id: "'+b+'" not found!');var h=this.definitions[a],i=this;f=f.then(function(b){return i.$q.promisify(h.beforeDestroy)(a,b)}).then(function(){return i.adapters[c.adapter||h.defaultAdapter].destroy(h,b,c)}).then(function(){return i.$q.promisify(h.afterDestroy)(a,g)}).then(function(){return i.eject(a,b),b}),e.resolve(g)}catch(j){e.reject(j)}return f}var d="DS.destroy(resourceName, id): ";b.exports=c},{}],34:[function(a,b){function c(a,b,c){var e=this.$q.defer(),f=e.promise;try{var g=this,h=this.errors.IA;if(c=c||{},!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isObject(b))throw new h(d+"params: Must be an object!");if(!this.utils.isObject(c))throw new h(d+"options: Must be an object!");var i=this.definitions[a];f=f.then(function(){return g.adapters[c.adapter||i.defaultAdapter].destroyAll(i,b,c)}).then(function(){return g.ejectAll(a,b)}),e.resolve()}catch(j){e.reject(j)}return f}var d="DS.destroyAll(resourceName, params[, options]): ";b.exports=c},{}],35:[function(a,b){function c(a,b,c){var e=this.$q.defer(),f=e.promise;try{var g=this.errors.IA;if(c=c||{},!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new g(d+"id: Must be a string or a number!");if(!this.utils.isObject(c))throw new g(d+"options: Must be an object!");c.cacheResponse="cacheResponse"in c?!!c.cacheResponse:!0;var h=this.definitions[a],i=this.store[a],j=this;if(c.bypassCache&&delete i.completedQueries[b],!(b in i.completedQueries))return b in i.pendingQueries||(f=i.pendingQueries[b]=j.adapters[c.adapter||h.defaultAdapter].find(h,b,c).then(function(d){var e=h.deserialize(a,d);return c.cacheResponse?(delete i.pendingQueries[b],i.completedQueries[b]=(new Date).getTime(),j.inject(a,e)):e},function(a){return delete i.pendingQueries[b],j.$q.reject(a)})),i.pendingQueries[b];e.resolve(j.get(a,b))}catch(k){e.reject(k)}return f}var d="DS.find(resourceName, id[, options]): ";b.exports=c},{}],36:[function(a,b){function c(a,b,c,d){var e=this.store[c];return b=b||[],delete e.pendingQueries[d],e.completedQueries[d]=(new Date).getTime(),e.collectionModified=a.updateTimestamp(e.collectionModified),this.inject(c,b)}function d(a,b,d,e){var f=this.definitions[b],g=this.store[b],h=this,i=a.toJson(d);return e.bypassCache&&delete g.completedQueries[i],i in g.completedQueries?this.filter(b,d,e):(i in g.pendingQueries||(g.pendingQueries[i]=h.adapters[e.adapter||f.defaultAdapter].findAll(f,d,e).then(function(d){var g=f.deserialize(b,d);if(!e.cacheResponse)return g;try{return c.apply(h,[a,g,b,i])}catch(j){return h.$q.reject(j)}},function(a){return delete g.pendingQueries[i],h.$q.reject(a)})),g.pendingQueries[i])}function e(a,b,c){var e=this.$q.defer(),g=e.promise;try{var h=this.errors.IA,i=this;if(c=c||{},b=b||{},!this.definitions[a])throw new this.errors.NER(f+a);if(!this.utils.isObject(b))throw new h(f+"params: Must be an object!");if(!this.utils.isObject(c))throw new h(f+"options: Must be an object!");c.cacheResponse="cacheResponse"in c?!!c.cacheResponse:!0,g=g.then(function(){return d.apply(i,[i.utils,a,b,c])}),e.resolve()}catch(j){e.reject(j)}return g}var f="DS.findAll(resourceName, params[, options]): ";b.exports=e},{}],37:[function(a,b){b.exports={create:a("./create"),destroy:a("./destroy"),destroyAll:a("./destroyAll"),find:a("./find"),findAll:a("./findAll"),loadRelations:a("./loadRelations"),refresh:a("./refresh"),save:a("./save"),update:a("./update"),updateAll:a("./updateAll")}},{"./create":32,"./destroy":33,"./destroyAll":34,"./find":35,"./findAll":36,"./loadRelations":38,"./refresh":39,"./save":40,"./update":41,"./updateAll":42}],38:[function(a,b){function c(a,b,c,e){var f=this.$q.defer(),g=f.promise;try{var h=this.errors.IA;if(e=e||{},(angular.isString(b)||angular.isNumber(b))&&(b=this.get(a,b)),angular.isString(c)&&(c=[c]),!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isObject(b))throw new h(d+"instance(Id): Must be a string, number or object!");if(!this.utils.isArray(c))throw new h(d+"relations: Must be a string or an array!");if(!this.utils.isObject(e))throw new h(d+"options: Must be an object!");var i=this.definitions[a],j=this,k=[],l=[];j.utils.forOwn(i.relations,function(a,d){j.utils.forOwn(a,function(a,f){if(j.utils.contains(c,f)){var g,h={};h[a.foreignKey]=b[i.idAttribute],"hasMany"===d?g=j.findAll(f,h,e):"hasOne"===d?a.localKey&&b[a.localKey]?g=j.find(f,b[a.localKey],e):a.foreignKey&&(g=j.findAll(f,h,e)):g=j.find(f,b[a.localKey],e),g&&(k.push(g),l.push(a.localField))}})}),g=g.then(function(){return j.$q.all(k)}).then(function(a){return angular.forEach(l,function(c,d){b[c]=a[d]}),b}),f.resolve()}catch(m){f.reject(m)}return g}var d="DS.loadRelations(resourceName, instance(Id), relations[, options]): ";b.exports=c},{}],39:[function(a,b){function c(a,b,c){var e=this.errors.IA;if(c=c||{},this.definitions[a]){if(this.utils.isString(b)||this.utils.isNumber(b)){if(this.utils.isObject(c))return c.bypassCache=!0,this.get(a,b)?this.find(a,b,c):!1;throw new e(d+"options: Must be an object!")}throw new e(d+"id: Must be a string or a number!")}throw new this.errors.NER(d+a)}var d="DS.refresh(resourceName, id[, options]): ";b.exports=c},{}],40:[function(a,b){function c(a,b,c){var e=this.$q.defer(),f=e.promise;try{var g=this.errors.IA;if(c=c||{},!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new g(d+"id: Must be a string or a number!");if(!this.utils.isObject(c))throw new g(d+"options: Must be an object!");var h=this.get(a,b);if(!h)throw new this.errors.R(d+'id: "'+b+'" not found!');var i=this.definitions[a],j=this.store[a],k=this;f=f.then(function(b){return k.$q.promisify(i.beforeValidate)(a,b)}).then(function(b){return k.$q.promisify(i.validate)(a,b)}).then(function(b){return k.$q.promisify(i.afterValidate)(a,b)}).then(function(b){return k.$q.promisify(i.beforeUpdate)(a,b)}).then(function(d){if(c.changesOnly){j.observers[b].deliver();var e=[],f=k.changes(a,b);for(var g in f.added)e.push(g);for(g in f.changed)e.push(g);if(f=k.utils.pick(d,e),k.utils.isEmpty(f))return d;d=f}return k.adapters[c.adapter||i.defaultAdapter].update(i,b,i.serialize(a,d),c)}).then(function(b){return k.$q.promisify(i.afterUpdate)(a,i.deserialize(a,b))}).then(function(d){return k.inject(i.name,d,c),j.previousAttributes[b]=k.utils.deepMixIn({},d),j.saved[b]=k.utils.updateTimestamp(j.saved[b]),k.get(a,b)}),e.resolve(h)}catch(l){e.reject(l)}return f}var d="DS.save(resourceName, id[, options]): ";b.exports=c},{}],41:[function(a,b){function c(a,b,c,e){var f=this.$q.defer(),g=f.promise;try{var h=this.errors.IA;if(e=e||{},!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new h(d+"id: Must be a string or a number!");if(!this.utils.isObject(c))throw new h(d+"attrs: Must be an object!");if(!this.utils.isObject(e))throw new h(d+"options: Must be an object!");var i=this.definitions[a],j=this.store[a],k=this;e.cacheResponse="cacheResponse"in e?!!e.cacheResponse:!0,g=g.then(function(b){return k.$q.promisify(i.beforeValidate)(a,b)}).then(function(b){return k.$q.promisify(i.validate)(a,b)}).then(function(b){return k.$q.promisify(i.afterValidate)(a,b)}).then(function(b){return k.$q.promisify(i.beforeUpdate)(a,b)}).then(function(c){return k.adapters[e.adapter||i.defaultAdapter].update(i,b,i.serialize(a,c),e)}).then(function(b){return k.$q.promisify(i.afterUpdate)(a,i.deserialize(a,b))}).then(function(a){if(e.cacheResponse){var b=k.inject(i.name,a,e),c=b[i.idAttribute];return j.previousAttributes[c]=k.utils.deepMixIn({},b),j.saved[c]=k.utils.updateTimestamp(j.saved[c]),k.get(i.name,c)}return a}),f.resolve(c)}catch(l){f.reject(l)}return g}var d="DS.update(resourceName, id, attrs[, options]): ";b.exports=c},{}],42:[function(a,b){function c(a,b,c,e){var f=this.$q.defer(),g=f.promise;try{var h=this.errors.IA;if(e=e||{},!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isObject(b))throw new h(d+"attrs: Must be an object!");if(!this.utils.isObject(c))throw new h(d+"params: Must be an object!");if(!this.utils.isObject(e))throw new h(d+"options: Must be an object!");var i=this.definitions[a],j=this;e.cacheResponse="cacheResponse"in e?!!e.cacheResponse:!0,g=g.then(function(b){return j.$q.promisify(i.beforeValidate)(a,b)}).then(function(b){return j.$q.promisify(i.validate)(a,b)}).then(function(b){return j.$q.promisify(i.afterValidate)(a,b)}).then(function(b){return j.$q.promisify(i.beforeUpdate)(a,b)}).then(function(b){return j.adapters[e.adapter||i.defaultAdapter].updateAll(i,i.serialize(a,b),c,e)}).then(function(b){return j.$q.promisify(i.afterUpdate)(a,i.deserialize(a,b))}).then(function(a){return e.cacheResponse?j.inject(i.name,a,e):a}),f.resolve(b)}catch(k){f.reject(k)}return g}var d="DS.updateAll(resourceName, attrs, params[, options]): ";b.exports=c},{}],43:[function(a,b){function c(a,b,c){c(null,b)}function d(){}function e(){var b=this.defaults=new d;this.$get=["$rootScope","$log","$q","DSHttpAdapter","DSLocalStorageAdapter","DSUtils","DSErrors",function(c,d,e,f,g,h,i){var j,k=a("./sync_methods"),l=a("./async_methods");try{j=angular.injector(["angular-data.DSCacheFactory"]).get("DSCacheFactory")}catch(m){d.warn(m),d.warn("DSCacheFactory is unavailable. Resorting to the lesser capabilities of $cacheFactory."),j=angular.injector(["ng"]).get("$cacheFactory")}var n={$rootScope:c,$log:d,$q:e,cacheFactory:j,defaults:b,store:{},definitions:{},adapters:{DSHttpAdapter:f,DSLocalStorageAdapter:g},errors:i,utils:h};h.deepFreeze(k),h.deepFreeze(l),h.deepMixIn(n,k),h.deepMixIn(n,l),h.deepFreeze(n.errors),h.deepFreeze(n.utils);var o=c.$new();return o.$watch(function(){return(new Date).getTime()/100|0},function(){n.digest()}),n}]}a("../utils")[0]();d.prototype.idAttribute="id",d.prototype.defaultAdapter="DSHttpAdapter",d.prototype.filter=function(a,b,c,d){var e=this,f=a,g=null,h={skip:"",offset:"",where:"",limit:"",orderBy:"",sort:""};g=this.utils.isObject(c.where)?c.where:{},d.allowSimpleWhere&&this.utils.forOwn(c,function(a,b){b in h||b in g||(g[b]={"==":a})}),this.utils.isEmpty(g)&&(g=null),g&&(f=this.utils.filter(f,function(a){var b=!0,c=!0;return e.utils.forOwn(g,function(d,f){e.utils.isString(d)?d={"===":d}:e.utils.isNumber(d)&&(d={"==":d}),e.utils.isObject(d)&&e.utils.forOwn(d,function(d,g){"=="===g?c=b?a[f]==d:c&&a[f]==d:"==="===g?c=b?a[f]===d:c&&a[f]===d:"!="===g?c=b?a[f]!=d:c&&a[f]!=d:"!=="===g?c=b?a[f]!==d:c&&a[f]!==d:">"===g?c=b?a[f]>d:c&&a[f]>d:">="===g?c=b?a[f]>=d:c&&a[f]>=d:"<"===g?c=b?a[f]<d:c&&a[f]<d:"<="===g?c=b?a[f]<=d:c&&a[f]<=d:"in"===g?c=b?e.utils.contains(d,a[f]):c&&e.utils.contains(d,a[f]):"|=="===g?c=b?a[f]==d:c||a[f]==d:"|==="===g?c=b?a[f]===d:c||a[f]===d:"|!="===g?c=b?a[f]!=d:c||a[f]!=d:"|!=="===g?c=b?a[f]!==d:c||a[f]!==d:"|>"===g?c=b?a[f]>d:c||a[f]>d:"|>="===g?c=b?a[f]>=d:c||a[f]>=d:"|<"===g?c=b?a[f]<d:c||a[f]<d:"|<="===g?c=b?a[f]<=d:c||a[f]<=d:"|in"===g&&(c=b?e.utils.contains(d,a[f]):c||e.utils.contains(d,a[f])),b=!1})}),c}));var i=null;this.utils.isString(c.orderBy)?i=[[c.orderBy,"ASC"]]:this.utils.isArray(c.orderBy)&&(i=c.orderBy),!i&&this.utils.isString(c.sort)?i=[[c.sort,"ASC"]]:!i&&this.utils.isArray(c.sort)&&(i=c.sort),i&&angular.forEach(i,function(a){if(e.utils.isString(a))a=[a,"ASC"];else if(!e.utils.isArray(a))throw new e.errors.IllegalArgumentError("DS.filter(resourceName[, params][, options]): "+angular.toJson(a)+": Must be a string or an array!",{params:{"orderBy[i]":{actual:typeof a,expected:"string|array"}}});f=e.utils.sort(f,function(b,c){var d=b[a[0]],f=c[a[0]];return e.utils.isString(d)&&(d=e.utils.upperCase(d)),e.utils.isString(f)&&(f=e.utils.upperCase(f)),"DESC"===a[1]?d>f?-1:f>d?1:0:f>d?-1:d>f?1:0})});var j=angular.isNumber(c.limit)?c.limit:null,k=null;return angular.isNumber(c.skip)?k=c.skip:angular.isNumber(c.offset)&&(k=c.offset),j&&k?f=this.utils.slice(f,k,Math.min(f.length,k+j)):this.utils.isNumber(j)?f=this.utils.slice(f,0,Math.min(f.length,j)):this.utils.isNumber(k)&&(f=k<f.length?this.utils.slice(f,k):[]),f},d.prototype.baseUrl="",d.prototype.endpoint="",d.prototype.beforeValidate=c,d.prototype.validate=c,d.prototype.afterValidate=c,d.prototype.beforeCreate=c,d.prototype.afterCreate=c,d.prototype.beforeUpdate=c,d.prototype.afterUpdate=c,d.prototype.beforeDestroy=c,d.prototype.afterDestroy=c,d.prototype.beforeInject=function(a,b){return b},d.prototype.afterInject=function(a,b){return b},d.prototype.serialize=function(a,b){return b},d.prototype.deserialize=function(a,b){return b.data},b.exports=e},{"../utils":61,"./async_methods":37,"./sync_methods":54}],44:[function(a,b){function c(a,b,c,e,f){var g=this.errors.IA;if(!this.utils.isObject(a))throw new g(d+"scope: Must be an object!");if(!this.utils.isString(b))throw new g(d+"expr: Must be a string!");if(!this.definitions[c])throw new this.errors.NER(d+c);if(!this.utils.isObject(e))throw new g(d+"params: Must be an object!");var h=this;try{return a.$watch(function(){return h.lastModified(c)},function(){var d=h.filter(c,e);h.utils.set(a,b,d),f&&f(null,d)})}catch(i){if(!f)throw i;f(i)}}var d="DS.bindAll(scope, expr, resourceName, params[, cb]): ";b.exports=c},{}],45:[function(a,b){function c(a,b,c,e,f){var g=this.errors.IA;if(!this.utils.isObject(a))throw new g(d+"scope: Must be an object!");if(!this.utils.isString(b))throw new g(d+"expr: Must be a string!");if(!this.definitions[c])throw new this.errors.NER(d+c);if(!this.utils.isString(e)&&!this.utils.isNumber(e))throw new g(d+"id: Must be a string or a number!");var h=this;try{return a.$watch(function(){return h.lastModified(c,e)},function(){var d=h.get(c,e);h.utils.set(a,b,d),f&&f(null,d)})}catch(i){if(!f)throw i;f(i)}}var d="DS.bindOne(scope, expr, resourceName, id[, cb]): ";b.exports=c},{}],46:[function(a,b){function c(a,b){if(!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IA(d+"id: Must be a string or a number!");var c=this.get(a,b);return c?(this.store[a].observers[b].deliver(),this.utils.diffObjectFromOldObject(c,this.store[a].previousAttributes[b])):void 0}var d="DS.changes(resourceName, id): ";b.exports=c},{}],47:[function(require,module,exports){function Resource(a,b){a.deepMixIn(this,b),this.endpoint="endpoint"in b?b.endpoint:this.name}function defineResource(definition){var IA=this.errors.IA;if(this.utils.isString(definition)&&(definition={name:definition}),!this.utils.isObject(definition))throw new IA(errorPrefix+"definition: Must be an object!");if(!this.utils.isString(definition.name))throw new IA(errorPrefix+"definition.name: Must be a string!");if(definition.idAttribute&&!this.utils.isString(definition.idAttribute))throw new IA(errorPrefix+"definition.idAttribute: Must be a string!");if(definition.endpoint&&!this.utils.isString(definition.endpoint))throw new IA(errorPrefix+"definition.endpoint: Must be a string!");if(this.store[definition.name])throw new this.errors.R(errorPrefix+definition.name+" is already registered!");try{Resource.prototype=this.defaults,this.definitions[definition.name]=new Resource(this.utils,definition);var _this=this,def=this.definitions[definition.name],cache=this.cacheFactory("DS."+def.name,{maxAge:def.maxAge||null,recycleFreq:def.recycleFreq||1e3,cacheFlushInterval:def.cacheFlushInterval||null,deleteOnExpire:def.deleteOnExpire||"none",onExpire:function(a){_this.eject(def.name,a)},capacity:Number.MAX_VALUE,storageMode:"memory",storageImpl:null,disabled:!1,storagePrefix:"DS."+def.name});def.methods&&(def.class=definition.name[0].toUpperCase()+definition.name.substring(1),eval("function "+def.class+"() {}"),def[def.class]=eval(def.class),this.utils.deepMixIn(def[def.class].prototype,def.methods)),def.computed&&this.utils.forOwn(def.computed,function(a,b){def.methods&&b in def.methods&&_this.$log.warn(errorPrefix+'Computed property "'+b+'" conflicts with previously defined prototype method!');var c=a.toString().match(/function.*?\(([\s\S]*?)\)/),d=c[1].split(",");a.deps=_this.utils.filter(d,function(a){return!!a}),angular.forEach(a.deps,function(b,c){a.deps[c]=b.trim()})}),this.store[def.name]={collection:[],completedQueries:{},pendingQueries:{},index:cache,modified:{},saved:{},previousAttributes:{},observers:{},collectionModified:0}}catch(err){throw delete this.definitions[definition.name],delete this.store[definition.name],err}}var errorPrefix="DS.defineResource(definition): ";module.exports=defineResource},{}],48:[function(a,b){function c(){this.$rootScope.$$phase?d.Platform.performMicrotaskCheckpoint():this.$rootScope.$apply(function(){d.Platform.performMicrotaskCheckpoint()})}var d=a("../../../lib/observe-js/observe-js");b.exports=c},{"../../../lib/observe-js/observe-js":1}],49:[function(a,b){function c(a,b,c){for(var d=!1,e=0;e<b.collection.length;e++)if(b.collection[e][a.idAttribute]==c){d=!0;break}d&&(b.collection.splice(e,1),b.observers[c].close(),delete b.observers[c],b.index.remove(c),delete b.previousAttributes[c],delete b.modified[c],delete b.saved[c])}function d(a,b){if(!this.definitions[a])throw new this.errors.NER(e+a);if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IA(e+"id: Must be a string or a number!"); | ||
var d=this.store[a],f=this;this.$rootScope.$$phase?(c(f.definitions[a],d,b),d.collectionModified=f.utils.updateTimestamp(d.collectionModified)):this.$rootScope.$apply(function(){c(f.definitions[a],d,b),d.collectionModified=f.utils.updateTimestamp(d.collectionModified)}),delete this.store[a].completedQueries[b]}var e="DS.eject(resourceName, id): ";b.exports=d},{}],50:[function(a,b){function c(a,b,c){var d=this.utils.toJson(c),e=this.filter(a.name,c),f=this.utils.toLookup(e,a.idAttribute),g=this;angular.forEach(f,function(b,c){g.eject(a.name,c)}),delete b.completedQueries[d]}function d(a,b){if(b=b||{},!this.definitions[a])throw new this.errors.NER(e+a);if(!this.utils.isObject(b))throw new this.errors.IA(e+"params: Must be an object!");var d=this,f=this.store[a],g=this.utils.toJson(b);delete f.completedQueries[g],this.utils.isEmpty(b)&&(f.completedQueries={}),this.$rootScope.$$phase?(c.apply(d,[d.definitions[a],f,b]),f.collectionModified=this.utils.updateTimestamp(f.collectionModified)):this.$rootScope.$apply(function(){c.apply(d,[d.definitions[a],f,b]),f.collectionModified=d.utils.updateTimestamp(f.collectionModified)})}var e="DS.ejectAll(resourceName[, params]): ";b.exports=d},{}],51:[function(a,b){function c(a,b,c){var e=this.errors.IA;if(c=c||{},!this.definitions[a])throw new this.errors.NER(d+a);if(b&&!this.utils.isObject(b))throw new e(d+"params: Must be an object!");if(!this.utils.isObject(c))throw new e(d+"options: Must be an object!");var f=this.definitions[a],g=this.store[a];b=b||{},c.allowSimpleWhere="allowSimpleWhere"in c?!!c.allowSimpleWhere:!0;var h=this.utils.toJson(b);return h in g.completedQueries||!c.loadFromServer||g.pendingQueries[h]||this.findAll(a,b,c),f.filter.call(this,g.collection,a,b,c)}var d="DS.filter(resourceName[, params][, options]): ";b.exports=c},{}],52:[function(a,b){function c(a,b,c){var e=this.errors.IA;if(c=c||{},!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new e(d+"id: Must be a string or a number!");if(!this.utils.isObject(c))throw new e(d+"options: Must be an object!");var f=this,g=this.store[a].index.get(b);return!g&&c.loadFromServer&&this.find(a,b).then(null,function(a){return f.$q.reject(a)}),g}var d="DS.get(resourceName, id[, options]): ";b.exports=c},{}],53:[function(a,b){function c(a,b){return!(a.isEmpty(b.added)&&a.isEmpty(b.removed)&&a.isEmpty(b.changed))}function d(a,b){if(!this.definitions[a])throw new this.errors.NER(e+a);if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IA(e+"id: Must be a string or a number!");return this.get(a,b)?c(this.utils,this.changes(a,b)):!1}var e="DS.hasChanges(resourceName, id): ";b.exports=d},{}],54:[function(a,b){b.exports={defineResource:a("./defineResource"),bindOne:a("./bindOne"),bindAll:a("./bindAll"),eject:a("./eject"),ejectAll:a("./ejectAll"),filter:a("./filter"),get:a("./get"),inject:a("./inject"),lastModified:a("./lastModified"),lastSaved:a("./lastSaved"),digest:a("./digest"),changes:a("./changes"),previous:a("./previous"),hasChanges:a("./hasChanges")}},{"./bindAll":44,"./bindOne":45,"./changes":46,"./defineResource":47,"./digest":48,"./eject":49,"./ejectAll":50,"./filter":51,"./get":52,"./hasChanges":53,"./inject":55,"./lastModified":56,"./lastSaved":57,"./previous":58}],55:[function(a,b){function c(a,b,d){function e(c,d,e,f){var g=f(a.idAttribute);if(b.modified[g]=i.utils.updateTimestamp(b.modified[g]),b.collectionModified=i.utils.updateTimestamp(b.collectionModified),a.computed){var h=i.get(a.name,g);i.utils.forOwn(a.computed,function(a,b){var c=!1;if(angular.forEach(a.deps,function(a){(a in e||a in d||a in e||!(b in h))&&(c=!0)}),c){var f=[];angular.forEach(a.deps,function(a){f.push(h[a])}),h[b]=a.apply(h,f)}})}a.idAttribute in e&&j.error("Doh! You just changed the primary key of an object! I don't know how to handle this yet, so your data for the \""+a.name+'" resource is now in an undefined (probably broken) state.')}var h,i=this,j=i.$log;if(i.utils.isArray(d)){h=[];for(var k=0;k<d.length;k++)h.push(c.call(i,a,b,d[k]))}else{if(a.computed&&a.computed[a.idAttribute]){var l=[];angular.forEach(a.computed[a.idAttribute].deps,function(a){l.push(d[a])}),d[a.idAttribute]=a.computed[a.idAttribute].apply(d,l)}if(!(a.idAttribute in d))throw new i.errors.R(g+"attrs: Must contain the property specified by `idAttribute`!");try{a.beforeInject(a.name,d);var m=d[a.idAttribute],n=this.get(a.name,m);n?(i.utils.deepMixIn(n,d),"function"==typeof b.index.touch?b.index.touch(m):b.index.put(m,b.index.get(m)),b.observers[m].deliver()):(n=a.class?d instanceof a[a.class]?d:new a[a.class]:{},b.previousAttributes[m]={},i.utils.deepMixIn(n,d),i.utils.deepMixIn(b.previousAttributes[m],d),b.collection.push(n),b.observers[m]=new f.ObjectObserver(n,e),b.index.put(m,n),e({},{},{},function(){return m})),b.saved[m]=i.utils.updateTimestamp(b.saved[m]),a.afterInject(a.name,n),h=n}catch(o){j.error(o),j.error("inject failed!",a.name,d)}}return h}function d(a,b){var c=this;c.utils.forOwn(a.relations,function(a,d){c.utils.forOwn(a,function(a,e){if(c.definitions[e]&&b[a.localField])try{b[a.localField]=c.inject(e,b[a.localField])}catch(f){c.$log.error(g+"Failed to inject "+d+' relation: "'+e+'"!',f)}})})}function e(a,b,e){var f=this.errors.IA;if(e=e||{},!this.definitions[a])throw new this.errors.NER(g+a);if(!this.utils.isObject(b)&&!this.utils.isArray(b))throw new f(g+"attrs: Must be an object or an array!");if(!this.utils.isObject(e))throw new f(g+"options: Must be an object!");var h,i=this.definitions[a],j=this.store[a],k=this;return this.$rootScope.$$phase?h=c.call(k,i,j,b):this.$rootScope.$apply(function(){h=c.call(k,i,j,b)}),i.relations&&d.call(k,i,h),h}var f=a("../../../lib/observe-js/observe-js"),g="DS.inject(resourceName, attrs[, options]): ";b.exports=e},{"../../../lib/observe-js/observe-js":1}],56:[function(a,b){function c(a,b){if(!this.definitions[a])throw new this.errors.NER(d+a);if(b&&!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IA(d+"id: Must be a string or a number!");return b?(b in this.store[a].modified||(this.store[a].modified[b]=0),this.store[a].modified[b]):this.store[a].collectionModified}var d="DS.lastModified(resourceName[, id]): ";b.exports=c},{}],57:[function(a,b){function c(a,b){if(!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IA(d+"id: Must be a string or a number!");return b in this.store[a].saved||(this.store[a].saved[b]=0),this.store[a].saved[b]}var d="DS.lastSaved(resourceName[, id]): ";b.exports=c},{}],58:[function(a,b){function c(a,b){if(!this.definitions[a])throw new this.errors.NER(d+a);if(!this.utils.isString(b)&&!this.utils.isNumber(b))throw new this.errors.IA(d+"id: Must be a string or a number!");return angular.copy(this.store[a].previousAttributes[b])}var d="DS.previous(resourceName, id): ";b.exports=c},{}],59:[function(a,b){function c(a){Error.call(this),"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.type=this.constructor.name,this.message=a||"Illegal Argument!"}function d(a){Error.call(this),"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.type=this.constructor.name,this.message=a||"RuntimeError Error!"}function e(a){Error.call(this),"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.type=this.constructor.name,this.message=(a||"")+" is not a registered resource!"}c.prototype=Object.create(Error.prototype),c.prototype.constructor=c,d.prototype=Object.create(Error.prototype),d.prototype.constructor=d,e.prototype=Object.create(Error.prototype),e.prototype.constructor=e,b.exports=[function(){return{IllegalArgumentError:c,IA:c,RuntimeError:d,R:d,NonexistentResourceError:e,NER:e}}]},{}],60:[function(a){!function(b,c){"use strict";c.module("angular-data.DS",["ng"]).factory("DSUtils",a("./utils")).factory("DSErrors",a("./errors")).provider("DSHttpAdapter",a("./adapters/http")).provider("DSLocalStorageAdapter",a("./adapters/localStorage")).provider("DS",a("./datastore")).config(["$provide",function(a){a.decorator("$q",["$delegate",function(a){return a.promisify=function(a,b){var c=this;return function(){var d=c.defer(),e=Array.prototype.slice.apply(arguments);e.push(function(a,b){a?d.reject(a):d.resolve(b)});try{a.apply(b||this,e)}catch(f){d.reject(f)}return d.promise}},a}])}])}(window,window.angular)},{"./adapters/http":30,"./adapters/localStorage":31,"./datastore":43,"./errors":59,"./utils":61}],61:[function(a,b){b.exports=[function(){return{isString:angular.isString,isArray:angular.isArray,isObject:angular.isObject,isNumber:angular.isNumber,isFunction:angular.isFunction,isEmpty:a("mout/lang/isEmpty"),toJson:angular.toJson,makePath:a("mout/string/makePath"),upperCase:a("mout/string/upperCase"),deepMixIn:a("mout/object/deepMixIn"),forOwn:a("mout/object/forOwn"),pick:a("mout/object/pick"),set:a("mout/object/set"),contains:a("mout/array/contains"),filter:a("mout/array/filter"),toLookup:a("mout/array/toLookup"),slice:a("mout/array/slice"),sort:a("mout/array/sort"),updateTimestamp:function(a){var b="function"==typeof Date.now?Date.now():(new Date).getTime();return a&&a>=b?a+1:b},deepFreeze:function b(a){if("function"==typeof Object.freeze){var c,d;Object.freeze(a);for(d in a)c=a[d],a.hasOwnProperty(d)&&"object"==typeof c&&!Object.isFrozen(c)&&b(c)}},diffObjectFromOldObject:function(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var h in a)h in b||(c[h]=a[h]);return{added:c,removed:d,changed:e}}}}]},{"mout/array/contains":2,"mout/array/filter":3,"mout/array/slice":7,"mout/array/sort":8,"mout/array/toLookup":9,"mout/lang/isEmpty":14,"mout/object/deepMixIn":21,"mout/object/forOwn":23,"mout/object/pick":26,"mout/object/set":27,"mout/string/makePath":28,"mout/string/upperCase":29}]},{},[60]); |
714
Gruntfile.js
@@ -9,375 +9,373 @@ /* | ||
module.exports = function (grunt) { | ||
'use strict'; | ||
'use strict'; | ||
require('load-grunt-tasks')(grunt); | ||
require('time-grunt')(grunt); | ||
require('load-grunt-tasks')(grunt); | ||
require('time-grunt')(grunt); | ||
var dev = process.cwd().indexOf('/home/codetrain/angular-data') === -1, | ||
pkg = grunt.file.readJSON('package.json'); | ||
var dev = process.cwd().indexOf('/home/jdobry/angular-data') === -1, | ||
pkg = grunt.file.readJSON('package.json'); | ||
// Project configuration. | ||
grunt.initConfig({ | ||
pkg: pkg, | ||
clean: { | ||
coverage: ['coverage/'], | ||
dist: ['dist/'], | ||
doc: ['doc/'], | ||
afterDoc: [ | ||
'doc/resources/img/angular.png', | ||
'doc/resources/img/angular_grey.png', | ||
'doc/resources/img/AngularJS-small.png', | ||
'doc/resources/img/docular-small.png', | ||
'doc/resources/img/favicon.ico', | ||
'doc/resources/img/grunt.png', | ||
'doc/resources/img/grunt_grey.png', | ||
'doc/resources/img/node.png', | ||
'doc/resources/img/node_grey.png', | ||
'doc/resources/angular/', | ||
'doc/resources/doc_api_resources/doc_api.js', | ||
'doc/resources/js/docs*.js', | ||
'doc/resources/js/jquery*.js' | ||
] | ||
}, | ||
jshint: { | ||
all: ['Gruntfile.js', 'src/**/*.js', 'test/*.js'], | ||
jshintrc: '.jshintrc' | ||
}, | ||
watch: { | ||
files: ['src/**/*.js'], | ||
tasks: ['build'] | ||
}, | ||
uglify: { | ||
main: { | ||
options: { | ||
banner: '/**\n' + | ||
'* @author Jason Dobry <jason.dobry@gmail.com>\n' + | ||
'* @file angular-data.min.js\n' + | ||
'* @version <%= pkg.version %> - Homepage <http://angular-data.codetrain.io/>\n' + | ||
'* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/>\n' + | ||
'* @license MIT <https://github.com/jmdobry/angular-data/blob/master/LICENSE>\n' + | ||
'*\n' + | ||
'* @overview Data store for Angular.js.\n' + | ||
'*/\n' | ||
}, | ||
files: { | ||
'dist/angular-data.min.js': ['dist/angular-data.js'] | ||
} | ||
}, | ||
scripts: { | ||
files: { | ||
'doc/resources/js/libs.min.js': ['doc/resources/js/libs.js'] | ||
} | ||
} | ||
}, | ||
browserify: { | ||
dist: { | ||
files: { | ||
'dist/angular-data.js': ['src/index.js'] | ||
}, | ||
options: { | ||
alias: [ | ||
'lib/observe-js/observe-js.js:observejs', | ||
'src/errors.js:errors', | ||
'src/utils.js:utils' | ||
], | ||
// TODO: There's got to be a better way to consume observe-js without it polluting the global space | ||
postBundleCB: function (err, src, next) { | ||
if (err) { | ||
next(err); | ||
} | ||
src = src.replace('(typeof global !== \'undefined\' && global ? global : window)', '((exports.Number = { isNaN: window.isNaN }) ? exports : exports)'); | ||
next(err, src); | ||
} | ||
} | ||
} | ||
}, | ||
karma: { | ||
options: { | ||
configFile: './karma.conf.js' | ||
}, | ||
dev: { | ||
browsers: ['Chrome'], | ||
autoWatch: true, | ||
singleRun: false, | ||
exclude: [ | ||
'test/integration/datastore/cacheFactory.test.js' | ||
] | ||
}, | ||
min: { | ||
browsers: ['Firefox', 'PhantomJS'], | ||
options: { | ||
files: [ | ||
'bower_components/angular/angular.js', | ||
'bower_components/angular-mocks/angular-mocks.js', | ||
'bower_components/angular-cache/dist/angular-cache.js', | ||
'dist/angular-data.min.js', | ||
'karma.start.js', | ||
'test/integration/**/*.js' | ||
] | ||
}, | ||
exclude: [ | ||
'test/integration/datastore/cacheFactory.test.js' | ||
] | ||
}, | ||
cacheFactory: { | ||
browsers: ['Firefox', 'PhantomJS'], | ||
options: { | ||
files: [ | ||
'bower_components/angular/angular.js', | ||
'bower_components/angular-mocks/angular-mocks.js', | ||
'dist/angular-data.js', | ||
'karma.start.js', | ||
'test/integration/datastore/cacheFactory.test.js' | ||
] | ||
} | ||
}, | ||
ci: { | ||
browsers: ['Firefox', 'PhantomJS'], | ||
exclude: [ | ||
'test/integration/datastore/cacheFactory.test.js' | ||
] | ||
} | ||
}, | ||
coveralls: { | ||
options: { | ||
coverage_dir: 'coverage' | ||
} | ||
}, | ||
// Project configuration. | ||
grunt.initConfig({ | ||
pkg: pkg, | ||
clean: { | ||
coverage: ['coverage/'], | ||
dist: ['dist/'], | ||
doc: ['doc/'], | ||
afterDoc: [ | ||
'doc/resources/img/angular.png', | ||
'doc/resources/img/angular_grey.png', | ||
'doc/resources/img/AngularJS-small.png', | ||
'doc/resources/img/docular-small.png', | ||
'doc/resources/img/favicon.ico', | ||
'doc/resources/img/grunt.png', | ||
'doc/resources/img/grunt_grey.png', | ||
'doc/resources/img/node.png', | ||
'doc/resources/img/node_grey.png', | ||
'doc/resources/angular/', | ||
'doc/resources/doc_api_resources/doc_api.js', | ||
'doc/resources/js/docs*.js', | ||
'doc/resources/js/jquery*.js' | ||
] | ||
}, | ||
jshint: { | ||
all: ['Gruntfile.js', 'src/**/*.js', 'test/*.js'], | ||
jshintrc: '.jshintrc' | ||
}, | ||
watch: { | ||
files: ['src/**/*.js'], | ||
tasks: ['build'] | ||
}, | ||
uglify: { | ||
main: { | ||
options: { | ||
banner: '/**\n' + | ||
'* @author Jason Dobry <jason.dobry@gmail.com>\n' + | ||
'* @file angular-data.min.js\n' + | ||
'* @version <%= pkg.version %> - Homepage <http://angular-data.pseudobry.com/>\n' + | ||
'* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/>\n' + | ||
'* @license MIT <https://github.com/jmdobry/angular-data/blob/master/LICENSE>\n' + | ||
'*\n' + | ||
'* @overview Data store for Angular.js.\n' + | ||
'*/\n' | ||
}, | ||
files: { | ||
'dist/angular-data.min.js': ['dist/angular-data.js'] | ||
} | ||
}, | ||
scripts: { | ||
files: { | ||
'doc/resources/js/libs.min.js': ['doc/resources/js/libs.js'] | ||
} | ||
} | ||
}, | ||
browserify: { | ||
dist: { | ||
files: { | ||
'dist/angular-data.js': ['src/index.js'] | ||
}, | ||
options: { | ||
// TODO: There's got to be a better way to consume observe-js without it polluting the global space | ||
postBundleCB: function (err, src, next) { | ||
if (err) { | ||
next(err); | ||
} | ||
src = src.replace('(typeof global !== \'undefined\' && global ? global : window)', '((exports.Number = { isNaN: window.isNaN }) ? exports : exports)'); | ||
next(err, src); | ||
} | ||
} | ||
} | ||
}, | ||
karma: { | ||
options: { | ||
configFile: './karma.conf.js' | ||
}, | ||
dev: { | ||
browsers: ['Chrome'], | ||
autoWatch: true, | ||
singleRun: false, | ||
reporters: ['spec'], | ||
preprocessors: {}, | ||
exclude: [ | ||
'test/integration/datastore/cacheFactory.test.js' | ||
] | ||
}, | ||
min: { | ||
browsers: ['Firefox', 'PhantomJS'], | ||
options: { | ||
files: [ | ||
'bower_components/angular/angular.js', | ||
'bower_components/angular-mocks/angular-mocks.js', | ||
'bower_components/angular-cache/dist/angular-cache.js', | ||
'dist/angular-data.min.js', | ||
'karma.start.js', | ||
'test/integration/**/*.js' | ||
] | ||
}, | ||
exclude: [ | ||
'test/integration/datastore/cacheFactory.test.js' | ||
] | ||
}, | ||
cacheFactory: { | ||
browsers: ['Firefox', 'PhantomJS'], | ||
options: { | ||
files: [ | ||
'bower_components/angular/angular.js', | ||
'bower_components/angular-mocks/angular-mocks.js', | ||
'dist/angular-data.js', | ||
'karma.start.js', | ||
'test/integration/datastore/cacheFactory.test.js' | ||
] | ||
} | ||
}, | ||
ci: { | ||
browsers: ['Firefox', 'PhantomJS'], | ||
exclude: [ | ||
'test/integration/datastore/cacheFactory.test.js' | ||
] | ||
} | ||
}, | ||
coveralls: { | ||
options: { | ||
coverage_dir: 'coverage' | ||
} | ||
}, | ||
concat: { | ||
libs: { | ||
src: [ | ||
'doc/resources/js/jquery.js', | ||
'doc/resources/js/jquery.goto.js', | ||
'doc/resources/js/jquery.cookie.js', | ||
'doc/resources/angular/angular.js', | ||
'doc/resources/angular/angular-bootstrap.js', | ||
'doc/resources/angular/angular-bootstrap-prettify.js', | ||
'doc/resources/angular/angular-cookies.js', | ||
'doc/resources/angular/angular-resource.js', | ||
'doc/resources/angular/angular-sanitize.js' | ||
concat: { | ||
libs: { | ||
src: [ | ||
'doc/resources/js/jquery.js', | ||
'doc/resources/js/jquery.goto.js', | ||
'doc/resources/js/jquery.cookie.js', | ||
'doc/resources/angular/angular.js', | ||
'doc/resources/angular/angular-bootstrap.js', | ||
'doc/resources/angular/angular-bootstrap-prettify.js', | ||
'doc/resources/angular/angular-cookies.js', | ||
'doc/resources/angular/angular-resource.js', | ||
'doc/resources/angular/angular-sanitize.js' | ||
], | ||
dest: 'doc/resources/js/libs.js' | ||
}, | ||
scripts: { | ||
src: [ | ||
'doc/resources/js/docs_module_begin.js', | ||
'guide/angular-data.js', | ||
'doc/resources/doc_api_resources/doc_api.js', | ||
'doc/resources/js/docs_module_end.js', | ||
'doc/documentation/docs-metadata.js', | ||
'doc/documentation/groups-metadata.js', | ||
'doc/documentation/layout-metadata.js' | ||
], | ||
dest: 'doc/resources/js/libs.js' | ||
}, | ||
scripts: { | ||
src: [ | ||
'doc/resources/js/docs_module_begin.js', | ||
'guide/angular-data.js', | ||
'doc/resources/doc_api_resources/doc_api.js', | ||
'doc/resources/js/docs_module_end.js', | ||
'doc/documentation/docs-metadata.js', | ||
'doc/documentation/groups-metadata.js', | ||
'doc/documentation/layout-metadata.js' | ||
], | ||
dest: 'doc/resources/js/scripts.js' | ||
}, | ||
css: { | ||
src: [ | ||
'doc/resources/css/bootstrap.min.css', | ||
'doc/resources/css/font-awesome.css', | ||
'doc/resources/css/docular.css', | ||
'doc/resources/css/custom.css', | ||
'doc/resources/doc_api_resources/doc_api.css', | ||
'guide/angular-data.css' | ||
], | ||
dest: 'doc/resources/css/styles.css' | ||
} | ||
}, | ||
], | ||
dest: 'doc/resources/js/scripts.js' | ||
}, | ||
css: { | ||
src: [ | ||
'doc/resources/css/bootstrap.min.css', | ||
'doc/resources/css/font-awesome.css', | ||
'doc/resources/css/docular.css', | ||
'doc/resources/css/custom.css', | ||
'doc/resources/doc_api_resources/doc_api.css', | ||
'guide/angular-data.css' | ||
], | ||
dest: 'doc/resources/css/styles.css' | ||
} | ||
}, | ||
copy: { | ||
favicon: { | ||
expand: true, | ||
cwd: 'guide/', | ||
src: 'favicon.ico', | ||
dest: 'doc/', | ||
flatten: true | ||
}, | ||
index: { | ||
expand: true, | ||
cwd: 'guide/', | ||
src: 'index.html', | ||
dest: 'doc/', | ||
flatten: true | ||
}, | ||
data_white: { | ||
expand: true, | ||
cwd: 'guide/', | ||
src: 'data_white.png', | ||
dest: 'doc/resources/img/', | ||
flatten: true | ||
}, | ||
chart: { | ||
expand: true, | ||
cwd: 'guide/', | ||
src: 'chart.png', | ||
dest: 'doc/resources/img/', | ||
flatten: true | ||
}, | ||
cream_dust: { | ||
expand: true, | ||
cwd: 'guide/', | ||
src: 'cream_dust.png', | ||
dest: 'doc/resources/img/', | ||
flatten: true | ||
} | ||
}, | ||
docular: { | ||
groups: [ | ||
{ | ||
groupTitle: 'Guide', | ||
groupId: 'guide', | ||
groupIcon: 'icon-book', | ||
sections: [ | ||
{ | ||
id: 'angular-data', | ||
title: 'angular-data', | ||
docs: [ | ||
'guide/angular-data/index.doc', | ||
'guide/angular-data/overview.doc', | ||
'guide/angular-data/resources.doc', | ||
'guide/angular-data/asynchronous.doc', | ||
'guide/angular-data/synchronous.doc', | ||
'guide/angular-data/queries.doc', | ||
'guide/angular-data/adapters.doc', | ||
'guide/angular-data/how.doc' | ||
], | ||
rank: { | ||
index: 1, | ||
overview: 2, | ||
resources: 3, | ||
asynchronous: 4, | ||
synchronous: 5, | ||
queries: 6, | ||
adapters: 7, | ||
how: 8 | ||
} | ||
}, | ||
{ | ||
id: 'angular-cache', | ||
title: 'angular-cache', | ||
docs: ['guide/angular-cache/'], | ||
rank: { | ||
index: 1, | ||
basics: 2, | ||
configure: 3, | ||
http: 4, | ||
storage: 5 | ||
} | ||
}, | ||
{ | ||
id: 'angular-data-mocks', | ||
title: 'angular-data-mocks', | ||
docs: ['guide/angular-data-mocks/'], | ||
rank: { | ||
index: 1, | ||
overview: 2, | ||
setup: 3, | ||
testing: 4 | ||
} | ||
}, | ||
{ | ||
id: 'angular-data-resource', | ||
title: 'Defining Resources', | ||
docs: ['guide/angular-data/resource/'], | ||
rank: { | ||
index: 1, | ||
overview: 2, | ||
basic: 3, | ||
advanced: 4, | ||
lifecycle: 5, | ||
custom: 6 | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
groupTitle: 'API', | ||
groupId: 'api', | ||
groupIcon: 'icon-wrench', | ||
showSource: true, | ||
sections: [ | ||
{ | ||
id: 'angular-data', | ||
title: 'angular-data', | ||
scripts: [ | ||
'src/' | ||
], | ||
docs: ['guide/api'] | ||
}, | ||
{ | ||
id: 'angular-cache', | ||
title: 'angular-cache', | ||
scripts: [ | ||
'bower_components/angular-cache/dist/angular-cache.js' | ||
], | ||
docs: ['guide/api'] | ||
}, | ||
{ | ||
id: 'angular-data-mocks', | ||
title: 'angular-data-mocks', | ||
scripts: [ | ||
'bower_components/angular-data-mocks/dist/angular-data-mocks.js' | ||
], | ||
docs: ['guide/api'] | ||
} | ||
] | ||
} | ||
], | ||
docular_webapp_target: 'doc', | ||
showDocularDocs: false, | ||
showAngularDocs: false, | ||
docular_partial_home: 'guide/home.html', | ||
docular_partial_navigation: 'guide/nav.html', | ||
docular_partial_footer: 'guide/footer.html', | ||
analytics: { | ||
account: 'UA-46792694-5', | ||
domainName: 'angular-data.codetrain.io' | ||
}, | ||
discussions: { | ||
shortName: 'angular-data', | ||
url: 'http://angular-data.codetrain.io', | ||
dev: dev | ||
} | ||
} | ||
}); | ||
copy: { | ||
favicon: { | ||
expand: true, | ||
cwd: 'guide/', | ||
src: 'favicon.ico', | ||
dest: 'doc/', | ||
flatten: true | ||
}, | ||
index: { | ||
expand: true, | ||
cwd: 'guide/', | ||
src: 'index.html', | ||
dest: 'doc/', | ||
flatten: true | ||
}, | ||
data_white: { | ||
expand: true, | ||
cwd: 'guide/', | ||
src: 'data_white.png', | ||
dest: 'doc/resources/img/', | ||
flatten: true | ||
}, | ||
chart: { | ||
expand: true, | ||
cwd: 'guide/', | ||
src: 'chart.png', | ||
dest: 'doc/resources/img/', | ||
flatten: true | ||
}, | ||
cream_dust: { | ||
expand: true, | ||
cwd: 'guide/', | ||
src: 'cream_dust.png', | ||
dest: 'doc/resources/img/', | ||
flatten: true | ||
} | ||
}, | ||
docular: { | ||
groups: [ | ||
{ | ||
groupTitle: 'Guide', | ||
groupId: 'guide', | ||
groupIcon: 'icon-book', | ||
sections: [ | ||
{ | ||
id: 'angular-data', | ||
title: 'angular-data', | ||
docs: [ | ||
'guide/angular-data/index.md', | ||
'guide/angular-data/overview.md', | ||
'guide/angular-data/resources.md', | ||
'guide/angular-data/asynchronous.md', | ||
'guide/angular-data/synchronous.md', | ||
'guide/angular-data/queries.md', | ||
'guide/angular-data/adapters.md', | ||
'guide/angular-data/how.md' | ||
], | ||
rank: { | ||
index: 1, | ||
overview: 2, | ||
resources: 3, | ||
asynchronous: 4, | ||
synchronous: 5, | ||
queries: 6, | ||
adapters: 7, | ||
how: 8 | ||
} | ||
}, | ||
{ | ||
id: 'angular-cache', | ||
title: 'angular-cache', | ||
docs: ['guide/angular-cache/'], | ||
rank: { | ||
index: 1, | ||
basics: 2, | ||
configure: 3, | ||
http: 4, | ||
storage: 5 | ||
} | ||
}, | ||
{ | ||
id: 'angular-data-mocks', | ||
title: 'angular-data-mocks', | ||
docs: ['guide/angular-data-mocks/'], | ||
rank: { | ||
index: 1, | ||
overview: 2, | ||
setup: 3, | ||
testing: 4 | ||
} | ||
}, | ||
{ | ||
id: 'angular-data-resource', | ||
title: 'Defining Resources', | ||
docs: ['guide/angular-data/resource/'], | ||
rank: { | ||
index: 1, | ||
overview: 2, | ||
basic: 3, | ||
advanced: 4, | ||
lifecycle: 5, | ||
custom: 6, | ||
relations: 7 | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
groupTitle: 'API', | ||
groupId: 'api', | ||
groupIcon: 'icon-wrench', | ||
showSource: true, | ||
sections: [ | ||
{ | ||
id: 'angular-data', | ||
title: 'angular-data', | ||
scripts: [ | ||
'src/' | ||
], | ||
docs: ['guide/api'] | ||
}, | ||
{ | ||
id: 'angular-cache', | ||
title: 'angular-cache', | ||
scripts: [ | ||
'bower_components/angular-cache/dist/angular-cache.js' | ||
], | ||
docs: ['guide/api'] | ||
}, | ||
{ | ||
id: 'angular-data-mocks', | ||
title: 'angular-data-mocks', | ||
scripts: [ | ||
'bower_components/angular-data-mocks/dist/angular-data-mocks.js' | ||
], | ||
docs: ['guide/api'] | ||
} | ||
] | ||
} | ||
], | ||
docular_webapp_target: 'doc', | ||
showDocularDocs: false, | ||
showAngularDocs: false, | ||
docular_partial_home: 'guide/home.html', | ||
docular_partial_navigation: 'guide/nav.html', | ||
docular_partial_footer: 'guide/footer.html', | ||
analytics: { | ||
account: 'UA-34445126-2', | ||
domainName: 'angular-data.pseudobry.com' | ||
}, | ||
discussions: { | ||
shortName: 'angular-data', | ||
url: 'http://angular-data.pseudobry.com', | ||
dev: dev | ||
} | ||
} | ||
}); | ||
grunt.registerTask('version', function (filePath) { | ||
var file = grunt.file.read(filePath); | ||
grunt.registerTask('version', function (filePath) { | ||
var file = grunt.file.read(filePath); | ||
file = file.replace(/<%= pkg\.version %>/gi, pkg.version); | ||
file = file.replace(/<%= pkg\.version %>/gi, pkg.version); | ||
grunt.file.write(filePath, file); | ||
}); | ||
grunt.file.write(filePath, file); | ||
}); | ||
grunt.registerTask('banner', function () { | ||
var file = grunt.file.read('dist/angular-data.js'); | ||
grunt.registerTask('banner', function () { | ||
var file = grunt.file.read('dist/angular-data.js'); | ||
var banner = '/**\n' + | ||
'* @author Jason Dobry <jason.dobry@gmail.com>\n' + | ||
'* @file angular-data.js\n' + | ||
'* @version ' + pkg.version + ' - Homepage <http://angular-data.codetrain.io/>\n' + | ||
'* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/>\n' + | ||
'* @license MIT <https://github.com/jmdobry/angular-data/blob/master/LICENSE>\n' + | ||
'*\n' + | ||
'* @overview Data store for Angular.js.\n' + | ||
'*/\n'; | ||
var banner = '/**\n' + | ||
'* @author Jason Dobry <jason.dobry@gmail.com>\n' + | ||
'* @file angular-data.js\n' + | ||
'* @version ' + pkg.version + ' - Homepage <http://angular-data.pseudobry.com/>\n' + | ||
'* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/>\n' + | ||
'* @license MIT <https://github.com/jmdobry/angular-data/blob/master/LICENSE>\n' + | ||
'*\n' + | ||
'* @overview Data store for Angular.js.\n' + | ||
'*/\n'; | ||
file = banner + file; | ||
file = banner + file; | ||
grunt.file.write('dist/angular-data.js', file); | ||
}); | ||
grunt.file.write('dist/angular-data.js', file); | ||
}); | ||
grunt.registerTask('test', ['build', 'karma:ci', 'karma:cacheFactory', 'karma:min']); | ||
grunt.registerTask('doc', ['clean:doc', 'docular', 'concat', 'copy', 'clean:afterDoc', 'uglify:scripts']); | ||
grunt.registerTask('build', [ | ||
'clean', | ||
'jshint', | ||
'browserify', | ||
'banner', | ||
'uglify:main' | ||
]); | ||
grunt.registerTask('go', ['build', 'watch']); | ||
grunt.registerTask('default', ['build']); | ||
grunt.registerTask('test', ['build', 'karma:ci', 'karma:cacheFactory', 'karma:min']); | ||
grunt.registerTask('doc', ['clean:doc', 'docular', 'concat', 'copy', 'clean:afterDoc', 'uglify:scripts']); | ||
grunt.registerTask('build', [ | ||
'clean', | ||
'jshint', | ||
'browserify', | ||
'banner', | ||
'uglify:main' | ||
]); | ||
grunt.registerTask('go', ['build', 'watch']); | ||
grunt.registerTask('default', ['build']); | ||
}; |
{ | ||
"name": "angular-data", | ||
"description": "Data store for Angular.js.", | ||
"version": "0.9.0", | ||
"homepage": "http://angular-data.codetrain.io", | ||
"version": "0.10.0-beta.1", | ||
"homepage": "http://angular-data.pseudobry.com", | ||
"repository": { | ||
@@ -7,0 +7,0 @@ "type": "git", |
@@ -5,4 +5,4 @@ ## angular-data | ||
__Latest Release:__ [0.8.1](http://angular-data.codetrain.io/) | ||
__master:__ [0.9.0](http://angular-data-next.codetrain.io/) | ||
__Latest Release:__ [0.9.1](http://angular-data.pseudobry.com/) | ||
__master:__ [0.9.1](http://angular-data-next.pseudobry.com/) | ||
@@ -9,0 +9,0 @@ Angular-data is in a pre-1.0.0 development stage; the API is fluctuating, not a lot of tests yet, etc. |
@@ -8,421 +8,421 @@ /** | ||
/** | ||
* @doc property | ||
* @id DSHttpAdapterProvider.properties:defaults | ||
* @name defaults | ||
* @description | ||
* Default configuration for this adapter. | ||
* | ||
* Properties: | ||
* | ||
* - `{function}` - `queryTransform` - See [the guide](/documentation/guide/adapters/index). Default: No-op. | ||
*/ | ||
var defaults = this.defaults = { | ||
/** | ||
* @doc property | ||
* @id DSHttpAdapterProvider.properties:defaults.queryTransform | ||
* @name defaults.queryTransform | ||
* @description | ||
* Transform the angular-data query to something your server understands. You might just do this on the server instead. | ||
* | ||
* @param {string} resourceName The name of the resource. | ||
* @param {object} query Response object from `$http()`. | ||
* @returns {*} Returns `query` as-is. | ||
*/ | ||
queryTransform: function (resourceName, query) { | ||
return query; | ||
} | ||
}; | ||
/** | ||
* @doc property | ||
* @id DSHttpAdapterProvider.properties:defaults | ||
* @name defaults | ||
* @description | ||
* Default configuration for this adapter. | ||
* | ||
* Properties: | ||
* | ||
* - `{function}` - `queryTransform` - See [the guide](/documentation/guide/adapters/index). Default: No-op. | ||
*/ | ||
var defaults = this.defaults = { | ||
/** | ||
* @doc property | ||
* @id DSHttpAdapterProvider.properties:defaults.queryTransform | ||
* @name defaults.queryTransform | ||
* @description | ||
* Transform the angular-data query to something your server understands. You might just do this on the server instead. | ||
* | ||
* @param {string} resourceName The name of the resource. | ||
* @param {object} params Params sent through from `$http()`. | ||
* @returns {*} Returns `params` as-is. | ||
*/ | ||
queryTransform: function (resourceName, params) { | ||
return params; | ||
} | ||
}; | ||
this.$get = ['$http', '$log', 'DSUtils', function ($http, $log, DSUtils) { | ||
this.$get = ['$http', '$log', 'DSUtils', function ($http, $log, DSUtils) { | ||
/** | ||
* @doc interface | ||
* @id DSHttpAdapter | ||
* @name DSHttpAdapter | ||
* @description | ||
* Default adapter used by angular-data. This adapter uses AJAX and JSON to send/retrieve data to/from a server. | ||
* Developers may provide custom adapters that implement the adapter interface. | ||
*/ | ||
return { | ||
/** | ||
* @doc property | ||
* @id DSHttpAdapter.properties:defaults | ||
* @name defaults | ||
* @description | ||
* Reference to [DSHttpAdapterProvider.defaults](/documentation/api/api/DSHttpAdapterProvider.properties:defaults). | ||
*/ | ||
defaults: defaults, | ||
/** | ||
* @doc interface | ||
* @id DSHttpAdapter | ||
* @name DSHttpAdapter | ||
* @description | ||
* Default adapter used by angular-data. This adapter uses AJAX and JSON to send/retrieve data to/from a server. | ||
* Developers may provide custom adapters that implement the adapter interface. | ||
*/ | ||
return { | ||
/** | ||
* @doc property | ||
* @id DSHttpAdapter.properties:defaults | ||
* @name defaults | ||
* @description | ||
* Reference to [DSHttpAdapterProvider.defaults](/documentation/api/api/DSHttpAdapterProvider.properties:defaults). | ||
*/ | ||
defaults: defaults, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:HTTP | ||
* @name HTTP | ||
* @description | ||
* Wrapper for `$http()`. | ||
* | ||
* ## Signature: | ||
* ```js | ||
* DS.HTTP(config) | ||
* ``` | ||
* | ||
* ## Example: | ||
* | ||
* ```js | ||
* works the same as $http() | ||
* ``` | ||
* | ||
* @param {object} config Configuration for the request. | ||
* @returns {Promise} Promise produced by the `$q` service. | ||
*/ | ||
HTTP: HTTP, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:HTTP | ||
* @name HTTP | ||
* @description | ||
* Wrapper for `$http()`. | ||
* | ||
* ## Signature: | ||
* ```js | ||
* DS.HTTP(config) | ||
* ``` | ||
* | ||
* ## Example: | ||
* | ||
* ```js | ||
* works the same as $http() | ||
* ``` | ||
* | ||
* @param {object} config Configuration for the request. | ||
* @returns {Promise} Promise produced by the `$q` service. | ||
*/ | ||
HTTP: HTTP, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:GET | ||
* @name GET | ||
* @description | ||
* Wrapper for `$http.get()`. | ||
* | ||
* ## Signature: | ||
* ```js | ||
* DS.GET(url[, config]) | ||
* ``` | ||
* | ||
* ## Example: | ||
* | ||
* ```js | ||
* Works the same as $http.get() | ||
* ``` | ||
* | ||
* @param {string} url The url of the request. | ||
* @param {object=} config Configuration for the request. | ||
* @returns {Promise} Promise produced by the `$q` service. | ||
*/ | ||
GET: GET, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:GET | ||
* @name GET | ||
* @description | ||
* Wrapper for `$http.get()`. | ||
* | ||
* ## Signature: | ||
* ```js | ||
* DS.GET(url[, config]) | ||
* ``` | ||
* | ||
* ## Example: | ||
* | ||
* ```js | ||
* Works the same as $http.get() | ||
* ``` | ||
* | ||
* @param {string} url The url of the request. | ||
* @param {object=} config Configuration for the request. | ||
* @returns {Promise} Promise produced by the `$q` service. | ||
*/ | ||
GET: GET, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:POST | ||
* @name POST | ||
* @description | ||
* Wrapper for `$http.post()`. | ||
* | ||
* ## Signature: | ||
* ```js | ||
* DS.POST(url[, attrs][, config]) | ||
* ``` | ||
* | ||
* ## Example: | ||
* | ||
* ```js | ||
* Works the same as $http.post() | ||
* ``` | ||
* | ||
* @param {string} url The url of the request. | ||
* @param {object=} attrs Request payload. | ||
* @param {object=} config Configuration for the request. | ||
* @returns {Promise} Promise produced by the `$q` service. | ||
*/ | ||
POST: POST, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:POST | ||
* @name POST | ||
* @description | ||
* Wrapper for `$http.post()`. | ||
* | ||
* ## Signature: | ||
* ```js | ||
* DS.POST(url[, attrs][, config]) | ||
* ``` | ||
* | ||
* ## Example: | ||
* | ||
* ```js | ||
* Works the same as $http.post() | ||
* ``` | ||
* | ||
* @param {string} url The url of the request. | ||
* @param {object=} attrs Request payload. | ||
* @param {object=} config Configuration for the request. | ||
* @returns {Promise} Promise produced by the `$q` service. | ||
*/ | ||
POST: POST, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:PUT | ||
* @name PUT | ||
* @description | ||
* Wrapper for `$http.put()`. | ||
* | ||
* ## Signature: | ||
* ```js | ||
* DS.PUT(url[, attrs][, config]) | ||
* ``` | ||
* | ||
* ## Example: | ||
* | ||
* ```js | ||
* Works the same as $http.put() | ||
* ``` | ||
* | ||
* @param {string} url The url of the request. | ||
* @param {object=} attrs Request payload. | ||
* @param {object=} config Configuration for the request. | ||
* @returns {Promise} Promise produced by the `$q` service. | ||
*/ | ||
PUT: PUT, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:PUT | ||
* @name PUT | ||
* @description | ||
* Wrapper for `$http.put()`. | ||
* | ||
* ## Signature: | ||
* ```js | ||
* DS.PUT(url[, attrs][, config]) | ||
* ``` | ||
* | ||
* ## Example: | ||
* | ||
* ```js | ||
* Works the same as $http.put() | ||
* ``` | ||
* | ||
* @param {string} url The url of the request. | ||
* @param {object=} attrs Request payload. | ||
* @param {object=} config Configuration for the request. | ||
* @returns {Promise} Promise produced by the `$q` service. | ||
*/ | ||
PUT: PUT, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:DEL | ||
* @name DEL | ||
* @description | ||
* Wrapper for `$http.delete()`. | ||
* | ||
* ## Signature: | ||
* ```js | ||
* DS.DEL(url[, config]) | ||
* ``` | ||
* | ||
* ## Example: | ||
* | ||
* ```js | ||
* Works the same as $http.delete | ||
* ``` | ||
* | ||
* @param {string} url The url of the request. | ||
* @param {object} config Configuration for the request. | ||
* @returns {Promise} Promise produced by the `$q` service. | ||
*/ | ||
DEL: DEL, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:DEL | ||
* @name DEL | ||
* @description | ||
* Wrapper for `$http.delete()`. | ||
* | ||
* ## Signature: | ||
* ```js | ||
* DS.DEL(url[, config]) | ||
* ``` | ||
* | ||
* ## Example: | ||
* | ||
* ```js | ||
* Works the same as $http.delete | ||
* ``` | ||
* | ||
* @param {string} url The url of the request. | ||
* @param {object} config Configuration for the request. | ||
* @returns {Promise} Promise produced by the `$q` service. | ||
*/ | ||
DEL: DEL, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:find | ||
* @name find | ||
* @description | ||
* Retrieve a single entity from the server. | ||
* | ||
* Sends a `GET` request to `:baseUrl/:endpoint/:id`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {string|number} id The primary key of the entity to retrieve. | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.get`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
find: find, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:find | ||
* @name find | ||
* @description | ||
* Retrieve a single entity from the server. | ||
* | ||
* Sends a `GET` request to `:baseUrl/:endpoint/:id`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {string|number} id The primary key of the entity to retrieve. | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.get`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
find: find, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:findAll | ||
* @name findAll | ||
* @description | ||
* Retrieve a collection of entities from the server. | ||
* | ||
* Sends a `GET` request to `:baseUrl/:endpoint`. | ||
* | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {object=} params Search query parameters. See the [query guide](/documentation/guide/queries/index). | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.get`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
findAll: findAll, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:findAll | ||
* @name findAll | ||
* @description | ||
* Retrieve a collection of entities from the server. | ||
* | ||
* Sends a `GET` request to `:baseUrl/:endpoint`. | ||
* | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {object=} params Search query parameters. See the [query guide](/documentation/guide/queries/index). | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.get`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
findAll: findAll, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:findAll | ||
* @name find | ||
* @description | ||
* Create a new entity on the server. | ||
* | ||
* Sends a `POST` request to `:baseUrl/:endpoint`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {object=} params Search query parameters. See the [query guide](/documentation/guide/queries/index). | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.post`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
create: create, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:findAll | ||
* @name find | ||
* @description | ||
* Create a new entity on the server. | ||
* | ||
* Sends a `POST` request to `:baseUrl/:endpoint`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {object=} params Search query parameters. See the [query guide](/documentation/guide/queries/index). | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.post`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
create: create, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:update | ||
* @name update | ||
* @description | ||
* Update an entity on the server. | ||
* | ||
* Sends a `PUT` request to `:baseUrl/:endpoint/:id`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {string|number} id The primary key of the entity to update. | ||
* @param {object} attrs The attributes with which to update the entity. See the [query guide](/documentation/guide/queries/index). | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.put`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
update: update, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:update | ||
* @name update | ||
* @description | ||
* Update an entity on the server. | ||
* | ||
* Sends a `PUT` request to `:baseUrl/:endpoint/:id`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {string|number} id The primary key of the entity to update. | ||
* @param {object} attrs The attributes with which to update the entity. See the [query guide](/documentation/guide/queries/index). | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.put`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
update: update, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:updateAll | ||
* @name updateAll | ||
* @description | ||
* Update a collection of entities on the server. | ||
* | ||
* Sends a `PUT` request to `:baseUrl/:endpoint`. | ||
* | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {object=} params Search query parameters. See the [query guide](/documentation/guide/queries/index). | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.put`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
updateAll: updateAll, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:updateAll | ||
* @name updateAll | ||
* @description | ||
* Update a collection of entities on the server. | ||
* | ||
* Sends a `PUT` request to `:baseUrl/:endpoint`. | ||
* | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {object=} params Search query parameters. See the [query guide](/documentation/guide/queries/index). | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.put`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
updateAll: updateAll, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:destroy | ||
* @name destroy | ||
* @description | ||
* destroy an entity on the server. | ||
* | ||
* Sends a `PUT` request to `:baseUrl/:endpoint/:id`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {string|number} id The primary key of the entity to destroy. | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.delete`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
destroy: destroy, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:destroy | ||
* @name destroy | ||
* @description | ||
* destroy an entity on the server. | ||
* | ||
* Sends a `PUT` request to `:baseUrl/:endpoint/:id`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {string|number} id The primary key of the entity to destroy. | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.delete`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
destroy: destroy, | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:destroyAll | ||
* @name destroyAll | ||
* @description | ||
* Retrieve a collection of entities from the server. | ||
* | ||
* Sends a `DELETE` request to `:baseUrl/:endpoint`. | ||
* | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {object=} params Search query parameters. See the [query guide](/documentation/guide/queries/index). | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.delete`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
destroyAll: destroyAll | ||
}; | ||
/** | ||
* @doc method | ||
* @id DSHttpAdapter.methods:destroyAll | ||
* @name destroyAll | ||
* @description | ||
* Retrieve a collection of entities from the server. | ||
* | ||
* Sends a `DELETE` request to `:baseUrl/:endpoint`. | ||
* | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {object=} params Search query parameters. See the [query guide](/documentation/guide/queries/index). | ||
* @param {object=} options Optional configuration. Refer to the documentation for `$http.delete`. | ||
* @returns {Promise} Promise. | ||
*/ | ||
destroyAll: destroyAll | ||
}; | ||
function HTTP(config) { | ||
var start = new Date().getTime(); | ||
function HTTP(config) { | ||
var start = new Date().getTime(); | ||
return $http(config).then(function (data) { | ||
$log.debug(data.config.method + ' request:' + data.config.url + ' Time taken: ' + (new Date().getTime() - start) + 'ms', arguments); | ||
return data; | ||
}); | ||
} | ||
return $http(config).then(function (data) { | ||
$log.debug(data.config.method + ' request:' + data.config.url + ' Time taken: ' + (new Date().getTime() - start) + 'ms', arguments); | ||
return data; | ||
}); | ||
} | ||
function GET(url, config) { | ||
config = config || {}; | ||
return HTTP(DSUtils.deepMixIn(config, { | ||
url: url, | ||
method: 'GET' | ||
})); | ||
} | ||
function GET(url, config) { | ||
config = config || {}; | ||
return HTTP(DSUtils.deepMixIn(config, { | ||
url: url, | ||
method: 'GET' | ||
})); | ||
} | ||
function POST(url, attrs, config) { | ||
config = config || {}; | ||
return HTTP(DSUtils.deepMixIn(config, { | ||
url: url, | ||
data: attrs, | ||
method: 'POST' | ||
})); | ||
} | ||
function POST(url, attrs, config) { | ||
config = config || {}; | ||
return HTTP(DSUtils.deepMixIn(config, { | ||
url: url, | ||
data: attrs, | ||
method: 'POST' | ||
})); | ||
} | ||
function PUT(url, attrs, config) { | ||
config = config || {}; | ||
return HTTP(DSUtils.deepMixIn(config, { | ||
url: url, | ||
data: attrs, | ||
method: 'PUT' | ||
})); | ||
} | ||
function PUT(url, attrs, config) { | ||
config = config || {}; | ||
return HTTP(DSUtils.deepMixIn(config, { | ||
url: url, | ||
data: attrs, | ||
method: 'PUT' | ||
})); | ||
} | ||
function DEL(url, config) { | ||
config = config || {}; | ||
return this.HTTP(DSUtils.deepMixIn(config, { | ||
url: url, | ||
method: 'DELETE' | ||
})); | ||
} | ||
function DEL(url, config) { | ||
config = config || {}; | ||
return this.HTTP(DSUtils.deepMixIn(config, { | ||
url: url, | ||
method: 'DELETE' | ||
})); | ||
} | ||
function create(resourceConfig, attrs, options) { | ||
options = options || {}; | ||
return this.POST( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint), | ||
attrs, | ||
options | ||
); | ||
} | ||
function create(resourceConfig, attrs, options) { | ||
options = options || {}; | ||
return this.POST( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint), | ||
attrs, | ||
options | ||
); | ||
} | ||
function destroy(resourceConfig, id, options) { | ||
options = options || {}; | ||
return this.DEL( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
options | ||
); | ||
} | ||
function destroy(resourceConfig, id, options) { | ||
options = options || {}; | ||
return this.DEL( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
options | ||
); | ||
} | ||
function destroyAll(resourceConfig, params, options) { | ||
options = options || {}; | ||
options.params = options.params || {}; | ||
if (params) { | ||
params.query = params.query ? defaults.queryTransform(resourceConfig.name, params.query) : params.query; | ||
DSUtils.deepMixIn(options.params, params); | ||
} | ||
return this.DEL( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint), | ||
options | ||
); | ||
} | ||
function destroyAll(resourceConfig, params, options) { | ||
options = options || {}; | ||
options.params = options.params || {}; | ||
if (params) { | ||
params = defaults.queryTransform(resourceConfig.name, params); | ||
DSUtils.deepMixIn(options.params, params); | ||
} | ||
return this.DEL( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint), | ||
options | ||
); | ||
} | ||
function find(resourceConfig, id, options) { | ||
options = options || {}; | ||
return this.GET( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
options | ||
); | ||
} | ||
function find(resourceConfig, id, options) { | ||
options = options || {}; | ||
return this.GET( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
options | ||
); | ||
} | ||
function findAll(resourceConfig, params, options) { | ||
options = options || {}; | ||
options.params = options.params || {}; | ||
if (params) { | ||
params.query = params.query ? defaults.queryTransform(resourceConfig.name, params.query) : params.query; | ||
DSUtils.deepMixIn(options.params, params); | ||
} | ||
return this.GET( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint), | ||
options | ||
); | ||
} | ||
function findAll(resourceConfig, params, options) { | ||
options = options || {}; | ||
options.params = options.params || {}; | ||
if (params) { | ||
params = defaults.queryTransform(resourceConfig.name, params); | ||
DSUtils.deepMixIn(options.params, params); | ||
} | ||
return this.GET( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint), | ||
options | ||
); | ||
} | ||
function update(resourceConfig, id, attrs, options) { | ||
options = options || {}; | ||
return this.PUT( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
attrs, | ||
options | ||
); | ||
} | ||
function update(resourceConfig, id, attrs, options) { | ||
options = options || {}; | ||
return this.PUT( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
attrs, | ||
options | ||
); | ||
} | ||
function updateAll(resourceConfig, attrs, params, options) { | ||
options = options || {}; | ||
options.params = options.params || {}; | ||
if (params) { | ||
params.query = params.query ? defaults.queryTransform(resourceConfig.name, params.query) : params.query; | ||
DSUtils.deepMixIn(options.params, params); | ||
} | ||
return this.PUT( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint), | ||
attrs, | ||
options | ||
); | ||
} | ||
}]; | ||
function updateAll(resourceConfig, attrs, params, options) { | ||
options = options || {}; | ||
options.params = options.params || {}; | ||
if (params) { | ||
params = defaults.queryTransform(resourceConfig.name, params); | ||
DSUtils.deepMixIn(options.params, params); | ||
} | ||
return this.PUT( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint), | ||
attrs, | ||
options | ||
); | ||
} | ||
}]; | ||
} | ||
module.exports = DSHttpAdapterProvider; |
@@ -8,177 +8,177 @@ /** | ||
this.$get = ['$q', 'DSUtils', function ($q, DSUtils) { | ||
this.$get = ['$q', 'DSUtils', function ($q, DSUtils) { | ||
/** | ||
* @doc interface | ||
* @id DSLocalStorage | ||
* @name DSLocalStorage | ||
* @description | ||
* Default adapter used by angular-data. This adapter uses AJAX and JSON to send/retrieve data to/from a server. | ||
* Developers may provide custom adapters that implement the adapter interface. | ||
*/ | ||
return { | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:find | ||
* @name find | ||
* @description | ||
* Retrieve a single entity from localStorage. | ||
* | ||
* Calls `localStorage.getItem(key)`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to retrieve. | ||
* @returns {Promise} Promise. | ||
*/ | ||
find: find, | ||
/** | ||
* @doc interface | ||
* @id DSLocalStorage | ||
* @name DSLocalStorage | ||
* @description | ||
* Default adapter used by angular-data. This adapter uses AJAX and JSON to send/retrieve data to/from a server. | ||
* Developers may provide custom adapters that implement the adapter interface. | ||
*/ | ||
return { | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:find | ||
* @name find | ||
* @description | ||
* Retrieve a single entity from localStorage. | ||
* | ||
* Calls `localStorage.getItem(key)`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to retrieve. | ||
* @returns {Promise} Promise. | ||
*/ | ||
find: find, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:findAll | ||
* @name findAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
findAll: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:findAll | ||
* @name findAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
findAll: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:findAll | ||
* @name find | ||
* @description | ||
* Not supported. | ||
*/ | ||
create: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:findAll | ||
* @name find | ||
* @description | ||
* Not supported. | ||
*/ | ||
create: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:update | ||
* @name update | ||
* @description | ||
* Update an entity in localStorage. | ||
* | ||
* Calls `localStorage.setItem(key, value)`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to update. | ||
* @param {object} attrs The attributes with which to update the entity. | ||
* @returns {Promise} Promise. | ||
*/ | ||
update: update, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:update | ||
* @name update | ||
* @description | ||
* Update an entity in localStorage. | ||
* | ||
* Calls `localStorage.setItem(key, value)`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to update. | ||
* @param {object} attrs The attributes with which to update the entity. | ||
* @returns {Promise} Promise. | ||
*/ | ||
update: update, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:updateAll | ||
* @name updateAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
updateAll: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:updateAll | ||
* @name updateAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
updateAll: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:destroy | ||
* @name destroy | ||
* @description | ||
* Destroy an entity from localStorage. | ||
* | ||
* Calls `localStorage.removeItem(key)`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {string|number} id The primary key of the entity to destroy. | ||
* @returns {Promise} Promise. | ||
*/ | ||
destroy: destroy, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:destroy | ||
* @name destroy | ||
* @description | ||
* Destroy an entity from localStorage. | ||
* | ||
* Calls `localStorage.removeItem(key)`. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `endpoint` - Endpoint path for the resource. | ||
* @param {string|number} id The primary key of the entity to destroy. | ||
* @returns {Promise} Promise. | ||
*/ | ||
destroy: destroy, | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:destroyAll | ||
* @name destroyAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
destroyAll: function () { | ||
throw new Error('Not supported!'); | ||
} | ||
}; | ||
/** | ||
* @doc method | ||
* @id DSLocalStorage.methods:destroyAll | ||
* @name destroyAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
destroyAll: function () { | ||
throw new Error('Not supported!'); | ||
} | ||
}; | ||
function GET(key) { | ||
var deferred = $q.defer(); | ||
try { | ||
var item = localStorage.getItem(key); | ||
deferred.resolve(item ? angular.fromJson(item) : undefined); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return deferred.promise; | ||
} | ||
function GET(key) { | ||
var deferred = $q.defer(); | ||
try { | ||
var item = localStorage.getItem(key); | ||
deferred.resolve(item ? angular.fromJson(item) : undefined); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return deferred.promise; | ||
} | ||
function PUT(key, value) { | ||
var deferred = $q.defer(); | ||
try { | ||
var item = localStorage.getItem(key); | ||
if (item) { | ||
item = angular.fromJson(item); | ||
DSUtils.deepMixIn(item, value); | ||
deferred.resolve(localStorage.setItem(key, angular.toJson(item))); | ||
} else { | ||
deferred.resolve(localStorage.setItem(key, angular.toJson(value))); | ||
} | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return deferred.promise; | ||
} | ||
function PUT(key, value) { | ||
var deferred = $q.defer(); | ||
try { | ||
var item = localStorage.getItem(key); | ||
if (item) { | ||
item = angular.fromJson(item); | ||
DSUtils.deepMixIn(item, value); | ||
deferred.resolve(localStorage.setItem(key, angular.toJson(item))); | ||
} else { | ||
deferred.resolve(localStorage.setItem(key, angular.toJson(value))); | ||
} | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return deferred.promise; | ||
} | ||
function DEL(key) { | ||
var deferred = $q.defer(); | ||
try { | ||
deferred.resolve(localStorage.removeItem(key)); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return deferred.promise; | ||
} | ||
function DEL(key) { | ||
var deferred = $q.defer(); | ||
try { | ||
deferred.resolve(localStorage.removeItem(key)); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return deferred.promise; | ||
} | ||
function destroy(resourceConfig, id, options) { | ||
options = options || {}; | ||
return DEL( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
options | ||
); | ||
} | ||
function destroy(resourceConfig, id, options) { | ||
options = options || {}; | ||
return DEL( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
options | ||
); | ||
} | ||
function find(resourceConfig, id, options) { | ||
options = options || {}; | ||
return GET( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
options | ||
); | ||
} | ||
function find(resourceConfig, id, options) { | ||
options = options || {}; | ||
return GET( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
options | ||
); | ||
} | ||
function update(resourceConfig, id, attrs, options) { | ||
options = options || {}; | ||
return PUT( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
attrs, | ||
options | ||
).then(function () { | ||
return GET(DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id)); | ||
}); | ||
} | ||
}]; | ||
function update(resourceConfig, id, attrs, options) { | ||
options = options || {}; | ||
return PUT( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
attrs, | ||
options | ||
).then(function () { | ||
return GET(DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id)); | ||
}); | ||
} | ||
}]; | ||
} | ||
module.exports = DSLocalStorageProvider; |
@@ -42,57 +42,55 @@ var errorPrefix = 'DS.create(resourceName, attrs[, options]): '; | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
*/ | ||
function create(resourceName, attrs, options) { | ||
var deferred = this.$q.defer(), | ||
promise = deferred.promise; | ||
var deferred = this.$q.defer(); | ||
var promise = deferred.promise; | ||
options = options || {}; | ||
try { | ||
options = options || {}; | ||
if (!this.definitions[resourceName]) { | ||
deferred.reject(new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!')); | ||
} else if (!this.utils.isObject(attrs)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'attrs: Must be an object!', { attrs: { actual: typeof attrs, expected: 'object' } })); | ||
} else { | ||
try { | ||
var definition = this.definitions[resourceName], | ||
resource = this.store[resourceName], | ||
_this = this; | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isObject(attrs)) { | ||
throw new this.errors.IA(errorPrefix + 'attrs: Must be an object!'); | ||
} | ||
var definition = this.definitions[resourceName]; | ||
var resource = this.store[resourceName]; | ||
var _this = this; | ||
promise = promise | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.validate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.afterValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeCreate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.adapters[options.adapter || definition.defaultAdapter].create(definition, definition.serialize(resourceName, attrs), options); | ||
}) | ||
.then(function (res) { | ||
return _this.$q.promisify(definition.afterCreate)(resourceName, definition.deserialize(resourceName, res)); | ||
}) | ||
.then(function (data) { | ||
var created = _this.inject(definition.name, data); | ||
var id = created[definition.idAttribute]; | ||
resource.previousAttributes[id] = _this.utils.deepMixIn({}, created); | ||
resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]); | ||
return _this.get(definition.name, id); | ||
}); | ||
promise = promise | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.validate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.afterValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeCreate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.adapters[options.adapter || definition.defaultAdapter].create(definition, definition.serialize(resourceName, attrs), options); | ||
}) | ||
.then(function (res) { | ||
return _this.$q.promisify(definition.afterCreate)(resourceName, definition.deserialize(resourceName, res)); | ||
}) | ||
.then(function (data) { | ||
var created = _this.inject(definition.name, data); | ||
var id = created[definition.idAttribute]; | ||
resource.previousAttributes[id] = _this.utils.deepMixIn({}, created); | ||
resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]); | ||
return _this.get(definition.name, id); | ||
}); | ||
deferred.resolve(attrs); | ||
} catch (err) { | ||
deferred.reject(new this.errors.UnhandledError(err)); | ||
} | ||
} | ||
deferred.resolve(attrs); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return promise; | ||
return promise; | ||
} | ||
module.exports = create; |
@@ -43,44 +43,47 @@ var errorPrefix = 'DS.destroy(resourceName, id): '; | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
*/ | ||
function destroy(resourceName, id, options) { | ||
var deferred = this.$q.defer(), | ||
promise = deferred.promise; | ||
var deferred = this.$q.defer(); | ||
var promise = deferred.promise; | ||
options = options || {}; | ||
try { | ||
options = options || {}; | ||
if (!this.definitions[resourceName]) { | ||
deferred.reject(new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!')); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } })); | ||
} else { | ||
var item = this.get(resourceName, id); | ||
if (!item) { | ||
deferred.reject(new this.errors.RuntimeError(errorPrefix + 'id: "' + id + '" not found!')); | ||
} else { | ||
var definition = this.definitions[resourceName], | ||
resource = this.store[resourceName], | ||
_this = this; | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} | ||
promise = promise | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeDestroy)(resourceName, attrs); | ||
}) | ||
.then(function () { | ||
return _this.adapters[options.adapter || definition.defaultAdapter].destroy(definition, id, options); | ||
}) | ||
.then(function () { | ||
return _this.$q.promisify(definition.afterDestroy)(resourceName, item); | ||
}) | ||
.then(function () { | ||
_this.eject(resourceName, id); | ||
return id; | ||
}); | ||
deferred.resolve(item); | ||
} | ||
} | ||
var item = this.get(resourceName, id); | ||
if (!item) { | ||
throw new this.errors.R(errorPrefix + 'id: "' + id + '" not found!'); | ||
} | ||
return promise; | ||
var definition = this.definitions[resourceName]; | ||
var _this = this; | ||
promise = promise | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeDestroy)(resourceName, attrs); | ||
}) | ||
.then(function () { | ||
return _this.adapters[options.adapter || definition.defaultAdapter].destroy(definition, id, options); | ||
}) | ||
.then(function () { | ||
return _this.$q.promisify(definition.afterDestroy)(resourceName, item); | ||
}) | ||
.then(function () { | ||
_this.eject(resourceName, id); | ||
return id; | ||
}); | ||
deferred.resolve(item); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return promise; | ||
} | ||
module.exports = destroy; |
@@ -19,3 +19,3 @@ var errorPrefix = 'DS.destroyAll(resourceName, params[, options]): '; | ||
* ```js | ||
* var query = { | ||
* var params = { | ||
* where: { | ||
@@ -28,9 +28,5 @@ * author: { | ||
* | ||
* DS.destroyAll('document', { | ||
* query: query | ||
* }).then(function (documents) { | ||
* DS.destroyAll('document', params).then(function (documents) { | ||
* // The documents are gone from the data store | ||
* DS.filter('document', { | ||
* query: query | ||
* }); // [] | ||
* DS.filter('document', params); // [] | ||
* | ||
@@ -45,7 +41,7 @@ * }, function (err) { | ||
* | ||
* - `{object=}` - `query` - The query object by which to filter items of the type specified by `resourceName`. Properties: | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{skip=}` - `skip` - Skip clause. | ||
* - `{orderBy=}` - `orderBy` - OrderBy clause. | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{number=}` - `skip` - Skip clause. | ||
* - `{number=}` - `offset` - Same as skip. | ||
* - `{string|array=}` - `orderBy` - OrderBy clause. | ||
* | ||
@@ -60,38 +56,39 @@ * @param {object=} options Optional configuration. Properties: | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
*/ | ||
function destroyAll(resourceName, params, options) { | ||
var deferred = this.$q.defer(), | ||
promise = deferred.promise, | ||
_this = this; | ||
var deferred = this.$q.defer(); | ||
var promise = deferred.promise; | ||
options = options || {}; | ||
try { | ||
var _this = this; | ||
var IA = this.errors.IA; | ||
if (!this.definitions[resourceName]) { | ||
deferred.reject(new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!')); | ||
} else if (!this.utils.isObject(params)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'params: Must be an object!')); | ||
} else if (!this.utils.isObject(options)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!')); | ||
} else { | ||
try { | ||
var definition = this.definitions[resourceName]; | ||
options = options || {}; | ||
promise = promise | ||
.then(function () { | ||
return _this.adapters[options.adapter || definition.defaultAdapter].destroyAll(definition, params, options); | ||
}) | ||
.then(function () { | ||
return _this.ejectAll(resourceName, params); | ||
}); | ||
deferred.resolve(); | ||
} catch (err) { | ||
deferred.reject(new this.errors.UnhandledError(err)); | ||
} | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isObject(params)) { | ||
throw new IA(errorPrefix + 'params: Must be an object!'); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new IA(errorPrefix + 'options: Must be an object!'); | ||
} | ||
return promise; | ||
var definition = this.definitions[resourceName]; | ||
promise = promise | ||
.then(function () { | ||
return _this.adapters[options.adapter || definition.defaultAdapter].destroyAll(definition, params, options); | ||
}) | ||
.then(function () { | ||
return _this.ejectAll(resourceName, params); | ||
}); | ||
deferred.resolve(); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return promise; | ||
} | ||
module.exports = destroyAll; |
@@ -44,63 +44,65 @@ var errorPrefix = 'DS.find(resourceName, id[, options]): '; | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
*/ | ||
function find(resourceName, id, options) { | ||
var deferred = this.$q.defer(), | ||
promise = deferred.promise; | ||
var deferred = this.$q.defer(); | ||
var promise = deferred.promise; | ||
options = options || {}; | ||
try { | ||
var IA = this.errors.IA; | ||
if (!this.definitions[resourceName]) { | ||
deferred.reject(new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!')); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } })); | ||
} else if (!this.utils.isObject(options)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!', { options: { actual: typeof options, expected: 'object' } })); | ||
} else { | ||
if (!('cacheResponse' in options)) { | ||
options.cacheResponse = true; | ||
} else { | ||
options.cacheResponse = !!options.cacheResponse; | ||
} | ||
try { | ||
var definition = this.definitions[resourceName], | ||
resource = this.store[resourceName], | ||
_this = this; | ||
options = options || {}; | ||
if (options.bypassCache) { | ||
delete resource.completedQueries[id]; | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new IA(errorPrefix + 'options: Must be an object!'); | ||
} | ||
if (!(id in resource.completedQueries)) { | ||
if (!(id in resource.pendingQueries)) { | ||
promise = resource.pendingQueries[id] = _this.adapters[options.adapter || definition.defaultAdapter].find(definition, id, options) | ||
.then(function (res) { | ||
var data = definition.deserialize(resourceName, res); | ||
if (options.cacheResponse) { | ||
// Query is no longer pending | ||
delete resource.pendingQueries[id]; | ||
resource.completedQueries[id] = new Date().getTime(); | ||
return _this.inject(resourceName, data); | ||
} else { | ||
return data; | ||
} | ||
}, function (err) { | ||
delete resource.pendingQueries[id]; | ||
return err; | ||
}); | ||
} | ||
if (!('cacheResponse' in options)) { | ||
options.cacheResponse = true; | ||
} else { | ||
options.cacheResponse = !!options.cacheResponse; | ||
} | ||
return resource.pendingQueries[id]; | ||
} else { | ||
deferred.resolve(_this.get(resourceName, id)); | ||
} | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
} | ||
var definition = this.definitions[resourceName]; | ||
var resource = this.store[resourceName]; | ||
var _this = this; | ||
return promise; | ||
if (options.bypassCache) { | ||
delete resource.completedQueries[id]; | ||
} | ||
if (!(id in resource.completedQueries)) { | ||
if (!(id in resource.pendingQueries)) { | ||
promise = resource.pendingQueries[id] = _this.adapters[options.adapter || definition.defaultAdapter].find(definition, id, options) | ||
.then(function (res) { | ||
var data = definition.deserialize(resourceName, res); | ||
if (options.cacheResponse) { | ||
// Query is no longer pending | ||
delete resource.pendingQueries[id]; | ||
resource.completedQueries[id] = new Date().getTime(); | ||
return _this.inject(resourceName, data); | ||
} else { | ||
return data; | ||
} | ||
}, function (err) { | ||
delete resource.pendingQueries[id]; | ||
return _this.$q.reject(err); | ||
}); | ||
} | ||
return resource.pendingQueries[id]; | ||
} else { | ||
deferred.resolve(_this.get(resourceName, id)); | ||
} | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return promise; | ||
} | ||
module.exports = find; |
var errorPrefix = 'DS.findAll(resourceName, params[, options]): '; | ||
function processResults(utils, data, resourceName, queryHash) { | ||
var resource = this.store[resourceName]; | ||
var resource = this.store[resourceName]; | ||
data = data || []; | ||
data = data || []; | ||
// Query is no longer pending | ||
delete resource.pendingQueries[queryHash]; | ||
resource.completedQueries[queryHash] = new Date().getTime(); | ||
// Query is no longer pending | ||
delete resource.pendingQueries[queryHash]; | ||
resource.completedQueries[queryHash] = new Date().getTime(); | ||
// Merge the new values into the cache | ||
this.inject(resourceName, data); | ||
// Update modified timestamp of collection | ||
resource.collectionModified = utils.updateTimestamp(resource.collectionModified); | ||
// Update modified timestamp of collection | ||
resource.collectionModified = utils.updateTimestamp(resource.collectionModified); | ||
return data; | ||
// Merge the new values into the cache | ||
return this.inject(resourceName, data); | ||
} | ||
function _findAll(utils, resourceName, params, options) { | ||
var definition = this.definitions[resourceName], | ||
resource = this.store[resourceName], | ||
_this = this, | ||
queryHash = utils.toJson(params); | ||
var definition = this.definitions[resourceName], | ||
resource = this.store[resourceName], | ||
_this = this, | ||
queryHash = utils.toJson(params); | ||
if (options.bypassCache) { | ||
delete resource.completedQueries[queryHash]; | ||
} | ||
if (options.bypassCache) { | ||
delete resource.completedQueries[queryHash]; | ||
} | ||
if (!(queryHash in resource.completedQueries)) { | ||
// This particular query has never been completed | ||
if (!(queryHash in resource.completedQueries)) { | ||
// This particular query has never been completed | ||
if (!(queryHash in resource.pendingQueries)) { | ||
if (!(queryHash in resource.pendingQueries)) { | ||
// This particular query has never even been made | ||
resource.pendingQueries[queryHash] = _this.adapters[options.adapter || definition.defaultAdapter].findAll(definition, params, options) | ||
.then(function (res) { | ||
var data = definition.deserialize(resourceName, res); | ||
if (options.cacheResponse) { | ||
try { | ||
return processResults.apply(_this, [utils, data, resourceName, queryHash]); | ||
} catch (err) { | ||
throw new _this.errors.UnhandledError(err); | ||
} | ||
} else { | ||
return data; | ||
} | ||
}, function (err) { | ||
delete resource.pendingQueries[queryHash]; | ||
return err; | ||
}); | ||
} | ||
// This particular query has never even been made | ||
resource.pendingQueries[queryHash] = _this.adapters[options.adapter || definition.defaultAdapter].findAll(definition, params, options) | ||
.then(function (res) { | ||
var data = definition.deserialize(resourceName, res); | ||
if (options.cacheResponse) { | ||
try { | ||
return processResults.apply(_this, [utils, data, resourceName, queryHash]); | ||
} catch (err) { | ||
return _this.$q.reject(err); | ||
} | ||
} else { | ||
return data; | ||
} | ||
}, function (err) { | ||
delete resource.pendingQueries[queryHash]; | ||
return _this.$q.reject(err); | ||
}); | ||
} | ||
return resource.pendingQueries[queryHash]; | ||
} else { | ||
return this.filter(resourceName, params, options); | ||
} | ||
return resource.pendingQueries[queryHash]; | ||
} else { | ||
return this.filter(resourceName, params, options); | ||
} | ||
} | ||
@@ -76,3 +75,3 @@ | ||
* ```js | ||
* var query = { | ||
* var params = { | ||
* where: { | ||
@@ -85,13 +84,9 @@ * author: { | ||
* | ||
* DS.findAll('document', { | ||
* query: query | ||
* }).then(function (documents) { | ||
* documents; // [{ id: 'aab7ff66-e21e-46e2-8be8-264d82aee535', author: 'John Anderson', title: 'How to cook' }, | ||
* // { id: 'ee7f3f4d-98d5-4934-9e5a-6a559b08479f', author: 'John Anderson', title: 'How NOT to cook' }] | ||
* DS.findAll('document', params).then(function (documents) { | ||
* documents; // [{ id: '1', author: 'John Anderson', title: 'How to cook' }, | ||
* // { id: '2', author: 'John Anderson', title: 'How NOT to cook' }] | ||
* | ||
* // The documents are now in the data store | ||
* DS.filter('document', { | ||
* query: query | ||
* }); // [{ id: 'aab7ff66-e21e-46e2-8be8-264d82aee535', author: 'John Anderson', title: 'How to cook' }, | ||
* // { id: 'ee7f3f4d-98d5-4934-9e5a-6a559b08479f', author: 'John Anderson', title: 'How NOT to cook' }] | ||
* DS.filter('document', params); // [{ id: '1', author: 'John Anderson', title: 'How to cook' }, | ||
* // { id: '2', author: 'John Anderson', title: 'How NOT to cook' }] | ||
* | ||
@@ -104,9 +99,9 @@ * }, function (err) { | ||
* @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
* @param {object} params Parameter object that is serialized into the query string. Properties: | ||
* @param {object=} params Parameter object that is serialized into the query string. Properties: | ||
* | ||
* - `{object=}` - `query` - The query object by which to filter items of the type specified by `resourceName`. Properties: | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{skip=}` - `skip` - Skip clause. | ||
* - `{orderBy=}` - `orderBy` - OrderBy clause. | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{number=}` - `skip` - Skip clause. | ||
* - `{number=}` - `offset` - Same as skip. | ||
* - `{string|array=}` - `orderBy` - OrderBy clause. | ||
* | ||
@@ -126,37 +121,40 @@ * @param {object=} options Optional configuration. Properties: | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
*/ | ||
function findAll(resourceName, params, options) { | ||
var deferred = this.$q.defer(), | ||
promise = deferred.promise, | ||
_this = this; | ||
var deferred = this.$q.defer(); | ||
var promise = deferred.promise; | ||
options = options || {}; | ||
try { | ||
var IA = this.errors.IA; | ||
var _this = this; | ||
if (!this.definitions[resourceName]) { | ||
deferred.reject(new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!')); | ||
} else if (!this.utils.isObject(params)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'params: Must be an object!')); | ||
} else if (!this.utils.isObject(options)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!')); | ||
} else { | ||
if (!('cacheResponse' in options)) { | ||
options.cacheResponse = true; | ||
} else { | ||
options.cacheResponse = !!options.cacheResponse; | ||
} | ||
try { | ||
promise = promise.then(function () { | ||
return _findAll.apply(_this, [_this.utils, resourceName, params, options]); | ||
}); | ||
deferred.resolve(); | ||
} catch (err) { | ||
deferred.reject(new this.errors.UnhandledError(err)); | ||
} | ||
} | ||
options = options || {}; | ||
params = params || {}; | ||
return promise; | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isObject(params)) { | ||
throw new IA(errorPrefix + 'params: Must be an object!'); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new IA(errorPrefix + 'options: Must be an object!'); | ||
} | ||
if (!('cacheResponse' in options)) { | ||
options.cacheResponse = true; | ||
} else { | ||
options.cacheResponse = !!options.cacheResponse; | ||
} | ||
promise = promise.then(function () { | ||
return _findAll.apply(_this, [_this.utils, resourceName, params, options]); | ||
}); | ||
deferred.resolve(); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return promise; | ||
} | ||
module.exports = findAll; |
module.exports = { | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:create | ||
* @name create | ||
* @methodOf DS | ||
* @description | ||
* See [DS.create](/documentation/api/api/DS.async_methods:create). | ||
*/ | ||
create: require('./create'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:create | ||
* @name create | ||
* @methodOf DS | ||
* @description | ||
* See [DS.create](/documentation/api/api/DS.async_methods:create). | ||
*/ | ||
create: require('./create'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:destroy | ||
* @name destroy | ||
* @methodOf DS | ||
* @description | ||
* See [DS.destroy](/documentation/api/api/DS.async_methods:destroy). | ||
*/ | ||
destroy: require('./destroy'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:destroy | ||
* @name destroy | ||
* @methodOf DS | ||
* @description | ||
* See [DS.destroy](/documentation/api/api/DS.async_methods:destroy). | ||
*/ | ||
destroy: require('./destroy'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:destroyAll | ||
* @name destroyAll | ||
* @methodOf DS | ||
* @description | ||
* See [DS.destroyAll](/documentation/api/api/DS.async_methods:destroyAll). | ||
*/ | ||
destroyAll: require('./destroyAll'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:destroyAll | ||
* @name destroyAll | ||
* @methodOf DS | ||
* @description | ||
* See [DS.destroyAll](/documentation/api/api/DS.async_methods:destroyAll). | ||
*/ | ||
destroyAll: require('./destroyAll'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:find | ||
* @name find | ||
* @methodOf DS | ||
* @description | ||
* See [DS.find](/documentation/api/api/DS.async_methods:find). | ||
*/ | ||
find: require('./find'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:find | ||
* @name find | ||
* @methodOf DS | ||
* @description | ||
* See [DS.find](/documentation/api/api/DS.async_methods:find). | ||
*/ | ||
find: require('./find'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:findAll | ||
* @name findAll | ||
* @methodOf DS | ||
* @description | ||
* See [DS.findAll](/documentation/api/api/DS.async_methods:findAll). | ||
*/ | ||
findAll: require('./findAll'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:findAll | ||
* @name findAll | ||
* @methodOf DS | ||
* @description | ||
* See [DS.findAll](/documentation/api/api/DS.async_methods:findAll). | ||
*/ | ||
findAll: require('./findAll'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:refresh | ||
* @name refresh | ||
* @methodOf DS | ||
* @description | ||
* See [DS.refresh](/documentation/api/api/DS.async_methods:refresh). | ||
*/ | ||
refresh: require('./refresh'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:loadRelations | ||
* @name loadRelations | ||
* @methodOf DS | ||
* @description | ||
* See [DS.loadRelations](/documentation/api/api/DS.async_methods:loadRelations). | ||
*/ | ||
loadRelations: require('./loadRelations'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:save | ||
* @name save | ||
* @methodOf DS | ||
* @description | ||
* See [DS.save](/documentation/api/api/DS.async_methods:save). | ||
*/ | ||
save: require('./save'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:refresh | ||
* @name refresh | ||
* @methodOf DS | ||
* @description | ||
* See [DS.refresh](/documentation/api/api/DS.async_methods:refresh). | ||
*/ | ||
refresh: require('./refresh'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:update | ||
* @name update | ||
* @methodOf DS | ||
* @description | ||
* See [DS.update](/documentation/api/api/DS.async_methods:update). | ||
*/ | ||
update: require('./update'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:save | ||
* @name save | ||
* @methodOf DS | ||
* @description | ||
* See [DS.save](/documentation/api/api/DS.async_methods:save). | ||
*/ | ||
save: require('./save'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:updateAll | ||
* @name updateAll | ||
* @methodOf DS | ||
* @description | ||
* See [DS.updateAll](/documentation/api/api/DS.async_methods:updateAll). | ||
*/ | ||
updateAll: require('./updateAll') | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:update | ||
* @name update | ||
* @methodOf DS | ||
* @description | ||
* See [DS.update](/documentation/api/api/DS.async_methods:update). | ||
*/ | ||
update: require('./update'), | ||
/** | ||
* @doc method | ||
* @id DS.async_methods:updateAll | ||
* @name updateAll | ||
* @methodOf DS | ||
* @description | ||
* See [DS.updateAll](/documentation/api/api/DS.async_methods:updateAll). | ||
*/ | ||
updateAll: require('./updateAll') | ||
}; |
@@ -34,3 +34,3 @@ var errorPrefix = 'DS.refresh(resourceName, id[, options]): '; | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -50,25 +50,26 @@ * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
*/ | ||
function refresh(resourceName, id, options) { | ||
options = options || {}; | ||
var IA = this.errors.IA; | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } }); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!', { options: { actual: typeof options, expected: 'object' } }); | ||
} else { | ||
options.bypassCache = true; | ||
options = options || {}; | ||
if (this.get(resourceName, id)) { | ||
return this.find(resourceName, id, options); | ||
} else { | ||
return false; | ||
} | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new IA(errorPrefix + 'options: Must be an object!'); | ||
} else { | ||
options.bypassCache = true; | ||
if (this.get(resourceName, id)) { | ||
return this.find(resourceName, id, options); | ||
} else { | ||
return false; | ||
} | ||
} | ||
} | ||
module.exports = refresh; |
@@ -43,76 +43,83 @@ var errorPrefix = 'DS.save(resourceName, id[, options]): '; | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
*/ | ||
function save(resourceName, id, options) { | ||
var deferred = this.$q.defer(), | ||
promise = deferred.promise; | ||
var deferred = this.$q.defer(); | ||
var promise = deferred.promise; | ||
options = options || {}; | ||
try { | ||
var IA = this.errors.IA; | ||
if (!this.definitions[resourceName]) { | ||
deferred.reject(new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!')); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } })); | ||
} else if (!this.utils.isObject(options)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!', { options: { actual: typeof options, expected: 'object' } })); | ||
} else { | ||
var item = this.get(resourceName, id); | ||
if (!item) { | ||
deferred.reject(new this.errors.RuntimeError(errorPrefix + 'id: "' + id + '" not found!')); | ||
} else { | ||
var definition = this.definitions[resourceName], | ||
resource = this.store[resourceName], | ||
_this = this; | ||
options = options || {}; | ||
promise = promise | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.validate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.afterValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeUpdate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
if (options.changesOnly) { | ||
resource.observers[id].deliver(); | ||
var toKeep = [], | ||
changes = _this.changes(resourceName, id); | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new IA(errorPrefix + 'options: Must be an object!'); | ||
} | ||
for (var key in changes.added) { | ||
toKeep.push(key); | ||
} | ||
for (key in changes.changed) { | ||
toKeep.push(key); | ||
} | ||
changes = _this.utils.pick(attrs, toKeep); | ||
if (_this.utils.isEmpty(changes)) { | ||
// no changes, return | ||
return attrs; | ||
} else { | ||
attrs = changes; | ||
} | ||
} | ||
return _this.adapters[options.adapter || definition.defaultAdapter].update(definition, id, definition.serialize(resourceName, attrs), options); | ||
}) | ||
.then(function (res) { | ||
return _this.$q.promisify(definition.afterUpdate)(resourceName, definition.deserialize(resourceName, res)); | ||
}) | ||
.then(function (data) { | ||
_this.inject(definition.name, data, options); | ||
resource.previousAttributes[id] = _this.utils.deepMixIn({}, data); | ||
resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]); | ||
return _this.get(resourceName, id); | ||
}); | ||
var item = this.get(resourceName, id); | ||
if (!item) { | ||
throw new this.errors.R(errorPrefix + 'id: "' + id + '" not found!'); | ||
} | ||
deferred.resolve(item); | ||
} | ||
} | ||
return promise; | ||
var definition = this.definitions[resourceName]; | ||
var resource = this.store[resourceName]; | ||
var _this = this; | ||
promise = promise | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.validate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.afterValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeUpdate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
if (options.changesOnly) { | ||
resource.observers[id].deliver(); | ||
var toKeep = [], | ||
changes = _this.changes(resourceName, id); | ||
for (var key in changes.added) { | ||
toKeep.push(key); | ||
} | ||
for (key in changes.changed) { | ||
toKeep.push(key); | ||
} | ||
changes = _this.utils.pick(attrs, toKeep); | ||
if (_this.utils.isEmpty(changes)) { | ||
// no changes, return | ||
return attrs; | ||
} else { | ||
attrs = changes; | ||
} | ||
} | ||
return _this.adapters[options.adapter || definition.defaultAdapter].update(definition, id, definition.serialize(resourceName, attrs), options); | ||
}) | ||
.then(function (res) { | ||
return _this.$q.promisify(definition.afterUpdate)(resourceName, definition.deserialize(resourceName, res)); | ||
}) | ||
.then(function (data) { | ||
_this.inject(definition.name, data, options); | ||
resource.previousAttributes[id] = _this.utils.deepMixIn({}, data); | ||
resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]); | ||
return _this.get(resourceName, id); | ||
}); | ||
deferred.resolve(item); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return promise; | ||
} | ||
module.exports = save; |
@@ -45,66 +45,72 @@ var errorPrefix = 'DS.update(resourceName, id, attrs[, options]): '; | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
*/ | ||
function update(resourceName, id, attrs, options) { | ||
var deferred = this.$q.defer(), | ||
promise = deferred.promise; | ||
var deferred = this.$q.defer(); | ||
var promise = deferred.promise; | ||
options = options || {}; | ||
try { | ||
var IA = this.errors.IA; | ||
if (!this.definitions[resourceName]) { | ||
deferred.reject(new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!')); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!')); | ||
} else if (!this.utils.isObject(attrs)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'attrs: Must be an object!')); | ||
} else if (!this.utils.isObject(options)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!')); | ||
} else { | ||
var definition = this.definitions[resourceName], | ||
resource = this.store[resourceName], | ||
_this = this; | ||
options = options || {}; | ||
if (!('cacheResponse' in options)) { | ||
options.cacheResponse = true; | ||
} else { | ||
options.cacheResponse = !!options.cacheResponse; | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} else if (!this.utils.isObject(attrs)) { | ||
throw new IA(errorPrefix + 'attrs: Must be an object!'); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new IA(errorPrefix + 'options: Must be an object!'); | ||
} | ||
promise = promise | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.validate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.afterValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeUpdate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.adapters[options.adapter || definition.defaultAdapter].update(definition, id, definition.serialize(resourceName, attrs), options); | ||
}) | ||
.then(function (res) { | ||
return _this.$q.promisify(definition.afterUpdate)(resourceName, definition.deserialize(resourceName, res)); | ||
}) | ||
.then(function (data) { | ||
if (options.cacheResponse) { | ||
var updated = _this.inject(definition.name, data, options); | ||
var id = updated[definition.idAttribute]; | ||
resource.previousAttributes[id] = _this.utils.deepMixIn({}, updated); | ||
resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]); | ||
return _this.get(definition.name, id); | ||
} else { | ||
return data; | ||
} | ||
}); | ||
var definition = this.definitions[resourceName]; | ||
var resource = this.store[resourceName]; | ||
var _this = this; | ||
deferred.resolve(attrs); | ||
} | ||
return promise; | ||
if (!('cacheResponse' in options)) { | ||
options.cacheResponse = true; | ||
} else { | ||
options.cacheResponse = !!options.cacheResponse; | ||
} | ||
promise = promise | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.validate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.afterValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeUpdate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.adapters[options.adapter || definition.defaultAdapter].update(definition, id, definition.serialize(resourceName, attrs), options); | ||
}) | ||
.then(function (res) { | ||
return _this.$q.promisify(definition.afterUpdate)(resourceName, definition.deserialize(resourceName, res)); | ||
}) | ||
.then(function (data) { | ||
if (options.cacheResponse) { | ||
var updated = _this.inject(definition.name, data, options); | ||
var id = updated[definition.idAttribute]; | ||
resource.previousAttributes[id] = _this.utils.deepMixIn({}, updated); | ||
resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]); | ||
return _this.get(definition.name, id); | ||
} else { | ||
return data; | ||
} | ||
}); | ||
deferred.resolve(attrs); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return promise; | ||
} | ||
module.exports = update; |
@@ -23,7 +23,5 @@ var errorPrefix = 'DS.updateAll(resourceName, attrs, params[, options]): '; | ||
* DS.updateAll('document', 5, { author: 'Sally' }, { | ||
* query: { | ||
* where: { | ||
* author: { | ||
* '==': 'John Anderson' | ||
* } | ||
* where: { | ||
* author: { | ||
* '==': 'John Anderson' | ||
* } | ||
@@ -44,7 +42,7 @@ * } | ||
* | ||
* - `{object=}` - `query` - The query object by which to filter items of the type specified by `resourceName`. Properties: | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{skip=}` - `skip` - Skip clause. | ||
* - `{orderBy=}` - `orderBy` - OrderBy clause. | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{number=}` - `skip` - Skip clause. | ||
* - `{number=}` - `offset` - Same as skip. | ||
* - `{string|array=}` - `orderBy` - OrderBy clause. | ||
* | ||
@@ -63,62 +61,67 @@ * @param {object=} options Optional configuration. Properties: | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
*/ | ||
function updateAll(resourceName, attrs, params, options) { | ||
var deferred = this.$q.defer(), | ||
promise = deferred.promise; | ||
var deferred = this.$q.defer(); | ||
var promise = deferred.promise; | ||
options = options || {}; | ||
try { | ||
var IA = this.errors.IA; | ||
if (!this.definitions[resourceName]) { | ||
deferred.reject(new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!')); | ||
} else if (!this.utils.isObject(attrs)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'attrs: Must be an object!')); | ||
} else if (!this.utils.isObject(params)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'params: Must be an object!')); | ||
} else if (!this.utils.isObject(options)) { | ||
deferred.reject(new this.errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!')); | ||
} else { | ||
var definition = this.definitions[resourceName], | ||
resource = this.store[resourceName], | ||
_this = this; | ||
options = options || {}; | ||
if (!('cacheResponse' in options)) { | ||
options.cacheResponse = true; | ||
} else { | ||
options.cacheResponse = !!options.cacheResponse; | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isObject(attrs)) { | ||
throw new IA(errorPrefix + 'attrs: Must be an object!'); | ||
} else if (!this.utils.isObject(params)) { | ||
throw new IA(errorPrefix + 'params: Must be an object!'); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new IA(errorPrefix + 'options: Must be an object!'); | ||
} | ||
promise = promise | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.validate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.afterValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeUpdate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.adapters[options.adapter || definition.defaultAdapter].updateAll(definition, definition.serialize(resourceName, attrs), params, options); | ||
}) | ||
.then(function (res) { | ||
return _this.$q.promisify(definition.afterUpdate)(resourceName, definition.deserialize(resourceName, res)); | ||
}) | ||
.then(function (data) { | ||
if (options.cacheResponse) { | ||
return _this.inject(definition.name, data, options); | ||
} else { | ||
return data; | ||
} | ||
}); | ||
var definition = this.definitions[resourceName]; | ||
var _this = this; | ||
deferred.resolve(attrs); | ||
} | ||
return promise; | ||
if (!('cacheResponse' in options)) { | ||
options.cacheResponse = true; | ||
} else { | ||
options.cacheResponse = !!options.cacheResponse; | ||
} | ||
promise = promise | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.validate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.afterValidate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.$q.promisify(definition.beforeUpdate)(resourceName, attrs); | ||
}) | ||
.then(function (attrs) { | ||
return _this.adapters[options.adapter || definition.defaultAdapter].updateAll(definition, definition.serialize(resourceName, attrs), params, options); | ||
}) | ||
.then(function (res) { | ||
return _this.$q.promisify(definition.afterUpdate)(resourceName, definition.deserialize(resourceName, res)); | ||
}) | ||
.then(function (data) { | ||
if (options.cacheResponse) { | ||
return _this.inject(definition.name, data, options); | ||
} else { | ||
return data; | ||
} | ||
}); | ||
deferred.resolve(attrs); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return promise; | ||
} | ||
module.exports = updateAll; |
var utils = require('../utils')[0](); | ||
function lifecycleNoop(resourceName, attrs, cb) { | ||
cb(null, attrs); | ||
cb(null, attrs); | ||
} | ||
function BaseConfig() { | ||
function Defaults() { | ||
} | ||
BaseConfig.prototype.idAttribute = 'id'; | ||
BaseConfig.prototype.defaultAdapter = 'DSHttpAdapter'; | ||
BaseConfig.prototype.filter = function (resourceName, where, attrs) { | ||
var keep = true; | ||
utils.forOwn(where, function (clause, field) { | ||
if (utils.isString(clause)) { | ||
clause = { | ||
'===': clause | ||
}; | ||
} else if (utils.isNumber(clause)) { | ||
clause = { | ||
'==': clause | ||
}; | ||
} | ||
if ('==' in clause) { | ||
keep = keep && (attrs[field] == clause['==']); | ||
} else if ('===' in clause) { | ||
keep = keep && (attrs[field] === clause['===']); | ||
} else if ('!=' in clause) { | ||
keep = keep && (attrs[field] != clause['!=']); | ||
} else if ('>' in clause) { | ||
keep = keep && (attrs[field] > clause['>']); | ||
} else if ('>=' in clause) { | ||
keep = keep && (attrs[field] >= clause['>=']); | ||
} else if ('<' in clause) { | ||
keep = keep && (attrs[field] < clause['<']); | ||
} else if ('<=' in clause) { | ||
keep = keep && (attrs[field] <= clause['<=']); | ||
} else if ('in' in clause) { | ||
keep = keep && utils.contains(clause['in'], attrs[field]); | ||
} | ||
}); | ||
return keep; | ||
Defaults.prototype.idAttribute = 'id'; | ||
Defaults.prototype.defaultAdapter = 'DSHttpAdapter'; | ||
Defaults.prototype.filter = function (collection, resourceName, params, options) { | ||
var _this = this; | ||
var filtered = collection; | ||
var where = null; | ||
var reserved = { | ||
skip: '', | ||
offset: '', | ||
where: '', | ||
limit: '', | ||
orderBy: '', | ||
sort: '' | ||
}; | ||
if (this.utils.isObject(params.where)) { | ||
where = params.where; | ||
} else { | ||
where = {}; | ||
} | ||
if (options.allowSimpleWhere) { | ||
this.utils.forOwn(params, function (value, key) { | ||
if (!(key in reserved) && !(key in where)) { | ||
where[key] = { | ||
'==': value | ||
}; | ||
} | ||
}); | ||
} | ||
if (this.utils.isEmpty(where)) { | ||
where = null; | ||
} | ||
if (where) { | ||
filtered = this.utils.filter(filtered, function (attrs) { | ||
// console.log(attrs); | ||
var first = true; | ||
var keep = true; | ||
_this.utils.forOwn(where, function (clause, field) { | ||
// console.log(clause, field); | ||
if (_this.utils.isString(clause)) { | ||
clause = { | ||
'===': clause | ||
}; | ||
} else if (_this.utils.isNumber(clause)) { | ||
clause = { | ||
'==': clause | ||
}; | ||
} | ||
if (_this.utils.isObject(clause)) { | ||
_this.utils.forOwn(clause, function (val, op) { | ||
// console.log(op, val); | ||
if (op === '==') { | ||
keep = first ? (attrs[field] == val) : keep && (attrs[field] == val); | ||
} else if (op === '===') { | ||
keep = first ? (attrs[field] === val) : keep && (attrs[field] === val); | ||
} else if (op === '!=') { | ||
keep = first ? (attrs[field] != val) : keep && (attrs[field] != val); | ||
} else if (op === '!==') { | ||
keep = first ? (attrs[field] !== val) : keep && (attrs[field] !== val); | ||
} else if (op === '>') { | ||
keep = first ? (attrs[field] > val) : keep && (attrs[field] > val); | ||
} else if (op === '>=') { | ||
keep = first ? (attrs[field] >= val) : keep && (attrs[field] >= val); | ||
} else if (op === '<') { | ||
keep = first ? (attrs[field] < val) : keep && (attrs[field] < val); | ||
} else if (op === '<=') { | ||
keep = first ? (attrs[field] <= val) : keep && (attrs[field] <= val); | ||
} else if (op === 'in') { | ||
keep = first ? _this.utils.contains(val, attrs[field]) : keep && _this.utils.contains(val, attrs[field]); | ||
} else if (op === '|==') { | ||
keep = first ? (attrs[field] == val) : keep || (attrs[field] == val); | ||
} else if (op === '|===') { | ||
keep = first ? (attrs[field] === val) : keep || (attrs[field] === val); | ||
} else if (op === '|!=') { | ||
keep = first ? (attrs[field] != val) : keep || (attrs[field] != val); | ||
} else if (op === '|!==') { | ||
keep = first ? (attrs[field] !== val) : keep || (attrs[field] !== val); | ||
} else if (op === '|>') { | ||
keep = first ? (attrs[field] > val) : keep || (attrs[field] > val); | ||
} else if (op === '|>=') { | ||
keep = first ? (attrs[field] >= val) : keep || (attrs[field] >= val); | ||
} else if (op === '|<') { | ||
keep = first ? (attrs[field] < val) : keep || (attrs[field] < val); | ||
} else if (op === '|<=') { | ||
keep = first ? (attrs[field] <= val) : keep || (attrs[field] <= val); | ||
} else if (op === '|in') { | ||
keep = first ? _this.utils.contains(val, attrs[field]) : keep || _this.utils.contains(val, attrs[field]); | ||
} | ||
first = false; | ||
// console.log(keep, first); | ||
}); | ||
} | ||
}); | ||
return keep; | ||
}); | ||
} | ||
var orderBy = null; | ||
if (this.utils.isString(params.orderBy)) { | ||
orderBy = [ | ||
[params.orderBy, 'ASC'] | ||
]; | ||
} else if (this.utils.isArray(params.orderBy)) { | ||
orderBy = params.orderBy; | ||
} | ||
if (!orderBy && this.utils.isString(params.sort)) { | ||
orderBy = [ | ||
[params.sort, 'ASC'] | ||
]; | ||
} else if (!orderBy && this.utils.isArray(params.sort)) { | ||
orderBy = params.sort; | ||
} | ||
// Apply 'orderBy' | ||
if (orderBy) { | ||
angular.forEach(orderBy, function (def) { | ||
if (_this.utils.isString(def)) { | ||
def = [def, 'ASC']; | ||
} else if (!_this.utils.isArray(def)) { | ||
throw new _this.errors.IllegalArgumentError('DS.filter(resourceName[, params][, options]): ' + angular.toJson(def) + ': Must be a string or an array!', { params: { 'orderBy[i]': { actual: typeof def, expected: 'string|array' } } }); | ||
} | ||
filtered = _this.utils.sort(filtered, function (a, b) { | ||
var cA = a[def[0]], cB = b[def[0]]; | ||
if (_this.utils.isString(cA)) { | ||
cA = _this.utils.upperCase(cA); | ||
} | ||
if (_this.utils.isString(cB)) { | ||
cB = _this.utils.upperCase(cB); | ||
} | ||
if (def[1] === 'DESC') { | ||
if (cB < cA) { | ||
return -1; | ||
} else if (cB > cA) { | ||
return 1; | ||
} else { | ||
return 0; | ||
} | ||
} else { | ||
if (cA < cB) { | ||
return -1; | ||
} else if (cA > cB) { | ||
return 1; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
var limit = angular.isNumber(params.limit) ? params.limit : null; | ||
var skip = null; | ||
if (angular.isNumber(params.skip)) { | ||
skip = params.skip; | ||
} else if (angular.isNumber(params.offset)) { | ||
skip = params.offset; | ||
} | ||
// Apply 'limit' and 'skip' | ||
if (limit && skip) { | ||
filtered = this.utils.slice(filtered, skip, Math.min(filtered.length, skip + limit)); | ||
} else if (this.utils.isNumber(limit)) { | ||
filtered = this.utils.slice(filtered, 0, Math.min(filtered.length, limit)); | ||
} else if (this.utils.isNumber(skip)) { | ||
if (skip < filtered.length) { | ||
filtered = this.utils.slice(filtered, skip); | ||
} else { | ||
filtered = []; | ||
} | ||
} | ||
return filtered; | ||
}; | ||
BaseConfig.prototype.baseUrl = ''; | ||
BaseConfig.prototype.endpoint = ''; | ||
Defaults.prototype.baseUrl = ''; | ||
Defaults.prototype.endpoint = ''; | ||
/** | ||
@@ -76,3 +221,3 @@ * @doc property | ||
*/ | ||
BaseConfig.prototype.beforeValidate = lifecycleNoop; | ||
Defaults.prototype.beforeValidate = lifecycleNoop; | ||
/** | ||
@@ -108,3 +253,3 @@ * @doc property | ||
*/ | ||
BaseConfig.prototype.validate = lifecycleNoop; | ||
Defaults.prototype.validate = lifecycleNoop; | ||
/** | ||
@@ -140,3 +285,3 @@ * @doc property | ||
*/ | ||
BaseConfig.prototype.afterValidate = lifecycleNoop; | ||
Defaults.prototype.afterValidate = lifecycleNoop; | ||
/** | ||
@@ -172,3 +317,3 @@ * @doc property | ||
*/ | ||
BaseConfig.prototype.beforeCreate = lifecycleNoop; | ||
Defaults.prototype.beforeCreate = lifecycleNoop; | ||
/** | ||
@@ -204,3 +349,3 @@ * @doc property | ||
*/ | ||
BaseConfig.prototype.afterCreate = lifecycleNoop; | ||
Defaults.prototype.afterCreate = lifecycleNoop; | ||
/** | ||
@@ -236,3 +381,3 @@ * @doc property | ||
*/ | ||
BaseConfig.prototype.beforeUpdate = lifecycleNoop; | ||
Defaults.prototype.beforeUpdate = lifecycleNoop; | ||
/** | ||
@@ -268,3 +413,3 @@ * @doc property | ||
*/ | ||
BaseConfig.prototype.afterUpdate = lifecycleNoop; | ||
Defaults.prototype.afterUpdate = lifecycleNoop; | ||
/** | ||
@@ -300,3 +445,3 @@ * @doc property | ||
*/ | ||
BaseConfig.prototype.beforeDestroy = lifecycleNoop; | ||
Defaults.prototype.beforeDestroy = lifecycleNoop; | ||
/** | ||
@@ -332,3 +477,3 @@ * @doc property | ||
*/ | ||
BaseConfig.prototype.afterDestroy = lifecycleNoop; | ||
Defaults.prototype.afterDestroy = lifecycleNoop; | ||
/** | ||
@@ -358,4 +503,4 @@ * @doc property | ||
*/ | ||
BaseConfig.prototype.beforeInject = function (resourceName, attrs) { | ||
return attrs; | ||
Defaults.prototype.beforeInject = function (resourceName, attrs) { | ||
return attrs; | ||
}; | ||
@@ -386,4 +531,4 @@ /** | ||
*/ | ||
BaseConfig.prototype.afterInject = function (resourceName, attrs) { | ||
return attrs; | ||
Defaults.prototype.afterInject = function (resourceName, attrs) { | ||
return attrs; | ||
}; | ||
@@ -411,4 +556,4 @@ /** | ||
*/ | ||
BaseConfig.prototype.serialize = function (resourceName, data) { | ||
return data; | ||
Defaults.prototype.serialize = function (resourceName, data) { | ||
return data; | ||
}; | ||
@@ -435,4 +580,4 @@ | ||
*/ | ||
BaseConfig.prototype.deserialize = function (resourceName, data) { | ||
return data.data; | ||
Defaults.prototype.deserialize = function (resourceName, data) { | ||
return data.data; | ||
}; | ||
@@ -447,145 +592,146 @@ | ||
/** | ||
* @doc property | ||
* @id DSProvider.properties:defaults | ||
* @name defaults | ||
* @description | ||
* See the [configuration guide](/documentation/guide/configure/global). | ||
* | ||
* Properties: | ||
* | ||
* - `{string}` - `baseUrl` - The url relative to which all AJAX requests will be made. | ||
* - `{string}` - `idAttribute` - Default: `"id"` - The attribute that specifies the primary key for resources. | ||
* - `{string}` - `defaultAdapter` - Default: `"DSHttpAdapter"` | ||
* - `{function}` - `filter` - Default: See [angular-data query language](/documentation/guide/queries/custom). | ||
* - `{function}` - `beforeValidate` - See [DSProvider.defaults.beforeValidate](/documentation/api/angular-data/DSProvider.properties:defaults.beforeValidate). Default: No-op | ||
* - `{function}` - `validate` - See [DSProvider.defaults.validate](/documentation/api/angular-data/DSProvider.properties:defaults.validate). Default: No-op | ||
* - `{function}` - `afterValidate` - See [DSProvider.defaults.afterValidate](/documentation/api/angular-data/DSProvider.properties:defaults.afterValidate). Default: No-op | ||
* - `{function}` - `beforeCreate` - See [DSProvider.defaults.beforeCreate](/documentation/api/angular-data/DSProvider.properties:defaults.beforeCreate). Default: No-op | ||
* - `{function}` - `afterCreate` - See [DSProvider.defaults.afterCreate](/documentation/api/angular-data/DSProvider.properties:defaults.afterCreate). Default: No-op | ||
* - `{function}` - `beforeUpdate` - See [DSProvider.defaults.beforeUpdate](/documentation/api/angular-data/DSProvider.properties:defaults.beforeUpdate). Default: No-op | ||
* - `{function}` - `afterUpdate` - See [DSProvider.defaults.afterUpdate](/documentation/api/angular-data/DSProvider.properties:defaults.afterUpdate). Default: No-op | ||
* - `{function}` - `beforeDestroy` - See [DSProvider.defaults.beforeDestroy](/documentation/api/angular-data/DSProvider.properties:defaults.beforeDestroy). Default: No-op | ||
* - `{function}` - `afterDestroy` - See [DSProvider.defaults.afterDestroy](/documentation/api/angular-data/DSProvider.properties:defaults.afterDestroy). Default: No-op | ||
* - `{function}` - `afterInject` - See [DSProvider.defaults.afterInject](/documentation/api/angular-data/DSProvider.properties:defaults.afterInject). Default: No-op | ||
* - `{function}` - `beforeInject` - See [DSProvider.defaults.beforeInject](/documentation/api/angular-data/DSProvider.properties:defaults.beforeInject). Default: No-op | ||
* - `{function}` - `serialize` - See [DSProvider.defaults.serialize](/documentation/api/angular-data/DSProvider.properties:defaults.serialize). Default: No-op | ||
* - `{function}` - `deserialize` - See [DSProvider.defaults.deserialize](/documentation/api/angular-data/DSProvider.properties:defaults.deserialize). Default: No-op | ||
*/ | ||
var defaults = this.defaults = new BaseConfig(); | ||
/** | ||
* @doc property | ||
* @id DSProvider.properties:defaults | ||
* @name defaults | ||
* @description | ||
* See the [configuration guide](/documentation/guide/configure/global). | ||
* | ||
* Properties: | ||
* | ||
* - `{string}` - `baseUrl` - The url relative to which all AJAX requests will be made. | ||
* - `{string}` - `idAttribute` - Default: `"id"` - The attribute that specifies the primary key for resources. | ||
* - `{string}` - `defaultAdapter` - Default: `"DSHttpAdapter"` | ||
* - `{function}` - `filter` - Default: See [angular-data query language](/documentation/guide/queries/custom). | ||
* - `{function}` - `beforeValidate` - See [DSProvider.defaults.beforeValidate](/documentation/api/angular-data/DSProvider.properties:defaults.beforeValidate). Default: No-op | ||
* - `{function}` - `validate` - See [DSProvider.defaults.validate](/documentation/api/angular-data/DSProvider.properties:defaults.validate). Default: No-op | ||
* - `{function}` - `afterValidate` - See [DSProvider.defaults.afterValidate](/documentation/api/angular-data/DSProvider.properties:defaults.afterValidate). Default: No-op | ||
* - `{function}` - `beforeCreate` - See [DSProvider.defaults.beforeCreate](/documentation/api/angular-data/DSProvider.properties:defaults.beforeCreate). Default: No-op | ||
* - `{function}` - `afterCreate` - See [DSProvider.defaults.afterCreate](/documentation/api/angular-data/DSProvider.properties:defaults.afterCreate). Default: No-op | ||
* - `{function}` - `beforeUpdate` - See [DSProvider.defaults.beforeUpdate](/documentation/api/angular-data/DSProvider.properties:defaults.beforeUpdate). Default: No-op | ||
* - `{function}` - `afterUpdate` - See [DSProvider.defaults.afterUpdate](/documentation/api/angular-data/DSProvider.properties:defaults.afterUpdate). Default: No-op | ||
* - `{function}` - `beforeDestroy` - See [DSProvider.defaults.beforeDestroy](/documentation/api/angular-data/DSProvider.properties:defaults.beforeDestroy). Default: No-op | ||
* - `{function}` - `afterDestroy` - See [DSProvider.defaults.afterDestroy](/documentation/api/angular-data/DSProvider.properties:defaults.afterDestroy). Default: No-op | ||
* - `{function}` - `afterInject` - See [DSProvider.defaults.afterInject](/documentation/api/angular-data/DSProvider.properties:defaults.afterInject). Default: No-op | ||
* - `{function}` - `beforeInject` - See [DSProvider.defaults.beforeInject](/documentation/api/angular-data/DSProvider.properties:defaults.beforeInject). Default: No-op | ||
* - `{function}` - `serialize` - See [DSProvider.defaults.serialize](/documentation/api/angular-data/DSProvider.properties:defaults.serialize). Default: No-op | ||
* - `{function}` - `deserialize` - See [DSProvider.defaults.deserialize](/documentation/api/angular-data/DSProvider.properties:defaults.deserialize). Default: No-op | ||
*/ | ||
var defaults = this.defaults = new Defaults(); | ||
this.$get = [ | ||
'$rootScope', '$log', '$q', 'DSHttpAdapter', 'DSLocalStorageAdapter', 'DSUtils', 'DSErrors', | ||
function ($rootScope, $log, $q, DSHttpAdapter, DSLocalStorageAdapter, DSUtils, DSErrors) { | ||
this.$get = [ | ||
'$rootScope', '$log', '$q', 'DSHttpAdapter', 'DSLocalStorageAdapter', 'DSUtils', 'DSErrors', | ||
function ($rootScope, $log, $q, DSHttpAdapter, DSLocalStorageAdapter, DSUtils, DSErrors) { | ||
var syncMethods = require('./sync_methods'), | ||
asyncMethods = require('./async_methods'), | ||
cache; | ||
var syncMethods = require('./sync_methods'), | ||
asyncMethods = require('./async_methods'), | ||
cache; | ||
try { | ||
cache = angular.injector(['angular-data.DSCacheFactory']).get('DSCacheFactory'); | ||
} catch (err) { | ||
$log.warn(err); | ||
$log.warn('DSCacheFactory is unavailable. Resorting to the lesser capabilities of $cacheFactory.'); | ||
cache = angular.injector(['ng']).get('$cacheFactory'); | ||
} | ||
try { | ||
cache = angular.injector(['angular-data.DSCacheFactory']).get('DSCacheFactory'); | ||
} catch (err) { | ||
$log.warn(err); | ||
$log.warn('DSCacheFactory is unavailable. Resorting to the lesser capabilities of $cacheFactory.'); | ||
cache = angular.injector(['ng']).get('$cacheFactory'); | ||
} | ||
/** | ||
* @doc interface | ||
* @id DS | ||
* @name DS | ||
* @description | ||
* Public data store interface. Consists of several properties and a number of methods. Injectable as `DS`. | ||
* | ||
* See the [guide](/documentation/guide/overview/index). | ||
*/ | ||
var DS = { | ||
$rootScope: $rootScope, | ||
$log: $log, | ||
$q: $q, | ||
/** | ||
* @doc interface | ||
* @id DS | ||
* @name DS | ||
* @description | ||
* Public data store interface. Consists of several properties and a number of methods. Injectable as `DS`. | ||
* | ||
* See the [guide](/documentation/guide/overview/index). | ||
*/ | ||
var DS = { | ||
$rootScope: $rootScope, | ||
$log: $log, | ||
$q: $q, | ||
cacheFactory: cache, | ||
cacheFactory: cache, | ||
/** | ||
* @doc property | ||
* @id DS.properties:defaults | ||
* @name defaults | ||
* @description | ||
* Reference to [DSProvider.defaults](/documentation/api/api/DSProvider.properties:defaults). | ||
*/ | ||
defaults: defaults, | ||
/** | ||
* @doc property | ||
* @id DS.properties:defaults | ||
* @name defaults | ||
* @description | ||
* Reference to [DSProvider.defaults](/documentation/api/api/DSProvider.properties:defaults). | ||
*/ | ||
defaults: defaults, | ||
/*! | ||
* @doc property | ||
* @id DS.properties:store | ||
* @name store | ||
* @description | ||
* Meta data for each registered resource. | ||
*/ | ||
store: {}, | ||
/*! | ||
* @doc property | ||
* @id DS.properties:store | ||
* @name store | ||
* @description | ||
* Meta data for each registered resource. | ||
*/ | ||
store: {}, | ||
/*! | ||
* @doc property | ||
* @id DS.properties:definitions | ||
* @name definitions | ||
* @description | ||
* Registered resource definitions available to the data store. | ||
*/ | ||
definitions: {}, | ||
/*! | ||
* @doc property | ||
* @id DS.properties:definitions | ||
* @name definitions | ||
* @description | ||
* Registered resource definitions available to the data store. | ||
*/ | ||
definitions: {}, | ||
/** | ||
* @doc property | ||
* @id DS.properties:adapters | ||
* @name adapters | ||
* @description | ||
* Registered adapters available to the data store. Object consists of key-values pairs where the key is | ||
* the name of the adapter and the value is the adapter itself. | ||
*/ | ||
adapters: { | ||
DSHttpAdapter: DSHttpAdapter, | ||
DSLocalStorageAdapter: DSLocalStorageAdapter | ||
}, | ||
/** | ||
* @doc property | ||
* @id DS.properties:adapters | ||
* @name adapters | ||
* @description | ||
* Registered adapters available to the data store. Object consists of key-values pairs where the key is | ||
* the name of the adapter and the value is the adapter itself. | ||
*/ | ||
adapters: { | ||
DSHttpAdapter: DSHttpAdapter, | ||
DSLocalStorageAdapter: DSLocalStorageAdapter | ||
}, | ||
/** | ||
* @doc property | ||
* @id DS.properties:errors | ||
* @name errors | ||
* @description | ||
* References to the various [error types](/documentation/api/api/errors) used by angular-data. | ||
*/ | ||
errors: DSErrors, | ||
/** | ||
* @doc property | ||
* @id DS.properties:errors | ||
* @name errors | ||
* @description | ||
* References to the various [error types](/documentation/api/api/errors) used by angular-data. | ||
*/ | ||
errors: DSErrors, | ||
/*! | ||
* @doc property | ||
* @id DS.properties:utils | ||
* @name utils | ||
* @description | ||
* Utility functions used internally by angular-data. | ||
*/ | ||
utils: DSUtils | ||
}; | ||
/*! | ||
* @doc property | ||
* @id DS.properties:utils | ||
* @name utils | ||
* @description | ||
* Utility functions used internally by angular-data. | ||
*/ | ||
utils: DSUtils | ||
}; | ||
DSUtils.deepFreeze(syncMethods); | ||
DSUtils.deepFreeze(asyncMethods); | ||
DSUtils.deepFreeze(syncMethods); | ||
DSUtils.deepFreeze(asyncMethods); | ||
DSUtils.deepMixIn(DS, syncMethods); | ||
DSUtils.deepMixIn(DS, asyncMethods); | ||
DSUtils.deepMixIn(DS, syncMethods); | ||
DSUtils.deepMixIn(DS, asyncMethods); | ||
DSUtils.deepFreeze(DS.errors); | ||
DSUtils.deepFreeze(DS.utils); | ||
DSUtils.deepFreeze(DS.errors); | ||
DSUtils.deepFreeze(DS.utils); | ||
var $dirtyCheckScope = $rootScope.$new(); | ||
var $dirtyCheckScope = $rootScope.$new(); | ||
$dirtyCheckScope.$watch(function () { | ||
// Throttle angular-data's digest loop to tenths of a second | ||
// TODO: Is this okay? | ||
return new Date().getTime() / 100 | 0; | ||
}, function () { | ||
DS.digest(); | ||
}); | ||
$dirtyCheckScope.$watch(function () { | ||
// Throttle angular-data's digest loop to tenths of a second | ||
// TODO: Is this okay? | ||
return new Date().getTime() / 100 | 0; | ||
}, function () { | ||
DS.digest(); | ||
}); | ||
return DS; | ||
}]; | ||
return DS; | ||
} | ||
]; | ||
} | ||
module.exports = DSProvider; |
@@ -1,2 +0,2 @@ | ||
var errorPrefix = 'DS.bindAll(scope, expr, resourceName, params): '; | ||
var errorPrefix = 'DS.bindAll(scope, expr, resourceName, params[, cb]): '; | ||
@@ -12,3 +12,3 @@ /** | ||
* ```js | ||
* DS.bindAll(scope, expr, resourceName, params) | ||
* DS.bindAll(scope, expr, resourceName, params[, cb]) | ||
* ``` | ||
@@ -21,6 +21,4 @@ * | ||
* var deregisterFunc = DS.bindAll($scope, 'docs', 'document', { | ||
* query: { | ||
* criteria: { | ||
* ownerId: 5 | ||
* } | ||
* where: { | ||
* ownerId: 5 | ||
* } | ||
@@ -33,4 +31,3 @@ * }); | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -42,33 +39,46 @@ * @param {object} scope The scope to bind to. | ||
* | ||
* - `{object=}` - `query` - The query object by which to filter items of the type specified by `resourceName`. Properties: | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{skip=}` - `skip` - Skip clause. | ||
* - `{orderBy=}` - `orderBy` - OrderBy clause. | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{number=}` - `skip` - Skip clause. | ||
* - `{number=}` - `offset` - Same as skip. | ||
* - `{string|array=}` - `orderBy` - OrderBy clause. | ||
* | ||
* @param {function=} cb Optional callback executed on change. Signature: `cb(err, items)`. | ||
* | ||
* @returns {function} Scope $watch deregistration function. | ||
*/ | ||
function bindOne(scope, expr, resourceName, params) { | ||
if (!this.utils.isObject(scope)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'scope: Must be an object!'); | ||
} else if (!this.utils.isString(expr)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'expr: Must be a string!'); | ||
} else if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isObject(params)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'params: Must be an object!'); | ||
} | ||
function bindOne(scope, expr, resourceName, params, cb) { | ||
var IA = this.errors.IA; | ||
var _this = this; | ||
if (!this.utils.isObject(scope)) { | ||
throw new IA(errorPrefix + 'scope: Must be an object!'); | ||
} else if (!this.utils.isString(expr)) { | ||
throw new IA(errorPrefix + 'expr: Must be a string!'); | ||
} else if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isObject(params)) { | ||
throw new IA(errorPrefix + 'params: Must be an object!'); | ||
} | ||
try { | ||
return scope.$watch(function () { | ||
return _this.lastModified(resourceName); | ||
}, function () { | ||
_this.utils.set(scope, expr, _this.filter(resourceName, params)); | ||
}); | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
var _this = this; | ||
try { | ||
return scope.$watch(function () { | ||
return _this.lastModified(resourceName); | ||
}, function () { | ||
var items = _this.filter(resourceName, params); | ||
_this.utils.set(scope, expr, items); | ||
if (cb) { | ||
cb(null, items); | ||
} | ||
}); | ||
} catch (err) { | ||
if (cb) { | ||
cb(err); | ||
} else { | ||
throw err; | ||
} | ||
} | ||
} | ||
module.exports = bindOne; |
@@ -1,2 +0,2 @@ | ||
var errorPrefix = 'DS.bindOne(scope, expr, resourceName, id): '; | ||
var errorPrefix = 'DS.bindOne(scope, expr, resourceName, id[, cb]): '; | ||
@@ -12,3 +12,3 @@ /** | ||
* ```js | ||
* DS.bindOne(scope, expr, resourceName, id) | ||
* DS.bindOne(scope, expr, resourceName, id[, cb]) | ||
* ``` | ||
@@ -26,4 +26,3 @@ * | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -34,28 +33,39 @@ * @param {object} scope The scope to bind to. | ||
* @param {string|number} id The primary key of the item to bind. | ||
* @param {function=} cb Optional callback executed on change. Signature: `cb(err, item)`. | ||
* @returns {function} Scope $watch deregistration function. | ||
*/ | ||
function bindOne(scope, expr, resourceName, id) { | ||
if (!this.utils.isObject(scope)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'scope: Must be an object!'); | ||
} else if (!this.utils.isString(expr)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'expr: Must be a string!'); | ||
} else if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!'); | ||
} | ||
function bindOne(scope, expr, resourceName, id, cb) { | ||
var IA = this.errors.IA; | ||
var _this = this; | ||
if (!this.utils.isObject(scope)) { | ||
throw new IA(errorPrefix + 'scope: Must be an object!'); | ||
} else if (!this.utils.isString(expr)) { | ||
throw new IA(errorPrefix + 'expr: Must be a string!'); | ||
} else if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} | ||
try { | ||
return scope.$watch(function () { | ||
return _this.lastModified(resourceName, id); | ||
}, function () { | ||
_this.utils.set(scope, expr, _this.get(resourceName, id)); | ||
}); | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
var _this = this; | ||
try { | ||
return scope.$watch(function () { | ||
return _this.lastModified(resourceName, id); | ||
}, function () { | ||
var item = _this.get(resourceName, id); | ||
_this.utils.set(scope, expr, item); | ||
if (cb) { | ||
cb(null, item); | ||
} | ||
}); | ||
} catch (err) { | ||
if (cb) { | ||
cb(err); | ||
} else { | ||
throw err; | ||
} | ||
} | ||
} | ||
module.exports = bindOne; |
@@ -30,4 +30,3 @@ var errorPrefix = 'DS.changes(resourceName, id): '; | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -39,19 +38,15 @@ * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
function changes(resourceName, id) { | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } }); | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} | ||
try { | ||
var item = this.get(resourceName, id); | ||
if (item) { | ||
this.store[resourceName].observers[id].deliver(); | ||
return this.utils.diffObjectFromOldObject(item, this.store[resourceName].previousAttributes[id]); | ||
} | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
var item = this.get(resourceName, id); | ||
if (item) { | ||
this.store[resourceName].observers[id].deliver(); | ||
return this.utils.diffObjectFromOldObject(item, this.store[resourceName].previousAttributes[id]); | ||
} | ||
} | ||
module.exports = changes; |
@@ -6,9 +6,9 @@ /*jshint evil:true*/ | ||
utils.deepMixIn(this, options); | ||
utils.deepMixIn(this, options); | ||
if ('endpoint' in options) { | ||
this.endpoint = options.endpoint; | ||
} else { | ||
this.endpoint = this.name; | ||
} | ||
if ('endpoint' in options) { | ||
this.endpoint = options.endpoint; | ||
} else { | ||
this.endpoint = this.name; | ||
} | ||
} | ||
@@ -47,3 +47,2 @@ | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* | ||
@@ -78,66 +77,86 @@ * @param {string|object} definition Name of resource or resource definition object: Properties: | ||
function defineResource(definition) { | ||
if (this.utils.isString(definition)) { | ||
definition = { | ||
name: definition | ||
}; | ||
} | ||
if (!this.utils.isObject(definition)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'definition: Must be an object!', { definition: { actual: typeof definition, expected: 'object' } }); | ||
} else if (!this.utils.isString(definition.name)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'definition.name: Must be a string!', { definition: { name: { actual: typeof definition.name, expected: 'string' } } }); | ||
} else if (definition.idAttribute && !this.utils.isString(definition.idAttribute)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'definition.idAttribute: Must be a string!', { definition: { idAttribute: { actual: typeof definition.idAttribute, expected: 'string' } } }); | ||
} else if (definition.endpoint && !this.utils.isString(definition.endpoint)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'definition.endpoint: Must be a string!', { definition: { endpoint: { actual: typeof definition.endpoint, expected: 'string' } } }); | ||
} else if (this.store[definition.name]) { | ||
throw new this.errors.RuntimeError(errorPrefix + definition.name + ' is already registered!'); | ||
} | ||
var IA = this.errors.IA; | ||
try { | ||
Resource.prototype = this.defaults; | ||
this.definitions[definition.name] = new Resource(this.utils, definition); | ||
if (this.utils.isString(definition)) { | ||
definition = { | ||
name: definition | ||
}; | ||
} | ||
if (!this.utils.isObject(definition)) { | ||
throw new IA(errorPrefix + 'definition: Must be an object!'); | ||
} else if (!this.utils.isString(definition.name)) { | ||
throw new IA(errorPrefix + 'definition.name: Must be a string!'); | ||
} else if (definition.idAttribute && !this.utils.isString(definition.idAttribute)) { | ||
throw new IA(errorPrefix + 'definition.idAttribute: Must be a string!'); | ||
} else if (definition.endpoint && !this.utils.isString(definition.endpoint)) { | ||
throw new IA(errorPrefix + 'definition.endpoint: Must be a string!'); | ||
} else if (this.store[definition.name]) { | ||
throw new this.errors.R(errorPrefix + definition.name + ' is already registered!'); | ||
} | ||
var _this = this, | ||
def = this.definitions[definition.name]; | ||
try { | ||
Resource.prototype = this.defaults; | ||
this.definitions[definition.name] = new Resource(this.utils, definition); | ||
var cache = this.cacheFactory('DS.' + def.name, { | ||
maxAge: def.maxAge || null, | ||
recycleFreq: def.recycleFreq || 1000, | ||
cacheFlushInterval: def.cacheFlushInterval || null, | ||
deleteOnExpire: def.deleteOnExpire || 'none', | ||
onExpire: function (id) { | ||
_this.eject(def.name, id); | ||
}, | ||
capacity: Number.MAX_VALUE, | ||
storageMode: 'memory', | ||
storageImpl: null, | ||
disabled: false, | ||
storagePrefix: 'DS.' + def.name | ||
}); | ||
var _this = this; | ||
var def = this.definitions[definition.name]; | ||
if (def.methods) { | ||
def.class = definition.name[0].toUpperCase() + definition.name.substring(1); | ||
eval('function ' + def.class + '() {}'); | ||
def[def.class] = eval(def.class); | ||
this.utils.deepMixIn(def[def.class].prototype, def.methods); | ||
} | ||
var cache = this.cacheFactory('DS.' + def.name, { | ||
maxAge: def.maxAge || null, | ||
recycleFreq: def.recycleFreq || 1000, | ||
cacheFlushInterval: def.cacheFlushInterval || null, | ||
deleteOnExpire: def.deleteOnExpire || 'none', | ||
onExpire: function (id) { | ||
_this.eject(def.name, id); | ||
}, | ||
capacity: Number.MAX_VALUE, | ||
storageMode: 'memory', | ||
storageImpl: null, | ||
disabled: false, | ||
storagePrefix: 'DS.' + def.name | ||
}); | ||
this.store[def.name] = { | ||
collection: [], | ||
completedQueries: {}, | ||
pendingQueries: {}, | ||
index: cache, | ||
modified: {}, | ||
saved: {}, | ||
previousAttributes: {}, | ||
observers: {}, | ||
collectionModified: 0 | ||
}; | ||
} catch (err) { | ||
delete this.definitions[definition.name]; | ||
delete this.store[definition.name]; | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
if (def.methods) { | ||
def.class = definition.name[0].toUpperCase() + definition.name.substring(1); | ||
eval('function ' + def.class + '() {}'); | ||
def[def.class] = eval(def.class); | ||
this.utils.deepMixIn(def[def.class].prototype, def.methods); | ||
} | ||
if (def.computed) { | ||
this.utils.forOwn(def.computed, function (fn, field) { | ||
if (def.methods && field in def.methods) { | ||
_this.$log.warn(errorPrefix + 'Computed property "' + field + '" conflicts with previously defined prototype method!'); | ||
} | ||
var match = fn.toString().match(/function.*?\(([\s\S]*?)\)/); | ||
var deps = match[1].split(','); | ||
fn.deps = _this.utils.filter(deps, function (dep) { | ||
return !!dep; | ||
}); | ||
angular.forEach(fn.deps, function (val, index) { | ||
fn.deps[index] = val.trim(); | ||
}); | ||
}); | ||
} | ||
this.store[def.name] = { | ||
collection: [], | ||
completedQueries: {}, | ||
pendingQueries: {}, | ||
index: cache, | ||
modified: {}, | ||
saved: {}, | ||
previousAttributes: {}, | ||
observers: {}, | ||
collectionModified: 0 | ||
}; | ||
} | ||
catch | ||
(err) { | ||
delete this.definitions[definition.name]; | ||
delete this.store[definition.name]; | ||
throw err; | ||
} | ||
} | ||
module.exports = defineResource; |
@@ -1,2 +0,2 @@ | ||
var observe = require('observejs'); | ||
var observe = require('../../../lib/observe-js/observe-js'); | ||
@@ -22,20 +22,13 @@ /** | ||
* | ||
* ## Throws | ||
* | ||
* - `{UnhandledError}` | ||
*/ | ||
function digest() { | ||
try { | ||
if (!this.$rootScope.$$phase) { | ||
this.$rootScope.$apply(function () { | ||
observe.Platform.performMicrotaskCheckpoint(); | ||
}); | ||
} else { | ||
observe.Platform.performMicrotaskCheckpoint(); | ||
} | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
if (!this.$rootScope.$$phase) { | ||
this.$rootScope.$apply(function () { | ||
observe.Platform.performMicrotaskCheckpoint(); | ||
}); | ||
} else { | ||
observe.Platform.performMicrotaskCheckpoint(); | ||
} | ||
} | ||
module.exports = digest; |
var errorPrefix = 'DS.eject(resourceName, id): '; | ||
function _eject(definition, resource, id) { | ||
var found = false; | ||
for (var i = 0; i < resource.collection.length; i++) { | ||
if (resource.collection[i][definition.idAttribute] == id) { | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (found) { | ||
resource.collection.splice(i, 1); | ||
resource.observers[id].close(); | ||
delete resource.observers[id]; | ||
var found = false; | ||
for (var i = 0; i < resource.collection.length; i++) { | ||
if (resource.collection[i][definition.idAttribute] == id) { | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (found) { | ||
resource.collection.splice(i, 1); | ||
resource.observers[id].close(); | ||
delete resource.observers[id]; | ||
resource.index.remove(id); | ||
delete resource.previousAttributes[id]; | ||
delete resource.modified[id]; | ||
delete resource.saved[id]; | ||
} | ||
resource.index.remove(id); | ||
delete resource.previousAttributes[id]; | ||
delete resource.modified[id]; | ||
delete resource.saved[id]; | ||
} | ||
} | ||
@@ -49,4 +49,3 @@ | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -57,27 +56,23 @@ * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
function eject(resourceName, id) { | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } }); | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} | ||
var resource = this.store[resourceName], | ||
_this = this; | ||
var resource = this.store[resourceName]; | ||
var _this = this; | ||
try { | ||
if (!this.$rootScope.$$phase) { | ||
this.$rootScope.$apply(function () { | ||
_eject(_this.definitions[resourceName], resource, id); | ||
resource.collectionModified = _this.utils.updateTimestamp(resource.collectionModified); | ||
}); | ||
} else { | ||
_eject(_this.definitions[resourceName], resource, id); | ||
resource.collectionModified = _this.utils.updateTimestamp(resource.collectionModified); | ||
} | ||
delete this.store[resourceName].completedQueries[id]; | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
if (!this.$rootScope.$$phase) { | ||
this.$rootScope.$apply(function () { | ||
_eject(_this.definitions[resourceName], resource, id); | ||
resource.collectionModified = _this.utils.updateTimestamp(resource.collectionModified); | ||
}); | ||
} else { | ||
_eject(_this.definitions[resourceName], resource, id); | ||
resource.collectionModified = _this.utils.updateTimestamp(resource.collectionModified); | ||
} | ||
delete this.store[resourceName].completedQueries[id]; | ||
} | ||
module.exports = eject; |
var errorPrefix = 'DS.ejectAll(resourceName[, params]): '; | ||
function _ejectAll(definition, resource, params) { | ||
var queryHash = this.utils.toJson(params), | ||
items = this.filter(definition.name, params); | ||
var queryHash = this.utils.toJson(params); | ||
var items = this.filter(definition.name, params); | ||
var ids = this.utils.toLookup(items, definition.idAttribute); | ||
var _this = this; | ||
for (var i = 0; i < items.length; i++) { | ||
this.eject(definition.name, items[i][definition.idAttribute]); | ||
} | ||
angular.forEach(ids, function (item, id) { | ||
_this.eject(definition.name, id); | ||
}); | ||
delete resource.completedQueries[queryHash]; | ||
delete resource.completedQueries[queryHash]; | ||
} | ||
@@ -44,3 +46,3 @@ | ||
* | ||
* DS.ejectAll('document', { query: { where: { author: 'Sally Jane' } } }); | ||
* DS.ejectAll('document', { where: { author: 'Sally Jane' } }); | ||
* | ||
@@ -64,4 +66,3 @@ * DS.filter('document'); // [ { title: 'How to Cook', id: 45, author: 'John Anderson' } ] | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -71,35 +72,38 @@ * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
* | ||
* - `{object=}` - `query` - The query object by which to filter items of the type specified by `resourceName`. Properties: | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{skip=}` - `skip` - Skip clause. | ||
* - `{orderBy=}` - `orderBy` - OrderBy clause. | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{number=}` - `skip` - Skip clause. | ||
* - `{number=}` - `offset` - Same as skip. | ||
* - `{string|array=}` - `orderBy` - OrderBy clause. | ||
*/ | ||
function ejectAll(resourceName, params) { | ||
params = params || {}; | ||
params = params || {}; | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isObject(params)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'params: Must be an object!', { params: { actual: typeof params, expected: 'object' } }); | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isObject(params)) { | ||
throw new this.errors.IA(errorPrefix + 'params: Must be an object!'); | ||
} | ||
var resource = this.store[resourceName], | ||
_this = this; | ||
var _this = this; | ||
var resource = this.store[resourceName]; | ||
var queryHash = this.utils.toJson(params); | ||
try { | ||
if (!this.$rootScope.$$phase) { | ||
this.$rootScope.$apply(function () { | ||
_ejectAll.apply(_this, [_this.definitions[resourceName], resource, params]); | ||
resource.collectionModified = _this.utils.updateTimestamp(resource.collectionModified); | ||
}); | ||
} else { | ||
_ejectAll.apply(_this, [_this.definitions[resourceName], resource, params]); | ||
resource.collectionModified = this.utils.updateTimestamp(resource.collectionModified); | ||
} | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
delete resource.completedQueries[queryHash]; | ||
if (this.utils.isEmpty(params)) { | ||
resource.completedQueries = {}; | ||
} | ||
if (!this.$rootScope.$$phase) { | ||
this.$rootScope.$apply(function () { | ||
_ejectAll.apply(_this, [_this.definitions[resourceName], resource, params]); | ||
resource.collectionModified = _this.utils.updateTimestamp(resource.collectionModified); | ||
}); | ||
} else { | ||
_ejectAll.apply(_this, [_this.definitions[resourceName], resource, params]); | ||
resource.collectionModified = this.utils.updateTimestamp(resource.collectionModified); | ||
} | ||
} | ||
module.exports = ejectAll; |
@@ -1,3 +0,2 @@ | ||
/* jshint loopfunc: true */ | ||
var errorPrefix = 'DS.filter(resourceName, params[, options]): '; | ||
var errorPrefix = 'DS.filter(resourceName[, params][, options]): '; | ||
@@ -13,3 +12,3 @@ /** | ||
* ```js | ||
* DS.filter(resourceName, params[, options]) | ||
* DS.filter(resourceName[, params][, options]) | ||
* ``` | ||
@@ -26,132 +25,57 @@ * | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
* @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
* @param {object} params Parameter object that is serialized into the query string. Properties: | ||
* @param {object=} params Parameter object that is serialized into the query string. Properties: | ||
* | ||
* - `{object=}` - `query` - The query object by which to filter items of the type specified by `resourceName`. Properties: | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{skip=}` - `skip` - Skip clause. | ||
* - `{orderBy=}` - `orderBy` - OrderBy clause. | ||
* - `{object=}` - `where` - Where clause. | ||
* - `{number=}` - `limit` - Limit clause. | ||
* - `{number=}` - `skip` - Skip clause. | ||
* - `{number=}` - `offset` - Same as skip. | ||
* - `{string|array=}` - `orderBy` - OrderBy clause. | ||
* | ||
* @param {object=} options Optional configuration. Properties: | ||
* - `{boolean=}` - `loadFromServer` - Send the query to server if it has not been sent yet. Default: `false`. | ||
* - `{boolean=}` - `allowSimpleWhere` - Treat top-level fields on the `params` argument as simple "where" equality clauses. Default: `true`. | ||
* @returns {array} The filtered collection of items of the type specified by `resourceName`. | ||
*/ | ||
function filter(resourceName, params, options) { | ||
options = options || {}; | ||
var IA = this.errors.IA; | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isObject(params)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'params: Must be an object!', { params: { actual: typeof params, expected: 'object' } }); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!', { options: { actual: typeof options, expected: 'object' } }); | ||
} | ||
options = options || {}; | ||
try { | ||
var definition = this.definitions[resourceName], | ||
resource = this.store[resourceName], | ||
_this = this; | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (params && !this.utils.isObject(params)) { | ||
throw new IA(errorPrefix + 'params: Must be an object!'); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new IA(errorPrefix + 'options: Must be an object!'); | ||
} | ||
// Protect against null | ||
params.query = params.query || {}; | ||
var definition = this.definitions[resourceName]; | ||
var resource = this.store[resourceName]; | ||
var queryHash = this.utils.toJson(params); | ||
// Protect against null | ||
params = params || {}; | ||
if (!(queryHash in resource.completedQueries) && options.loadFromServer) { | ||
// This particular query has never been completed | ||
if ('allowSimpleWhere' in options) { | ||
options.allowSimpleWhere = !!options.allowSimpleWhere; | ||
} else { | ||
options.allowSimpleWhere = true; | ||
} | ||
if (!resource.pendingQueries[queryHash]) { | ||
// This particular query has never even been started | ||
this.findAll(resourceName, params, options); | ||
} | ||
} | ||
var queryHash = this.utils.toJson(params); | ||
// The query has been completed, so hit the cache with the query | ||
var filtered = this.utils.filter(resource.collection, function (attrs) { | ||
var keep = true, | ||
where = params.query.where; | ||
if (!(queryHash in resource.completedQueries) && options.loadFromServer) { | ||
// This particular query has never been completed | ||
// Apply 'where' clauses | ||
if (where) { | ||
if (!_this.utils.isObject(where)) { | ||
throw new _this.errors.IllegalArgumentError(errorPrefix + 'params.query.where: Must be an object!', { params: { query: { where: { actual: typeof params.query.where, expected: 'object' } } } }); | ||
} | ||
keep = definition.filter(resourceName, where, attrs); | ||
} | ||
return keep; | ||
}); | ||
if (!resource.pendingQueries[queryHash]) { | ||
// This particular query has never even been started | ||
this.findAll(resourceName, params, options); | ||
} | ||
} | ||
// Apply 'orderBy' | ||
if (params.query.orderBy) { | ||
if (this.utils.isString(params.query.orderBy)) { | ||
params.query.orderBy = [ | ||
[params.query.orderBy, 'ASC'] | ||
]; | ||
} | ||
if (this.utils.isArray(params.query.orderBy)) { | ||
for (var i = 0; i < params.query.orderBy.length; i++) { | ||
if (this.utils.isString(params.query.orderBy[i])) { | ||
params.query.orderBy[i] = [params.query.orderBy[i], 'ASC']; | ||
} else if (!this.utils.isArray(params.query.orderBy[i])) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'params.query.orderBy[' + i + ']: Must be a string or an array!', { params: { query: { 'orderBy[i]': { actual: typeof params.query.orderBy[i], expected: 'string|array' } } } }); | ||
} | ||
filtered = this.utils.sort(filtered, function (a, b) { | ||
var cA = a[params.query.orderBy[i][0]], cB = b[params.query.orderBy[i][0]]; | ||
if (_this.utils.isString(cA)) { | ||
cA = _this.utils.upperCase(cA); | ||
} | ||
if (_this.utils.isString(cB)) { | ||
cB = _this.utils.upperCase(cB); | ||
} | ||
if (params.query.orderBy[i][1] === 'DESC') { | ||
if (cB < cA) { | ||
return -1; | ||
} else if (cB > cA) { | ||
return 1; | ||
} else { | ||
return 0; | ||
} | ||
} else { | ||
if (cA < cB) { | ||
return -1; | ||
} else if (cA > cB) { | ||
return 1; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
}); | ||
} | ||
} else { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'params.query.orderBy: Must be a string or an array!', { params: { query: { orderBy: { actual: typeof params.query.orderBy, expected: 'string|array' } } } }); | ||
} | ||
} | ||
// Apply 'limit' and 'skip' | ||
if (this.utils.isNumber(params.query.limit) && this.utils.isNumber(params.query.skip)) { | ||
filtered = this.utils.slice(filtered, params.query.skip, Math.min(filtered.length, params.query.skip + params.query.limit)); | ||
} else if (this.utils.isNumber(params.query.limit)) { | ||
filtered = this.utils.slice(filtered, 0, Math.min(filtered.length, params.query.limit)); | ||
} else if (this.utils.isNumber(params.query.skip)) { | ||
if (params.query.skip < filtered.length) { | ||
filtered = this.utils.slice(filtered, params.query.skip); | ||
} else { | ||
filtered = []; | ||
} | ||
} | ||
return filtered; | ||
} catch (err) { | ||
if (err instanceof this.errors.IllegalArgumentError) { | ||
throw err; | ||
} else { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
} | ||
return definition.filter.call(this, resource.collection, resourceName, params, options); | ||
} | ||
module.exports = filter; |
@@ -25,4 +25,3 @@ var errorPrefix = 'DS.get(resourceName, id[, options]): '; | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -36,28 +35,27 @@ * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
function get(resourceName, id, options) { | ||
options = options || {}; | ||
var IA = this.errors.IA; | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } }); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!', { options: { actual: typeof options, expected: 'object' } }); | ||
} | ||
options = options || {}; | ||
try { | ||
// cache miss, request resource from server | ||
var item = this.store[resourceName].index.get(id); | ||
if (!item && options.loadFromServer) { | ||
this.find(resourceName, id).then(null, function (err) { | ||
throw err; | ||
}); | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new IA(errorPrefix + 'options: Must be an object!'); | ||
} | ||
var _this = this; | ||
// return resource from cache | ||
return item; | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
// cache miss, request resource from server | ||
var item = this.store[resourceName].index.get(id); | ||
if (!item && options.loadFromServer) { | ||
this.find(resourceName, id).then(null, function (err) { | ||
return _this.$q.reject(err); | ||
}); | ||
} | ||
// return resource from cache | ||
return item; | ||
} | ||
module.exports = get; |
var errorPrefix = 'DS.hasChanges(resourceName, id): '; | ||
function diffIsEmpty(utils, diff) { | ||
return !(utils.isEmpty(diff.added) && | ||
utils.isEmpty(diff.removed) && | ||
utils.isEmpty(diff.changed)); | ||
return !(utils.isEmpty(diff.added) && | ||
utils.isEmpty(diff.removed) && | ||
utils.isEmpty(diff.changed)); | ||
} | ||
@@ -35,4 +35,3 @@ | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -44,20 +43,16 @@ * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
function hasChanges(resourceName, id) { | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } }); | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} | ||
try { | ||
// return resource from cache | ||
if (this.get(resourceName, id)) { | ||
return diffIsEmpty(this.utils, this.changes(resourceName, id)); | ||
} else { | ||
return false; | ||
} | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
// return resource from cache | ||
if (this.get(resourceName, id)) { | ||
return diffIsEmpty(this.utils, this.changes(resourceName, id)); | ||
} else { | ||
return false; | ||
} | ||
} | ||
module.exports = hasChanges; |
module.exports = { | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:defineResource | ||
* @name defineResource | ||
* @methodOf DS | ||
* @description | ||
* See [DS.defineResource](/documentation/api/api/DS.sync_methods:defineResource). | ||
*/ | ||
defineResource: require('./defineResource'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:defineResource | ||
* @name defineResource | ||
* @methodOf DS | ||
* @description | ||
* See [DS.defineResource](/documentation/api/api/DS.sync_methods:defineResource). | ||
*/ | ||
defineResource: require('./defineResource'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:bindOne | ||
* @name bindOne | ||
* @methodOf DS | ||
* @description | ||
* See [DS.bindOne](/documentation/api/api/DS.sync_methods:bindOne). | ||
*/ | ||
bindOne: require('./bindOne'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:bindOne | ||
* @name bindOne | ||
* @methodOf DS | ||
* @description | ||
* See [DS.bindOne](/documentation/api/api/DS.sync_methods:bindOne). | ||
*/ | ||
bindOne: require('./bindOne'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:bindAll | ||
* @name bindAll | ||
* @methodOf DS | ||
* @description | ||
* See [DS.bindAll](/documentation/api/api/DS.sync_methods:bindAll). | ||
*/ | ||
bindAll: require('./bindAll'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:bindAll | ||
* @name bindAll | ||
* @methodOf DS | ||
* @description | ||
* See [DS.bindAll](/documentation/api/api/DS.sync_methods:bindAll). | ||
*/ | ||
bindAll: require('./bindAll'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:eject | ||
* @name eject | ||
* @methodOf DS | ||
* @description | ||
* See [DS.eject](/documentation/api/api/DS.sync_methods:eject). | ||
*/ | ||
eject: require('./eject'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:eject | ||
* @name eject | ||
* @methodOf DS | ||
* @description | ||
* See [DS.eject](/documentation/api/api/DS.sync_methods:eject). | ||
*/ | ||
eject: require('./eject'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:ejectAll | ||
* @name ejectAll | ||
* @methodOf DS | ||
* @description | ||
* See [DS.ejectAll](/documentation/api/api/DS.sync_methods:ejectAll). | ||
*/ | ||
ejectAll: require('./ejectAll'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:ejectAll | ||
* @name ejectAll | ||
* @methodOf DS | ||
* @description | ||
* See [DS.ejectAll](/documentation/api/api/DS.sync_methods:ejectAll). | ||
*/ | ||
ejectAll: require('./ejectAll'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:filter | ||
* @name filter | ||
* @methodOf DS | ||
* @description | ||
* See [DS.filter](/documentation/api/api/DS.sync_methods:filter). | ||
*/ | ||
filter: require('./filter'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:filter | ||
* @name filter | ||
* @methodOf DS | ||
* @description | ||
* See [DS.filter](/documentation/api/api/DS.sync_methods:filter). | ||
*/ | ||
filter: require('./filter'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:get | ||
* @name get | ||
* @methodOf DS | ||
* @description | ||
* See [DS.get](/documentation/api/api/DS.sync_methods:get). | ||
*/ | ||
get: require('./get'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:get | ||
* @name get | ||
* @methodOf DS | ||
* @description | ||
* See [DS.get](/documentation/api/api/DS.sync_methods:get). | ||
*/ | ||
get: require('./get'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:inject | ||
* @name inject | ||
* @methodOf DS | ||
* @description | ||
* See [DS.inject](/documentation/api/api/DS.sync_methods:inject). | ||
*/ | ||
inject: require('./inject'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:inject | ||
* @name inject | ||
* @methodOf DS | ||
* @description | ||
* See [DS.inject](/documentation/api/api/DS.sync_methods:inject). | ||
*/ | ||
inject: require('./inject'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:lastModified | ||
* @name lastModified | ||
* @methodOf DS | ||
* @description | ||
* See [DS.lastModified](/documentation/api/api/DS.sync_methods:lastModified). | ||
*/ | ||
lastModified: require('./lastModified'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:lastModified | ||
* @name lastModified | ||
* @methodOf DS | ||
* @description | ||
* See [DS.lastModified](/documentation/api/api/DS.sync_methods:lastModified). | ||
*/ | ||
lastModified: require('./lastModified'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:lastSaved | ||
* @name lastSaved | ||
* @methodOf DS | ||
* @description | ||
* See [DS.lastSaved](/documentation/api/api/DS.sync_methods:lastSaved). | ||
*/ | ||
lastSaved: require('./lastSaved'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:lastSaved | ||
* @name lastSaved | ||
* @methodOf DS | ||
* @description | ||
* See [DS.lastSaved](/documentation/api/api/DS.sync_methods:lastSaved). | ||
*/ | ||
lastSaved: require('./lastSaved'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:digest | ||
* @name digest | ||
* @methodOf DS | ||
* @description | ||
* See [DS.digest](/documentation/api/api/DS.sync_methods:digest). | ||
*/ | ||
digest: require('./digest'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:digest | ||
* @name digest | ||
* @methodOf DS | ||
* @description | ||
* See [DS.digest](/documentation/api/api/DS.sync_methods:digest). | ||
*/ | ||
digest: require('./digest'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:changes | ||
* @name changes | ||
* @methodOf DS | ||
* @description | ||
* See [DS.changes](/documentation/api/api/DS.sync_methods:changes). | ||
*/ | ||
changes: require('./changes'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:changes | ||
* @name changes | ||
* @methodOf DS | ||
* @description | ||
* See [DS.changes](/documentation/api/api/DS.sync_methods:changes). | ||
*/ | ||
changes: require('./changes'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:previous | ||
* @name previous | ||
* @methodOf DS | ||
* @description | ||
* See [DS.previous](/documentation/api/api/DS.sync_methods:previous). | ||
*/ | ||
previous: require('./previous'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:previous | ||
* @name previous | ||
* @methodOf DS | ||
* @description | ||
* See [DS.previous](/documentation/api/api/DS.sync_methods:previous). | ||
*/ | ||
previous: require('./previous'), | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:hasChanges | ||
* @name hasChanges | ||
* @methodOf DS | ||
* @description | ||
* See [DS.hasChanges](/documentation/api/api/DS.sync_methods:hasChanges). | ||
*/ | ||
hasChanges: require('./hasChanges') | ||
/** | ||
* @doc method | ||
* @id DS.sync_methods:hasChanges | ||
* @name hasChanges | ||
* @methodOf DS | ||
* @description | ||
* See [DS.hasChanges](/documentation/api/api/DS.sync_methods:hasChanges). | ||
*/ | ||
hasChanges: require('./hasChanges') | ||
}; |
@@ -1,80 +0,124 @@ | ||
var observe = require('observejs'), | ||
errorPrefix = 'DS.inject(resourceName, attrs[, options]): '; | ||
var observe = require('../../../lib/observe-js/observe-js'); | ||
var errorPrefix = 'DS.inject(resourceName, attrs[, options]): '; | ||
function _inject(definition, resource, attrs) { | ||
var _this = this, | ||
$log = _this.$log; | ||
var _this = this; | ||
var $log = _this.$log; | ||
function _react(added, removed, changed, getOldValueFn) { | ||
try { | ||
var innerId = getOldValueFn(definition.idAttribute); | ||
function _react(added, removed, changed, getOldValueFn) { | ||
var innerId = getOldValueFn(definition.idAttribute); | ||
resource.modified[innerId] = _this.utils.updateTimestamp(resource.modified[innerId]); | ||
resource.collectionModified = _this.utils.updateTimestamp(resource.collectionModified); | ||
resource.modified[innerId] = _this.utils.updateTimestamp(resource.modified[innerId]); | ||
resource.collectionModified = _this.utils.updateTimestamp(resource.collectionModified); | ||
if (definition.idAttribute in changed) { | ||
$log.error('Doh! You just changed the primary key of an object! ' + | ||
'I don\'t know how to handle this yet, so your data for the "' + definition.name + | ||
'" resource is now in an undefined (probably broken) state.'); | ||
} | ||
} catch (err) { | ||
throw new _this.errors.UnhandledError(err); | ||
} | ||
} | ||
if (definition.computed) { | ||
var item = _this.get(definition.name, innerId); | ||
_this.utils.forOwn(definition.computed, function (fn, field) { | ||
var compute = false; | ||
// check if required fields changed | ||
angular.forEach(fn.deps, function (dep) { | ||
if (dep in changed || dep in removed || dep in changed || !(field in item)) { | ||
compute = true; | ||
} | ||
}); | ||
if (compute) { | ||
var args = []; | ||
angular.forEach(fn.deps, function (dep) { | ||
args.push(item[dep]); | ||
}); | ||
// recompute property | ||
item[field] = fn.apply(item, args); | ||
} | ||
}); | ||
} | ||
if (_this.utils.isArray(attrs)) { | ||
for (var i = 0; i < attrs.length; i++) { | ||
_inject.call(_this, definition, resource, attrs[i]); | ||
} | ||
} else { | ||
if (!(definition.idAttribute in attrs)) { | ||
throw new _this.errors.RuntimeError(errorPrefix + 'attrs: Must contain the property specified by `idAttribute`!'); | ||
} else { | ||
try { | ||
definition.beforeInject(definition.name, attrs); | ||
var id = attrs[definition.idAttribute], | ||
item = this.get(definition.name, id); | ||
if (definition.idAttribute in changed) { | ||
$log.error('Doh! You just changed the primary key of an object! ' + | ||
'I don\'t know how to handle this yet, so your data for the "' + definition.name + | ||
'" resource is now in an undefined (probably broken) state.'); | ||
} | ||
} | ||
if (!item) { | ||
if (definition.class) { | ||
if (attrs instanceof definition[definition.class]) { | ||
item = attrs; | ||
} else { | ||
item = new definition[definition.class](); | ||
} | ||
} else { | ||
item = {}; | ||
} | ||
resource.previousAttributes[id] = {}; | ||
var injected; | ||
if (_this.utils.isArray(attrs)) { | ||
injected = []; | ||
for (var i = 0; i < attrs.length; i++) { | ||
injected.push(_inject.call(_this, definition, resource, attrs[i])); | ||
} | ||
} else { | ||
// check if "idAttribute" is a computed property | ||
if (definition.computed && definition.computed[definition.idAttribute]) { | ||
var args = []; | ||
angular.forEach(definition.computed[definition.idAttribute].deps, function (dep) { | ||
args.push(attrs[dep]); | ||
}); | ||
attrs[definition.idAttribute] = definition.computed[definition.idAttribute].apply(attrs, args); | ||
} | ||
if (!(definition.idAttribute in attrs)) { | ||
throw new _this.errors.R(errorPrefix + 'attrs: Must contain the property specified by `idAttribute`!'); | ||
} else { | ||
try { | ||
definition.beforeInject(definition.name, attrs); | ||
var id = attrs[definition.idAttribute], | ||
item = this.get(definition.name, id); | ||
_this.utils.deepMixIn(item, attrs); | ||
_this.utils.deepMixIn(resource.previousAttributes[id], attrs); | ||
if (!item) { | ||
if (definition.class) { | ||
if (attrs instanceof definition[definition.class]) { | ||
item = attrs; | ||
} else { | ||
item = new definition[definition.class](); | ||
} | ||
} else { | ||
item = {}; | ||
} | ||
resource.previousAttributes[id] = {}; | ||
resource.collection.push(item); | ||
_this.utils.deepMixIn(item, attrs); | ||
_this.utils.deepMixIn(resource.previousAttributes[id], attrs); | ||
resource.observers[id] = new observe.ObjectObserver(item, _react); | ||
resource.index.put(id, item); | ||
resource.collection.push(item); | ||
_react({}, {}, {}, function () { | ||
return id; | ||
}); | ||
} else { | ||
_this.utils.deepMixIn(item, attrs); | ||
if (typeof resource.index.touch === 'function') { | ||
resource.index.touch(id); | ||
} else { | ||
resource.index.put(id, resource.index.get(id)); | ||
} | ||
resource.observers[id].deliver(); | ||
} | ||
resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]); | ||
definition.afterInject(definition.name, item); | ||
} catch (err) { | ||
$log.error(err); | ||
$log.error('inject failed!', definition.name, attrs); | ||
} | ||
} | ||
} | ||
resource.observers[id] = new observe.ObjectObserver(item, _react); | ||
resource.index.put(id, item); | ||
_react({}, {}, {}, function () { | ||
return id; | ||
}); | ||
} else { | ||
_this.utils.deepMixIn(item, attrs); | ||
if (typeof resource.index.touch === 'function') { | ||
resource.index.touch(id); | ||
} else { | ||
resource.index.put(id, resource.index.get(id)); | ||
} | ||
resource.observers[id].deliver(); | ||
} | ||
resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]); | ||
definition.afterInject(definition.name, item); | ||
injected = item; | ||
} catch (err) { | ||
$log.error(err); | ||
$log.error('inject failed!', definition.name, attrs); | ||
} | ||
} | ||
} | ||
return injected; | ||
} | ||
function _injectRelations(definition, injected) { | ||
var _this = this; | ||
_this.utils.forOwn(definition.relations, function (relation, type) { | ||
_this.utils.forOwn(relation, function (def, relationName) { | ||
if (_this.definitions[relationName] && injected[def.localField]) { | ||
try { | ||
injected[def.localField] = _this.inject(relationName, injected[def.localField]); | ||
} catch (err) { | ||
_this.$log.error(errorPrefix + 'Failed to inject ' + type + ' relation: "' + relationName + '"!', err); | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
/** | ||
@@ -117,3 +161,3 @@ * @doc method | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -127,38 +171,33 @@ * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
function inject(resourceName, attrs, options) { | ||
options = options || {}; | ||
var IA = this.errors.IA; | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isObject(attrs) && !this.utils.isArray(attrs)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'attrs: Must be an object or an array!', { attrs: { actual: typeof attrs, expected: 'object|array' } }); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!', { options: { actual: typeof options, expected: 'object' } }); | ||
} | ||
options = options || {}; | ||
var definition = this.definitions[resourceName], | ||
resource = this.store[resourceName], | ||
_this = this; | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isObject(attrs) && !this.utils.isArray(attrs)) { | ||
throw new IA(errorPrefix + 'attrs: Must be an object or an array!'); | ||
} else if (!this.utils.isObject(options)) { | ||
throw new IA(errorPrefix + 'options: Must be an object!'); | ||
} | ||
try { | ||
if (!this.$rootScope.$$phase) { | ||
this.$rootScope.$apply(function () { | ||
_inject.apply(_this, [definition, resource, attrs]); | ||
}); | ||
} else { | ||
_inject.apply(_this, [definition, resource, attrs]); | ||
} | ||
if (_this.utils.isArray(attrs)) { | ||
return attrs; | ||
} else { | ||
return this.get(resourceName, attrs[definition.idAttribute]); | ||
} | ||
} catch (err) { | ||
if (!(err instanceof this.errors.RuntimeError)) { | ||
throw new this.errors.UnhandledError(err); | ||
} else { | ||
throw err; | ||
} | ||
} | ||
var definition = this.definitions[resourceName]; | ||
var resource = this.store[resourceName]; | ||
var _this = this; | ||
var injected; | ||
if (!this.$rootScope.$$phase) { | ||
this.$rootScope.$apply(function () { | ||
injected = _inject.call(_this, definition, resource, attrs); | ||
}); | ||
} else { | ||
injected = _inject.call(_this, definition, resource, attrs); | ||
} | ||
if (definition.relations) { | ||
_injectRelations.call(_this, definition, injected); | ||
} | ||
return injected; | ||
} | ||
module.exports = inject; |
@@ -29,4 +29,3 @@ var errorPrefix = 'DS.lastModified(resourceName[, id]): '; | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -39,20 +38,16 @@ * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
function lastModified(resourceName, id) { | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (id && !this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } }); | ||
} | ||
try { | ||
if (id) { | ||
if (!(id in this.store[resourceName].modified)) { | ||
this.store[resourceName].modified[id] = 0; | ||
} | ||
return this.store[resourceName].modified[id]; | ||
} | ||
return this.store[resourceName].collectionModified; | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (id && !this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} | ||
if (id) { | ||
if (!(id in this.store[resourceName].modified)) { | ||
this.store[resourceName].modified[id] = 0; | ||
} | ||
return this.store[resourceName].modified[id]; | ||
} | ||
return this.store[resourceName].collectionModified; | ||
} | ||
module.exports = lastModified; |
@@ -36,4 +36,3 @@ var errorPrefix = 'DS.lastSaved(resourceName[, id]): '; | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -45,17 +44,13 @@ * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
function lastSaved(resourceName, id) { | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } }); | ||
} | ||
try { | ||
if (!(id in this.store[resourceName].saved)) { | ||
this.store[resourceName].saved[id] = 0; | ||
} | ||
return this.store[resourceName].saved[id]; | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} | ||
if (!(id in this.store[resourceName].saved)) { | ||
this.store[resourceName].saved[id] = 0; | ||
} | ||
return this.store[resourceName].saved[id]; | ||
} | ||
module.exports = lastSaved; |
@@ -31,4 +31,3 @@ var errorPrefix = 'DS.previous(resourceName, id): '; | ||
* - `{IllegalArgumentError}` | ||
* - `{RuntimeError}` | ||
* - `{UnhandledError}` | ||
* - `{NonexistentResourceError}` | ||
* | ||
@@ -40,16 +39,12 @@ * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. | ||
function previous(resourceName, id) { | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } }); | ||
} | ||
if (!this.definitions[resourceName]) { | ||
throw new this.errors.NER(errorPrefix + resourceName); | ||
} else if (!this.utils.isString(id) && !this.utils.isNumber(id)) { | ||
throw new this.errors.IA(errorPrefix + 'id: Must be a string or a number!'); | ||
} | ||
try { | ||
// return resource from cache | ||
return angular.copy(this.store[resourceName].previousAttributes[id]); | ||
} catch (err) { | ||
throw new this.errors.UnhandledError(err); | ||
} | ||
// return resource from cache | ||
return angular.copy(this.store[resourceName].previousAttributes[id]); | ||
} | ||
module.exports = previous; |
/** | ||
* @doc function | ||
* @id errors.types:UnhandledError | ||
* @name UnhandledError | ||
* @description Error that is thrown/returned when Reheat encounters an uncaught/unknown exception. | ||
* @param {Error} error The originally thrown error. | ||
* @returns {UnhandledError} A new instance of `UnhandledError`. | ||
*/ | ||
function UnhandledError(error) { | ||
Error.call(this); | ||
if (typeof Error.captureStackTrace === 'function') { | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
error = error || {}; | ||
/** | ||
* @doc property | ||
* @id errors.types:UnhandledError.type | ||
* @name type | ||
* @propertyOf errors.types:UnhandledError | ||
* @description Name of error type. Default: `"UnhandledError"`. | ||
*/ | ||
this.type = this.constructor.name; | ||
/** | ||
* @doc property | ||
* @id errors.types:UnhandledError.originalError | ||
* @name originalError | ||
* @propertyOf errors.types:UnhandledError | ||
* @description A reference to the original error that was thrown. | ||
*/ | ||
this.originalError = error; | ||
/** | ||
* @doc property | ||
* @id errors.types:UnhandledError.message | ||
* @name message | ||
* @propertyOf errors.types:UnhandledError | ||
* @description Message and stack trace. Same as `UnhandledError#stack`. | ||
*/ | ||
this.message = 'UnhandledError: This is an uncaught exception. Please consider submitting an issue at https://github.com/jmdobry/angular-data/issues.\n\n' + | ||
'Original Uncaught Exception:\n' + (error.stack ? error.stack.toString() : error.stack); | ||
/** | ||
* @doc property | ||
* @id errors.types:UnhandledError.stack | ||
* @name stack | ||
* @propertyOf errors.types:UnhandledError | ||
* @description Message and stack trace. Same as `UnhandledError#message`. | ||
*/ | ||
this.stack = this.message; | ||
} | ||
UnhandledError.prototype = Object.create(Error.prototype); | ||
UnhandledError.prototype.constructor = UnhandledError; | ||
/** | ||
* @doc function | ||
* @id errors.types:IllegalArgumentError | ||
@@ -64,37 +7,27 @@ * @name IllegalArgumentError | ||
* @param {string=} message Error message. Default: `"Illegal Argument!"`. | ||
* @param {object=} errors Object containing information about the error. | ||
* @returns {IllegalArgumentError} A new instance of `IllegalArgumentError`. | ||
*/ | ||
function IllegalArgumentError(message, errors) { | ||
Error.call(this); | ||
if (typeof Error.captureStackTrace === 'function') { | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
function IllegalArgumentError(message) { | ||
Error.call(this); | ||
if (typeof Error.captureStackTrace === 'function') { | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
/** | ||
* @doc property | ||
* @id errors.types:IllegalArgumentError.type | ||
* @name type | ||
* @propertyOf errors.types:IllegalArgumentError | ||
* @description Name of error type. Default: `"IllegalArgumentError"`. | ||
*/ | ||
this.type = this.constructor.name; | ||
/** | ||
* @doc property | ||
* @id errors.types:IllegalArgumentError.type | ||
* @name type | ||
* @propertyOf errors.types:IllegalArgumentError | ||
* @description Name of error type. Default: `"IllegalArgumentError"`. | ||
*/ | ||
this.type = this.constructor.name; | ||
/** | ||
* @doc property | ||
* @id errors.types:IllegalArgumentError.errors | ||
* @name errors | ||
* @propertyOf errors.types:IllegalArgumentError | ||
* @description Object containing information about the error. | ||
*/ | ||
this.errors = errors || {}; | ||
/** | ||
* @doc property | ||
* @id errors.types:IllegalArgumentError.message | ||
* @name message | ||
* @propertyOf errors.types:IllegalArgumentError | ||
* @description Error message. Default: `"Illegal Argument!"`. | ||
*/ | ||
this.message = message || 'Illegal Argument!'; | ||
/** | ||
* @doc property | ||
* @id errors.types:IllegalArgumentError.message | ||
* @name message | ||
* @propertyOf errors.types:IllegalArgumentError | ||
* @description Error message. Default: `"Illegal Argument!"`. | ||
*/ | ||
this.message = message || 'Illegal Argument!'; | ||
} | ||
@@ -111,37 +44,27 @@ | ||
* @param {string=} message Error message. Default: `"Runtime Error!"`. | ||
* @param {object=} errors Object containing information about the error. | ||
* @returns {RuntimeError} A new instance of `RuntimeError`. | ||
*/ | ||
function RuntimeError(message, errors) { | ||
Error.call(this); | ||
if (typeof Error.captureStackTrace === 'function') { | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
function RuntimeError(message) { | ||
Error.call(this); | ||
if (typeof Error.captureStackTrace === 'function') { | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
/** | ||
* @doc property | ||
* @id errors.types:RuntimeError.type | ||
* @name type | ||
* @propertyOf errors.types:RuntimeError | ||
* @description Name of error type. Default: `"RuntimeError"`. | ||
*/ | ||
this.type = this.constructor.name; | ||
/** | ||
* @doc property | ||
* @id errors.types:RuntimeError.type | ||
* @name type | ||
* @propertyOf errors.types:RuntimeError | ||
* @description Name of error type. Default: `"RuntimeError"`. | ||
*/ | ||
this.type = this.constructor.name; | ||
/** | ||
* @doc property | ||
* @id errors.types:RuntimeError.errors | ||
* @name errors | ||
* @propertyOf errors.types:RuntimeError | ||
* @description Object containing information about the error. | ||
*/ | ||
this.errors = errors || {}; | ||
/** | ||
* @doc property | ||
* @id errors.types:RuntimeError.message | ||
* @name message | ||
* @propertyOf errors.types:RuntimeError | ||
* @description Error message. Default: `"Runtime Error!"`. | ||
*/ | ||
this.message = message || 'RuntimeError Error!'; | ||
/** | ||
* @doc property | ||
* @id errors.types:RuntimeError.message | ||
* @name message | ||
* @propertyOf errors.types:RuntimeError | ||
* @description Error message. Default: `"Runtime Error!"`. | ||
*/ | ||
this.message = message || 'RuntimeError Error!'; | ||
} | ||
@@ -153,2 +76,38 @@ | ||
/** | ||
* @doc function | ||
* @id errors.types:NonexistentResourceError | ||
* @name NonexistentResourceError | ||
* @description Error that is thrown/returned when trying to access a resource that does not exist. | ||
* @param {string=} resourceName Name of non-existent resource. | ||
* @returns {NonexistentResourceError} A new instance of `NonexistentResourceError`. | ||
*/ | ||
function NonexistentResourceError(resourceName) { | ||
Error.call(this); | ||
if (typeof Error.captureStackTrace === 'function') { | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
/** | ||
* @doc property | ||
* @id errors.types:NonexistentResourceError.type | ||
* @name type | ||
* @propertyOf errors.types:NonexistentResourceError | ||
* @description Name of error type. Default: `"NonexistentResourceError"`. | ||
*/ | ||
this.type = this.constructor.name; | ||
/** | ||
* @doc property | ||
* @id errors.types:NonexistentResourceError.message | ||
* @name message | ||
* @propertyOf errors.types:NonexistentResourceError | ||
* @description Error message. Default: `"Runtime Error!"`. | ||
*/ | ||
this.message = (resourceName || '') + ' is not a registered resource!'; | ||
} | ||
NonexistentResourceError.prototype = Object.create(Error.prototype); | ||
NonexistentResourceError.prototype.constructor = NonexistentResourceError; | ||
/** | ||
* @doc interface | ||
@@ -160,5 +119,5 @@ * @id errors | ||
* | ||
* - [UnhandledError](/documentation/api/api/errors.types:UnhandledError) | ||
* - [IllegalArgumentError](/documentation/api/api/errors.types:IllegalArgumentError) | ||
* - [RuntimeError](/documentation/api/api/errors.types:RuntimeError) | ||
* - [NonexistentResourceError](/documentation/api/api/errors.types:NonexistentResourceError) | ||
* | ||
@@ -168,7 +127,10 @@ * References to the constructor functions of these errors can be found in `DS.errors`. | ||
module.exports = [function () { | ||
return { | ||
UnhandledError: UnhandledError, | ||
IllegalArgumentError: IllegalArgumentError, | ||
RuntimeError: RuntimeError | ||
}; | ||
return { | ||
IllegalArgumentError: IllegalArgumentError, | ||
IA: IllegalArgumentError, | ||
RuntimeError: RuntimeError, | ||
R: RuntimeError, | ||
NonexistentResourceError: NonexistentResourceError, | ||
NER: NonexistentResourceError | ||
}; | ||
}]; |
148
src/index.js
(function (window, angular, undefined) { | ||
'use strict'; | ||
'use strict'; | ||
/** | ||
* @doc overview | ||
* @id angular-data | ||
* @name angular-data | ||
* @description | ||
* __Version:__ 0.9.0 | ||
* | ||
* ## Install | ||
* | ||
* #### Bower | ||
* ```text | ||
* bower install angular-data | ||
* ``` | ||
* | ||
* Load `dist/angular-data.js` or `dist/angular-data.min.js` onto your web page after Angular.js. | ||
* | ||
* #### Npm | ||
* ```text | ||
* npm install angular-data | ||
* ``` | ||
* | ||
* Load `dist/angular-data.js` or `dist/angular-data.min.js` onto your web page after Angular.js. | ||
* | ||
* #### Manual download | ||
* Download angular-data-<%= pkg.version %>.js from the [Releases](https://github.com/jmdobry/angular-data/releases) | ||
* section of the angular-data GitHub project. | ||
* | ||
* ## Load into Angular | ||
* Your Angular app must depend on the module `"angular-data.DS"` in order to use angular-data. Loading | ||
* angular-data into your app allows you to inject the following: | ||
* | ||
* - `DS` | ||
* - `DSHttpAdapter` | ||
* - `DSUtils` | ||
* - `DSErrors` | ||
* | ||
* [DS](/documentation/api/api/DS) is the Data Store itself, which you will inject often. | ||
* [DSHttpAdapter](/documentation/api/api/DSHttpAdapter) is useful as a wrapper for `$http` and is configurable. | ||
* [DSUtils](/documentation/api/api/DSUtils) has some useful utility methods. | ||
* [DSErrors](/documentation/api/api/DSErrors) provides references to the various errors thrown by the data store. | ||
*/ | ||
angular.module('angular-data.DS', ['ng']) | ||
.factory('DSUtils', require('./utils')) | ||
.factory('DSErrors', require('./errors')) | ||
.provider('DSHttpAdapter', require('./adapters/http')) | ||
.provider('DSLocalStorageAdapter', require('./adapters/localStorage')) | ||
.provider('DS', require('./datastore')) | ||
.config(['$provide', function ($provide) { | ||
$provide.decorator('$q', ['$delegate', function ($delegate) { | ||
// do whatever you you want | ||
$delegate.promisify = function (fn, target) { | ||
var _this = this; | ||
return function () { | ||
var deferred = _this.defer(), | ||
args = Array.prototype.slice.apply(arguments); | ||
/** | ||
* @doc overview | ||
* @id angular-data | ||
* @name angular-data | ||
* @description | ||
* __Version:__ 0.10.0 | ||
* | ||
* ## Install | ||
* | ||
* #### Bower | ||
* ```text | ||
* bower install angular-data | ||
* ``` | ||
* | ||
* Load `dist/angular-data.js` or `dist/angular-data.min.js` onto your web page after Angular.js. | ||
* | ||
* #### Npm | ||
* ```text | ||
* npm install angular-data | ||
* ``` | ||
* | ||
* Load `dist/angular-data.js` or `dist/angular-data.min.js` onto your web page after Angular.js. | ||
* | ||
* #### Manual download | ||
* Download angular-data-<%= pkg.version %>.js from the [Releases](https://github.com/jmdobry/angular-data/releases) | ||
* section of the angular-data GitHub project. | ||
* | ||
* ## Load into Angular | ||
* Your Angular app must depend on the module `"angular-data.DS"` in order to use angular-data. Loading | ||
* angular-data into your app allows you to inject the following: | ||
* | ||
* - `DS` | ||
* - `DSHttpAdapter` | ||
* - `DSUtils` | ||
* - `DSErrors` | ||
* | ||
* [DS](/documentation/api/api/DS) is the Data Store itself, which you will inject often. | ||
* [DSHttpAdapter](/documentation/api/api/DSHttpAdapter) is useful as a wrapper for `$http` and is configurable. | ||
* [DSUtils](/documentation/api/api/DSUtils) has some useful utility methods. | ||
* [DSErrors](/documentation/api/api/DSErrors) provides references to the various errors thrown by the data store. | ||
*/ | ||
angular.module('angular-data.DS', ['ng']) | ||
.factory('DSUtils', require('./utils')) | ||
.factory('DSErrors', require('./errors')) | ||
.provider('DSHttpAdapter', require('./adapters/http')) | ||
.provider('DSLocalStorageAdapter', require('./adapters/localStorage')) | ||
.provider('DS', require('./datastore')) | ||
.config(['$provide', function ($provide) { | ||
$provide.decorator('$q', ['$delegate', function ($delegate) { | ||
// do whatever you you want | ||
$delegate.promisify = function (fn, target) { | ||
var _this = this; | ||
return function () { | ||
var deferred = _this.defer(), | ||
args = Array.prototype.slice.apply(arguments); | ||
args.push(function (err, result) { | ||
if (err) { | ||
deferred.reject(err); | ||
} else { | ||
deferred.resolve(result); | ||
} | ||
}); | ||
args.push(function (err, result) { | ||
if (err) { | ||
deferred.reject(err); | ||
} else { | ||
deferred.resolve(result); | ||
} | ||
}); | ||
try { | ||
fn.apply(target || this, args); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
try { | ||
fn.apply(target || this, args); | ||
} catch (err) { | ||
deferred.reject(err); | ||
} | ||
return deferred.promise; | ||
}; | ||
}; | ||
return $delegate; | ||
}]); | ||
}]); | ||
return deferred.promise; | ||
}; | ||
}; | ||
return $delegate; | ||
}]); | ||
}]); | ||
})(window, window.angular); |
140
src/utils.js
module.exports = [function () { | ||
return { | ||
isString: angular.isString, | ||
isArray: angular.isArray, | ||
isObject: angular.isObject, | ||
isNumber: angular.isNumber, | ||
isFunction: angular.isFunction, | ||
isEmpty: require('mout/lang/isEmpty'), | ||
toJson: angular.toJson, | ||
makePath: require('mout/string/makePath'), | ||
upperCase: require('mout/string/upperCase'), | ||
deepMixIn: require('mout/object/deepMixIn'), | ||
forOwn: require('mout/object/forOwn'), | ||
pick: require('mout/object/pick'), | ||
set: require('mout/object/set'), | ||
contains: require('mout/array/contains'), | ||
filter: require('mout/array/filter'), | ||
toLookup: require('mout/array/toLookup'), | ||
slice: require('mout/array/slice'), | ||
sort: require('mout/array/sort'), | ||
updateTimestamp: function (timestamp) { | ||
var newTimestamp = typeof Date.now === 'function' ? Date.now() : new Date().getTime(); | ||
if (timestamp && newTimestamp <= timestamp) { | ||
return timestamp + 1; | ||
} else { | ||
return newTimestamp; | ||
} | ||
}, | ||
deepFreeze: function deepFreeze(o) { | ||
if (typeof Object.freeze === 'function') { | ||
var prop, propKey; | ||
Object.freeze(o); // First freeze the object. | ||
for (propKey in o) { | ||
prop = o[propKey]; | ||
if (!o.hasOwnProperty(propKey) || typeof prop !== 'object' || Object.isFrozen(prop)) { | ||
// If the object is on the prototype, not an object, or is already frozen, | ||
// skip it. Note that this might leave an unfrozen reference somewhere in the | ||
// object if there is an already frozen object containing an unfrozen object. | ||
continue; | ||
} | ||
return { | ||
isString: angular.isString, | ||
isArray: angular.isArray, | ||
isObject: angular.isObject, | ||
isNumber: angular.isNumber, | ||
isFunction: angular.isFunction, | ||
isEmpty: require('mout/lang/isEmpty'), | ||
toJson: angular.toJson, | ||
makePath: require('mout/string/makePath'), | ||
upperCase: require('mout/string/upperCase'), | ||
deepMixIn: require('mout/object/deepMixIn'), | ||
forOwn: require('mout/object/forOwn'), | ||
pick: require('mout/object/pick'), | ||
set: require('mout/object/set'), | ||
contains: require('mout/array/contains'), | ||
filter: require('mout/array/filter'), | ||
toLookup: require('mout/array/toLookup'), | ||
slice: require('mout/array/slice'), | ||
sort: require('mout/array/sort'), | ||
updateTimestamp: function (timestamp) { | ||
var newTimestamp = typeof Date.now === 'function' ? Date.now() : new Date().getTime(); | ||
if (timestamp && newTimestamp <= timestamp) { | ||
return timestamp + 1; | ||
} else { | ||
return newTimestamp; | ||
} | ||
}, | ||
deepFreeze: function deepFreeze(o) { | ||
if (typeof Object.freeze === 'function') { | ||
var prop, propKey; | ||
Object.freeze(o); // First freeze the object. | ||
for (propKey in o) { | ||
prop = o[propKey]; | ||
if (!o.hasOwnProperty(propKey) || typeof prop !== 'object' || Object.isFrozen(prop)) { | ||
// If the object is on the prototype, not an object, or is already frozen, | ||
// skip it. Note that this might leave an unfrozen reference somewhere in the | ||
// object if there is an already frozen object containing an unfrozen object. | ||
continue; | ||
} | ||
deepFreeze(prop); // Recursively call deepFreeze. | ||
} | ||
} | ||
}, | ||
diffObjectFromOldObject: function (object, oldObject) { | ||
var added = {}; | ||
var removed = {}; | ||
var changed = {}; | ||
deepFreeze(prop); // Recursively call deepFreeze. | ||
} | ||
} | ||
}, | ||
diffObjectFromOldObject: function (object, oldObject) { | ||
var added = {}; | ||
var removed = {}; | ||
var changed = {}; | ||
for (var prop in oldObject) { | ||
var newValue = object[prop]; | ||
for (var prop in oldObject) { | ||
var newValue = object[prop]; | ||
if (newValue !== undefined && newValue === oldObject[prop]) | ||
continue; | ||
if (newValue !== undefined && newValue === oldObject[prop]) | ||
continue; | ||
if (!(prop in object)) { | ||
removed[prop] = undefined; | ||
continue; | ||
} | ||
if (!(prop in object)) { | ||
removed[prop] = undefined; | ||
continue; | ||
} | ||
if (newValue !== oldObject[prop]) | ||
changed[prop] = newValue; | ||
} | ||
if (newValue !== oldObject[prop]) | ||
changed[prop] = newValue; | ||
} | ||
for (var prop2 in object) { | ||
if (prop2 in oldObject) | ||
continue; | ||
for (var prop2 in object) { | ||
if (prop2 in oldObject) | ||
continue; | ||
added[prop2] = object[prop2]; | ||
} | ||
added[prop2] = object[prop2]; | ||
} | ||
return { | ||
added: added, | ||
removed: removed, | ||
changed: changed | ||
}; | ||
} | ||
}; | ||
return { | ||
added: added, | ||
removed: removed, | ||
changed: changed | ||
}; | ||
} | ||
}; | ||
}]; |
Sorry, the diff of this file is too big to display
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
385165
46
9415