Skip to content

Commit

Permalink
sync @orpc/vue-query
Browse files Browse the repository at this point in the history
  • Loading branch information
unnoq committed Dec 29, 2024
1 parent bad022f commit 2d3984c
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 49 deletions.
9 changes: 6 additions & 3 deletions packages/vue-query/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ export type NonUndefinedGuard<T> = T extends undefined ? never : T

export type InferCursor<T> = T extends { cursor?: any } ? T['cursor'] : never

export type QueryOptions<TInput, TOutput, TSelectData> =
export type QueryOptions<TInput, TOutput, TClientContext, TSelectData> =
& (undefined extends TInput ? { input?: MaybeDeepRef<TInput> } : { input: MaybeDeepRef<TInput> })
& (undefined extends TClientContext ? { context?: MaybeDeepRef<TClientContext> } : { context: MaybeDeepRef<TClientContext> })
& SetOptional<{
[P in keyof QueryObserverOptions<TOutput, DefaultError, TSelectData, TOutput, QueryKey>]: P extends 'enabled'
? MaybeRefOrGetter<QueryObserverOptions<TOutput, DefaultError, TSelectData, TOutput, QueryKey>[P]>
Expand All @@ -28,14 +29,16 @@ export type QueryOptions<TInput, TOutput, TSelectData> =
initialData?: NonUndefinedGuard<TOutput> | (() => NonUndefinedGuard<TOutput>) | undefined
}

export type InfiniteOptions<TInput, TOutput, TSelectData> =
export type InfiniteOptions<TInput, TOutput, TClientContext, TSelectData> =
& (undefined extends TInput ? { input?: MaybeDeepRef<Omit<TInput, 'cursor'>> } : { input: MaybeDeepRef<Omit<TInput, 'cursor'>> })
& (undefined extends TClientContext ? { context?: MaybeDeepRef<TClientContext> } : { context: MaybeDeepRef<TClientContext> })
& SetOptional<
UseInfiniteQueryOptions<TOutput, DefaultError, TSelectData, TOutput, QueryKey, InferCursor<TInput>>,
'queryKey' | (undefined extends InferCursor<TInput> ? 'initialPageParam' : never)
>

export type MutationOptions<TInput, TOutput> =
export type MutationOptions<TInput, TOutput, TClientContext> =
& (undefined extends TClientContext ? { context?: MaybeDeepRef<TClientContext> } : { context: MaybeDeepRef<TClientContext> })
& {
[P in keyof MutationObserverOptions<TOutput, DefaultError, TInput, unknown>]: MaybeDeepRef<MutationObserverOptions<TOutput, DefaultError, TInput, unknown>[P]>
}
Expand Down
119 changes: 106 additions & 13 deletions packages/vue-query/src/utils-procedure.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import type { ProcedureClient } from '@orpc/server'
import type { InfiniteData, QueryKey } from '@tanstack/vue-query'
import { useInfiniteQuery, useQuery } from '@tanstack/vue-query'
import type { ProcedureUtils } from './utils-procedure'
import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/vue-query'
import { ref } from 'vue'
import { createProcedureUtils } from './utils-procedure'

