Skip to content

Commit c0e96ff

Browse files
authored
Merge pull request #2940 from kobaska/add-optional-options-to-bulkupdate
Add options to bulkUpdate
2 parents 007b20d + bc923bd commit c0e96ff

File tree

2 files changed

+121
-14
lines changed

2 files changed

+121
-14
lines changed

lib/persisted-model.js

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,7 +1075,7 @@ module.exports = function(registry) {
10751075
*
10761076
* @param {Number} [since] Since this checkpoint
10771077
* @param {Model} targetModel Target this model class
1078-
* @param {Object} [options]
1078+
* @param {Object} [options] An optional options object to pass to underlying data-access calls.
10791079
* @param {Object} [options.filter] Replicate models that match this filter
10801080
* @callback {Function} [callback] Callback function called with `(err, conflicts)` arguments.
10811081
* @param {Error} err Error object; see [Error object](http://docs.strongloop.com/display/LB/Error+object).
@@ -1100,6 +1100,10 @@ module.exports = function(registry) {
11001100
since = { source: since, target: since };
11011101
}
11021102

1103+
if (typeof options === 'function') {
1104+
options = {};
1105+
}
1106+
11031107
options = options || {};
11041108

11051109
var sourceModel = this;
@@ -1214,7 +1218,7 @@ module.exports = function(registry) {
12141218
function bulkUpdate(_updates, cb) {
12151219
debug('\tstarting bulk update');
12161220
updates = _updates;
1217-
targetModel.bulkUpdate(updates, function(err) {
1221+
targetModel.bulkUpdate(updates, options, function(err) {
12181222
var conflicts = err && err.details && err.details.conflicts;
12191223
if (conflicts && err.statusCode == 409) {
12201224
diff.conflicts = conflicts;
@@ -1328,15 +1332,28 @@ module.exports = function(registry) {
13281332
* **Note: this is not atomic**
13291333
*
13301334
* @param {Array} updates An updates list, usually from [createUpdates()](#persistedmodel-createupdates).
1335+
* @param {Object} [options] An optional options object to pass to underlying data-access calls.
13311336
* @param {Function} callback Callback function.
13321337
*/
13331338

1334-
PersistedModel.bulkUpdate = function(updates, callback) {
1339+
PersistedModel.bulkUpdate = function(updates, options, callback) {
13351340
var tasks = [];
13361341
var Model = this;
13371342
var Change = this.getChangeModel();
13381343
var conflicts = [];
13391344

1345+
var lastArg = arguments[arguments.length - 1];
1346+
1347+
if (typeof lastArg === 'function' && arguments.length > 1) {
1348+
callback = lastArg;
1349+
}
1350+
1351+
if (typeof options === 'function') {
1352+
options = {};
1353+
}
1354+
1355+
options = options || {};
1356+
13401357
buildLookupOfAffectedModelData(Model, updates, function(err, currentMap) {
13411358
if (err) return callback(err);
13421359

@@ -1346,18 +1363,18 @@ module.exports = function(registry) {
13461363
switch (update.type) {
13471364
case Change.UPDATE:
13481365
tasks.push(function(cb) {
1349-
applyUpdate(Model, id, current, update.data, update.change, conflicts, cb);
1366+
applyUpdate(Model, id, current, update.data, update.change, conflicts, options, cb);
13501367
});
13511368
break;
13521369

13531370
case Change.CREATE:
13541371
tasks.push(function(cb) {
1355-
applyCreate(Model, id, current, update.data, update.change, conflicts, cb);
1372+
applyCreate(Model, id, current, update.data, update.change, conflicts, options, cb);
13561373
});
13571374
break;
13581375
case Change.DELETE:
13591376
tasks.push(function(cb) {
1360-
applyDelete(Model, id, current, update.change, conflicts, cb);
1377+
applyDelete(Model, id, current, update.change, conflicts, options, cb);
13611378
});
13621379
break;
13631380
}
@@ -1391,7 +1408,7 @@ module.exports = function(registry) {
13911408
});
13921409
}
13931410

1394-
function applyUpdate(Model, id, current, data, change, conflicts, cb) {
1411+
function applyUpdate(Model, id, current, data, change, conflicts, options, cb) {
13951412
var Change = Model.getChangeModel();
13961413
var rev = current ? Change.revisionForInst(current) : null;
13971414

@@ -1409,7 +1426,7 @@ module.exports = function(registry) {
14091426
// but not included in `data`
14101427
// See https://github.com/strongloop/loopback/issues/1215
14111428

1412-
Model.updateAll(current.toObject(), data, function(err, result) {
1429+
Model.updateAll(current.toObject(), data, options, function(err, result) {
14131430
if (err) return cb(err);
14141431

14151432
var count = result && result.count;
@@ -1444,8 +1461,8 @@ module.exports = function(registry) {
14441461
});
14451462
}
14461463

1447-
function applyCreate(Model, id, current, data, change, conflicts, cb) {
1448-
Model.create(data, function(createErr) {
1464+
function applyCreate(Model, id, current, data, change, conflicts, options, cb) {
1465+
Model.create(data, options, function(createErr) {
14491466
if (!createErr) return cb();
14501467

14511468
// We don't have a reliable way how to detect the situation
@@ -1473,7 +1490,7 @@ module.exports = function(registry) {
14731490
}
14741491
}
14751492

1476-
function applyDelete(Model, id, current, change, conflicts, cb) {
1493+
function applyDelete(Model, id, current, change, conflicts, options, cb) {
14771494
if (!current) {
14781495
// The instance was either already deleted or not created at all,
14791496
// we are done.
@@ -1491,7 +1508,7 @@ module.exports = function(registry) {
14911508
return Change.rectifyModelChanges(Model.modelName, [id], cb);
14921509
}
14931510

1494-
Model.deleteAll(current.toObject(), function(err, result) {
1511+
Model.deleteAll(current.toObject(), options, function(err, result) {
14951512
if (err) return cb(err);
14961513

14971514
var count = result && result.count;

test/replication.test.js

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,96 @@ describe('Replication / Change APIs', function() {
15371537
}
15381538
});
15391539

1540+
describe('ensure options object is set on context during bulkUpdate', function() {
1541+
var syncPropertyExists = false;
1542+
var OptionsSourceModel;
1543+
1544+
beforeEach(function() {
1545+
OptionsSourceModel = PersistedModel.extend(
1546+
'OptionsSourceModel-' + tid,
1547+
{ id: { id: true, type: String, defaultFn: 'guid' } },
1548+
{ trackChanges: true });
1549+
1550+
OptionsSourceModel.attachTo(dataSource);
1551+
1552+
OptionsSourceModel.observe('before save', function updateTimestamp(ctx, next) {
1553+
if (ctx.options.sync) {
1554+
syncPropertyExists = true;
1555+
} else {
1556+
syncPropertyExists = false;
1557+
}
1558+
next();
1559+
});
1560+
});
1561+
1562+
it('bulkUpdate should call Model updates with the provided options object', function(done) {
1563+
var testData = {name: 'Janie', surname: 'Doe'};
1564+
var updates = [
1565+
{
1566+
data: null,
1567+
change: null,
1568+
type: 'create'
1569+
}
1570+
];
1571+
1572+
var options = {
1573+
sync: true
1574+
};
1575+
1576+
async.waterfall([
1577+
function(callback) {
1578+
TargetModel.create(testData, callback);
1579+
},
1580+
function(data, callback) {
1581+
updates[0].data = data;
1582+
TargetModel.getChangeModel().find({where: {modelId: data.id}}, callback);
1583+
},
1584+
function(data, callback) {
1585+
updates[0].change = data;
1586+
OptionsSourceModel.bulkUpdate(updates, options, callback);
1587+
}],
1588+
function(err, result) {
1589+
if (err) return done(err);
1590+
1591+
expect(syncPropertyExists).to.eql(true);
1592+
1593+
done();
1594+
}
1595+
);
1596+
});
1597+
});
1598+
1599+
describe('ensure bulkUpdate works with just 2 args', function() {
1600+
it('bulkUpdate should successfully finish without options', function(done) {
1601+
var testData = {name: 'Janie', surname: 'Doe'};
1602+
var updates = [
1603+
{
1604+
data: null,
1605+
change: null,
1606+
type: 'create'
1607+
}
1608+
];
1609+
1610+
async.waterfall([
1611+
function(callback) {
1612+
TargetModel.create(testData, callback);
1613+
},
1614+
function(data, callback) {
1615+
updates[0].data = data;
1616+
TargetModel.getChangeModel().find({where: {modelId: data.id}}, callback);
1617+
},
1618+
function(data, callback) {
1619+
updates[0].change = data;
1620+
SourceModel.bulkUpdate(updates, callback);
1621+
}
1622+
], function(err, result) {
1623+
if (err) return done(err);
1624+
done();
1625+
}
1626+
);
1627+
});
1628+
});
1629+
15401630
var _since = {};
15411631
function replicate(source, target, since, next) {
15421632
if (typeof since === 'function') {
@@ -1591,14 +1681,14 @@ describe('Replication / Change APIs', function() {
15911681

15921682
function setupRaceConditionInReplication(fn) {
15931683
var bulkUpdate = TargetModel.bulkUpdate;
1594-
TargetModel.bulkUpdate = function(data, cb) {
1684+
TargetModel.bulkUpdate = function(data, options, cb) {
15951685
// simulate the situation when a 3rd party modifies the database
15961686
// while a replication run is in progress
15971687
var self = this;
15981688
fn(function(err) {
15991689
if (err) return cb(err);
16001690

1601-
bulkUpdate.call(self, data, cb);
1691+
bulkUpdate.call(self, data, options, cb);
16021692
});
16031693

16041694
// apply the 3rd party modification only once

0 commit comments

Comments
 (0)