Skip to content

Commit

Permalink
feat(svelte-query): useMutationState (#7477)
Browse files Browse the repository at this point in the history
* feat(svelte-query): createMutationState

* Fix pnpm-lock

* test: test cases for createMutationState for svelte-query

* Undo changes to pnpm-lock

* Export createMutationState

* Rename to useMutationState

* Fix eslint issues

* Fix eslint/prettier

---------

Co-authored-by: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com>
  • Loading branch information
sharmapukar217 and lachlancollins committed May 25, 2024
1 parent aadb831 commit c2cf0ce
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 0 deletions.
32 changes: 32 additions & 0 deletions packages/svelte-query/src/__tests__/UseMutationState.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import { QueryClient } from '@tanstack/query-core'
import { setQueryClientContext } from '../context'
import { createMutation } from '../createMutation'
import { useMutationState } from '../useMutationState'
import type { CreateMutationOptions, MutationStateOptions } from '../types'
export let successMutationOpts: CreateMutationOptions
export let errorMutationOpts: CreateMutationOptions
export let mutationStateOpts: MutationStateOptions | undefined = undefined
const queryClient = new QueryClient()
setQueryClientContext(queryClient)
const successMutation = createMutation(successMutationOpts)
const errorMutation = createMutation(errorMutationOpts)
const mutationState = useMutationState(mutationStateOpts)
$: statuses = $mutationState.map((state) => state.status)
</script>

<div data-testid="result">
{JSON.stringify(statuses)}
</div>

<button data-testid="success" on:click={() => $successMutation.mutate()}>
Click
</button>
<button data-testid="error" on:click={() => $errorMutation.mutate()}>
Click
</button>
121 changes: 121 additions & 0 deletions packages/svelte-query/src/__tests__/useMutationState.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { describe, expect, it, vi } from 'vitest'
import { fireEvent, render, waitFor } from '@testing-library/svelte'
import UseMutationState from './UseMutationState.svelte'

describe('useMutationState', () => {
it('run few mutation functions and check from useMutationState ', async () => {
const successMutationFn = vi.fn()

const errorMutationFn = vi.fn().mockImplementation(() => {
throw 'error'
})

const rendered = render(UseMutationState, {
props: {
successMutationOpts: {
mutationKey: ['success'],
mutationFn: successMutationFn,
},

errorMutationOpts: {
mutationKey: ['error'],
mutationFn: errorMutationFn,
},
},
})

fireEvent.click(rendered.getByTestId('success'))

await waitFor(() => {
expect(successMutationFn).toHaveBeenCalledTimes(1)
expect(rendered.getByTestId('result').innerHTML).toEqual('["success"]')
})

fireEvent.click(rendered.getByTestId('error'))

await waitFor(() => {
expect(errorMutationFn).toHaveBeenCalledTimes(1)
expect(rendered.getByTestId('result').innerHTML).toEqual(
'["success","error"]',
)
})
})

it('can select specific type of mutation ( i.e: error only )', async () => {
const successMutationFn = vi.fn()
const errorMutationFn = vi.fn().mockImplementation(() => {
throw 'error'
})

const rendered = render(UseMutationState, {
props: {
successMutationOpts: {
mutationKey: ['success'],
mutationFn: successMutationFn,
},

errorMutationOpts: {
mutationKey: ['error'],
mutationFn: errorMutationFn,
},

mutationStateOpts: {
filters: { status: 'error' },
},
},
})

fireEvent.click(rendered.getByTestId('success'))

await waitFor(() => {
expect(successMutationFn).toHaveBeenCalledTimes(1)
expect(rendered.getByTestId('result').innerHTML).toEqual('[]')
})

fireEvent.click(rendered.getByTestId('error'))

await waitFor(() => {
expect(errorMutationFn).toHaveBeenCalledTimes(1)
expect(rendered.getByTestId('result').innerHTML).toEqual('["error"]')
})
})

it('can select specific mutation using mutation key', async () => {
const successMutationFn = vi.fn()
const errorMutationFn = vi.fn().mockImplementation(() => {
throw 'error'
})

const rendered = render(UseMutationState, {
props: {
successMutationOpts: {
mutationKey: ['success'],
mutationFn: successMutationFn,
},

errorMutationOpts: {
mutationKey: ['error'],
mutationFn: errorMutationFn,
},

mutationStateOpts: {
filters: { mutationKey: ['success'] },
},
},
})

fireEvent.click(rendered.getByTestId('success'))

await waitFor(() => {
expect(successMutationFn).toHaveBeenCalledTimes(1)
expect(rendered.getByTestId('result').innerHTML).toEqual('["success"]')
})

fireEvent.click(rendered.getByTestId('error'))

await waitFor(() => {
expect(errorMutationFn).toHaveBeenCalledTimes(1)
expect(rendered.getByTestId('result').innerHTML).toEqual('["success"]')
})
})
})
1 change: 1 addition & 0 deletions packages/svelte-query/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export { createQueries } from './createQueries'
export { createInfiniteQuery } from './createInfiniteQuery'
export { infiniteQueryOptions } from './infiniteQueryOptions'
export { createMutation } from './createMutation'
export { useMutationState } from './useMutationState'
export { useQueryClient } from './useQueryClient'
export { useIsFetching } from './useIsFetching'
export { useIsMutating } from './useIsMutating'
Expand Down
11 changes: 11 additions & 0 deletions packages/svelte-query/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import type {
InfiniteQueryObserverOptions,
InfiniteQueryObserverResult,
MutateFunction,
Mutation,
MutationFilters,
MutationObserverOptions,
MutationObserverResult,
MutationState,
OmitKeyof,
QueryKey,
QueryObserverOptions,
Expand Down Expand Up @@ -134,3 +137,11 @@ type Override<TTargetA, TTargetB> = {
? TTargetB[AKey]
: TTargetA[AKey]
}

/** Options for useMutationState */
export type MutationStateOptions<TResult = MutationState> = {
filters?: MutationFilters
select?: (
mutation: Mutation<unknown, DefaultError, unknown, unknown>,
) => TResult
}
49 changes: 49 additions & 0 deletions packages/svelte-query/src/useMutationState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { readable } from 'svelte/store'
import { notifyManager, replaceEqualDeep } from '@tanstack/query-core'
import { useQueryClient } from './useQueryClient'
import type {
MutationCache,
MutationState,
QueryClient,
} from '@tanstack/query-core'
import type { Readable } from 'svelte/store'
import type { MutationStateOptions } from './types'

function getResult<TResult = MutationState>(
mutationCache: MutationCache,
options: MutationStateOptions<TResult>,
): Array<TResult> {
return mutationCache
.findAll(options.filters)
.map(
(mutation): TResult =>
(options.select ? options.select(mutation) : mutation.state) as TResult,
)
}

export function useMutationState<TResult = MutationState>(
options: MutationStateOptions<TResult> = {},
queryClient?: QueryClient,
): Readable<Array<TResult>> {
const client = useQueryClient(queryClient)
const mutationCache = client.getMutationCache()

let result = getResult(mutationCache, options)

const { subscribe } = readable(result, (set) => {
return mutationCache.subscribe(
notifyManager.batchCalls(() => {
const nextResult = replaceEqualDeep(
result,
getResult(mutationCache, options),
)
if (result !== nextResult) {
result = nextResult
set(result)
}
}),
)
})

return { subscribe }
}

0 comments on commit c2cf0ce

Please sign in to comment.