Skip to content

Commit 82225b7

Browse files
committed
Closes #7.
Implemented all lifecycle hooks, including tests. Cleaned up use of promises in async methods.
1 parent 079a9d9 commit 82225b7

File tree

17 files changed

+525
-142
lines changed

17 files changed

+525
-142
lines changed

dist/angular-data.js

+86-69
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
/**
2-
* @author Jason Dobry <[email protected]>
3-
* @file angular-data.js
4-
* @version 0.5.0 - Homepage <http://jmdobry.github.io/angular-data/>
5-
* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/angular-data>
6-
* @license MIT <https://github.com/jmdobry/angular-data/blob/master/LICENSE>
7-
*
8-
* @overview Data store for Angular.js.
9-
*/
101
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
112
var indexOf = require('./indexOf');
123

@@ -1924,31 +1915,36 @@ var utils = require('utils'),
19241915
* - `{UnhandledError}`
19251916
*/
19261917
function destroy(resourceName, id) {
1927-
var deferred = service.$q.defer();
1918+
var deferred = services.$q.defer(),
1919+
promise = deferred.promise;
1920+
19281921
if (!services.store[resourceName]) {
19291922
deferred.reject(new errors.RuntimeError(errorPrefix + resourceName + ' is not a registered resource!'));
19301923
} else if (!utils.isString(id) && !utils.isNumber(id)) {
19311924
deferred.reject(new errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } }));
1932-
}
1933-
1934-
try {
1925+
} else {
19351926
var resource = services.store[resourceName],
1936-
_this = this,
1937-
url = utils.makePath(resource.baseUrl || services.config.baseUrl, resource.endpoint || resource.name, id);
1927+
_this = this;
19381928

1939-
_this.DEL(url, null).then(function () {
1940-
try {
1929+
promise = promise
1930+
.then(function (attrs) {
1931+
return services.$q.promisify(resource.beforeDestroy)(resourceName, attrs);
1932+
})
1933+
.then(function () {
1934+
return _this.DEL(utils.makePath(resource.baseUrl, resource.endpoint, id), null);
1935+
})
1936+
.then(function () {
1937+
return services.$q.promisify(resource.afterDestroy)(resourceName, resource.index[id]);
1938+
})
1939+
.then(function () {
19411940
_this.eject(resourceName, id);
1942-
deferred.resolve(id);
1943-
} catch (err) {
1944-
deferred.reject(err);
1945-
}
1946-
}, deferred.reject);
1947-
} catch (err) {
1948-
deferred.reject(new errors.UnhandledError(err));
1941+
return id;
1942+
});
1943+
1944+
deferred.resolve(resource.index[id]);
19491945
}
19501946

1951-
return deferred.promise;
1947+
return promise;
19521948
}
19531949

