Getting started

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.

Retrieving Repository For The Model

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)
    }
  }
}

Map Repositories Helper

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 post repository.
    }
  }
}

Interacting With Store

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.

Custom Repository

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()

Abstract Custom Repository

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.