Pinia ORM supports the "Data Mapper" pattern to interact with the store. The Data Mapper pattern is one of the traditional ORM implementations. Using the Data Mapper approach, you define all your query methods in separate classes called "repositories", and you retrieve, insert, update, and delete objects using repositories.
In Data Mapper, your models are very dumb – they just define their properties and may have some "dummy" methods. Simply said, data mapper is an approach to access your database within repositories instead of models.
Repositories always correspond to a model. For example, if you have a User model, then you would insert, retrieve, update, and delete user records through user repository. Let's say you have the User model defined like this.
class User extends Model { static entity = 'users' static fields () { return { id: this.attr(null), name: this.string('') } }}
To retrieve repository for the User model, you may do so by calling the useRepo
method, and passing the User model as the argument. After retrieving the repository, you may call methods such as save
, or delete
on the repository.
const userRepo = useRepo(User)userRepo.save(...)
In Vue Component, you would probably want to define a computed property to retrieve the repository.
import User from '@/models/User'export default { computed: { userRepo () { return useRepo(User) } }, methods: { saveUser (user) { this.userRepo.save(user) } }}
In addition to use this.$store.$repo
to retrieve repositories, Pinia ORM provides a convenience helper function called mapRepos
to retrieve multiple repositories at once.
The mapRepos
helper will receive a list of models with its name as a key. The repositories is going to be injected to the this
context within Vue Component.
import { mapRepos } from 'pinia-orm'import User from '@/models/User'import Post from '@/models/Post'export default { computed: { ...mapRepos({ userRepo: User, postRepo: Post }) }, methods: { someMethod () { this.userRepo // <- the user repository. this.postRepo // <- the user repository. } }}
As mentioned earlier, you may use repositories to retrieve, insert, update, and delete data in the store. Please refer to the corresponding pages to learn more about how to interact with the store.
When you start using a repository to query the data, there is a high chance that you might want to reuse some common logic. For example, you might have Post
model, and you might want to query only the public posts in published order. Typically, you'll end up writing a query like this.
useRepo(Post) .where('public', true) .orderBy('publishedAt', 'desc') .get()
You may extract this query by using the custom repository and call it like this instead.
useRepo(PostRepository).getLatestPublished()
In order to create a custom repository, you must first create a new repository that extends the base Repository
class.
import { Repository } from 'pinia-orm'import Post from '@/models/Post'class PostRepository extends Repository { use = Post}
Notice the use
property. Here you must define which model the repository should correspond.
Next, let's add the custom method we were talking about.
import { Repository } from 'pinia-orm'import Post from '@/models/Post'class PostRepository extends Repository { use = Post getLatestPublished () { return this .where('public', true) .orderBy('publishedAt', 'desc') .get() }}
Now you may use this custom method to query data. Instead of calling useRepo(Model)
, pass the custom repository you've created instead.
useRepo(PostRepository).getLatestPublished()
In some case, you might want to interact with more than one model within a repository. For example, let's say you have post metadata in separate entities, such as post category and post type. Then you might want to query those together and combine it in a single object.
In such a case, you may use an abstract repository pattern that is not bound to a specific model. To declare such a repository, create a repository that extends Repository
but without use
property.
import { Repository } from 'pinia-orm'import PostCategory from '@/models/PostCategory'import PostType from '@/models/PostType'class PostMetaRepository extends Repository { getCategoryAndType () { return { category: this.getCategory(), type: this.getType() } } getCategory () { return this.repo(PostCategory).all() } getType () { return this.repo(PostType).all() }}
See we don't have use
property declare, but instead, we call this.repo(Model)
to retrieve specific repository. With abstract repository, you can not use method that requires the model such as where
or orderBy
, but you must first retrieve a new repository through repo
method.