-
Notifications
You must be signed in to change notification settings - Fork 573
Plugin: Model Registry
When defining relationships between your models and collections, you're probably going to run into issues with circular dependencies. Node returns unfinished copies of modules when you define circular dependencies. For example:
// file: a.js
var b = require('./b'); // => {}
module.exports = 'foo';
// file: b.js
var a = require('./a'); // => {}
module.exports = function() {
return 'bar';
};
//file: c.js
var b = require('./b');
b(); // => TypeError, a is not a function
Because Node creates empty copies of modules to avoid infinite loops with circular dependencies, even c.js
never gets the module.exports
object of b.js
. Circular dependencies are almost guaranteed if you're defining relationships between your model. To help get around this, Bookshelf lets you register your models and collections in a central location so you can call them without dependency issues.
Load the plugin on your Bookshelf instance using Bookshelf.plugin('registry')
.
Registers a model. Omit Model
to return a previously registered model with the provided name
.
Same semantics as Bookshelf.model
.
The plugin monkey patches Bookshelf's relation functions (hasOne
, hasMany
, belongsTo
, belongsToMany
, through
, morphOne
, morphMany
, morphTo
). Anywhere you'd normally require
a model, you can refer to it using its name supplied to Bookshelf.model
.
For example:
// file: customer.js
require('./order');
module.exports = bookshelf.model('Customer', {
tableName: 'customers',
orders: function() {
return this.hasMany('Order');
}
});
// file: order.js
require('./customer');
module.exports = bookshelf.model('Order', {
tableName: 'orders',
customer: function() {
return this.belongsTo('Customer');
}
});
or alternatively, with a defined model:
// file: customer.js
require('./order');
var Customer = Bookshelf.Model.extend({
tableName: 'customers',
orders: function() {
return this.hasMany('Order');
}
});
module.exports = Bookshelf.model('Customer', Customer);
// file: order.js
require('./customer');
var Order = Bookshelf.Model.extend({
tableName: 'orders',
customer: function() {
return this.belongsTo('Customer');
}
});
module.exports = Bookshelf.model('Order', Order);
You still have to require the model somewhere to make sure Bookshelf.model
is called. Here we're requiring it at the top of each file to make sure it's loaded into the registry, but we don't actually need to assign it to a variable. You don't have to worry that the module won't actually be available when required because of how Node handles circular references. By the time you call new Order({id: 1}).customer()
, the module will be ready and your relationships will work as expected.
Finally, note that it's possible to both use this plugin for some models/collections while still using the classical instantiation way for the other models/collections.This plugin is not an all-or-nothing strategy.