Skip to content

Commit

Permalink
Merge 09217a6 into 5648638
Browse files Browse the repository at this point in the history
  • Loading branch information
jmdobry committed May 15, 2014
2 parents 5648638 + 09217a6 commit 1920bd8
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- #30, #48 - DSCacheFactory integration
- #49 - DS.bindOne($scope, prop, resourceName, id)
- #50 - DS.bindAll($scope, prop, resourceName, query)
- #54 - Adding functionality to resources

##### 0.8.1 - 02 May 2014

Expand Down
49 changes: 38 additions & 11 deletions dist/angular-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -2501,6 +2501,10 @@ BaseConfig.prototype.beforeUpdate = lifecycleNoop;
BaseConfig.prototype.afterUpdate = lifecycleNoop;
BaseConfig.prototype.beforeDestroy = lifecycleNoop;
BaseConfig.prototype.afterDestroy = lifecycleNoop;
BaseConfig.prototype.beforeInject = function () {
};
BaseConfig.prototype.afterInject = function () {
};

/**
* @doc function
Expand Down Expand Up @@ -2531,6 +2535,8 @@ function DSProvider() {
* - `{function}` - `afterUpdate` - See [](). Default: No-op
* - `{function}` - `beforeDestroy` - See [](). Default: No-op
* - `{function}` - `afterDestroy` - See [](). Default: No-op
* - `{function}` - `beforeInject` - See [](). Default: No-op
* - `{function}` - `afterInject` - See [](). Default: No-op
*/
var defaults = this.defaults = new BaseConfig();

