Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mutation): add an optional key option to mutations #19

Merged
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
1 change: 1 addition & 0 deletions playground/src/pages/ecom/item/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const itemAvailability = ref()
watch(() => item.value?.availability, (value) => itemAvailability.value = value)

const { mutate: bookProduct } = useMutation({
key: (product) => ['book-item', product.id],
keys: (product) => [['items'], ['items', product.id]],
mutation: async (product: ProductListItem) => {
await delay(Math.random() * 1000 + 200)
Expand Down
7 changes: 7 additions & 0 deletions src/entry-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { EntryNodeKey } from './tree-map'
import type { _ObjectFlat } from './utils'

/**
* Key used to identify a query or a mutation. Always an array.
*/
export type EntryKey = Array<EntryNodeKey | _ObjectFlat>
5 changes: 4 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ export { defineQuery } from './define-query'
// export { type UseQueryKeyList } from './query-keys'

export {
type UseQueryKey,
type EntryKey,
} from './entry-options'

export {
type UseQueryOptions,
type UseQueryOptionsWithDefaults,
} from './query-options'
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/invalidate-queries.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/**
* @module @pinia/colada/plugins/invalidate-queries
*/
import type { UseQueryKey } from '@pinia/colada'
import type { EntryKey } from '@pinia/colada'

export interface UseMutationOptionsInvalidateQueries<TResult, TVars> {
/**
* Keys to invalidate if the mutation succeeds so that `useQuery()` refetch if used. Only available if
* `@pinia/colada/plugins/invalidate-queries` is installed.
*/
invalidateKeys?:
| UseQueryKey[]
| ((data: TResult, vars: TVars) => UseQueryKey[])
| EntryKey[]
| ((data: TResult, vars: TVars) => EntryKey[])
}

declare module '@pinia/colada' {
Expand Down
10 changes: 2 additions & 8 deletions src/query-options.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { type InjectionKey, type MaybeRefOrGetter, inject } from 'vue'
import type { EntryNodeKey } from './tree-map'
import type { _ObjectFlat } from './utils'
import type { EntryKey } from './entry-options'
import type { QueryPluginOptions } from './query-plugin'
import type { ErrorDefault } from './types-extension'

Expand All @@ -9,11 +8,6 @@ import type { ErrorDefault } from './types-extension'
*/
export type _RefetchOnControl = boolean | 'always'

/**
* Key used to identify a query. Always an array.
*/
export type UseQueryKey = Array<EntryNodeKey | _ObjectFlat>

/**
* Context object passed to the `query` function of `useQuery()`.
* @see {@link UseQueryOptions}
Expand Down Expand Up @@ -59,7 +53,7 @@ export interface UseQueryOptions<TResult = unknown, TError = ErrorDefault> {
* })
* ```
*/
key: MaybeRefOrGetter<UseQueryKey>
key: MaybeRefOrGetter<EntryKey>

/**
* The function that will be called to fetch the data. It **must** be async.
Expand Down
11 changes: 6 additions & 5 deletions src/query-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
} from 'vue'
import { stringifyFlatObject } from './utils'
import { type EntryNodeKey, TreeMapNode } from './tree-map'
import type { UseQueryKey, UseQueryOptionsWithDefaults } from './query-options'
import type { EntryKey } from './entry-options'
import type { UseQueryOptionsWithDefaults } from './query-options'
import type { ErrorDefault } from './types-extension'
import type { defineQuery } from './define-query'

Expand Down Expand Up @@ -152,7 +153,7 @@
}

function ensureEntry<TResult = unknown, TError = ErrorDefault>(
keyRaw: UseQueryKey,
keyRaw: EntryKey,
options: UseQueryOptionsWithDefaults<TResult, TError>,
): UseQueryEntry<TResult, TError> {
if (process.env.NODE_ENV !== 'production' && keyRaw.length === 0) {
Expand Down Expand Up @@ -187,7 +188,7 @@
* @param options.refetch - if true, it will refetch the data
*/
function invalidateEntry(
key: UseQueryKey,
key: EntryKey,

Check warning on line 191 in src/query-store.ts

View check run for this annotation

Codecov / codecov/patch

src/query-store.ts#L191

Added line #L191 was not covered by tests
{
refetch: shouldRefetch = true,
exact = false,
Expand Down Expand Up @@ -310,7 +311,7 @@

// TODO: tests, remove function version
function setQueryData<TResult = unknown>(
key: UseQueryKey,
key: EntryKey,

Check warning on line 314 in src/query-store.ts

View check run for this annotation

Codecov / codecov/patch

src/query-store.ts#L314

Added line #L314 was not covered by tests
data: TResult | ((data: Ref<TResult | undefined>) => void),
) {
const entry = caches.get(key.map(stringifyFlatObject)) as
Expand All @@ -331,7 +332,7 @@
}

function getQueryData<TResult = unknown>(
key: UseQueryKey,
key: EntryKey,

Check warning on line 335 in src/query-store.ts

View check run for this annotation

Codecov / codecov/patch

src/query-store.ts#L335

Added line #L335 was not covered by tests
): TResult | undefined {
const entry = caches.get(key.map(stringifyFlatObject)) as
| UseQueryEntry<TResult>
Expand Down
10 changes: 10 additions & 0 deletions src/use-mutation.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ import { expectTypeOf, it } from 'vitest'
import { useMutation } from './use-mutation'

it('types the parameters for the key', () => {
useMutation({
mutation: (_one: string) => Promise.resolve({ name: 'foo' }),
key(one) {
expectTypeOf(one).toBeString()
return ['foo']
},
})
})

it('types the parameters for the keys', () => {
const { mutate, mutateAsync } = useMutation({
mutation: (_one: string) => Promise.resolve({ name: 'foo' }),
keys(result, one) {
Expand Down
12 changes: 9 additions & 3 deletions src/use-mutation.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { computed, shallowRef } from 'vue'
import type { ComputedRef, ShallowRef } from 'vue'
import { useQueryCache } from './query-store'
import type { UseQueryKey } from './query-options'
import type { EntryKey } from './entry-options'
import type { ErrorDefault } from './types-extension'
import { type _Awaitable, noop } from './utils'

type _MutationKey<TVars> =
| EntryKey
| ((vars: TVars) => EntryKey)

// TODO: move to a plugin
/**
* The keys to invalidate when a mutation succeeds.
* @internal
*/
type _MutationKeys<TVars, TResult> =
| UseQueryKey[]
| ((data: TResult, vars: TVars) => UseQueryKey[])
| EntryKey[]
| ((data: TResult, vars: TVars) => EntryKey[])

/**
* The status of the mutation.
Expand Down Expand Up @@ -69,6 +73,8 @@ export interface UseMutationOptions<
*/
mutation: (vars: TVars, context: NoInfer<TContext>) => Promise<TResult>

key?: _MutationKey<TVars>

// TODO: move this to a plugin that calls invalidateEntry()
/**
* Keys to invalidate if the mutation succeeds so that `useQuery()` refetch if used.
Expand Down
6 changes: 3 additions & 3 deletions src/use-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
import { IS_CLIENT, computedRef, useEventListener } from './utils'
import { type _UseQueryEntry_State, useQueryCache } from './query-store'
import { useQueryOptions } from './query-options'
import type { EntryKey } from './entry-options'
import type {
UseQueryKey,
UseQueryOptions,
UseQueryOptionsWithDefaults,
} from './query-options'
Expand Down Expand Up @@ -176,9 +176,9 @@
* @returns - the computed key
*/
function _computedKeyWithWarnings(
key: MaybeRefOrGetter<UseQueryKey>,
key: MaybeRefOrGetter<EntryKey>,

Check warning on line 179 in src/use-query.ts

View check run for this annotation

Codecov / codecov/patch

src/use-query.ts#L179

Added line #L179 was not covered by tests
warnChecksMap: WeakMap<object, boolean>,
): () => UseQueryKey {
): () => EntryKey {

Check warning on line 181 in src/use-query.ts

View check run for this annotation

Codecov / codecov/patch

src/use-query.ts#L181

Added line #L181 was not covered by tests
const componentInstance = getCurrentInstance()
// probably correct scope, no need to warn
if (!componentInstance) return () => toValue(key)
Expand Down
Loading