From 9e34ce2c81f90e44558c9309ad26bfaa12129142 Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Sun, 20 Jul 2014 16:21:09 -0600 Subject: [PATCH] Fixes #98. Stable Version 0.10.1. --- CHANGELOG.md | 3 ++- dist/angular-data.js | 4 +++- dist/angular-data.min.js | 2 +- src/datastore/sync_methods/inject.js | 4 +++- .../datastore/async_methods/findAll.test.js | 19 +++++++++++++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ba770c..ba762a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -##### 0.10.1 - xx July 2014 +##### 0.10.1 - 20 July 2014 ##### Backwards compatible API changes - #93 - Added `DS.createInstance(resourceName[, attrs][, options])` @@ -9,6 +9,7 @@ - #91 - dist/angular-data(.min).js doesn't end with a semicolon (upgraded Browserify) - #94 - Resource object name/class inconsistency (added `useClass` option to `DS.defineResource`) - #95 - observe-js outdated (Upgraded observe-js.js an refactored to new API) +- #98 - Missing id warning ##### 0.10.0 - 18 July 2014 diff --git a/dist/angular-data.js b/dist/angular-data.js index 5840d7f..e6035e7 100644 --- a/dist/angular-data.js +++ b/dist/angular-data.js @@ -5020,7 +5020,9 @@ function _inject(definition, resource, attrs) { 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`!'); + var error = new _this.errors.R(errorPrefix + 'attrs: Must contain the property specified by `idAttribute`!'); + $log.error(error); + throw error; } else { try { definition.beforeInject(definition.name, attrs); diff --git a/dist/angular-data.min.js b/dist/angular-data.min.js index a181059..e91640d 100644 --- a/dist/angular-data.min.js +++ b/dist/angular-data.min.js @@ -8,4 +8,4 @@ * @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_();)b++;return global.testingExposeCycleCount&&(global.dirtyCheckCycleCount=b),b>0}function objectIsEmpty(a){for(var b in a)return!1;return!0}function diffIsEmpty(a){return objectIsEmpty(a.added)&&objectIsEmpty(a.removed)&&objectIsEmpty(a.changed)}function diffObjectFromOldObject(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 runEOMTasks(){if(!eomTasks.length)return!1;for(var a=0;acycles&&anyChanged);global.testingExposeCycleCount&&(global.dirtyCheckCycleCount=cycles),runningMicrotaskCheckpoint=!1}}},collectObservers&&(global.Platform.clearObservers=function(){allObservers=[]}),ObjectObserver.prototype=createObject({__proto__:Observer.prototype,arrayObserve:!1,connect_:function(){hasObserve?this.directObserver_=getObservedObject(this,this.value_,this.arrayObserve):this.oldObject_=this.copyObject(this.value_)},copyObject:function(a){var b=Array.isArray(a)?[]:{};for(var c in a)b[c]=a[c];return Array.isArray(a)&&(b.length=a.length),b},check_:function(a){var b,c;if(hasObserve){if(!a)return!1;c={},b=diffObjectFromChangeRecords(this.value_,a,c)}else c=this.oldObject_,b=diffObjectFromOldObject(this.value_,this.oldObject_);return diffIsEmpty(b)?!1:(hasObserve||(this.oldObject_=this.copyObject(this.value_)),this.report_([b.added||{},b.removed||{},b.changed||{},function(a){return c[a]}]),!0)},disconnect_:function(){hasObserve?(this.directObserver_.close(),this.directObserver_=void 0):this.oldObject_=void 0},deliver:function(){this.state_==OPENED&&(hasObserve?this.directObserver_.deliver(!1):dirtyCheck(this))},discardChanges:function(){return this.directObserver_?this.directObserver_.deliver(!0):this.oldObject_=this.copyObject(this.value_),this.value_}});var observerSentinel={},expectedRecordTypes={add:!0,update:!0,"delete":!0};global.Observer=Observer,global.Observer.runEOM_=runEOM,global.Observer.observerSentinel_=observerSentinel,global.Observer.hasObjectObserve=hasObserve,global.ObjectObserver=ObjectObserver}((exports.Number={isNaN:window.isNaN})?exports:exports)},{}],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}]},{},[62]); \ No newline at end of file +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=DS.defaults,DS.definitions[definition.name]=new Resource(DS.utils,definition);var def=DS.definitions[definition.name];def.filter&&(def.defaultFilter=def.filter,delete def.filter);var cache=DS.cacheFactory("DS."+def.name,{maxAge:def.maxAge||null,recycleFreq:def.recycleFreq||1e3,cacheFlushInterval:def.cacheFlushInterval||null,deleteOnExpire:def.deleteOnExpire||"none",onExpire:function(a){DS.eject(def.name,a)},capacity:Number.MAX_VALUE,storageMode:"memory",storageImpl:null,disabled:!1,storagePrefix:"DS."+def.name});return def.class=definition.name[0].toUpperCase()+definition.name.substring(1),eval("function "+def.class+"() {}"),def[def.class]=eval(def.class),def.methods&&DS.utils.deepMixIn(def[def.class].prototype,def.methods),def.computed&&DS.utils.forOwn(def.computed,function(a,b){def.methods&&b in def.methods&&DS.$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=DS.utils.filter(d,function(a){return!!a}),angular.forEach(a.deps,function(b,c){a.deps[c]=b.trim()})}),DS.store[def.name]={collection:[],completedQueries:{},pendingQueries:{},index:cache,modified:{},saved:{},previousAttributes:{},observers:{},collectionModified:0},angular.forEach(methodsToProxy,function(a){def[a]="bindOne"===a||"bindAll"===a?function(){var b=Array.prototype.slice.call(arguments);return b.splice(2,0,def.name),DS[a].apply(DS,b)}:function(){var b=Array.prototype.slice.call(arguments);return b.unshift(def.name),DS[a].apply(DS,b)}}),def}catch(err){throw DS.$log.error(err),delete this.definitions[definition.name],delete this.store[definition.name],err}}var errorPrefix="DS.defineResource(definition): ",methodsToProxy=["bindAll","bindOne","create","createInstance","destroy","destroyAll","filter","find","findAll","get","hasChanges","inject","lastModified","lastSaved","loadRelations","previous","refresh","save","update","updateAll"];module.exports=defineResource},{}],50:[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}],51:[function(a,b){function c(a,b,c){for(var d=!1,e=0;e=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}]},{},[62]); \ No newline at end of file diff --git a/src/datastore/sync_methods/inject.js b/src/datastore/sync_methods/inject.js index 35ca837..ca3a970 100644 --- a/src/datastore/sync_methods/inject.js +++ b/src/datastore/sync_methods/inject.js @@ -56,7 +56,9 @@ function _inject(definition, resource, attrs) { 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`!'); + var error = new _this.errors.R(errorPrefix + 'attrs: Must contain the property specified by `idAttribute`!'); + $log.error(error); + throw error; } else { try { definition.beforeInject(definition.name, attrs); diff --git a/test/integration/datastore/async_methods/findAll.test.js b/test/integration/datastore/async_methods/findAll.test.js index d7de101..143683a 100644 --- a/test/integration/datastore/async_methods/findAll.test.js +++ b/test/integration/datastore/async_methods/findAll.test.js @@ -84,6 +84,25 @@ describe('DS.findAll(resourceName, params[, options]): ', function () { assert.equal(lifecycle.serialize.callCount, 0, 'serialize should have been called'); assert.equal(lifecycle.deserialize.callCount, 2, 'deserialize should have been called'); }); + it('should fail when no "idAttribute" is present on an item in the response', function () { + $httpBackend.expectGET(/http:\/\/test\.angular-cache\.com\/posts\??/).respond(200, [ + { author: 'John', age: 30 }, + { author: 'Sally', age: 31 } + ]); + + DS.findAll('post', {}).then(function () { + fail('Should not have succeeded!'); + }, function (err) { + assert(err.message, 'DS.inject(resourceName, attrs[, options]): attrs: Must contain the property specified by `idAttribute`!'); + assert.deepEqual(DS.filter('post', {}), [], 'The posts should not be in the store'); + }); + + $httpBackend.flush(); + + assert($log.error.logs[0][0].message, 'DS.inject(resourceName, attrs[, options]): attrs: Must contain the property specified by `idAttribute`!'); + assert.equal(lifecycle.beforeInject.callCount, 0, 'beforeInject should not have been called'); + assert.equal(lifecycle.afterInject.callCount, 0, 'afterInject should not have been called'); + }); it('should query the server for a collection but not store the data if cacheResponse is false', function () { $httpBackend.expectGET(/http:\/\/test\.angular-cache\.com\/posts\??/).respond(200, [p1, p2, p3, p4]);