19541950
module.exports = destroy;
@@ -2005,7 +2001,9 @@ var utils = require('utils'),
20052001
* - `{UnhandledError}`
20062002
*/
20072003
function find(resourceName, id, options) {
2008-
var deferred = services.$q.defer();
2004+
var deferred = services.$q.defer(),
2005+
promise = deferred.promise;
2006+
20092007
options = options || {};
20102008

20112009
if (!services.store[resourceName]) {
@@ -2015,43 +2013,35 @@ function find(resourceName, id, options) {
20152013
} else if (!utils.isObject(options)) {
20162014
deferred.reject(new errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!', { options: { actual: typeof options, expected: 'object' } }));
20172015
} else {
2018-
var _this = this;
2019-
20202016
try {
2021-
var resource = services.store[resourceName];
2017+
var resource = services.store[resourceName],
2018+
_this = this;
20222019

2023-
if (id in resource.index && !options.bypassCache) {
2024-
deferred.resolve(_this.get(resourceName, id));
2025-
} else {
2026-
var url = utils.makePath(resource.baseUrl || services.config.baseUrl, resource.endpoint || resource.name, id),
2027-
config = null;
2020+
if (options.bypassCache) {
2021+
delete resource.completedQueries[id];
2022+
}
20282023

2029-
if (options.bypassCache) {
2030-
config = {
2031-
headers: {
2032-
'Last-Modified': new Date(resource.modified[id])
2033-
}
2034-
};
2024+
if (!(id in resource.completedQueries)) {
2025+
if (!(id in resource.pendingQueries)) {
2026+
promise = resource.pendingQueries[id] = GET(utils.makePath(resource.baseUrl, resource.endpoint, id), null)
2027+
.then(function (data) {
2028+
// Query is no longer pending
2029+
delete resource.pendingQueries[id];
2030+
resource.completedQueries[id] = new Date().getTime();
2031+
return _this.inject(resourceName, data);
2032+
});
20352033
}
2036-
GET(url, config).then(function (data) {
2037-
try {
2038-
_this.inject(resourceName, data);
2039-
deferred.resolve(_this.get(resourceName, id));
2040-
} catch (err) {
2041-
deferred.reject(err);
2042-
}
2043-
}, deferred.reject);
2044-
}
2045-
} catch (err) {
2046-
if (!(err instanceof errors.UnhandledError)) {
2047-
deferred.reject(new errors.UnhandledError(err));
2034+
2035+
return resource.pendingQueries[id];
20482036
} else {
2049-
deferred.reject(err);
2037+
deferred.resolve(_this.get(resourceName, id));
20502038
}
2039+
} catch (err) {
2040+
deferred.reject(err);
20512041
}
20522042
}
20532043

2054-
return deferred.promise;
2044+
return promise;
20552045
}
20562046

20572047
module.exports = find;
@@ -2087,9 +2077,8 @@ function processResults(data, resourceName, queryHash) {
20872077

20882078
function _findAll(resourceName, params, options) {
20892079
var resource = services.store[resourceName],
2090-
_this = this;
2091-
2092-
var queryHash = utils.toJson(params);
2080+
_this = this,
2081+
queryHash = utils.toJson(params);
20932082

20942083
if (options.bypassCache) {
20952084
delete resource.completedQueries[queryHash];
@@ -2098,7 +2087,7 @@ function _findAll(resourceName, params, options) {
20982087
if (!(queryHash in resource.completedQueries)) {
20992088
// This particular query has never been completed
21002089

2101-
if (!resource.pendingQueries[queryHash]) {
2090+
if (!(queryHash in resource.pendingQueries)) {
21022091

21032092
// This particular query has never even been made
21042093
resource.pendingQueries[queryHash] = GET(utils.makePath(resource.baseUrl, resource.endpoint), { params: params })
@@ -2110,6 +2099,7 @@ function _findAll(resourceName, params, options) {
21102099
}
21112100
});
21122101
}
2102+
21132103
return resource.pendingQueries[queryHash];
21142104
} else {
21152105
return this.filter(resourceName, params, options);
@@ -2413,7 +2403,7 @@ function save(resourceName, id, options) {
24132403
} else if (!utils.isString(id) && !utils.isNumber(id)) {
24142404
deferred.reject(new errors.IllegalArgumentError(errorPrefix + 'id: Must be a string or a number!', { id: { actual: typeof id, expected: 'string|number' } }));
24152405
} else if (!utils.isObject(options)) {
2416-
deferred.reject(new errors.IllegalArgumentError(errorPrefix + 'id: Must be an object!', { options: { actual: typeof options, expected: 'object' } }));
2406+
deferred.reject(new errors.IllegalArgumentError(errorPrefix + 'options: Must be an object!', { options: { actual: typeof options, expected: 'object' } }));
24172407
} else if (!(id in services.store[resourceName].index)) {
24182408
deferred.reject(new errors.RuntimeError(errorPrefix + 'id: "' + id + '" not found!'));
24192409
} else {
@@ -2707,15 +2697,30 @@ var utils = require('utils'),
27072697
* ```js
27082698
* DSProvider.config({
27092699
* baseUrl: 'http://myapp.com/api',
2710-
* idAttribute: '_id'
2700+
* idAttribute: '_id',
2701+
* validate: function (resourceName, attrs, cb) {
2702+
* console.log('looks good to me');
2703+
* cb(null, attrs);
2704+
* }
27112705
* });
27122706
* ```
27132707
*
27142708
* ## Throws:
27152709
*
27162710
* - `{IllegalArgumentError}`
27172711
*
2718-
* @param {object} options Configuration for the data store.
2712+
* @param {object} options Global configuration for the data store. Properties:
2713+
* - `{string=}` - `baseUrl` - The default base url to be used by the data store. Can be overridden via `DS.defineResource`.
2714+
* - `{string=}` - `idAttribute` - The default property that specifies the primary key of an object. Default: `"id"`.
2715+
* - `{function=}` - `beforeValidate` - Global lifecycle hook. Signature: `beforeValidate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
2716+
* - `{function=}` - `validate` - Global lifecycle hook. Signature: `validate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
2717+
* - `{function=}` - `afterValidate` - Global lifecycle hook. Signature: `afterValidate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
2718+
* - `{function=}` - `beforeCreate` - Global lifecycle hook. Signature: `beforeCreate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
2719+
* - `{function=}` - `afterCreate` - Global lifecycle hook. Signature: `afterCreate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
2720+
* - `{function=}` - `beforeUpdate` - Global lifecycle hook. Signature: `beforeUpdate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
2721+
* - `{function=}` - `afterUpdate` - Global lifecycle hook. Signature: `afterUpdate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
2722+
* - `{function=}` - `beforeDestroy` - Global lifecycle hook. Signature: `beforeDestroy(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
2723+
* - `{function=}` - `afterDestroy` - Global lifecycle hook. Signature: `afterDestroy(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
27192724
*/
27202725
function config(options) {
27212726
options = options || {};
@@ -2968,6 +2973,8 @@ function Resource(options) {
29682973
this.collectionModified = 0;
29692974
}
29702975

2976+
Resource.prototype = services.config;
2977+
29712978
/**
29722979
* @doc method
29732980
* @id DS.sync_methods:defineResource
@@ -3006,8 +3013,16 @@ function Resource(options) {
30063013
* - `{string}` - `name` - The name by which this resource will be identified.
30073014
* - `{string="id"}` - `idAttribute` - The attribute that specifies the primary key for this resource.
30083015
* - `{string=}` - `endpoint` - The attribute that specifies the primary key for this resource. Default is the value of `name`.
3009-
* - `{string="/"}` - `baseUrl` - The url relative to which all AJAX requests will be made.
3010-
* - `{function=}` - `validate` - The validation function to be executed before create operations.
3016+
* - `{string=}` - `baseUrl` - The url relative to which all AJAX requests will be made.
3017+
* - `{function=}` - `beforeValidate` - Lifecycle hook. Overrides global. Signature: `beforeValidate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
3018+
* - `{function=}` - `validate` - Lifecycle hook. Overrides global. Signature: `validate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
3019+
* - `{function=}` - `afterValidate` - Lifecycle hook. Overrides global. Signature: `afterValidate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
3020+
* - `{function=}` - `beforeCreate` - Lifecycle hook. Overrides global. Signature: `beforeCreate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
3021+
* - `{function=}` - `afterCreate` - Lifecycle hook. Overrides global. Signature: `afterCreate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
3022+
* - `{function=}` - `beforeUpdate` - Lifecycle hook. Overrides global. Signature: `beforeUpdate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
3023+
* - `{function=}` - `afterUpdate` - Lifecycle hook. Overrides global. Signature: `afterUpdate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
3024+
* - `{function=}` - `beforeDestroy` - Lifecycle hook. Overrides global. Signature: `beforeDestroy(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
3025+
* - `{function=}` - `afterDestroy` - Lifecycle hook. Overrides global. Signature: `afterDestroy(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
30113026
*/
30123027
function defineResource(definition) {
30133028
if (utils.isString(definition)) {
@@ -3026,7 +3041,6 @@ function defineResource(definition) {
30263041
}
30273042

30283043
try {
3029-
Resource.prototype = services.config;
30303044
services.store[definition.name] = new Resource(definition);
30313045
} catch (err) {
30323046
delete services.store[definition.name];
@@ -3405,7 +3419,9 @@ function get(resourceName, id, options) {
34053419
try {
34063420
// cache miss, request resource from server
34073421
if (!(id in services.store[resourceName].index) && options.loadFromServer) {
3408-
this.find(resourceName, id);
3422+
this.find(resourceName, id).then(null, function (err) {
3423+
throw err;
3424+
});
34093425
}
34103426

34113427
// return resource from cache
@@ -3910,9 +3926,7 @@ function previous(resourceName, id) {
39103926

39113927
module.exports = previous;
39123928

3913-
},{"errors":"hIh4e1","services":"cX8q+p","utils":"uE/lJt"}],"errors":[function(require,module,exports){
3914-
module.exports=require('hIh4e1');
3915-
},{}],"hIh4e1":[function(require,module,exports){
3929+
},{"errors":"hIh4e1","services":"cX8q+p","utils":"uE/lJt"}],"hIh4e1":[function(require,module,exports){
39163930
/**
39173931
* @doc function
39183932
* @id errors.types:UnhandledError
@@ -4124,6 +4138,8 @@ module.exports = {
41244138
RuntimeError: RuntimeError
41254139
};
41264140

4141+
},{}],"errors":[function(require,module,exports){
4142+
module.exports=require('hIh4e1');
41274143
},{}],52:[function(require,module,exports){
41284144
(function (window, angular, undefined) {
41294145
'use strict';
@@ -4206,6 +4222,7 @@ module.exports = {
42064222
isArray: angular.isArray,
42074223
isObject: angular.isObject,
42084224
isNumber: angular.isNumber,
4225+
isFunction: angular.isFunction,
42094226
isEmpty: require('mout/lang/isEmpty'),
42104227
toJson: angular.toJson,
42114228
makePath: require('mout/string/makePath'),
@@ -4279,4 +4296,4 @@ module.exports = {
42794296

42804297
},{"mout/array/contains":1,"mout/array/filter":2,"mout/array/slice":5,"mout/array/sort":6,"mout/array/toLookup":7,"mout/lang/isEmpty":12,"mout/object/deepMixIn":19,"mout/object/forOwn":21,"mout/string/makePath":23,"mout/string/upperCase":24}],"utils":[function(require,module,exports){
42814298
module.exports=require('uE/lJt');
4282-
},{}]},{},[52])
4299+
},{}]},{},[52])

dist/angular-data.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)