Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions docs/content/4.cookbook/1.vue-query.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
title: 'Vue Query'
description: 'Combine pinia-orm with TanStack Query for fetching, caching and background refetching.'
---

# Using pinia-orm with Vue Query

[TanStack Query](https://tanstack.com/query/latest/docs/framework/vue/overview) (Vue Query) handles fetching, caching, retries and background refetching β€” pinia-orm normalizes the fetched data and gives you relational access to it. They complement each other well: let Vue Query own the request lifecycle and persist every successful response into the store.

## Setup

```bash
npm install @tanstack/vue-query pinia-orm
```

```ts
// main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { createORM } from 'pinia-orm'
import { VueQueryPlugin } from '@tanstack/vue-query'
import App from './App.vue'

const app = createApp(App)

app.use(createPinia().use(createORM()))
app.use(VueQueryPlugin)
app.mount('#app')
```

## A query-aware base repository

Extend the repository with a `useQuery` helper that persists the response into the store and returns the hydrated models. The entity name doubles as the query key:

```ts
// repositories/QueryRepository.ts
import type { Model } from 'pinia-orm'
import { Repository } from 'pinia-orm'
import type { UseQueryOptions } from '@tanstack/vue-query'
import { useQuery } from '@tanstack/vue-query'

export class QueryRepository<M extends Model = Model> extends Repository<M> {
useQuery (
queryFn: () => Promise<unknown>,
options: Omit<UseQueryOptions, 'queryKey' | 'queryFn'> = {},
) {
return useQuery({
queryKey: [this.getModel().$entity()],
queryFn: async () => {
const data = await queryFn()
// Persist the response β€” components read the store, not the query data.
this.save(data as any)
return data
},
...options,
})
}
}
```

## Usage in a component

```vue
<script setup lang="ts">
import { computed } from 'vue'
import { useRepo } from 'pinia-orm'
import { QueryRepository } from '@/repositories/QueryRepository'
import User from '@/models/User'

const userRepo = useRepo(QueryRepository<User>).setModel(User)

const { isLoading, isError, refetch } = userRepo.useQuery(
() => fetch('/api/users').then(response => response.json()),
{ staleTime: 60_000 },
)

// Reactive, normalized and relation-aware β€” independent of the query cache.
const users = computed(() => userRepo.withAll().get())
</script>

<template>
<p v-if="isLoading">Loading…</p>
<p v-else-if="isError">Failed to load users.</p>
<ul v-else>
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
<button @click="refetch()">Refresh</button>
</template>
```

::alert{type="info"}
If the API response should be the single source of truth β€” including deletions β€” persist with `this.fresh(data)` instead of `this.save(data)`. See [Replacing Whole Data](/guide/repository/inserting-data#replacing-whole-data).
::
80 changes: 80 additions & 0 deletions docs/content/4.cookbook/2.axios.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title: 'Axios'
description: 'Use pinia-orm together with axios β€” with or without the official plugin.'
---

# Using pinia-orm with Axios

The recommended way to combine pinia-orm with axios is the official [`@pinia-orm/axios` plugin](/plugins/axios/guide/setup), which persists responses automatically and adds a request API to every repository. This recipe shows both the plugin and the manual approach for cases where you want full control over the request layer.

## With the plugin

```ts
// main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { createORM } from 'pinia-orm'
import { createPiniaOrmAxios } from '@pinia-orm/axios'
import axios from 'axios'
import App from './App.vue'

const pinia = createPinia()
pinia.use(createORM({
plugins: [
createPiniaOrmAxios({
axios,
baseURL: 'https://api.example.com',
}),
],
}))

createApp(App).use(pinia).mount('#app')
```

```vue
<script setup lang="ts">
import { computed } from 'vue'
import { useAxiosRepo } from '@pinia-orm/axios'
import User from '@/models/User'

const userRepo = useAxiosRepo(User)

// Fetches /users and persists the response into the store.
userRepo.api().get('/users')

const users = computed(() => userRepo.all())
</script>
```

**See also**: [Axios plugin usage](/plugins/axios/guide/usage) for `dataKey`, `persistBy: 'fresh'`, delete requests and custom actions.

## Without the plugin

A thin service layer keeps requests explicit β€” persist the response yourself:

```ts
// services/userService.ts
import axios from 'axios'
import { useRepo } from 'pinia-orm'
import User from '@/models/User'

export async function fetchUsers () {
const { data } = await axios.get('https://api.example.com/users')

// The response replaces the store content; use save() to merge instead.
return useRepo(User).fresh(data)
}
```

```vue
<script setup lang="ts">
import { computed } from 'vue'
import { useRepo } from 'pinia-orm'
import { fetchUsers } from '@/services/userService'
import User from '@/models/User'

fetchUsers()

const users = computed(() => useRepo(User).withAll().get())
</script>
```
2 changes: 2 additions & 0 deletions docs/content/4.cookbook/_dir.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
icon: heroicons-outline:bookmark-alt
title: Cookbook
Loading