SystemicPlural
SystemicPlural

Reputation: 5789

How to extend bookshelf.js

I have a validate function that I am copying into almost every model. I want to abstract it by extending the base bookshelf.Model object. I'm not sure what the correct way to go about this is in ES6. I'd like to do this without forking bookshelf.

An example model:

import bookshelf from '../bookshelf';
import Checkit from 'checkit';

const Design = bookshelf.Model.extend({
  tableName: 'foo',

  constructor: function() {
    bookshelf.Model.apply(this, arguments); // super()
    this.on('saving', this.validate.bind(this));
  },

  validations: {
    barColumn: ['required', 'integer', 'greaterThan:0'],
  },

  validate: function(model, attrs, options) {
    let validations;
    if (options.patch === true) {
      Object.keys(this.validations).forEach((value, index) => {
        if (this.attributes[index] !== undefined) {
          validations[index] = value;
        }
      });
    } else {
      validations = this.validations;
    }
    return new Checkit(validations).run(this.toJSON());
  }
});

export default Design;

The main bookshelf file is here.

Upvotes: 0

Views: 926

Answers (2)

SystemicPlural
SystemicPlural

Reputation: 5789

I couldn't work out how to extend Bookshelf so I solved it like this:

import bookshelf from '../bookshelf';
import validate from '../utils/validate';

const Design = bookshelf.Model.extend({
  tableName: 'foo',

  constructor: function() {
    bookshelf.Model.apply(this, arguments); // super()
    this.on('saving', validate);
  },

  validations: {
    barColumn: ['required', 'integer', 'greaterThan:0'],
  },
});

export default Design;

And the new validate file:

import Checkit from 'checkit';

export default function validate(model, attributes, options) {
  let validations;
  if (options.patch === true) {
    Object.keys(model.validations).forEach((value, index) => {
      if (attributes[index] !== undefined) {
        validations[index] = value;
      }
    });
  } else {
    validations = model.validations;
  }
  return new Checkit(validations).run(model.toJSON());
};

Upvotes: 1

Roman Pushkin
Roman Pushkin

Reputation: 6079

I think you need Facade or Decorator pattern + some dependency injection.

I used Facade for my own purposes the following way:

class MyFacade {

  constructor(legacyLibrary) {
    this.legacyLibrary = legacyLibrary;
  }

  newMethod() {
    this.legacyLibrary.doSomething();
    this.legacyLibrary.doSomethingElse();
  }

}

export default MyFacade;

Idea of decorator is the same, but you should extend your existing class. So all the functionality will remain the same, but you'll have more methods in it.

The good thing about decorator is that you can nest them. Decorate with one, then with another, etc.

Upvotes: 0

Related Questions