tabebqena
tabebqena

Reputation: 1260

sequelize ignore "save()" method on JSON object

I am trying to take benefits of model instance methods, as stated in the doc. So I defined User class as following:

class User extends Model {
    addRole(role){
        let roles = this. roles;
        roles[role] = true;
        this.roles = roles;
        this.save();
    }

    removeRole (role) {
        let roles = this.roles;
        delete roles[role];
        this.save();
    }
    
    hasRole (role){
        return this.roles[role] != null;
    }
}


User.init({
// some attributes
,
roles:{
  type: DataTypes.JSON,
  allowNull: false,
}
}, { sequelize});

I expected to use methods addRole(), removeRole() and hasRole() in any User instance.

The problem that all the methods can't save their changes to database. (Can read only!)

// example 
let user = null; 
// get the first user to test.
User.findAll() 
    .then(users =>{
          user = users[0];
          user.addRole("admin");
          console.log(user.roles); // {admin: true} 
          user.save();
          // However the changes don't appear in the database.
}); 

Upvotes: 2

Views: 743

Answers (1)

tabebqena
tabebqena

Reputation: 1260

I had found the answer. For some reasons, sequelise can't detect the changes of the json object properly. As sequelise is optimised internally to ignore call to model.save() if there is no changes of the model. So, sequelize randomly ignore the save method.

This behavior had no relation with instance method as I believed when I face this problem first time.

To get out of this problem, I had to use :

 user.addRole("admin");
 user.changed("roles", true); // <<<< look at this;
 console.log(user.roles); // {admin: true} 
 user.save();

Please note that this function will return false when a property from a nested (for example JSON) property was edited manually, you must call changed('key', true) manually in these cases. Writing an entirely new object (eg. deep cloned) will be detected.

Example:

const mdl = await MyModel.findOne();
mdl.myJsonField.a = 1;
console.log(mdl.changed()) => false
mdl.save(); // this will not save anything
mdl.changed('myJsonField', true);
console.log(mdl.changed()) => ['myJsonField']
mdl.save(); // will save

changed method usage

Upvotes: 8

Related Questions