Skip to content

Commit 989e256

Browse files
committed
Wrote several test for sync methods. #15
1 parent 9777e5b commit 989e256

File tree

11 files changed

+332
-125
lines changed

11 files changed

+332
-125
lines changed

dist/angular-data.js

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3044,6 +3044,8 @@ function defineResource(definition) {
30443044
throw new errors.IllegalArgumentError(errorPrefix + 'definition.name: Must be a string!', { definition: { name: { actual: typeof definition.name, expected: 'string' } } });
30453045
} else if (definition.idAttribute && !utils.isString(definition.idAttribute)) {
30463046
throw new errors.IllegalArgumentError(errorPrefix + 'definition.idAttribute: Must be a string!', { definition: { idAttribute: { actual: typeof definition.idAttribute, expected: 'string' } } });
3047+
} else if (definition.endpoint && !utils.isString(definition.endpoint)) {
3048+
throw new errors.IllegalArgumentError(errorPrefix + 'definition.endpoint: Must be a string!', { definition: { endpoint: { actual: typeof definition.endpoint, expected: 'string' } } });
30473049
} else if (services.store[definition.name]) {
30483050
throw new errors.RuntimeError(errorPrefix + definition.name + ' is already registered!');
30493051
}
@@ -3448,9 +3450,9 @@ var utils = require('utils'),
34483450
errorPrefix = 'DS.hasChanges(resourceName, id): ';
34493451

34503452
function diffIsEmpty(diff) {
3451-
return utils.isEmpty(diff.added) &&
3453+
return !(utils.isEmpty(diff.added) &&
34523454
utils.isEmpty(diff.removed) &&
3453-
utils.isEmpty(diff.changed);
3455+
utils.isEmpty(diff.changed));
34543456
}
34553457

