Skip to content

Commit 0980600

Browse files
committed
Closes #145. Closes #156. Closes #167.
1 parent 5cd3490 commit 0980600

File tree

15 files changed

+128
-60
lines changed

15 files changed

+128
-60
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
##### 1.0.0-rc.2 - xx September 2014
2+
3+
###### Backwards compatible API changes
4+
- #145 - Add "useClass" option to inject, find, findAll, create
5+
- #167 - Default params argument of bindAll to empty object
6+
7+
###### Backwards compatible bug fixes
8+
- #156 - cached findAll pending query doesn't get removed sometimes
9+
110
##### 1.0.0-rc.1 - 03 September 2014
211

312
###### Backwards compatible API changes

dist/angular-data.js

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,6 +2199,7 @@ function errorPrefix(resourceName) {
21992199
* @param {object} attrs The attributes with which to create the item of the type specified by `resourceName`.
22002200
* @param {object=} options Configuration options. Also passed along to the adapter's `create` method. Properties:
22012201
*
2202+
* - `{boolean=}` - `useClass` - Whether to wrap the injected item with the resource's instance constructor.
22022203
* - `{boolean=}` - `cacheResponse` - Inject the data returned by the adapter into the data store. Default: `true`.
22032204
* - `{boolean=}` - `upsert` - If `attrs` already contains a primary key, then attempt to call `DS.update` instead. Default: `true`.
22042205
* - `{function=}` - `beforeValidate` - Override the resource or global lifecycle hook.
@@ -2280,7 +2281,7 @@ function create(resourceName, attrs, options) {
22802281
resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]);
22812282
return DS.get(definition.name, id);
22822283
} else {
2283-
return data;
2284+
return DS.createInstance(resourceName, data, options);
22842285
}
22852286
});
22862287
}
@@ -2510,6 +2511,7 @@ function errorPrefix(resourceName, id) {
25102511
* @param {string|number} id The primary key of the item to retrieve.
25112512
* @param {object=} options Optional configuration. Also passed along to the adapter's `find` method. Properties:
25122513
*
2514+
* - `{boolean=}` - `useClass` - Whether to wrap the injected item with the resource's instance constructor.
25132515
* - `{boolean=}` - `bypassCache` - Bypass the cache. Default: `false`.
25142516
* - `{boolean=}` - `cacheResponse` - Inject the data returned by the adapter into the data store. Default: `true`.
25152517
*
@@ -2563,7 +2565,7 @@ function find(resourceName, id, options) {
25632565
resource.completedQueries[id] = new Date().getTime();
25642566
return DS.inject(resourceName, data, options);
25652567
} else {
2566-
return data;
2568+
return DS.createInstance(resourceName, data, options);
25672569
}
25682570
}, function (err) {
25692571
delete resource.pendingQueries[id];
@@ -2640,6 +2642,7 @@ function _findAll(resourceName, params, options) {
26402642
// This particular query has never even been made
26412643
resource.pendingQueries[queryHash] = DS.adapters[options.adapter || definition.defaultAdapter].findAll(definition, params, options)
26422644
.then(function (res) {
2645+
delete resource.pendingQueries[queryHash];
26432646
var data = definition.deserialize(resourceName, res);
26442647
if (options.cacheResponse) {
26452648
try {
@@ -2648,6 +2651,10 @@ function _findAll(resourceName, params, options) {
26482651
return DS.$q.reject(err);
26492652
}
26502653
} else {
2654+
console.log(data);
2655+
DS.utils.forEach(data, function (item, i) {
2656+
data[i] = DS.createInstance(resourceName, item, options);
2657+
});
26512658
return data;
26522659
}
26532660
}, function (err) {
@@ -2708,6 +2715,7 @@ function _findAll(resourceName, params, options) {
27082715
*
27092716
* @param {object=} options Optional configuration. Also passed along to the adapter's `findAll` method. Properties:
27102717
*
2718+
* - `{boolean=}` - `useClass` - Whether to wrap the injected item with the resource's instance constructor.
27112719
* - `{boolean=}` - `bypassCache` - Bypass the cache. Default: `false`.
27122720
* - `{boolean=}` - `cacheResponse` - Inject the data returned by the adapter into the data store. Default: `true`.
27132721
*
@@ -2970,7 +2978,9 @@ function loadRelations(resourceName, instance, relations, options) {
29702978
if (def.localKey && instance[def.localKey]) {
29712979
task = DS.find(relationName, instance[def.localKey], options);
29722980
} else if (def.foreignKey) {
2973-
task = DS.findAll(relationName, params, options);
2981+
task = DS.findAll(relationName, params, options).then(function (hasOnes) {
2982+
return hasOnes.length ? hasOnes[0] : null;
2983+
});
29742984
}
29752985
} else {
29762986
task = DS.find(relationName, instance[def.localKey], options);
@@ -3681,7 +3691,7 @@ Defaults.prototype.defaultFilter = function (collection, resourceName, params, o
36813691
};
36823692
Defaults.prototype.baseUrl = '';
36833693
Defaults.prototype.endpoint = '';
3684-
Defaults.prototype.useClass = false;
3694+
Defaults.prototype.useClass = true;
36853695
/**
36863696
* @doc property
36873697
* @id DSProvider.properties:defaults.beforeValidate
@@ -4300,6 +4310,8 @@ function bindAll(scope, expr, resourceName, params, cb) {
43004310
var DS = this;
43014311
var IA = DS.errors.IA;
43024312

4313+
params = params || {};
4314+
43034315
if (!DS.utils.isObject(scope)) {
43044316
throw new IA(errorPrefix(resourceName) + 'scope: Must be an object!');
43054317
} else if (!DS.utils.isString(expr)) {
@@ -4625,7 +4637,7 @@ function errorPrefix(resourceName) {
46254637
* @param {object=} attrs Optional attributes to mix in to the new instance.
46264638
* @param {object=} options Optional configuration. Properties:
46274639
*
4628-
* - `{boolean=}` - `useClass` - Whether to use the resource's wrapper class. Default: `true`.
4640+
* - `{boolean=}` - `useClass` - Whether to wrap the injected item with the resource's instance constructor.
46294641
*
46304642
* @returns {object} The new instance.
46314643
*/
@@ -4646,7 +4658,7 @@ function createInstance(resourceName, attrs, options) {
46464658
}
46474659

46484660
if (!('useClass' in options)) {
4649-
options.useClass = true;
4661+
options.useClass = definition.useClass;
46504662
}
46514663

46524664
var item;
@@ -5650,7 +5662,7 @@ function errorPrefix(resourceName) {
56505662
return 'DS.inject(' + resourceName + ', attrs[, options]): ';
56515663
}
56525664

5653-
function _inject(definition, resource, attrs) {
5665+
function _inject(definition, resource, attrs, options) {
56545666
var DS = this;
56555667
var $log = DS.$log;
56565668

@@ -5707,7 +5719,7 @@ function _inject(definition, resource, attrs) {
57075719
if (DS.utils.isArray(attrs)) {
57085720
injected = [];
57095721
for (var i = 0; i < attrs.length; i++) {
5710-
injected.push(_inject.call(DS, definition, resource, attrs[i]));
5722+
injected.push(_inject.call(DS, definition, resource, attrs[i], options));
57115723
}
57125724
} else {
57135725
// check if "idAttribute" is a computed property
@@ -5731,7 +5743,7 @@ function _inject(definition, resource, attrs) {
57315743
var item = DS.get(definition.name, id);
57325744

57335745
if (!item) {
5734-
if (definition.methods || definition.useClass) {
5746+
if (options.useClass) {
57355747
if (attrs instanceof definition[definition.class]) {
57365748
item = attrs;
57375749
} else {
@@ -5862,6 +5874,7 @@ function _injectRelations(definition, injected, options) {
58625874
* @param {object|array} attrs The item or collection of items to inject into the data store.
58635875
* @param {object=} options The item or collection of items to inject into the data store. Properties:
58645876
*
5877+
* - `{boolean=}` - `useClass` - Whether to wrap the injected item with the resource's instance constructor.
58655878
* - `{boolean=}` - `findBelongsTo` - Find and attach any existing "belongsTo" relationships to the newly injected item. Potentially expensive if enabled. Default: `false`.
58665879
* - `{boolean=}` - `findHasMany` - Find and attach any existing "hasMany" relationships to the newly injected item. Potentially expensive if enabled. Default: `false`.
58675880
* - `{boolean=}` - `findHasOne` - Find and attach any existing "hasOne" relationships to the newly injected item. Potentially expensive if enabled. Default: `false`.
@@ -5890,12 +5903,15 @@ function inject(resourceName, attrs, options) {
58905903
stack++;
58915904

58925905
try {
5906+
if (!('useClass' in options)) {
5907+
options.useClass = definition.useClass;
5908+
}
58935909
if (!DS.$rootScope.$$phase) {
58945910
DS.$rootScope.$apply(function () {
5895-
injected = _inject.call(DS, definition, resource, attrs);
5911+
injected = _inject.call(DS, definition, resource, attrs, options);
58965912
});
58975913
} else {
5898-
injected = _inject.call(DS, definition, resource, attrs);
5914+
injected = _inject.call(DS, definition, resource, attrs, options);
58995915
}
59005916
if (definition.relations) {
59015917
_injectRelations.call(DS, definition, injected, options);

dist/angular-data.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/datastore/async_methods/create.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ function errorPrefix(resourceName) {
3232
* @param {object} attrs The attributes with which to create the item of the type specified by `resourceName`.
3333
* @param {object=} options Configuration options. Also passed along to the adapter's `create` method. Properties:
3434
*
35+
* - `{boolean=}` - `useClass` - Whether to wrap the injected item with the resource's instance constructor.
3536
* - `{boolean=}` - `cacheResponse` - Inject the data returned by the adapter into the data store. Default: `true`.
3637
* - `{boolean=}` - `upsert` - If `attrs` already contains a primary key, then attempt to call `DS.update` instead. Default: `true`.
3738
* - `{function=}` - `beforeValidate` - Override the resource or global lifecycle hook.
@@ -113,7 +114,7 @@ function create(resourceName, attrs, options) {
113114
resource.saved[id] = DS.utils.updateTimestamp(resource.saved[id]);
114115
return DS.get(definition.name, id);
115116
} else {
116-
return data;
117+
return DS.createInstance(resourceName, data, options);
117118
}
118119
});
119120
}

src/datastore/async_methods/find.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ function errorPrefix(resourceName, id) {
3131
* @param {string|number} id The primary key of the item to retrieve.
3232
* @param {object=} options Optional configuration. Also passed along to the adapter's `find` method. Properties:
3333
*
34+
* - `{boolean=}` - `useClass` - Whether to wrap the injected item with the resource's instance constructor.
3435
* - `{boolean=}` - `bypassCache` - Bypass the cache. Default: `false`.
3536
* - `{boolean=}` - `cacheResponse` - Inject the data returned by the adapter into the data store. Default: `true`.
3637
*
@@ -84,7 +85,7 @@ function find(resourceName, id, options) {
8485
resource.completedQueries[id] = new Date().getTime();
8586
return DS.inject(resourceName, data, options);
8687
} else {
87-
return data;
88+
return DS.createInstance(resourceName, data, options);
8889
}
8990
}, function (err) {
9091
delete resource.pendingQueries[id];

src/datastore/async_methods/findAll.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ function _findAll(resourceName, params, options) {
5353
// This particular query has never even been made
5454
resource.pendingQueries[queryHash] = DS.adapters[options.adapter || definition.defaultAdapter].findAll(definition, params, options)
5555
.then(function (res) {
56+
delete resource.pendingQueries[queryHash];
5657
var data = definition.deserialize(resourceName, res);
5758
if (options.cacheResponse) {
5859
try {
@@ -61,6 +62,10 @@ function _findAll(resourceName, params, options) {
6162
return DS.$q.reject(err);
6263
}
6364
} else {
65+
console.log(data);
66+
DS.utils.forEach(data, function (item, i) {
67+
data[i] = DS.createInstance(resourceName, item, options);
68+
});
6469
return data;
6570
}
6671
}, function (err) {
@@ -121,6 +126,7 @@ function _findAll(resourceName, params, options) {
121126
*
122127
* @param {object=} options Optional configuration. Also passed along to the adapter's `findAll` method. Properties:
123128
*
129+
* - `{boolean=}` - `useClass` - Whether to wrap the injected item with the resource's instance constructor.
124130
* - `{boolean=}` - `bypassCache` - Bypass the cache. Default: `false`.
125131
* - `{boolean=}` - `cacheResponse` - Inject the data returned by the adapter into the data store. Default: `true`.
126132
*

src/datastore/async_methods/loadRelations.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ function loadRelations(resourceName, instance, relations, options) {
107107
if (def.localKey && instance[def.localKey]) {
108108
task = DS.find(relationName, instance[def.localKey], options);
109109
} else if (def.foreignKey) {
110-
task = DS.findAll(relationName, params, options);
110+
task = DS.findAll(relationName, params, options).then(function (hasOnes) {
111+
return hasOnes.length ? hasOnes[0] : null;
112+
});
111113
}
112114
} else {
113115
task = DS.find(relationName, instance[def.localKey], options);

src/datastore/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ Defaults.prototype.defaultFilter = function (collection, resourceName, params, o
184184
};
185185
Defaults.prototype.baseUrl = '';
186186
Defaults.prototype.endpoint = '';
187-
Defaults.prototype.useClass = false;
187+
Defaults.prototype.useClass = true;
188188
/**
189189
* @doc property
190190
* @id DSProvider.properties:defaults.beforeValidate

src/datastore/sync_methods/bindAll.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ function bindAll(scope, expr, resourceName, params, cb) {
4949
var DS = this;
5050
var IA = DS.errors.IA;
5151

52+
params = params || {};
53+
5254
if (!DS.utils.isObject(scope)) {
5355
throw new IA(errorPrefix(resourceName) + 'scope: Must be an object!');
5456
} else if (!DS.utils.isString(expr)) {

src/datastore/sync_methods/createInstance.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function errorPrefix(resourceName) {
5757
* @param {object=} attrs Optional attributes to mix in to the new instance.
5858
* @param {object=} options Optional configuration. Properties:
5959
*
60-
* - `{boolean=}` - `useClass` - Whether to use the resource's wrapper class. Default: `true`.
60+
* - `{boolean=}` - `useClass` - Whether to wrap the injected item with the resource's instance constructor.
6161
*
6262
* @returns {object} The new instance.
6363
*/
@@ -78,7 +78,7 @@ function createInstance(resourceName, attrs, options) {
7878
}
7979

8080
if (!('useClass' in options)) {
81-
options.useClass = true;
81+
options.useClass = definition.useClass;
8282
}
8383

8484
var item;

src/datastore/sync_methods/inject.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function errorPrefix(resourceName) {
99
return 'DS.inject(' + resourceName + ', attrs[, options]): ';
1010
}
1111

12-
function _inject(definition, resource, attrs) {
12+
function _inject(definition, resource, attrs, options) {
1313
var DS = this;
1414
var $log = DS.$log;
1515

@@ -66,7 +66,7 @@ function _inject(definition, resource, attrs) {
6666
if (DS.utils.isArray(attrs)) {
6767
injected = [];
6868
for (var i = 0; i < attrs.length; i++) {
69-
injected.push(_inject.call(DS, definition, resource, attrs[i]));
69+
injected.push(_inject.call(DS, definition, resource, attrs[i], options));
7070
}
7171
} else {
7272
// check if "idAttribute" is a computed property
@@ -90,7 +90,7 @@ function _inject(definition, resource, attrs) {
9090
var item = DS.get(definition.name, id);
9191

9292
if (!item) {
93-
if (definition.methods || definition.useClass) {
93+
if (options.useClass) {
9494
if (attrs instanceof definition[definition.class]) {
9595
item = attrs;
9696
} else {
@@ -221,6 +221,7 @@ function _injectRelations(definition, injected, options) {
221221
* @param {object|array} attrs The item or collection of items to inject into the data store.
222222
* @param {object=} options The item or collection of items to inject into the data store. Properties:
223223
*
224+
* - `{boolean=}` - `useClass` - Whether to wrap the injected item with the resource's instance constructor.
224225
* - `{boolean=}` - `findBelongsTo` - Find and attach any existing "belongsTo" relationships to the newly injected item. Potentially expensive if enabled. Default: `false`.
225226
* - `{boolean=}` - `findHasMany` - Find and attach any existing "hasMany" relationships to the newly injected item. Potentially expensive if enabled. Default: `false`.
226227
* - `{boolean=}` - `findHasOne` - Find and attach any existing "hasOne" relationships to the newly injected item. Potentially expensive if enabled. Default: `false`.
@@ -249,12 +250,15 @@ function inject(resourceName, attrs, options) {
249250
stack++;
250251

251252
try {
253+
if (!('useClass' in options)) {
254+
options.useClass = definition.useClass;
255+
}
252256
if (!DS.$rootScope.$$phase) {
253257
DS.$rootScope.$apply(function () {
254-
injected = _inject.call(DS, definition, resource, attrs);
258+
injected = _inject.call(DS, definition, resource, attrs, options);
255259
});
256260
} else {
257-
injected = _inject.call(DS, definition, resource, attrs);
261+
injected = _inject.call(DS, definition, resource, attrs, options);
258262
}
259263
if (definition.relations) {
260264
_injectRelations.call(DS, definition, injected, options);

test/integration/datastore/async_methods/find.test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,5 +162,22 @@ describe('DS.find(resourceName, id[, options]): ', function () {
162162
});
163163

164164
$httpBackend.flush();
165+
166+
$httpBackend.expectGET('http://test.angular-cache.com/organization/14/user/19/comment/19').respond(200, comment19);
167+
168+
DS.find('comment', 19, {
169+
bypassCache: true,
170+
params: {
171+
approvedBy: 19,
172+
organizationId: 14
173+
}
174+
}).then(function (comment) {
175+
assert.deepEqual(comment, comment19);
176+
assert.deepEqual(comment, DS.get('comment', 19));
177+
}, function () {
178+
fail('Should not have failed!');
179+
});
180+
181+
$httpBackend.flush();
165182
});
166183
});

test/integration/datastore/async_methods/loadRelations.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ describe('DS.loadRelations(resourceName, instance(Id), relations[, options]): ',
5656
comment12,
5757
comment13
5858
]);
59-
$httpBackend.expectGET('http://test.angular-cache.com/profile?userId=10').respond(200, profile15);
59+
$httpBackend.expectGET('http://test.angular-cache.com/profile?userId=10').respond(200, [profile15]);
6060

6161
DS.loadRelations('user', 10, ['comment', 'profile', 'organization'], { params: { approvedBy: 10 } }).then(function (user) {
6262
assert.deepEqual(user.comments[0].id, DS.get('comment', user.comments[0].id).id);
@@ -96,7 +96,7 @@ describe('DS.loadRelations(resourceName, instance(Id), relations[, options]): ',
9696
comment12,
9797
comment13
9898
]);
99-
$httpBackend.expectGET('http://test.angular-cache.com/profile?userId=10').respond(200, profile15);
99+
$httpBackend.expectGET('http://test.angular-cache.com/profile?userId=10').respond(200, [profile15]);
100100

101101
DS.loadRelations('user', 10, ['comment', 'profile', 'organization'], { cacheResponse: false }).then(function (user) {
102102
assert.deepEqual(user.comments, [

test/integration/datastore/sync_methods/bindAll.test.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ describe('DS.bindAll(scope, expr, resourceName, params[, cb])', function () {
3232
}, DS.errors.NonexistentResourceError, errorPrefix('does not exist') + 'does not exist is not a registered resource!');
3333

3434
angular.forEach(TYPES_EXCEPT_OBJECT, function (key) {
35-
assert.throws(function () {
36-
DS.bindAll($scope, 'post', 'post', key);
37-
}, DS.errors.IllegalArgumentError, errorPrefix('post') + 'params: Must be an object!');
35+
if (key) {
36+
assert.throws(function () {
37+
DS.bindAll($scope, 'post', 'post', key);
38+
}, DS.errors.IllegalArgumentError, errorPrefix('post') + 'params: Must be an object!');
39+
}
3840
});
3941
});
4042
it('should bind an item in the data store to the scope', function () {

0 commit comments

Comments
 (0)