Support dependency injection into instances
See original GitHub issueIssue Description
I would like to the ability to inject dependencies into model instances at the point where Sequelize creates them.
Is your feature request related to a problem? Please describe.
I often find myself wanting to use dependencies (e.g. api or messaging clients) from my model instances, e.g.
static async function ensureUser(username) {
let user = await User.findOneByCriteria({ where: { username }});
if (user) return user;
user = await this.userApi.fetchUserByEmail(username);
return User.save(user);
}
// n.b. There's a race condition in the above, this is just a simple example to demonstrate the dependency issue*
I haven’t found a nice way to achieve with Sequelize because there doesn’t appear to be a way to inject dependencies into model instances.
Describe the solution you’d like
I was wondering whether a afterConstruct
hook could be used to solve this. I understand it might be slow for large record sets, but hopefully not that slow if all it was doing was fetching a pre-created dependency.
function initModels(dependencies) {
User.init({
username: DataTypes.STRING,
}, {
hooks: {
afterConstruct: (user, options) => {
user.userApi = dependencies.userApi;
user.messageBroker = dependencies.messageBroker
// n.b. assignment might need to support async factories, although caution should be taken as this could be extremely slow for large record sets
},
},
sequelize
// An alternative solution might be to support a dependencies object here
});
}
Why should this be in Sequelize
One of the primary use cases for Sequelize (or any ORM) is to support rich domain models, which collocate behaviour and state. Not being able to inject dependencies undermines this.
Describe alternatives/workarounds you’ve considered
The options I’ve considered are:
- Requiring the dependency / using singletons. This is infeasible if the dependency has async setup or requires its own dependencies. Also makes TDD harder.
- Passing the dependencies as arguments to the function, e.g.
ensureUser(username, userApi)
. This adversely affects readability (by increasing the number of function arguments) and potentially means passing dependencies through several levels of function call, before they’re actually used - Copying the constructor approach you use for injecting
this.sequelize
(this is what we’re currently using as a workaround)
Additional context
Issue Template Checklist
Is this issue dialect-specific?
- No. This issue is relevant to Sequelize as a whole.
Would you be willing to resolve this issue by submitting a Pull Request?
- Yes, I have the time and I know how to start (but may also benefit from guidance).
Issue Analytics
- State:
- Created 4 years ago
- Comments:8 (3 by maintainers)
Thanks @papb. We have a hackday coming up soon. We’ll work on the PR then.
Hi @papb, we’d be happy to work on a PR. Any thoughts about hooks not being fired for nested / included entities?