cphill
cphill

Reputation: 5924

Sequelize - Calling a beforeDestroy hook on instance that has onDelete Cascade

I have a scenario involving two tables (one-to-many), where a user can delete a record or array of records from the first table (name: document, relationship: one) and then the record(s) associated to that table from my second table (name: file, relationship: many) will be removed. The onDelete cascading on the "file" table is working as it should, but my hook is never firing.

Here is the association between the two tables:

Document

var Document = sequelize.define('document', {
    ...
},
{
    underscored: true,
    freezeTableName: true,
    classMethods: {
        associate: function(db) {
            Document.hasMany(db.File, { foreignKey: 'document_id'}),
        }
    }
});
return Document;

File

var File = sequelize.define('file', {
    ...
},{
    underscored: true,
    freezeTableName: true,
    hooks: {
        beforeDestroy: function(whereClause, fn){
            //options.individualHooks = true;
            console.log('whereClause Start');
            console.log(whereClause);
            console.log('fn start');
            console.log(fn);
        },
        beforeBulkDestroy: function(whereClause, fn) {
            //options.individualHooks = true;
            console.log('whereClause Start');
            console.log(whereClause);
            console.log('fn start');
            console.log(fn);   
        }
    },
    classMethods: {
        associate: function(db) {
            File.belongsTo(db.Document, { onDelete: 'CASCADE', hooks: true});
        }
    }
});
return File;

Only Sequelize trigger scenario:

models.Document.destroy({
    where: {
        userId: req.user.userId,
        documentId: documentId //Replace with array in certain instances
    }
});

Upvotes: 3

Views: 4293

Answers (2)

defraggled
defraggled

Reputation: 1218

The Model.destroy() method doesn't invoke the beforeDestroy hook by default. You can force it to do so with the individualHooks: true option, like so

models.Document.destroy({
    where: {
        userId: req.user.userId,
        documentId: documentId //Replace with array in certain instances
    },
    individualHooks: true
})

See:

https://github.com/sequelize/sequelize/issues/10270

https://sequelize.org/master/manual/hooks.html#model-hooks

If you want, you could alternatively jimmy-rig any bulk destroy on this model to always fire the individual hooks. This can be done via the beforeBulkDestroy hook:

    beforeBulkDestroy: async (options) =>
        (options.individualHooks = true),

But of course this can be intensive and may not be desired behaviour.

Upvotes: 0

Baterka
Baterka

Reputation: 3714

I was facing same problem. Because documentation (v5):

Note: You can't use hooks with instances. Hooks are used with models.

and

Instance Hooks: The following hooks will emit whenever you're editing a single object

giving very mixed view I decided to not destroy by instances models.Document.destroy(where), but by models (Select model and then document.destroy()). Hooks are fired when doing so.

Seems that Sequelize (v5) is just not able to call hooks when you using cascades right now.

Upvotes: 2

Related Questions