Skip to content

Commit d908d3e

Browse files
author
Tom Kirkpatrick
committed
Merge pull request #4 from beeman/all-tests-passing
2 parents b1c623d + 2f3cb34 commit d908d3e

5 files changed

Lines changed: 183 additions & 49 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
node_modules/
2+
.idea

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,8 @@ Run with debugging output on:
107107
```bash
108108
DEBUG='loopback-ds-changed-mixin' npm test
109109
```
110+
111+
Run the test with a mongodb datasource
112+
```bash
113+
MONGODB_URL=mongodb://localhost/ds_changed_mixin npm test
114+
```

index.js

Lines changed: 137 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ function changed(Model, options) {
1313

1414
var loopback = require('loopback');
1515

16+
/**
17+
* Determine which properties are changed and store them in changedItems
18+
*/
1619
Model.observe('before save', function(ctx, next) {
1720
// Do nothing if a new instance if being created.
1821
if (ctx.instance && ctx.isNewInstance) {
@@ -32,48 +35,65 @@ function changed(Model, options) {
3235

3336
if (ctx.currentInstance) {
3437
debug('Detected prototype.updateAttributes');
35-
if (Model.propertiesChanged(ctx.currentInstance, ctx.data, properties)) {
36-
ctx.hookState.changedItems = [ctx.currentInstance.getId()];
37-
}
38+
//if (Model.propertiesChanged(ctx.currentInstance, ctx.data, properties)) {
39+
// ctx.hookState.changedItems = [ctx.currentInstance.getId()];
40+
//}
41+
ctx.hookState.changedItems = Model.getChangedProperties(ctx.currentInstance, ctx.data, properties);
42+
43+
//console.log('ctx.hookState.changedItems 1 a: ');
44+
//console.log(ctx.hookState.changedItems);
45+
3846
next();
3947
} else if (ctx.instance) {
4048
debug('Working with existing instance %o', ctx.instance);
4149
// Figure out wether this item has changed properties.
4250
ctx.instance.itemHasChangedProperties(ctx.instance, properties)
4351
.then(function(changed) {
44-
if (changed) {
45-
ctx.hookState.changedItems = [ctx.instance.getId()];
46-
}
52+
ctx.hookState.changedItems = changed;
4753
next();
4854
}).catch(next);
4955
} else {
5056
debug('anything else: upsert, updateAll');
5157
// Figure out which items have changed properties.
5258
Model.itemsWithChangedProperties(ctx.where, ctx.data, properties)
53-
.then(function(items) {
54-
debug('items: %o', ctx.items);
55-
if (items && items.length) {
56-
ctx.hookState.changedItems = items;
57-
}
59+
.then(function(changed) {
60+
ctx.hookState.changedItems = changed;
5861
next();
5962
}).catch(next);
6063
}
6164
});
6265

6366
Model.observe('after save', function(ctx, next) {
64-
if (ctx.hookState.changedItems && ctx.hookState.changedItems.length) {
67+
if (ctx.hookState.changedItems && !_.isEmpty(ctx.hookState.changedItems)) {
68+
69+
var changedItems = ctx.hookState.changedItems;
70+
71+
debug('after save: changedItems: %o', changedItems);
72+
73+
var idList = Object.keys(ctx.hookState.changedItems);
74+
debug('after save: idList: %o', idList);
75+
6576
Model.find({
6677
where: {
6778
id: {
68-
inq: ctx.hookState.changedItems
79+
inq: idList
6980
}
7081
},
7182
fields: [
7283
Model.getIdName()
7384
]
7485
}).then(function(items) {
86+
// Extract the ID's from the resultset
87+
var itemIds = Model.extractChangedItemIds(items);
88+
debug('after save: itemIds', itemIds);
89+
90+
// TODO remove changedItems keys that are not in itemIds
91+
var callbackItems = changedItems;
92+
93+
debug('after save: callbackItems', callbackItems);
94+
7595
if (typeof Model[options.callback] !== 'function') return false;
76-
return Model[options.callback](Model.extractChangedItemIds(items));
96+
return Model[options.callback](callbackItems);
7797
})
7898
.then(function(res) {
7999
next();
@@ -92,29 +112,38 @@ function changed(Model, options) {
92112
* @returns {Array} Returns a list of Model instance Ids whose data differ from
93113
* that in the properties argument.
94114
*/
95-
Model.itemsWithChangedProperties = function(conditions, target, properties, cb) {
96-
debug('Looking for items with changed properties...');
97-
debug('conditions is: %o', conditions);
98-
debug('target is: %o', target);
99-
debug('properties is: %o', properties);
115+
Model.itemsWithChangedProperties = function(conditions, newVals, properties, cb) {
116+
debug('itemsWithChangedProperties: Looking for items with changed properties...');
117+
debug('itemsWithChangedProperties: conditions is: %o', conditions);
118+
debug('itemsWithChangedProperties: newVals is: %o', newVals);
119+
debug('itemsWithChangedProperties: properties is 1 : %o', properties);
100120
cb = cb || utils.createPromiseCallback();
101121

102122
conditions = conditions || {};
103-
target = typeof target.toJSON === 'function' ? target.toJSON() : target || {};
123+
newVals = typeof newVals.toJSON === 'function' ? newVals.toJSON() : newVals || {};
104124
properties = properties || {};
105125

126+
var filterFields = [
127+
Model.getIdName()
128+
];
129+
106130
// Build up a list of property conditions to include in the query.
107-
var fields = {or: []};
108-
_.forEach(target, function(value, key) {
131+
var propertyConditions = {or: []};
132+
_.forEach(newVals, function(value, key) {
109133
if (_.includes(properties, key)) {
110134
var fieldFilter = {};
111135
fieldFilter[key] = {'neq': value};
112-
fields.or.push(fieldFilter);
136+
propertyConditions.or.push(fieldFilter);
137+
filterFields.push(key);
113138
}
114139
});
115140

141+
if (!propertyConditions.or.length) propertyConditions = {};
142+
143+
debug('itemsWithChangedProperties: propertyConditions 1 : %o', propertyConditions);
144+
116145
// If there are no property conditions, do nothing.
117-
if (_.isEmpty(properties)) {
146+
if (_.isEmpty(propertyConditions)) {
118147
process.nextTick(function() {
119148
cb(null, false);
120149
});
@@ -123,18 +152,63 @@ function changed(Model, options) {
123152

124153
// Build the final filter.
125154
var filter = {
126-
fields: [
127-
Model.getIdName()
128-
],
155+
fields: filterFields,
129156
where: {
130-
and: [fields, conditions]
157+
and: [propertyConditions, conditions]
131158
}
132159
};
133-
debug('Searching using filter: %s', JSON.stringify(filter, null, 4));
160+
161+
debug('itemsWithChangedProperties: propertyConditions 2 : %o', propertyConditions);
162+
debug('itemsWithChangedProperties: filter Fields %o', filterFields);
163+
debug('itemsWithChangedProperties: conditions %o', conditions);
164+
debug('itemsWithChangedProperties: final filter %o', filter);
165+
134166
Model.find(filter)
135167
.then(function(results) {
136-
debug('Found items that will be changed: %o', results);
137-
cb(null, Model.extractChangedItemIds(results));
168+
169+
debug('itemsWithChangedProperties: filter results %o', results);
170+
171+
var changedProperties = {};
172+
173+
results.map(function(oldVals) {
174+
175+
debug('itemsWithChangedProperties: oldVals %o', oldVals);
176+
debug('itemsWithChangedProperties: newVals %o', newVals);
177+
178+
//changedProperties[oldVals.id] = {};
179+
180+
var changed = {};
181+
182+
properties.map(function(property) {
183+
184+
debug('itemsWithChangedProperties: Matching property %s', property);
185+
186+
if (newVals[property] !== undefined) {
187+
188+
var newVal = newVals[property];
189+
190+
debug('itemsWithChangedProperties: - newVal %s : %s : ', property, newVal);
191+
192+
if (!oldVals[property]) {
193+
changed[property] = newVal;
194+
debug('itemsWithChangedProperties: - no oldVal %s : %s : ', property, newVal);
195+
} else if (newVal !== oldVals[property]) {
196+
var oldVal = oldVals[property];
197+
debug('itemsWithChangedProperties: - oldVal %s : %s : ', property, newVal);
198+
199+
changed[property] = newVal;
200+
}
201+
202+
}
203+
});
204+
205+
debug('itemsWithChangedProperties: changed %o', changed);
206+
changedProperties[oldVals.id] = changed;
207+
208+
});
209+
210+
debug('itemsWithChangedProperties: changedProperties %o', changedProperties);
211+
cb(null, changedProperties);
138212
}).catch(cb);
139213

140214
return cb.promise;
@@ -161,9 +235,9 @@ function changed(Model, options) {
161235

162236
Model.findById(this.getId())
163237
.then(function(instance) {
164-
var changed = Model.propertiesChanged(instance, data, properties);
165-
debug('found supposedly changed items: %o', changed);
166-
cb(null, changed);
238+
var changedProperties = Model.getChangedProperties(instance, data, properties);
239+
debug('itemHasChangedProperties: found supposedly changed items: %o', changedProperties);
240+
cb(null, changedProperties);
167241
}).catch(cb);
168242

169243
return cb.promise;
@@ -191,11 +265,39 @@ function changed(Model, options) {
191265
}
192266
});
193267
if (changed) {
194-
debug('properties were changed');
268+
debug('propertiesChanged: properties were changed');
195269
}
196270
return changed;
197271
};
198272

273+
Model.getChangedProperties = function(oldVals, newVals, properties) {
274+
debug('getChangedProperties: comparing oldVals %o with newVals %o in properties %o', oldVals, newVals, properties);
275+
276+
var itemId = oldVals[Model.getIdName()];
277+
var changedProperties = {};
278+
changedProperties[itemId] = {};
279+
280+
_.forEach(properties, function(key) {
281+
debug('getChangedProperties: - checking property %s ', key);
282+
283+
if (newVals[key]) {
284+
var newVal = newVals[key];
285+
debug('getChangedProperties: - new value %s ', newVal);
286+
287+
if (!oldVals[key] || newVal !== oldVals[key]) {
288+
debug('getChangedProperties: - changed or new value %s itemId %s', newVal, itemId);
289+
290+
changedProperties[itemId][key] = newVal;
291+
}
292+
}
293+
});
294+
if (!_.isEmpty(changedProperties[itemId])) {
295+
debug('getChangedProperties: Properties were changed %o', changedProperties);
296+
return changedProperties;
297+
}
298+
return false;
299+
};
300+
199301
Model.extractChangedItemIds = function(items) {
200302
return _.pluck(items, Model.getIdName());
201303
};

package.json

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "loopback-ds-changed-mixin",
3-
"version": "1.0.1",
3+
"version": "1.0.3",
44
"description": "A mixin to enable loopback Model properties to be marked as changed.",
55
"main": "index.js",
66
"keywords": [
@@ -17,17 +17,15 @@
1717
"debug": "2.x",
1818
"lodash": "latest"
1919
},
20-
"peerDependencies": {
21-
"loopback-datasource-juggler": ">=2.18.1"
22-
},
2320
"devDependencies": {
2421
"bluebird": "2.9.24",
2522
"chai": "latest",
26-
"loopback": "2.x",
27-
"loopback-testing": "1.x",
28-
"mocha": "2.x",
2923
"jscs": "1.13.x",
3024
"jshint": "latest",
25+
"loopback": "2.x",
26+
"loopback-connector-mongodb": "^1.11.1",
27+
"loopback-datasource-juggler": "^2.30.1",
28+
"loopback-testing": "1.x",
3129
"mocha": "latest",
3230
"mocha-sinon": "latest",
3331
"sinon": "latest",

0 commit comments

Comments
 (0)