Skip to content
This repository was archived by the owner on Oct 20, 2025. It is now read-only.
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 75 additions & 44 deletions lib/persisted-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -1474,28 +1474,71 @@ module.exports = function(registry) {
buildLookupOfAffectedModelData(Model, updates, function(err, currentMap) {
if (err) return callback(err);

updates.forEach(function(update) {

var deleteIds = [];
var deleteConflicts = [];

updates.forEach(function (update) {
var id = update.change.modelId;
var current = currentMap[id];
switch (update.type) {
case Change.UPDATE:
tasks.push(function(cb) {
applyUpdate(Model, id, current, update.data, update.change, conflicts, options, cb);
tasks.push(function (cb) {
applyUpdate(
Model,
id,
current,
update.data,
update.change,
conflicts,
options,
cb
);
});
break;

case Change.CREATE:
tasks.push(function(cb) {
applyCreate(Model, id, current, update.data, update.change, conflicts, options, cb);
tasks.push(function (cb) {
applyCreate(
Model,
id,
current,
update.data,
update.change,
conflicts,
options,
cb
);
});
break;
case Change.DELETE:
tasks.push(function(cb) {
applyDelete(Model, id, current, update.change, conflicts, options, cb);
});
const conflictId = findDeleteConflicts(
Model,
id,
current,
update.change,
conflicts
);
if (conflictId) {
deleteConflicts.push(conflictId);
} else {
deleteIds.push(id);
}

break;
}
});
if (deleteConflicts.length) {
tasks.push(function (cb) {
rectifyDeleteChanges(Model, deleteConflicts, cb);
});
}

if (deleteIds.length) {
tasks.push(function (cb) {
applyDeletes(Model, deleteIds, update.change, conflicts, options, cb);
});
}

async.parallel(tasks, function(err) {
if (err) return callback(err);
Expand Down Expand Up @@ -1619,56 +1662,44 @@ module.exports = function(registry) {
}
}

function applyDelete(Model, id, current, change, conflicts, options, cb) {
/**
* Returns an id if there is a conflict, otherwise null
* @param {*} Model
* @param {*} id
* @param {*} current
* @param {*} change
* @param {*} conflicts
* @param {*} options
*/
function findDeleteConflicts(Model, id, current, change, conflicts) {
if (!current) {
// The instance was either already deleted or not created at all,
// we are done.
return cb();
return null;
}

var Change = Model.getChangeModel();
var rev = Change.revisionForInst(current);
if (rev !== change.prev) {
debug('Detected non-rectified change of %s %j',
Model.modelName, id);
debug('Detected non-rectified change of %s %j', Model.modelName, id);
debug('\tExpected revision: %s', change.rev);
debug('\tActual revision: %s', rev);
conflicts.push(change);
return Change.rectifyModelChanges(Model.modelName, [id], cb);
return id;
}
}
function rectifyDeleteChanges(Model, ids, cb) {
return Change.rectifyModelChanges(Model.modelName, ids, cb);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is Change in scope here?

}

Model.deleteById(id, options, function(err, result) {
function applyDeletes(Model, ids, change, conflicts, options, cb) {
var idName = this.getIdName();
var where = {};
where[idName] = { inq: ids };
Model.deleteAll(where, options, function (err) {
if (err) return cb(err);

var count = result && result.count;
switch (count) {
case 1:
// The happy path, exactly one record was updated
return cb();

case 0:
debug('DeleteAll detected non-rectified change of %s %j',
Model.modelName, id);
conflicts.push(change);
// NOTE(bajtos) deleteAll triggers change rectification
// for all model instances, even when no records were updated,
// thus we don't need to rectify explicitly ourselves
return cb();

case undefined:
case null:
return cb(new Error(
g.f('Cannot apply bulk updates, ' +
'the connector does not correctly report ' +
'the number of deleted records.')));

default:
debug('%s.deleteAll modified unexpected number of instances: %j',
Model.modelName, count);
return cb(new Error(
g.f('Bulk update failed, the connector has deleted unexpected ' +
'number of records: %s', JSON.stringify(count))));
}
// all is good. exit gracefully, we deleted as much as we could!
return cb();
});
}

Expand Down