Search code examples
node.jsmongoosesequelize.js

Pre-save hook and instance methods in Sequelize?


Are there pre-save hooks and instance methods in Sequelize.js?

Specifically I need to convert this Mongoose code into an equivalent Sequelize code:

Schema

var userSchema = new mongoose.Schema({
  username: { type: String, unique: true },
  email: { type: String, unique: true },
  password: String,
  token: String
});

Pre-save

userSchema.pre('save', function(next) {
  var user = this;

  var hashContent = user.username + user.password + Date.now() + Math.random();
  user.token = crypto.createHash('sha1').update(hashContent).digest('hex');

  if (!user.isModified('password')) return next();
  bcrypt.genSalt(5, function(err, salt) {
    if (err) return next(err);
    bcrypt.hash(user.password, salt, function(err, hash) {
      if (err) return next(err);
      user.password = hash;
      next();
    });
  });
});

Instance method

userSchema.methods.comparePassword = function(candidatePassword, cb) {
  bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
    if(err) return cb(err);
    cb(null, isMatch);
  });
};

Solution

  • The best way is to expand your model with class or instance methods:

    var User = sequelize.define('User', {
        username: { type: Sequelize.STRING, unique: true },
        email: { type: Sequelize.STRING, unique: true },
        password: Sequelize.STRING,
        token: Sequelize.STRING
    }, {
        instanceMethods: {
            comparePassword : function(candidatePassword, cb) {
                bcrypt.compare(candidatePassword, this.getDataValue('password'), function(err, isMatch) {
                    if(err) return cb(err);
                    cb(null, isMatch);
                });
            },
            setToken: function(){
                // bla bla bla
                // bla bla bla
            },
            getFullname: function() {
                return [this.firstname, this.lastname].join(' ');
            }
        }
    })
    

    So when you do

    User.build({ firstname: 'foo', lastname: 'bar' }).getFullname(); // 'foo bar'
    

    So, to set the token, you can do it like this:

    User.build({ ... }).setToken().save();
    

    Or, to use the comparePassword function:

    User.find({ ... }).success(function(user) { user.comparePassword('the password to check', function(err, isMatch) { ... } });
    

    You can see this in the Sequelize docs

    Edit

    On recent versions of there are hooks for each model, you can check the hooks documentation which are very pretty straightforward and complement them with the class or instance methods.