Expand Down Expand Up @@ -2840,6 +2846,7 @@ function changes(resourceName, id) {
module.exports = changes;

},{}],44:[function(require,module,exports){
/*jshint evil:true*/
var errorPrefix = 'DS.defineResource(definition): ';

function Resource(utils, options) {
Expand Down Expand Up @@ -2892,6 +2899,10 @@ function Resource(utils, options) {
* - `{string="id"}` - `idAttribute` - The attribute that specifies the primary key for this resource.
* - `{string=}` - `endpoint` - The attribute that specifies the primary key for this resource. Default is the value of `name`.
* - `{string=}` - `baseUrl` - The url relative to which all AJAX requests will be made.
* - `{object=}` - `methods` - If provided, items of this resource will be wrapped in a constructor function that is
* empty save for the attributes in this option which will be mixed in to the constructor function prototype. Enabling
* this feature for this resource will incur a slight performance penalty, but allows you to give custom behavior to what
* are now "instances" of this resource.
* - `{function=}` - `beforeValidate` - Lifecycle hook. Overrides global. Signature: `beforeValidate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
* - `{function=}` - `validate` - Lifecycle hook. Overrides global. Signature: `validate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
* - `{function=}` - `afterValidate` - Lifecycle hook. Overrides global. Signature: `afterValidate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
Expand All @@ -2901,6 +2912,8 @@ function Resource(utils, options) {
* - `{function=}` - `afterUpdate` - Lifecycle hook. Overrides global. Signature: `afterUpdate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
* - `{function=}` - `beforeDestroy` - Lifecycle hook. Overrides global. Signature: `beforeDestroy(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
* - `{function=}` - `afterDestroy` - Lifecycle hook. Overrides global. Signature: `afterDestroy(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
* - `{function=}` - `beforeInject` - Lifecycle hook. Overrides global. Signature: `beforeInject(resourceName, attrs)`.
* - `{function=}` - `afterInject` - Lifecycle hook. Overrides global. Signature: `afterInject(resourceName, attrs)`.
*/
function defineResource(definition) {
if (this.utils.isString(definition)) {
Expand All @@ -2924,24 +2937,32 @@ function defineResource(definition) {
Resource.prototype = this.defaults;
this.definitions[definition.name] = new Resource(this.utils, definition);

var _this = this;
var _this = this,
def = this.definitions[definition.name];

var cache = this.cacheFactory('DS.' + definition.name, {
maxAge: definition.maxAge || null,
recycleFreq: definition.recycleFreq || 1000,
cacheFlushInterval: definition.cacheFlushInterval || null,
deleteOnExpire: definition.deleteOnExpire || 'none',
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(definition.name, id);
_this.eject(def.name, id);
},
capacity: Number.MAX_VALUE,
storageMode: 'memory',
storageImpl: null,
disabled: false,
storagePrefix: 'DS.' + definition.name
storagePrefix: 'DS.' + def.name
});

this.store[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);
}

this.store[def.name] = {
collection: [],
completedQueries: {},
pendingQueries: {},
Expand Down Expand Up @@ -3648,11 +3669,12 @@ function _inject(definition, resource, attrs) {
if (!(definition.idAttribute in attrs)) {
throw new _this.errors.RuntimeError(errorPrefix + 'attrs: Must contain the property specified by `idAttribute`!');
} else {
definition.beforeInject(definition.name, attrs);
var id = attrs[definition.idAttribute],
item = this.get(definition.name, id);

if (!item) {
item = {};
item = definition.class ? new definition[definition.class]() : {};
resource.previousAttributes[id] = {};

_this.utils.deepMixIn(item, attrs);
Expand All @@ -3676,6 +3698,7 @@ function _inject(definition, resource, attrs) {
resource.observers[id].deliver();
}
resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]);
definition.afterInject(definition.name, item);
}
}
}
Expand Down Expand Up @@ -3748,7 +3771,11 @@ function inject(resourceName, attrs, options) {
} else {
_inject.apply(_this, [definition, resource, attrs]);
}
return 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);
Expand Down
4 changes: 2 additions & 2 deletions dist/angular-data.min.js

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions karma.start.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ beforeEach(function (done) {
lifecycle.afterDestroy.callCount += 1;
cb(null, attrs);
};
lifecycle.beforeInject = function () {
lifecycle.beforeInject.callCount += 1;
};
lifecycle.afterInject = function () {
lifecycle.afterInject.callCount += 1;
};
module('app', function (_DSProvider_) {
DSProvider = _DSProvider_;
DSProvider.defaults.baseUrl = 'http://test.angular-cache.com';
Expand All @@ -79,6 +85,8 @@ beforeEach(function (done) {
DSProvider.defaults.afterUpdate = lifecycle.afterUpdate;
DSProvider.defaults.beforeDestroy = lifecycle.beforeDestroy;
DSProvider.defaults.afterDestroy = lifecycle.afterDestroy;
DSProvider.defaults.beforeInject = lifecycle.beforeInject;
DSProvider.defaults.afterInject = lifecycle.afterInject;
});
inject(function (_$rootScope_, _$q_, _$httpBackend_, _DS_, _$log_) {
// Setup global mocks
Expand All @@ -101,6 +109,8 @@ beforeEach(function (done) {
lifecycle.afterUpdate.callCount = 0;
lifecycle.beforeDestroy.callCount = 0;
lifecycle.afterDestroy.callCount = 0;
lifecycle.beforeInject.callCount = 0;
lifecycle.afterInject.callCount = 0;

p1 = { author: 'John', age: 30, id: 5 };
p2 = { author: 'Sally', age: 31, id: 6 };
Expand Down
6 changes: 6 additions & 0 deletions src/datastore/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ BaseConfig.prototype.beforeUpdate = lifecycleNoop;
BaseConfig.prototype.afterUpdate = lifecycleNoop;
BaseConfig.prototype.beforeDestroy = lifecycleNoop;
BaseConfig.prototype.afterDestroy = lifecycleNoop;
BaseConfig.prototype.beforeInject = function () {
};
BaseConfig.prototype.afterInject = function () {
};

/**
* @doc function
Expand Down Expand Up @@ -82,6 +86,8 @@ function DSProvider() {
* - `{function}` - `afterUpdate` - See [](). Default: No-op
* - `{function}` - `beforeDestroy` - See [](). Default: No-op
* - `{function}` - `afterDestroy` - See [](). Default: No-op
* - `{function}` - `beforeInject` - See [](). Default: No-op
* - `{function}` - `afterInject` - See [](). Default: No-op
*/
var defaults = this.defaults = new BaseConfig();

Expand Down
33 changes: 24 additions & 9 deletions src/datastore/sync_methods/defineResource.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*jshint evil:true*/
var errorPrefix = 'DS.defineResource(definition): ';

function Resource(utils, options) {
Expand Down Expand Up @@ -50,6 +51,10 @@ function Resource(utils, options) {
* - `{string="id"}` - `idAttribute` - The attribute that specifies the primary key for this resource.
* - `{string=}` - `endpoint` - The attribute that specifies the primary key for this resource. Default is the value of `name`.
* - `{string=}` - `baseUrl` - The url relative to which all AJAX requests will be made.
* - `{object=}` - `methods` - If provided, items of this resource will be wrapped in a constructor function that is
* empty save for the attributes in this option which will be mixed in to the constructor function prototype. Enabling
* this feature for this resource will incur a slight performance penalty, but allows you to give custom behavior to what
* are now "instances" of this resource.
* - `{function=}` - `beforeValidate` - Lifecycle hook. Overrides global. Signature: `beforeValidate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
* - `{function=}` - `validate` - Lifecycle hook. Overrides global. Signature: `validate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
* - `{function=}` - `afterValidate` - Lifecycle hook. Overrides global. Signature: `afterValidate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
Expand All @@ -59,6 +64,8 @@ function Resource(utils, options) {
* - `{function=}` - `afterUpdate` - Lifecycle hook. Overrides global. Signature: `afterUpdate(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
* - `{function=}` - `beforeDestroy` - Lifecycle hook. Overrides global. Signature: `beforeDestroy(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
* - `{function=}` - `afterDestroy` - Lifecycle hook. Overrides global. Signature: `afterDestroy(resourceName, attrs, cb)`. Callback signature: `cb(err, attrs)`.
* - `{function=}` - `beforeInject` - Lifecycle hook. Overrides global. Signature: `beforeInject(resourceName, attrs)`.
* - `{function=}` - `afterInject` - Lifecycle hook. Overrides global. Signature: `afterInject(resourceName, attrs)`.
*/
function defineResource(definition) {
if (this.utils.isString(definition)) {
Expand All @@ -82,24 +89,32 @@ function defineResource(definition) {
Resource.prototype = this.defaults;
this.definitions[definition.name] = new Resource(this.utils, definition);

var _this = this;
var _this = this,
def = this.definitions[definition.name];

var cache = this.cacheFactory('DS.' + definition.name, {
maxAge: definition.maxAge || null,
recycleFreq: definition.recycleFreq || 1000,
cacheFlushInterval: definition.cacheFlushInterval || null,
deleteOnExpire: definition.deleteOnExpire || 'none',
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(definition.name, id);
_this.eject(def.name, id);
},
capacity: Number.MAX_VALUE,
storageMode: 'memory',
storageImpl: null,
disabled: false,
storagePrefix: 'DS.' + definition.name
storagePrefix: 'DS.' + def.name
});

this.store[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);
}

this.store[def.name] = {
collection: [],
completedQueries: {},
pendingQueries: {},
Expand Down
10 changes: 8 additions & 2 deletions src/datastore/sync_methods/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ function _inject(definition, resource, attrs) {
if (!(definition.idAttribute in attrs)) {
throw new _this.errors.RuntimeError(errorPrefix + 'attrs: Must contain the property specified by `idAttribute`!');
} else {
definition.beforeInject(definition.name, attrs);
var id = attrs[definition.idAttribute],
item = this.get(definition.name, id);

if (!item) {
item = {};
item = definition.class ? new definition[definition.class]() : {};
resource.previousAttributes[id] = {};

_this.utils.deepMixIn(item, attrs);
Expand All @@ -57,6 +58,7 @@ function _inject(definition, resource, attrs) {
resource.observers[id].deliver();
}
resource.saved[id] = _this.utils.updateTimestamp(resource.saved[id]);
definition.afterInject(definition.name, item);
}
}
}
Expand Down Expand Up @@ -129,7 +131,11 @@ function inject(resourceName, attrs, options) {
} else {
_inject.apply(_this, [definition, resource, attrs]);
}
return 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);
Expand Down
30 changes: 30 additions & 0 deletions test/integration/datastore/sync_methods/defineResource.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,34 @@ describe('DS.defineResource(definition)', function () {
assert.equal(callCount, 1, 'overridden validate should have been called once');
assert.equal(lifecycle.validate.callCount, 0, 'global validate should not have been called');
});
it('should allow custom behavior to be applied to resources', function () {
DS.defineResource({
name: 'user',
methods: {
fullName: function () {
return this.first + ' ' + this.last;
}
}
});

DS.inject('user', {
first: 'John',
last: 'Anderson',
id: 1
});

var user = DS.get('user', 1);

assert.deepEqual(JSON.stringify(user), JSON.stringify({
first: 'John',
last: 'Anderson',
id: 1
}));
assert.equal(user.fullName(), 'John Anderson');
assert.isTrue(user instanceof DS.definitions.user[DS.definitions.user.class]);
assert.equal(DS.definitions.user.class, 'User');
assert.equal(DS.definitions.user[DS.definitions.user.class].name, 'User');
assert.equal(lifecycle.beforeInject.callCount, 1, 'beforeInject should have been called');
assert.equal(lifecycle.afterInject.callCount, 1, 'afterInject should have been called');
});
});
3 changes: 3 additions & 0 deletions test/integration/datastore/sync_methods/filter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ describe('DS.filter(resourceName, params[, options])', function () {
DS.inject('post', p4);
}, Error, 'should not throw an error');

assert.equal(lifecycle.beforeInject.callCount, 4);
assert.equal(lifecycle.afterInject.callCount, 4);

var params = {
query: {
where: {
Expand Down

0 comments on commit 1920bd8

Please sign in to comment.