Skip to content

Commit b4f1b2f

Browse files
kobaskabajtos
authored andcommitted
Add options to bulkUpdate
1 parent 54ee8d8 commit b4f1b2f

File tree

2 files changed

+118
-14
lines changed

2 files changed

+118
-14
lines changed

lib/persisted-model.js

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ module.exports = function(registry) {
10731073
*
10741074
* @param {Number} [since] Since this checkpoint
10751075
* @param {Model} targetModel Target this model class
1076-
* @param {Object} [options]
1076+
* @param {Object} [options] An optional options object to pass to underlying data-access calls.
10771077
* @param {Object} [options.filter] Replicate models that match this filter
10781078
* @callback {Function} [callback] Callback function called with `(err, conflicts)` arguments.
10791079
* @param {Error} err Error object; see [Error object](http://loopback.io/doc/en/lb2/Error-object.html).
@@ -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;
@@ -1212,7 +1216,7 @@ module.exports = function(registry) {
12121216
function bulkUpdate(_updates, cb) {
12131217
debug('\tstarting bulk update');
12141218
updates = _updates;
1215-
targetModel.bulkUpdate(updates, function(err) {
1219+
targetModel.bulkUpdate(updates, options, function(err) {
12161220
var conflicts = err && err.details && err.details.conflicts;
12171221
if (conflicts && err.statusCode == 409) {
12181222
diff.conflicts = conflicts;
@@ -1326,15 +1330,28 @@ module.exports = function(registry) {
13261330
* **Note: this is not atomic**
13271331
*
13281332
* @param {Array} updates An updates list, usually from [createUpdates()](#persistedmodel-createupdates).
1333+
* @param {Object} [options] An optional options object to pass to underlying data-access calls.
13291334
* @param {Function} callback Callback function.
13301335
*/
13311336

1332-
PersistedModel.bulkUpdate = function(updates, callback) {
1337+
PersistedModel.bulkUpdate = function(updates, options, callback) {
13331338
var tasks = [];
13341339
var Model = this;
13351340
var Change = this.getChangeModel();
13361341
var conflicts = [];
13371342

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

@@ -1344,18 +1361,18 @@ module.exports = function(registry) {
13441361
switch (update.type) {
13451362
case Change.UPDATE:
13461363
tasks.push(function(cb) {
1347-
applyUpdate(Model, id, current, update.data, update.change, conflicts, cb);
1364+
applyUpdate(Model, id, current, update.data, update.change, conflicts, options, cb);
13481365
});
13491366
break;
13501367

13511368
case Change.CREATE:
13521369
tasks.push(function(cb) {
1353-
applyCreate(Model, id, current, update.data, update.change, conflicts, cb);
1370+
applyCreate(Model, id, current, update.data, update.change, conflicts, options, cb);
13541371
});
13551372
break;
13561373
case Change.DELETE:
13571374
tasks.push(function(cb) {
1358-
applyDelete(Model, id, current, update.change, conflicts, cb);
1375+
applyDelete(Model, id, current, update.change, conflicts, options, cb);
13591376
});
13601377
break;
13611378
}
@@ -1389,7 +1406,7 @@ module.exports = function(registry) {
13891406
});
13901407
}
13911408

1392-
function applyUpdate(Model, id, current, data, change, conflicts, cb) {
1409+
function applyUpdate(Model, id, current, data, change, conflicts, options, cb) {
13931410
var Change = Model.getChangeModel();
13941411
var rev = current ? Change.revisionForInst(current) : null;
13951412

@@ -1407,7 +1424,7 @@ module.exports = function(registry) {
14071424
// but not included in `data`
14081425
// See https://github.com/strongloop/loopback/issues/1215
14091426

1410-
Model.updateAll(current.toObject(), data, function(err, result) {
1427+
Model.updateAll(current.toObject(), data, options, function(err, result) {
14111428
if (err) return cb(err);
14121429

14131430
var count = result && result.count;
@@ -1442,8 +1459,8 @@ module.exports = function(registry) {
14421459
});
14431460
}
14441461

1445-
function applyCreate(Model, id, current, data, change, conflicts, cb) {
1446-
Model.create(data, function(createErr) {
1462+
function applyCreate(Model, id, current, data, change, conflicts, options, cb) {
1463+
Model.create(data, options, function(createErr) {
14471464
if (!createErr) return cb();
14481465

14491466
// We don't have a reliable way how to detect the situation
@@ -1471,7 +1488,7 @@ module.exports = function(registry) {
14711488
}
14721489
}
14731490

1474-
function applyDelete(Model, id, current, change, conflicts, cb) {
1491+
function applyDelete(Model, id, current, change, conflicts, options, cb) {
14751492
if (!current) {
14761493
// The instance was either already deleted or not created at all,
14771494
// we are done.
@@ -1489,7 +1506,7 @@ module.exports = function(registry) {
14891506
return Change.rectifyModelChanges(Model.modelName, [id], cb);
14901507
}
14911508

1492-
Model.deleteAll(current.toObject(), function(err, result) {
1509+
Model.deleteAll(current.toObject(), options, function(err, result) {
14931510
if (err) return cb(err);
14941511

14951512
var count = result && result.count;

test/replication.test.js

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,6 +1535,93 @@ describe('Replication / Change APIs', function() {
15351535
}
15361536
});
15371537

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

15901677
function setupRaceConditionInReplication(fn) {
15911678
var bulkUpdate = TargetModel.bulkUpdate;
1592-
TargetModel.bulkUpdate = function(data, cb) {
1679+
TargetModel.bulkUpdate = function(data, options, cb) {
15931680
// simulate the situation when a 3rd party modifies the database
15941681
// while a replication run is in progress
15951682
var self = this;
15961683
fn(function(err) {
15971684
if (err) return cb(err);
15981685

1599-
bulkUpdate.call(self, data, cb);
1686+
bulkUpdate.call(self, data, options, cb);
16001687
});
16011688

16021689
// apply the 3rd party modification only once

0 commit comments

Comments
 (0)