From 12a029e95768dbde682e77411c43a0f4a6a9a6ef Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Thu, 10 Jul 2014 21:26:15 -0600 Subject: [PATCH] Fixes #88. Fixes #89. Stable Version 0.10.0-beta.2. --- CHANGELOG.md | 8 ++- Gruntfile.js | 4 +- README.md | 15 ++--- dist/angular-data.js | 57 +++++++++++------- dist/angular-data.min.js | 2 +- guide/angular-data/queries.md | 10 +++- src/datastore/async_methods/create.js | 23 ++++++-- src/datastore/async_methods/find.js | 3 +- src/datastore/async_methods/findAll.js | 3 +- src/datastore/async_methods/refresh.js | 2 +- src/datastore/async_methods/save.js | 20 +++++-- src/datastore/async_methods/update.js | 3 +- src/datastore/async_methods/updateAll.js | 3 +- .../datastore/async_methods/create.test.js | 20 +++++++ .../datastore/async_methods/save.test.js | 58 ++++++++++++++++--- 15 files changed, 170 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3771b34..e5f450d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,14 @@ -##### 0.10.0-beta.2 - xx July 2014 +##### 0.10.0-beta.2 - 10 July 2014 + +###### Backwards compatible API changes +- #89 - Added the `cacheResponse` option to `DS.create` and `DS.save` ###### Backwards compatible bug fixes - #87 - Filter where boolean values +###### Other +- #88 - Fixed guide documentation for the simple default `where` filter + ##### 0.10.0-beta.1 - 28 June 2014 ###### Breaking API changes diff --git a/Gruntfile.js b/Gruntfile.js index 2ec3e89..eaebe18 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -11,8 +11,8 @@ module.exports = function (grunt) { require('load-grunt-tasks')(grunt); require('time-grunt')(grunt); - var dev = process.cwd().indexOf('/home/jdobry/angular-data') === -1, - pkg = grunt.file.readJSON('package.json'); + var dev = process.cwd().indexOf('/home/jdobry/angular-data') === -1; + var pkg = grunt.file.readJSON('package.json'); // Project configuration. grunt.initConfig({ diff --git a/README.md b/README.md index 5891181..1ab17ab 100644 --- a/README.md +++ b/README.md @@ -3,23 +3,24 @@ __Data store for Angular.js.__ __Latest Release:__ [0.9.1](http://angular-data.pseudobry.com/) -__master:__ [0.9.1](http://angular-data-next.pseudobry.com/) +__master:__ [0.10.0-beta.2](http://angular-data-next.pseudobry.com/) -Angular-data is in a pre-1.0.0 development stage; the API is fluctuating, not a lot of tests yet, etc. +Angular-data is approaching 1.0.0 Beta. The API is stabilizing and angular-data is well tested. -Not for production use (yet). If you still want to develop with Angular-data, be prepared to keep a close eye on the changelog, as the API is still liable to change before 1.0.0. +Angular-data is being used in production, though it's not 1.0.0. If you want to use Angular-data, keep an eye on the changelog. 1.0.0 will introduce strict semver (minor number is bumped for breaking changes right now). Roadmap: -- Relations/Associations -- Various Adapters -- Schema Definition/Validation +- Even more adapters - Nested Resources -- See [issues](https://github.com/jmdobry/angular-data/issues?milestone=7&page=1&state=open) for what's in development +- See [issues](https://github.com/jmdobry/angular-data/issues?page=1&state=open) for what's in development - See [Design Doc](https://docs.google.com/document/d/1o069KLuBH4jpwm1FCLZFwKMgM73Xi8_1JyjhSxVpidM/edit?usp=sharing) for other juicy reading material ## Changelog [CHANGELOG.md](https://github.com/jmdobry/angular-data/blob/master/CHANGELOG.md) +## Version Migration +[TRANSITION.md](https://github.com/jmdobry/angular-data/blob/master/TRANSITION.md) + ## Resources #### Community diff --git a/dist/angular-data.js b/dist/angular-data.js index ccf55e0..440518b 100644 --- a/dist/angular-data.js +++ b/dist/angular-data.js @@ -1854,7 +1854,10 @@ var errorPrefix = 'DS.create(resourceName, attrs[, options]): '; * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. * @param {object} attrs The attributes with which to update the item of the type specified by `resourceName` that has * the primary key specified by `id`. - * @param {object=} options Configuration options. + * @param {object=} options Configuration options. Properties: + * + * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. + * * @returns {Promise} Promise produced by the `$q` service. * * ## Resolves with: @@ -1882,6 +1885,10 @@ function create(resourceName, attrs, options) { var resource = this.store[resourceName]; var _this = this; + if (!('cacheResponse' in options)) { + options.cacheResponse = true; + } + promise = promise .then(function (attrs) { return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); @@ -1902,11 +1909,15 @@ function create(resourceName, attrs, options) { 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); + if (options.cacheResponse) { + 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); + } else { + return data; + } }); deferred.resolve(attrs); @@ -2133,6 +2144,7 @@ var errorPrefix = 'DS.find(resourceName, id[, options]): '; * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. * @param {string|number} id The primary key of the item to retrieve. * @param {object=} options Optional configuration. Properties: + * * - `{boolean=}` - `bypassCache` - Bypass the cache. Default: `false`. * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. * @@ -2166,8 +2178,6 @@ function find(resourceName, id, options) { if (!('cacheResponse' in options)) { options.cacheResponse = true; - } else { - options.cacheResponse = !!options.cacheResponse; } var definition = this.definitions[resourceName]; @@ -2316,6 +2326,7 @@ function _findAll(utils, resourceName, params, options) { * - `{string|array=}` - `orderBy` - OrderBy clause. * * @param {object=} options Optional configuration. Properties: + * * - `{boolean=}` - `bypassCache` - Bypass the cache. Default: `false`. * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. * @@ -2351,8 +2362,6 @@ function findAll(resourceName, params, options) { if (!('cacheResponse' in options)) { options.cacheResponse = true; - } else { - options.cacheResponse = !!options.cacheResponse; } promise = promise.then(function () { @@ -2645,7 +2654,7 @@ var errorPrefix = 'DS.refresh(resourceName, id[, options]): '; * * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. * @param {string|number} id The primary key of the item to refresh from the server. - * @param {object=} options Optional configuration. Properties: + * @param {object=} options Optional configuration passed through to `DS.find` if it is called. * @returns {false|Promise} `false` if the item doesn't already exist in the data store. A `Promise` if the item does * exist in the data store and is being refreshed. * @@ -2712,7 +2721,9 @@ var errorPrefix = 'DS.save(resourceName, id[, options]): '; * * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. * @param {string|number} id The primary key of the item to retrieve. - * @param {object=} options Optional configuration. Properties: + * @param {object=} options Optional configuration. Properties:: + * + * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. * - `{boolean=}` - `changesOnly` - Only send changed and added values back to the server. * * @returns {Promise} Promise produced by the `$q` service. @@ -2753,6 +2764,10 @@ function save(resourceName, id, options) { var resource = this.store[resourceName]; var _this = this; + if (!('cacheResponse' in options)) { + options.cacheResponse = true; + } + promise = promise .then(function (attrs) { return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); @@ -2792,10 +2807,14 @@ function save(resourceName, id, options) { 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); + if (options.cacheResponse) { + var saved = _this.inject(definition.name, data, options); + resource.previousAttributes[id] = _this.utils.deepMixIn({}, saved); + resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]); + return _this.get(resourceName, id); + } else { + return data; + } }); deferred.resolve(item); @@ -2842,6 +2861,7 @@ var errorPrefix = 'DS.update(resourceName, id, attrs[, options]): '; * @param {string|number} id The primary key of the item to update. * @param {object} attrs The attributes with which to update the item. * @param {object=} options Optional configuration. Properties: + * * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. * * @returns {Promise} Promise produced by the `$q` service. @@ -2880,8 +2900,6 @@ function update(resourceName, id, attrs, options) { if (!('cacheResponse' in options)) { options.cacheResponse = true; - } else { - options.cacheResponse = !!options.cacheResponse; } promise = promise @@ -2973,6 +2991,7 @@ var errorPrefix = 'DS.updateAll(resourceName, attrs, params[, options]): '; * - `{string|array=}` - `orderBy` - OrderBy clause. * * @param {object=} options Optional configuration. Properties: + * * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. * * @returns {Promise} Promise produced by the `$q` service. @@ -3010,8 +3029,6 @@ function updateAll(resourceName, attrs, params, options) { if (!('cacheResponse' in options)) { options.cacheResponse = true; - } else { - options.cacheResponse = !!options.cacheResponse; } promise = promise diff --git a/dist/angular-data.min.js b/dist/angular-data.min.js index b9fe8d0..8b0e78d 100644 --- a/dist/angular-data.min.js +++ b/dist/angular-data.min.js @@ -7,5 +7,5 @@ * * @overview Data store for Angular.js. */ -!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;gb&&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;fa&&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;ba&&(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;++gc?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?c=b?a[f]>d:c&&a[f]>d:">="===g?c=b?a[f]>=d:c&&a[f]>=d:"<"===g?c=b?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]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=kb&&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;fa&&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;ba&&(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;++gc?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?c=b?a[f]>d:c&&a[f]>d:">="===g?c=b?a[f]>=d:c&&a[f]>=d:"<"===g?c=b?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]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=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/isBoolean":14,"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}]},{},[61]); \ No newline at end of file diff --git a/guide/angular-data/queries.md b/guide/angular-data/queries.md index ea7fc97..149dfb1 100644 --- a/guide/angular-data/queries.md +++ b/guide/angular-data/queries.md @@ -221,7 +221,9 @@ DS.filter('post', { #### Shortcuts -These are equivalent: +###### `==` operator shortcut + +The following are equivalent: ```js DS.filter('post', { author: 'John' @@ -234,13 +236,15 @@ DS.filter('post', { DS.filter('post', { where: { author: { - 'in': ['John', 'Sally'] + '==': 'John' } } }); ``` -These are equivalent: +###### `orderBy` shortcut + +The following are equivalent: ```js DS.filter('post', { orderBy: 'age' diff --git a/src/datastore/async_methods/create.js b/src/datastore/async_methods/create.js index 2be26c3..571bde9 100644 --- a/src/datastore/async_methods/create.js +++ b/src/datastore/async_methods/create.js @@ -29,7 +29,10 @@ var errorPrefix = 'DS.create(resourceName, attrs[, options]): '; * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. * @param {object} attrs The attributes with which to update the item of the type specified by `resourceName` that has * the primary key specified by `id`. - * @param {object=} options Configuration options. + * @param {object=} options Configuration options. Properties: + * + * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. + * * @returns {Promise} Promise produced by the `$q` service. * * ## Resolves with: @@ -57,6 +60,10 @@ function create(resourceName, attrs, options) { var resource = this.store[resourceName]; var _this = this; + if (!('cacheResponse' in options)) { + options.cacheResponse = true; + } + promise = promise .then(function (attrs) { return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); @@ -77,11 +84,15 @@ function create(resourceName, attrs, options) { 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); + if (options.cacheResponse) { + 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); + } else { + return data; + } }); deferred.resolve(attrs); diff --git a/src/datastore/async_methods/find.js b/src/datastore/async_methods/find.js index b94f8d6..038e6a7 100644 --- a/src/datastore/async_methods/find.js +++ b/src/datastore/async_methods/find.js @@ -29,6 +29,7 @@ var errorPrefix = 'DS.find(resourceName, id[, options]): '; * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. * @param {string|number} id The primary key of the item to retrieve. * @param {object=} options Optional configuration. Properties: + * * - `{boolean=}` - `bypassCache` - Bypass the cache. Default: `false`. * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. * @@ -62,8 +63,6 @@ function find(resourceName, id, options) { if (!('cacheResponse' in options)) { options.cacheResponse = true; - } else { - options.cacheResponse = !!options.cacheResponse; } var definition = this.definitions[resourceName]; diff --git a/src/datastore/async_methods/findAll.js b/src/datastore/async_methods/findAll.js index 98275bb..7820979 100644 --- a/src/datastore/async_methods/findAll.js +++ b/src/datastore/async_methods/findAll.js @@ -103,6 +103,7 @@ function _findAll(utils, resourceName, params, options) { * - `{string|array=}` - `orderBy` - OrderBy clause. * * @param {object=} options Optional configuration. Properties: + * * - `{boolean=}` - `bypassCache` - Bypass the cache. Default: `false`. * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. * @@ -138,8 +139,6 @@ function findAll(resourceName, params, options) { if (!('cacheResponse' in options)) { options.cacheResponse = true; - } else { - options.cacheResponse = !!options.cacheResponse; } promise = promise.then(function () { diff --git a/src/datastore/async_methods/refresh.js b/src/datastore/async_methods/refresh.js index 53f8144..918a6b6 100644 --- a/src/datastore/async_methods/refresh.js +++ b/src/datastore/async_methods/refresh.js @@ -35,7 +35,7 @@ var errorPrefix = 'DS.refresh(resourceName, id[, options]): '; * * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. * @param {string|number} id The primary key of the item to refresh from the server. - * @param {object=} options Optional configuration. Properties: + * @param {object=} options Optional configuration passed through to `DS.find` if it is called. * @returns {false|Promise} `false` if the item doesn't already exist in the data store. A `Promise` if the item does * exist in the data store and is being refreshed. * diff --git a/src/datastore/async_methods/save.js b/src/datastore/async_methods/save.js index 0429171..ac9c154 100644 --- a/src/datastore/async_methods/save.js +++ b/src/datastore/async_methods/save.js @@ -27,7 +27,9 @@ var errorPrefix = 'DS.save(resourceName, id[, options]): '; * * @param {string} resourceName The resource type, e.g. 'user', 'comment', etc. * @param {string|number} id The primary key of the item to retrieve. - * @param {object=} options Optional configuration. Properties: + * @param {object=} options Optional configuration. Properties:: + * + * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. * - `{boolean=}` - `changesOnly` - Only send changed and added values back to the server. * * @returns {Promise} Promise produced by the `$q` service. @@ -68,6 +70,10 @@ function save(resourceName, id, options) { var resource = this.store[resourceName]; var _this = this; + if (!('cacheResponse' in options)) { + options.cacheResponse = true; + } + promise = promise .then(function (attrs) { return _this.$q.promisify(definition.beforeValidate)(resourceName, attrs); @@ -107,10 +113,14 @@ function save(resourceName, id, options) { 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); + if (options.cacheResponse) { + var saved = _this.inject(definition.name, data, options); + resource.previousAttributes[id] = _this.utils.deepMixIn({}, saved); + resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]); + return _this.get(resourceName, id); + } else { + return data; + } }); deferred.resolve(item); diff --git a/src/datastore/async_methods/update.js b/src/datastore/async_methods/update.js index 784e756..e895692 100644 --- a/src/datastore/async_methods/update.js +++ b/src/datastore/async_methods/update.js @@ -31,6 +31,7 @@ var errorPrefix = 'DS.update(resourceName, id, attrs[, options]): '; * @param {string|number} id The primary key of the item to update. * @param {object} attrs The attributes with which to update the item. * @param {object=} options Optional configuration. Properties: + * * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. * * @returns {Promise} Promise produced by the `$q` service. @@ -69,8 +70,6 @@ function update(resourceName, id, attrs, options) { if (!('cacheResponse' in options)) { options.cacheResponse = true; - } else { - options.cacheResponse = !!options.cacheResponse; } promise = promise diff --git a/src/datastore/async_methods/updateAll.js b/src/datastore/async_methods/updateAll.js index a78f65a..26a62bb 100644 --- a/src/datastore/async_methods/updateAll.js +++ b/src/datastore/async_methods/updateAll.js @@ -45,6 +45,7 @@ var errorPrefix = 'DS.updateAll(resourceName, attrs, params[, options]): '; * - `{string|array=}` - `orderBy` - OrderBy clause. * * @param {object=} options Optional configuration. Properties: + * * - `{boolean=}` - `cacheResponse` - Inject the data returned by the server into the data store. Default: `true`. * * @returns {Promise} Promise produced by the `$q` service. @@ -82,8 +83,6 @@ function updateAll(resourceName, attrs, params, options) { if (!('cacheResponse' in options)) { options.cacheResponse = true; - } else { - options.cacheResponse = !!options.cacheResponse; } promise = promise diff --git a/test/integration/datastore/async_methods/create.test.js b/test/integration/datastore/async_methods/create.test.js index 02e198f..5f8d78b 100644 --- a/test/integration/datastore/async_methods/create.test.js +++ b/test/integration/datastore/async_methods/create.test.js @@ -40,6 +40,26 @@ describe('DS.create(resourceName, attrs[, options])', function () { assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called'); assert.deepEqual(DS.get('post', 5), p1); }); + it('should create an item and save it to the server but not inject the result', function () { + $httpBackend.expectPOST('http://test.angular-cache.com/posts').respond(200, p1); + + DS.create('post', { author: 'John', age: 30 }, { cacheResponse: false }).then(function (post) { + assert.deepEqual(post, p1, 'post 5 should have been created'); + }, function (err) { + console.error(err.stack); + fail('should not have rejected'); + }); + + $httpBackend.flush(); + + assert.equal(lifecycle.beforeCreate.callCount, 1, 'beforeCreate should have been called'); + assert.equal(lifecycle.afterCreate.callCount, 1, 'afterCreate should have been called'); + assert.equal(lifecycle.beforeInject.callCount, 0, 'beforeInject should not have been called'); + assert.equal(lifecycle.afterInject.callCount, 0, 'afterInject should not have been called'); + assert.equal(lifecycle.serialize.callCount, 1, 'serialize should have been called'); + assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called'); + assert.isUndefined(DS.get('post', 5)); + }); it('should create an item that includes relations, save them to the server and inject the results', function () { var payload = { id: 99, diff --git a/test/integration/datastore/async_methods/save.test.js b/test/integration/datastore/async_methods/save.test.js index 13d3822..dad558f 100644 --- a/test/integration/datastore/async_methods/save.test.js +++ b/test/integration/datastore/async_methods/save.test.js @@ -31,18 +31,22 @@ describe('DS.save(resourceName, id[, options])', function () { } }); }); - it('should save an item to the server', function () { - $httpBackend.expectPUT('http://test.angular-cache.com/posts/5').respond(200, p1); + it('should save an item to the server and inject the result', function () { + $httpBackend.expectPUT('http://test.angular-cache.com/posts/5').respond(200, { + author: 'Jake', + id: 5, + age: 30 + }); DS.inject('post', p1); - var initialModified = DS.lastModified('post', 5), - initialSaved = DS.lastSaved('post', 5); + var initialModified = DS.lastModified('post', 5); + var initialSaved = DS.lastSaved('post', 5); - p1.author = 'Jake'; + DS.get('post', 5).author = 'Jake'; DS.save('post', 5).then(function (post) { - assert.deepEqual(post, p1, 'post 5 should have been saved'); + assert.deepEqual(post, DS.get('post', 5), 'post 5 should have been saved'); assert.equal(post.author, 'Jake'); }, function (err) { console.error(err.stack); @@ -53,7 +57,11 @@ describe('DS.save(resourceName, id[, options])', function () { assert.equal(lifecycle.beforeUpdate.callCount, 1, 'beforeUpdate should have been called'); assert.equal(lifecycle.afterUpdate.callCount, 1, 'afterUpdate should have been called'); - assert.deepEqual(DS.get('post', 5), p1); + assert.deepEqual(DS.get('post', 5), { + author: 'Jake', + id: 5, + age: 30 + }); assert.notEqual(DS.lastModified('post', 5), initialModified); assert.notEqual(DS.lastSaved('post', 5), initialSaved); @@ -69,6 +77,42 @@ describe('DS.save(resourceName, id[, options])', function () { assert.equal(lifecycle.serialize.callCount, 1, 'serialize should have been called'); assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called'); }); + it('should save an item to the server but not inject the result', function () { + $httpBackend.expectPUT('http://test.angular-cache.com/posts/5').respond(200, { + random: 'stuff' + }); + + DS.inject('post', p1); + + var initialModified = DS.lastModified('post', 5); + var initialSaved = DS.lastSaved('post', 5); + + DS.get('post', 5).author = 'Jake'; + + DS.save('post', 5, { cacheResponse: false }).then(function (post) { + assert.deepEqual(post, { + random: 'stuff' + }, 'should have the right response'); + }, function (err) { + console.error(err.stack); + fail('should not have rejected'); + }); + + $httpBackend.flush(); + + assert.equal(lifecycle.beforeUpdate.callCount, 1, 'beforeUpdate should have been called'); + assert.equal(lifecycle.afterUpdate.callCount, 1, 'afterUpdate should have been called'); + assert.equal(lifecycle.beforeInject.callCount, 1, 'beforeInject should have been called only once'); + assert.equal(lifecycle.afterInject.callCount, 1, 'afterInject should have been called only once'); + assert.deepEqual(DS.get('post', 5), { + author: 'Jake', + id: 5, + age: 30 + }); + // item wasn't injected + assert.equal(DS.lastModified('post', 5), initialModified); + assert.equal(DS.lastSaved('post', 5), initialSaved); + }); it('should save changes of an item to the server', function () { $httpBackend.expectPUT('http://test.angular-cache.com/posts/5', { author: 'Jake' }).respond(200, { author: 'Jake',