This issue relates to several other issues, for example, #360.
What is the problem?
Currently, the Vuex ORM stores database to the Container object, which is a global singleton. This is needed to retrieve any relationships through Vuex Getters and Actions.
Having a singleton object is not always bad. As long as you are using it in a single app, everything should work fine. However, it's a bad practice when doing SSR, as stated here at Vue SSR doc.
Usually, models are stateless, and it can be a singleton, but the database is not because the database holds Vuex Store instance, and that's stateful. Vuex ORM works with SSR, but it might cause unexpected behavior in a future implementation, so I would like to discuss how we can achieve non-singleton based architecture.
How would API look like
The simplest solution I can think of is to register database instance to the Vuex Store instance, then fetch model from the store instance. It could look like this.
export default {
mounted () {
// `users` is the entity name for the user model.
this.$store.$db().users.insert({ data: {...} })
}
}
Now, this is not going to be type-safe. To be able to get typing for the user model, we could do something like this.
import User from '@/models/User'
export default {
mounted () {
this.$store.$db().model(User).insert({ data: {...} })
}
}
This will not look great as just doing User.insert() though, I think there's no easy way to retrieve injected store instance from the model.
It's a bit similar to how Redux ORM is doing things.
With the above approach, we can now easily create more than 1 database and attach them to the store.
export default {
mounted () {
// Get first database.
this.$store.$db('entities').$model(User).insert({ data: {...} })
// Get the second database.
this.$store.$db('other_db').$model(User).insert({ data: {...} })
}
}
Singleton based approach
As mentioned before, a singleton is not always bad. When you're not working with SSR, most of the time, you can use stateful singletons. In that case, we could continue with the current approach. In order to have multiple database connections, we could add new, for example, on method to the model. And you may;
import User from '@/models/User'
export default {
mounted () {
// Get first database.
User.on('my_database').insert()
}
}
This is similar to how Laravel handles multiple DB connections with their models.
We could set model connections when registering models to the database so that users don't have to set the connection name by themselves when using.
The implementation
To adapt to both approaches described above, I'm thinking of doing this.
- Register database instance on both Container object and store instance when installing Vuex ORM.
- When calling model methods in the singleton approach, fetch database instance from the container.
- When calling model methods in the injected approach, let
store.$db() method inject the store to the model instance.
Probably I need to think this deeper, but here's the starting point.
This issue relates to several other issues, for example, #360.
What is the problem?
Currently, the Vuex ORM stores database to the Container object, which is a global singleton. This is needed to retrieve any relationships through Vuex Getters and Actions.
Having a singleton object is not always bad. As long as you are using it in a single app, everything should work fine. However, it's a bad practice when doing SSR, as stated here at Vue SSR doc.
Usually, models are stateless, and it can be a singleton, but the database is not because the database holds Vuex Store instance, and that's stateful. Vuex ORM works with SSR, but it might cause unexpected behavior in a future implementation, so I would like to discuss how we can achieve non-singleton based architecture.
How would API look like
The simplest solution I can think of is to register database instance to the Vuex Store instance, then fetch model from the store instance. It could look like this.
Now, this is not going to be type-safe. To be able to get typing for the user model, we could do something like this.
This will not look great as just doing
User.insert()though, I think there's no easy way to retrieve injected store instance from the model.It's a bit similar to how Redux ORM is doing things.
With the above approach, we can now easily create more than 1 database and attach them to the store.
Singleton based approach
As mentioned before, a singleton is not always bad. When you're not working with SSR, most of the time, you can use stateful singletons. In that case, we could continue with the current approach. In order to have multiple database connections, we could add new, for example,
onmethod to the model. And you may;This is similar to how Laravel handles multiple DB connections with their models.
We could set model connections when registering models to the database so that users don't have to set the connection name by themselves when using.
The implementation
To adapt to both approaches described above, I'm thinking of doing this.
store.$db()method inject the store to the model instance.Probably I need to think this deeper, but here's the starting point.