0

To improve our program and reduce code redundancy, we wish to create some inheritance inside the models..

Now take a typical User model, it has a name and password field as "baseclass" and several subclasses can improve upon this depending in the specific application's needs.

So a baseuser would look like:

module.exports = {
  attributes: {
    username: {
      type: 'string',
      required: true,
      unique: true
    },
    password: {
      type: 'string',
      required: true,
    },
  },
  beforeCreate: async function(user, cb) {
    const hash = await bcrypt.hash(user.password, 10);
    user.password = hash;
    cb();
  },
}

This bare class doesn't correspond to any database table in its own. Now in derived class from this, VerifyableUser (a model for users that must have verification links), there are a few extra fields, one which is a verify url.

Now to "extend" classes lodash' _.merge function is used, as explained in this question .

const BaseUser = require("../../BaseUser.js");
module.exports = _.merge({}, BaseUser, {
  attributes: {
    verify_key: {
      type: 'string'
    }
  },
  beforeCreate: async function(user, cb) {
    user.verify_key = 'helloworld'; //crypto used to generate...
    cb();
  }
};

Now the problem should be obvious, the derived class' beforeCreate overwrites the original beforeCreate: in a normal OO environment this isn't a big problem either, as I could just call Base.beforeCreate() or something similar. However can something be done using lodash' merge? Or should I use another way to extend objects? (Or do I really have to repeat myself and retype the beforeCreate?).

Akrion
  • 18,117
  • 1
  • 34
  • 54
paul23
  • 8,799
  • 12
  • 66
  • 149

2 Answers2

0

or something similar:

 // VerifyableUser
 async beforeCreate(user, cb) {
  await BaseUser.beforeCreate(user, () => 0);
  //...
 }
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
0

You could also use _.mergeWith to check what each property being merged is and if it is a function just pick the object and not the source (in your case the source is BaseUser):

const BaseUser = require("../../BaseUser.js");

let obj = {
  attributes: {
    verify_key: {
      type: 'string'
    }
  },
  beforeCreate: async function(user, cb) {
    user.verify_key = 'helloworld'; //crypto used to generate...
    cb();
  }
}
module.exports = _.mergeWith(
  obj, 
  BaseUser, 
  (objValue, srcValue, key, object, source) => _.isFunction(objValue) ? objValue : _.merge(object[key], source[key])
)

Here is a test:

var data = {
  food: "chicken",
  foo: () => console.log('chicken!')
}

var source = {
  prop1: 1,
  prop2: 1,
  foo: () => console.log('foo!')
}

var result = _.merge(data, source, (objValue, srcValue, key, object, source) => _.isFunction(objValue) ? objValue : _.merge(object[key], source[key]))

console.log(result)
result.foo()
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Akrion
  • 18,117
  • 1
  • 34
  • 54