What is the use of defining a mixin instead of a instance method in sequilizejs?

Viewed 102

I was trying through some advanced techniques used to refactor sequilize.js models and came across how instanceMethods method can be used and util functions can be attached to it.

Example:

function get_instance_methods(sequelize) {
  return {
    is_admin : function() {
      return this.admin === true;
    },
  };
};

and then the above can be used like so :

module.exports = function(sequelize, DataTypes) {

  var instance_methods = get_instance_methods(sequelize);

  var User = sequelize.define("User", {
      email : {
          type      : DataTypes.STRING,
          allowNull : false
      },
  }, {
      instanceMethods : instance_methods,
    });

    return User;
};

But now I came across a mixin being defined and then being used like so inside a modal HERE .

 withCompanyAwareness.call ( instance_methods, sequelize ) ;

the code for the mixin itself is being defined HERE. A snapshot of what the mixin looks like can be found below :-

module.exports = function(sequelize){
  // more methods defined here .. just adding a snapshot here.
  this.get_company_with_all_leave_types = function() {
    return this.getCompany({
      include : [{
        model : sequelize.models.LeaveType,
        as    : 'leave_types',
      }],
      order : [
        [{ model : sequelize.models.LeaveType, as : 'leave_types' }, 'sort_order', 'DESC'],
        [{ model : sequelize.models.LeaveType, as : 'leave_types' }, 'name']
      ]
    });
  };

};

What exactly is the purpose of defining a mixin vs using instance methods? Why is there a need for defining a mixin?

1 Answers

Very interesting question! Let's start with what is clear so far:

  • the model should return the Model instance always
  • to create the Model instance, in both cases instanceMethods is being set as an object which contains methods.

get_instance_methods(sequelize) returns an object of functions in both situations. In the first example, this object is not extended with new functions. The function which were returned, are passed to the Model creation, hence, what get_instance_methods(...) returns, that arrives in the model's instanceMethods.

If needed, we can modify the instance_methods object before we send it to the model:

instance_methods.myNewMethod = function () { ... }

This would add myNewMethod in the instance functions of the specific model where add this functionality, but not for the other models where we call the get_instance_methods for.

Now, let's assume that we have a third model that would need myNewMethod exaclty in the same way. In that case, we have two options: to duplicate the myNewMethod function in the second and third models, ending up with duplicated code which is not fun, or create a mixin!

What is a mixin in this case? Just a function to unify that eventual duplicate code.

Hence, we can have a mixin function called:

function with_my_new_method () {
    this.myNewMethod = function () { ... }
} 

So, in the models we would have:

// Model1.js:
var instance_methods = get_instance_methods(sequelize);
var Model1 = sequelize.define("Model1", {
  ...
}, {
  instanceMethods: instance_methods
});

// Model2.js:
var instance_methods = get_instance_methods(sequelize);
with_my_new_method.call(instance_methods)
var Model2 = sequelize.define("Model2", {
  ...
}, {
  instanceMethods: instance_methods
});

// Model3.js:
var instance_methods = get_instance_methods(sequelize);
with_my_new_method.call(instance_methods)
var Model3 = sequelize.define("Model3", {
  ...
}, {
  instanceMethods: instance_methods
});

When calling the with_my_new_method mixin function with .call, that means we are passing the instance_methods as context to the function. So, instance_methods would become this inside of the mixin functions.

Conclusion

In this case the mixin functions work as utility functions to extend the instance methods object with new methods.

Related