34563458
/**
@@ -3495,7 +3497,11 @@ function hasChanges(resourceName, id) {
34953497

34963498
try {
34973499
// return resource from cache
3498-
return diffIsEmpty(services.store[resourceName].changes[id]);
3500+
if (id in services.store[resourceName].changes) {
3501+
return diffIsEmpty(services.store[resourceName].changes[id]);
3502+
} else {
3503+
return false;
3504+
}
34993505
} catch (err) {
35003506
throw new errors.UnhandledError(err);
35013507
}
@@ -3625,43 +3631,52 @@ var utils = require('utils'),
36253631
function _inject(resource, attrs) {
36263632
var _this = this;
36273633

3634+
function _react(added, removed, changed, getOldValueFn) {
3635+
try {
3636+
var innerId = getOldValueFn(resource.idAttribute);
3637+
3638+
resource.changes[innerId] = utils.diffObjectFromOldObject(resource.index[innerId], resource.previous_attributes[innerId]);
3639+
resource.modified[innerId] = utils.updateTimestamp(resource.modified[innerId]);
3640+
resource.collectionModified = utils.updateTimestamp(resource.collectionModified);
3641+
3642+
if (resource.idAttribute in changed) {
3643+
services.$log.error('Doh! You just changed the primary key of an object! ' +
3644+
'I don\'t know how to handle this yet, so your data for the "' + resource.name +
3645+
'" resource is now in an undefined (probably broken) state.');
3646+
}
3647+
} catch (err) {
3648+
throw new errors.UnhandledError(err);
3649+
}
3650+
}
3651+
36283652
if (utils.isArray(attrs)) {
36293653
for (var i = 0; i < attrs.length; i++) {
36303654
_inject.call(_this, resource, attrs[i]);
36313655
}
36323656
} else {
3633-
var id = attrs[resource.idAttribute || 'id'];
3634-
3635-
if (!(id in resource.index)) {
3636-
resource.index[id] = {};
3637-
resource.previous_attributes[id] = {};
3657+
if (!(resource.idAttribute in attrs)) {
3658+
throw new errors.RuntimeError(errorPrefix + 'attrs: Must contain the property specified by `idAttribute`!');
3659+
} else {
3660+
var id = attrs[resource.idAttribute];
36383661

3639-
utils.deepMixIn(resource.index[id], attrs);
3640-
utils.deepMixIn(resource.previous_attributes[id], attrs);
3662+
if (!(id in resource.index)) {
3663+
resource.index[id] = {};
3664+
resource.previous_attributes[id] = {};
36413665

3642-
resource.collection.push(resource.index[id]);
3666+
utils.deepMixIn(resource.index[id], attrs);
3667+
utils.deepMixIn(resource.previous_attributes[id], attrs);
36433668

3644-
resource.observers[id] = new observe.ObjectObserver(resource.index[id], function (added, removed, changed, getOldValueFn) {
3645-
try {
3646-
var innerId = getOldValueFn(resource.idAttribute || 'id');
3669+
resource.collection.push(resource.index[id]);
36473670

3648-
if (resource.index[innerId][resource.idAttribute || 'id'] != innerId) {
3649-
resource.index[innerId][resource.idAttribute || 'id'] = innerId;
3650-
services.$log.error('You cannot change the primary key of an object! Reverting change to primary key.');
3651-
}
3671+
resource.observers[id] = new observe.ObjectObserver(resource.index[id], _react);
36523672

3653-
resource.changes[innerId] = utils.diffObjectFromOldObject(resource.index[innerId], resource.previous_attributes[innerId]);
3654-
resource.modified[innerId] = utils.updateTimestamp(resource.modified[innerId]);
3655-
resource.collectionModified = utils.updateTimestamp(resource.collectionModified);
3656-
} catch (err) {
3657-
throw new errors.UnhandledError(err);
3658-
}
3659-
});
3660-
3661-
resource.observers[id].deliver();
3662-
} else {
3663-
utils.deepMixIn(resource.index[id], attrs);
3664-
resource.observers[id].deliver();
3673+
_react({}, {}, {}, function () {
3674+
return id;
3675+
});
3676+
} else {
3677+
utils.deepMixIn(resource.index[id], attrs);
3678+
resource.observers[id].deliver();
3679+
}
36653680
}
36663681
}
36673682
}
@@ -3726,22 +3741,21 @@ function inject(resourceName, attrs, options) {
37263741
var resource = services.store[resourceName],
37273742
_this = this;
37283743

3729-
var idAttribute = resource.idAttribute || 'id';
3730-
if (!attrs[idAttribute]) {
3731-
throw new errors.RuntimeError(errorPrefix + 'attrs: Must contain the property specified by `idAttribute` in the resource definition!');
3732-
} else {
3733-
try {
3734-
if (!services.$rootScope.$$phase) {
3735-
services.$rootScope.$apply(function () {
3736-
_inject.apply(_this, [services.store[resourceName], attrs]);
3737-
});
3738-
} else {
3744+
try {
3745+
if (!services.$rootScope.$$phase) {
3746+
services.$rootScope.$apply(function () {
37393747
_inject.apply(_this, [services.store[resourceName], attrs]);
3740-
}
3741-
} catch (err) {
3748+
});
3749+
} else {
3750+
_inject.apply(_this, [services.store[resourceName], attrs]);
3751+
}
3752+
return attrs;
3753+
} catch (err) {
3754+
if (!(err instanceof errors.RuntimeError)) {
37423755
throw new errors.UnhandledError(err);
3756+
} else {
3757+
throw err;
37433758
}
3744-
return resource.index[attrs[idAttribute]];
37453759
}
37463760
}
37473761

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.

karma.start.js

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ var fail = function (msg) {
1111
}],
1212
TYPES_EXCEPT_STRING_OR_ARRAY = [123, 123.123, null, undefined, {}, true, false, function () {
1313
}],
14+
TYPES_EXCEPT_STRING_OR_OBJECT = [123, 123.123, null, undefined, [], true, false, function () {
15+
}],
1416
TYPES_EXCEPT_ARRAY = ['string', 123, 123.123, null, undefined, {}, true, false, function () {
1517
}],
1618
TYPES_EXCEPT_STRING_OR_NUMBER = [null, undefined, {}, [], true, false, function () {
@@ -80,7 +82,7 @@ beforeEach(function (done) {
8082
afterDestroy: lifecycle.afterDestroy
8183
});
8284
});
83-
inject(function (_$rootScope_, _$q_, _$httpBackend_, _DS_) {
85+
inject(function (_$rootScope_, _$q_, _$httpBackend_, _DS_, _$log_) {
8486
// Setup global mocks
8587
$q = _$q_;
8688
$rootScope = _$rootScope_;
@@ -90,25 +92,7 @@ beforeEach(function (done) {
9092
name: 'post',
9193
endpoint: '/posts'
9294
});
93-
$log = {
94-
warn: function () {
95-
},
96-
log: function () {
97-
},
98-
info: function () {
99-
},
100-
error: function () {
101-
},
102-
debug: function () {
103-
}
104-
};
105-
106-
// Setup global spies
107-
sinon.spy($log, 'warn');
108-
sinon.spy($log, 'log');
109-
sinon.spy($log, 'info');
110-
sinon.spy($log, 'error');
111-
sinon.spy($log, 'debug');
95+
$log = _$log_;
11296

11397
lifecycle.beforeValidate.callCount = 0;
11498
lifecycle.validate.callCount = 0;
@@ -131,13 +115,7 @@ beforeEach(function (done) {
131115

132116
// Clean up after each test
133117
afterEach(function () {
134-
// Tear down global spies
135-
$log.warn.restore();
136-
$log.log.restore();
137-
$log.info.restore();
138-
$log.error.restore();
139-
$log.debug.restore();
140-
141118
$httpBackend.verifyNoOutstandingExpectation();
142119
$httpBackend.verifyNoOutstandingRequest();
120+
$log.reset();
143121
});

src/datastore/sync_methods/defineResource/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ function defineResource(definition) {
9191
throw new errors.IllegalArgumentError(errorPrefix + 'definition.name: Must be a string!', { definition: { name: { actual: typeof definition.name, expected: 'string' } } });
9292
} else if (definition.idAttribute && !utils.isString(definition.idAttribute)) {
9393
throw new errors.IllegalArgumentError(errorPrefix + 'definition.idAttribute: Must be a string!', { definition: { idAttribute: { actual: typeof definition.idAttribute, expected: 'string' } } });
94+
} else if (definition.endpoint && !utils.isString(definition.endpoint)) {
95+
throw new errors.IllegalArgumentError(errorPrefix + 'definition.endpoint: Must be a string!', { definition: { endpoint: { actual: typeof definition.endpoint, expected: 'string' } } });
9496
} else if (services.store[definition.name]) {
9597
throw new errors.RuntimeError(errorPrefix + definition.name + ' is already registered!');
9698
}

src/datastore/sync_methods/hasChanges/index.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ var utils = require('utils'),
44
errorPrefix = 'DS.hasChanges(resourceName, id): ';
55

66
function diffIsEmpty(diff) {
7-
return utils.isEmpty(diff.added) &&
7+
return !(utils.isEmpty(diff.added) &&
88
utils.isEmpty(diff.removed) &&
9-
utils.isEmpty(diff.changed);
9+
utils.isEmpty(diff.changed));
1010
}
1111

1212
/**
@@ -51,7 +51,11 @@ function hasChanges(resourceName, id) {
5151

5252
try {
5353
// return resource from cache
54-
return diffIsEmpty(services.store[resourceName].changes[id]);
54+
if (id in services.store[resourceName].changes) {
55+
return diffIsEmpty(services.store[resourceName].changes[id]);
56+
} else {
57+
return false;
58+
}
5559
} catch (err) {
5660
throw new errors.UnhandledError(err);
5761
}

src/datastore/sync_methods/inject/index.js

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,52 @@ var utils = require('utils'),
77
function _inject(resource, attrs) {
88
var _this = this;
99

10+
function _react(added, removed, changed, getOldValueFn) {
11+
try {
12+
var innerId = getOldValueFn(resource.idAttribute);
13+
14+
resource.changes[innerId] = utils.diffObjectFromOldObject(resource.index[innerId], resource.previous_attributes[innerId]);
15+
resource.modified[innerId] = utils.updateTimestamp(resource.modified[innerId]);
16+
resource.collectionModified = utils.updateTimestamp(resource.collectionModified);
17+
18+
if (resource.idAttribute in changed) {
19+
services.$log.error('Doh! You just changed the primary key of an object! ' +
20+
'I don\'t know how to handle this yet, so your data for the "' + resource.name +
21+
'" resource is now in an undefined (probably broken) state.');
22+
}
23+
} catch (err) {
24+
throw new errors.UnhandledError(err);
25+
}
26+
}
27+
1028
if (utils.isArray(attrs)) {
1129
for (var i = 0; i < attrs.length; i++) {
1230
_inject.call(_this, resource, attrs[i]);
1331
}
1432
} else {
15-
var id = attrs[resource.idAttribute || 'id'];
16-
17-
if (!(id in resource.index)) {
18-
resource.index[id] = {};
19-
resource.previous_attributes[id] = {};
20-
21-
utils.deepMixIn(resource.index[id], attrs);
22-
utils.deepMixIn(resource.previous_attributes[id], attrs);
33+
if (!(resource.idAttribute in attrs)) {
34+
throw new errors.RuntimeError(errorPrefix + 'attrs: Must contain the property specified by `idAttribute`!');
35+
} else {
36+
var id = attrs[resource.idAttribute];
2337

24-
resource.collection.push(resource.index[id]);
38+
if (!(id in resource.index)) {
39+
resource.index[id] = {};
40+
resource.previous_attributes[id] = {};
2541

26-
resource.observers[id] = new observe.ObjectObserver(resource.index[id], function (added, removed, changed, getOldValueFn) {
27-
try {
28-
var innerId = getOldValueFn(resource.idAttribute || 'id');
42+
utils.deepMixIn(resource.index[id], attrs);
43+
utils.deepMixIn(resource.previous_attributes[id], attrs);
2944

30-
if (resource.index[innerId][resource.idAttribute || 'id'] != innerId) {
31-
resource.index[innerId][resource.idAttribute || 'id'] = innerId;
32-
services.$log.error('You cannot change the primary key of an object! Reverting change to primary key.');
33-
}
45+
resource.collection.push(resource.index[id]);
3446

35-
resource.changes[innerId] = utils.diffObjectFromOldObject(resource.index[innerId], resource.previous_attributes[innerId]);
36-
resource.modified[innerId] = utils.updateTimestamp(resource.modified[innerId]);
37-
resource.collectionModified = utils.updateTimestamp(resource.collectionModified);
38-
} catch (err) {
39-
throw new errors.UnhandledError(err);
40-
}
41-
});
47+
resource.observers[id] = new observe.ObjectObserver(resource.index[id], _react);
4248

43-
resource.observers[id].deliver();
44-
} else {
45-
utils.deepMixIn(resource.index[id], attrs);
46-
resource.observers[id].deliver();
49+
_react({}, {}, {}, function () {
50+
return id;
51+
});
52+
} else {
53+
utils.deepMixIn(resource.index[id], attrs);
54+
resource.observers[id].deliver();
55+
}
4756
}
4857
}
4958
}
@@ -108,22 +117,21 @@ function inject(resourceName, attrs, options) {
108117
var resource = services.store[resourceName],
109118
_this = this;
110119

111-
var idAttribute = resource.idAttribute || 'id';
112-
if (!attrs[idAttribute]) {
113-
throw new errors.RuntimeError(errorPrefix + 'attrs: Must contain the property specified by `idAttribute` in the resource definition!');
114-
} else {
115-
try {
116-
if (!services.$rootScope.$$phase) {
117-
services.$rootScope.$apply(function () {
118-
_inject.apply(_this, [services.store[resourceName], attrs]);
119-
});
120-
} else {
120+
try {
121+
if (!services.$rootScope.$$phase) {
122+
services.$rootScope.$apply(function () {
121123
_inject.apply(_this, [services.store[resourceName], attrs]);
122-
}
123-
} catch (err) {
124+
});
125+
} else {
126+
_inject.apply(_this, [services.store[resourceName], attrs]);
127+
}
128+
return attrs;
129+
} catch (err) {
130+
if (!(err instanceof errors.RuntimeError)) {
124131
throw new errors.UnhandledError(err);
132+
} else {
133+
throw err;
125134
}
126-
return resource.index[attrs[idAttribute]];
127135
}
128136
}
129137

0 commit comments

Comments
 (0)