describe('queryOptions', () => {
const client = vi.fn <ProcedureClient<number | undefined, string | undefined>>(
const client = vi.fn <ProcedureClient<number | undefined, string | undefined, undefined>>(
(...[input]) => Promise.resolve(input?.toString()),
)
const utils = createProcedureUtils(client, [])

const client2 = vi.fn((input: number) => Promise.resolve(input.toString()))
const client2 = {} as ProcedureClient<number, string, undefined>
const utils2 = createProcedureUtils(client2, [])

it('infer correct input type', () => {
Expand Down Expand Up @@ -52,13 +53,42 @@ describe('queryOptions', () => {

expectTypeOf(query.data.value).toEqualTypeOf<{ value: number } | undefined>()
})

describe('client context', () => {
it('can be optional', () => {
const utils = {} as ProcedureUtils<undefined, string, undefined | { batch?: boolean }>
useQuery(utils.queryOptions())
useQuery(utils.queryOptions({}))
useQuery(utils.queryOptions({ context: undefined }))
useQuery(utils.queryOptions({ context: { batch: true } }))
useQuery(utils.queryOptions({ context: { batch: ref(true) } }))
// @ts-expect-error --- invalid context
useQuery(utils.queryOptions({ context: { batch: 'invalid' } }))
// @ts-expect-error --- invalid context
useQuery(utils.queryOptions({ context: { batch: ref('invalid') } }))
})

it('required pass context when non-optional', () => {
const utils = {} as ProcedureUtils<undefined, string, { batch?: boolean }>
// @ts-expect-error --- missing context
useQuery(utils.queryOptions())
// @ts-expect-error --- missing context
useQuery(utils.queryOptions({}))
useQuery(utils.queryOptions({ context: { batch: true } }))
useQuery(utils.queryOptions({ context: { batch: ref(false) } }))
// @ts-expect-error --- invalid context
useQuery(utils.queryOptions({ context: { batch: 'invalid' } }))
// @ts-expect-error --- invalid context
useQuery(utils.queryOptions({ context: { batch: ref('invalid') } }))
})
})
})

describe('infiniteOptions', () => {
const getNextPageParam = vi.fn()

it('cannot use on procedure without input object-able', () => {
const utils = createProcedureUtils({} as (input: number) => Promise<string>, [])
const utils = createProcedureUtils({} as ProcedureClient<number, string, undefined>, [])

// @ts-expect-error missing initialPageParam
utils.infiniteOptions({
Expand All @@ -81,7 +111,7 @@ describe('infiniteOptions', () => {
})

it('infer correct input type', () => {
const utils = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise<string>, [])
const utils = createProcedureUtils({} as ProcedureClient<{ limit?: number, cursor: number }, string, undefined>, [])

utils.infiniteOptions({
input: {
Expand Down Expand Up @@ -126,7 +156,7 @@ describe('infiniteOptions', () => {
})

it('infer correct initialPageParam type', () => {
const utils = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise<string>, [])
const utils = createProcedureUtils({} as ProcedureClient<{ limit?: number, cursor: number }, string, undefined>, [])

utils.infiniteOptions({
input: {},
Expand Down Expand Up @@ -162,14 +192,14 @@ describe('infiniteOptions', () => {
})

it('initialPageParam can be optional', () => {
const utils = createProcedureUtils({} as (input: { limit?: number, cursor?: number }) => Promise<string>, [])
const utils = createProcedureUtils({} as ProcedureClient<{ limit?: number, cursor?: number }, string, undefined>, [])

utils.infiniteOptions({
input: {},
getNextPageParam,
})

const utils2 = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise<string>, [])
const utils2 = createProcedureUtils({} as ProcedureClient<{ limit?: number, cursor: number }, string, undefined>, [])

// @ts-expect-error initialPageParam is required
utils2.infiniteOptions({
Expand All @@ -179,13 +209,13 @@ describe('infiniteOptions', () => {
})

it('input can be optional', () => {
const utils = createProcedureUtils({} as ProcedureClient<{ limit?: number, cursor?: number } | undefined, string>, [])
const utils = createProcedureUtils({} as ProcedureClient<{ limit?: number, cursor?: number } | undefined, string, undefined>, [])

utils.infiniteOptions({
getNextPageParam,
})

const utils2 = createProcedureUtils({} as (input: { limit?: number, cursor?: number }) => Promise<string>, [])
const utils2 = createProcedureUtils({} as ProcedureClient<{ limit?: number, cursor?: number }, string, undefined>, [])

// @ts-expect-error input is required
utils2.infiniteOptions({
Expand All @@ -194,7 +224,7 @@ describe('infiniteOptions', () => {
})

it('infer correct output type', () => {
const utils = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise<string>, [])
const utils = createProcedureUtils({} as ProcedureClient<{ limit?: number, cursor: number }, string, undefined>, [])
const query = useInfiniteQuery(utils.infiniteOptions({
input: {
limit: 1,
Expand All @@ -207,7 +237,7 @@ describe('infiniteOptions', () => {
})

it('work with select options', () => {
const utils = createProcedureUtils({} as (input: { limit?: number, cursor: number }) => Promise<string>, [])
const utils = createProcedureUtils({} as ProcedureClient<{ limit?: number, cursor: number }, string, undefined>, [])
const query = useInfiniteQuery(utils.infiniteOptions({
input: {
limit: ref(1),
Expand All @@ -223,10 +253,44 @@ describe('infiniteOptions', () => {

expectTypeOf(query.data.value).toEqualTypeOf<{ value: number } | undefined>()
})

describe('client context', () => {
it('can be optional', () => {
const utils = {} as ProcedureUtils<undefined | { limit?: number, cursor: number }, string, undefined | { batch?: boolean }>

const getNextPageParam = vi.fn()
const initialPageParam = 1

useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam }))
useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam, context: undefined }))
useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam, context: { batch: true } }))
useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam, context: { batch: ref(false) } }))
// @ts-expect-error --- invalid context
useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam, context: { batch: 'invalid' } }))
// @ts-expect-error --- invalid context
useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam, context: { batch: ref('invalid') } }))
})

it('required pass context when non-optional', () => {
const utils = {} as ProcedureUtils<undefined | { limit?: number, cursor: number }, string, { batch?: boolean }>

const getNextPageParam = vi.fn()
const initialPageParam = 1

// @ts-expect-error --- missing context
useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam }))
useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam, context: { batch: true } }))
useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam, context: { batch: ref(false) } }))
// @ts-expect-error --- invalid context
useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam, context: { batch: 'invalid' } }))
// @ts-expect-error --- invalid context
useInfiniteQuery(utils.infiniteOptions({ getNextPageParam, initialPageParam, context: { batch: ref('invalid') } }))
})
})
})

describe('mutationOptions', () => {
const client = vi.fn((input: number) => Promise.resolve(input.toString()))
const client = {} as ProcedureClient<number, string, undefined>
const utils = createProcedureUtils(client, [])

it('infer correct input type', () => {
Expand Down Expand Up @@ -261,4 +325,33 @@ describe('mutationOptions', () => {
expectTypeOf(option.mutationKey).toEqualTypeOf<QueryKey>()
expectTypeOf(option.mutationFn).toMatchTypeOf<(input: number) => Promise<string>>()
})

describe('client context', () => {
it('can be optional', () => {
const utils = {} as ProcedureUtils<undefined, string, undefined | { batch?: boolean }>
useMutation(utils.mutationOptions())
useMutation(utils.mutationOptions({}))
useMutation(utils.mutationOptions({ context: undefined }))
useMutation(utils.mutationOptions({ context: { batch: true } }))
useMutation(utils.mutationOptions({ context: { batch: ref(false) } }))
// @ts-expect-error --- invalid context
useMutation(utils.mutationOptions({ context: { batch: 'invalid' } }))
// @ts-expect-error --- invalid context
useMutation(utils.mutationOptions({ context: { batch: ref('invalid') } }))
})

it('required pass context when non-optional', () => {
const utils = {} as ProcedureUtils<undefined, string, { batch?: boolean }>
// @ts-expect-error --- missing context
useMutation(utils.mutationOptions())
// @ts-expect-error --- missing context
useMutation(utils.mutationOptions({}))
useMutation(utils.mutationOptions({ context: { batch: true } }))
useMutation(utils.mutationOptions({ context: { batch: ref(false) } }))
// @ts-expect-error --- invalid context
useMutation(utils.mutationOptions({ context: { batch: 123 } }))
// @ts-expect-error --- invalid context
useMutation(utils.mutationOptions({ context: { batch: ref(123) } }))
})
})
})
65 changes: 59 additions & 6 deletions packages/vue-query/src/utils-procedure.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ProcedureClient } from '@orpc/server'
import { ref } from 'vue'
import * as keyModule from './key'
import { createProcedureUtils } from './utils-procedure'
Expand All @@ -13,7 +12,7 @@ beforeEach(() => {
})

describe('queryOptions', () => {
const client = vi.fn<ProcedureClient<number | undefined, string | undefined>>(
const client = vi.fn(
(...[input]) => Promise.resolve(input?.toString()),
)
const utils = createProcedureUtils(client, ['ping'])
Expand Down Expand Up @@ -48,13 +47,29 @@ describe('queryOptions', () => {
expect(client).toHaveBeenCalledTimes(1)
expect(client).toBeCalledWith(1, { signal })
})

it('works with client context', async () => {
const client = vi.fn((...[input]) => Promise.resolve(input?.toString()))
const utils = createProcedureUtils(client, ['ping'])

const options = utils.queryOptions({ context: { batch: ref(true) } })

expect(options.queryKey.value).toEqual(['__ORPC__', ['ping'], { type: 'query' }])
expect(buildKeySpy).toHaveBeenCalledTimes(1)
expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'query' })

client.mockResolvedValueOnce('__mocked__')
await expect((options as any).queryFn({ signal })).resolves.toEqual('__mocked__')
expect(client).toHaveBeenCalledTimes(1)
expect(client).toBeCalledWith(undefined, { signal, context: { batch: true } })
})
})

describe('infiniteOptions', () => {
const getNextPageParam = vi.fn()

it('works ', async () => {
const client = vi.fn<(input: { limit?: number, cursor: number | undefined }) => Promise<string>>()
const client = vi.fn()
const utils = createProcedureUtils(client, [])

const options = utils.infiniteOptions({
Expand All @@ -75,7 +90,7 @@ describe('infiniteOptions', () => {
})

it('works without initialPageParam', async () => {
const client = vi.fn<(input: { limit?: number, cursor: number | undefined }) => Promise<string>>()
const client = vi.fn()
const utils = createProcedureUtils(client, [])

const options = utils.infiniteOptions({
Expand All @@ -94,7 +109,7 @@ describe('infiniteOptions', () => {
})

it('works with ref', async () => {
const client = vi.fn<(input: { limit?: number, cursor: number | undefined }) => Promise<string>>()
const client = vi.fn()
const utils = createProcedureUtils(client, [])

const input = ref({ limit: ref(5) })
Expand All @@ -114,10 +129,30 @@ describe('infiniteOptions', () => {
expect(client).toHaveBeenCalledTimes(1)
expect(client).toBeCalledWith({ limit: 5, cursor: 1 }, { signal })
})

it('works with client context', async () => {
const client = vi.fn()
const utils = createProcedureUtils(client, [])

const options = utils.infiniteOptions({
context: { batch: ref(true) },
getNextPageParam,
initialPageParam: 1,
})

expect(options.queryKey.value).toEqual(['__ORPC__', [], { type: 'infinite' }])
expect(buildKeySpy).toHaveBeenCalledTimes(1)
expect(buildKeySpy).toHaveBeenCalledWith([], { type: 'infinite' })

client.mockResolvedValueOnce('__mocked__')
await expect((options as any).queryFn({ pageParam: 1, signal })).resolves.toEqual('__mocked__')
expect(client).toHaveBeenCalledTimes(1)
expect(client).toBeCalledWith({ limit: undefined, cursor: 1 }, { signal, context: { batch: true } })
})
})

describe('mutationOptions', () => {
const client = vi.fn<ProcedureClient<number | undefined, string | undefined>>(
const client = vi.fn(
(...[input]) => Promise.resolve(input?.toString()),
)
const utils = createProcedureUtils(client, ['ping'])
Expand All @@ -138,4 +173,22 @@ describe('mutationOptions', () => {
expect(client).toHaveBeenCalledTimes(1)
expect(client).toBeCalledWith(1)
})

it('works with client context', async () => {
const client = vi.fn(
(...[input]) => Promise.resolve(input?.toString()),
)
const utils = createProcedureUtils(client, ['ping'])

const options = utils.mutationOptions({ context: { batch: ref(true) } })

expect(options.mutationKey).toEqual(['__ORPC__', ['ping'], { type: 'mutation' }])
expect(buildKeySpy).toHaveBeenCalledTimes(1)
expect(buildKeySpy).toHaveBeenCalledWith(['ping'], { type: 'mutation' })

client.mockResolvedValueOnce('__mocked__')
await expect(options.mutationFn(1)).resolves.toEqual('__mocked__')
expect(client).toHaveBeenCalledTimes(1)
expect(client).toBeCalledWith(1, { context: { batch: true } })
})
})
Loading

0 comments on commit 2d3984c

Please sign in to comment.