Skip to content

Instantly share code, notes, and snippets.

@Alexisvt
Forked from zbarbuto/cascade.js
Created January 9, 2018 12:08
Show Gist options
  • Save Alexisvt/92d55c19ace0bd31823597d44cdf14ae to your computer and use it in GitHub Desktop.
Save Alexisvt/92d55c19ace0bd31823597d44cdf14ae to your computer and use it in GitHub Desktop.
Loopback cascade mixin gist
// Cascade delete for loopback
// https://gist.github.com/CjS77/44b2f75c0ec468f590d0
/* jshint node:true */
'use strict';
/**
* There is an incubating feature to cascade the deletes to the relational tables. see
* https://github.com/strongloop/loopback-datasource-juggler/issues/88
*/
var lazy = require('lazy.js');
var async = require('async');
var log = require('debug')('mixins:cascade');
var Q = require('q');
module.exports = function (Model, options) {
var matchRelation = function (name) {
return lazy(Model.relations).find(function (mr) {
return mr.name === name;
});
};
//Pre-process and remove unsupported relations
lazy(options).keys().forEach(function (relationName) {
var relation = matchRelation(relationName);
if (relation && relation.type === 'referencesMany') {
log("Cascading to referencesMany is not supported - %s", relation.name);
delete options[relationName];
}
});
Model.observe('after delete', function (ctx, next) {
if (!(ctx.instance || ctx.where)) {
log("There is no way to apply cascading deletes on a multi-record delete");
return; //Nothing we can do
}
var promises = [];
var thisId = ctx.instance ? ctx.instance.id : ctx.where.id;
lazy(options).keys().each(function (relationName) {
var relation = matchRelation(relationName);
if (!relation) {
return;
}
var filter = {};
filter[relation.keyTo] = thisId;
if (options[relationName].unlink) {
var throughModel = relation.modelThrough;
if (throughModel) {
breakLinks(throughModel, filter, next);
} else {
log("%s.%s does not have a through model. Nothing to unlink", Model.definition.name, relationName);
}
} else {
//See https://gist.github.com/fabien/126ccfaca48ddf1cefb8
var promise = relation.modelTo.find({where: filter}).then(function (items) {
return Q.all(
lazy(items).map(function (inst) {
return inst.destroy();
}).toArray()
).then(function (results) {
log("Cascaded delete of: ", items);
if (relation.modelThrough) {
breakLinks(relation.modelThrough, filter, next);
}
});
});
promises.push(promise);
}
});
Promise.all(promises).then(function(results) {
log('Cascade: ' + results);
next();
});
});
function breakLinks(throughModel, filter, next) {
throughModel.destroyAll(filter).then(function (info) {
log("Removed %d links from %s referring to %s", info.count, throughModel.definition.name, Model.definition.name);
next();
}).catch(function (err) {
next(err);
});
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment