Skip to content
Closed
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
104 changes: 57 additions & 47 deletions src/createQueryClient.spec-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,26 @@ describe('query', () => {

test('tags', async () => {
const action = () => 'response'
const { query } = createQueryClient()
const numberTag = tag<number>()
const stringTag = tag<string>()
const { query, setQueryData } = createQueryClient()
const stringTag = tag().add<string>()
const untypedTag = tag()

// @ts-expect-error - number tag not assignable to string action
query(action, [], { tags: [numberTag, stringTag] })

// @ts-expect-error - number tag not assignable to string action
query(action, [], { tags: () => [numberTag, stringTag] })

query(action, [], { tags: [stringTag, untypedTag] })
query(action, [], { tags: () => [stringTag, untypedTag] })

query(action, [], { tags: [untypedTag] })
query(action, [], { tags: () => [untypedTag] })

setQueryData(stringTag, (data) => {
expectTypeOf(data).toEqualTypeOf<string>()
return data + 'bar'
})

// @ts-expect-error - sharedTag has data: never, can't return anything useful
setQueryData(untypedTag, (data) => {
expectTypeOf(data).toEqualTypeOf<never>()
return 'could be corrupting'
})
})
})
})
Expand Down Expand Up @@ -99,59 +103,63 @@ describe('defineQuery', () => {
})

describe('setQueryData', () => {
test('tags', async () => {
test('naked tag is not setQueryData-able (data: never)', () => {
const { setQueryData } = createQueryClient()
const myTag = tag()

// @ts-expect-error - data: never, return must be never (effectively impossible)
setQueryData(myTag, () => 'anything')
})

test('typed tag passes data through with its declared type', () => {
const { setQueryData } = createQueryClient()
const numberTag = tag<number>()
const stringTag = tag<string>()
const untypedTag = tag()

setQueryData(untypedTag, (data) => {
expectTypeOf(data).toEqualTypeOf<unknown>()
return 'foo'
setQueryData(numberTag, (data) => {
expectTypeOf(data).toEqualTypeOf<number>()
return data + 1
})

// @ts-expect-error - returning wrong type
setQueryData(numberTag, (data) => {
expectTypeOf(data).toEqualTypeOf<number>()
return 2
return 'wrong type'
})
})

setQueryData(stringTag, (data) => {
expectTypeOf(data).toEqualTypeOf<string>()
return 'new string'
})
test('descendant tag has its own data type', () => {
const { setQueryData } = createQueryClient()
const sharedTag = tag()
const userTag = sharedTag.add<{ id: number }>()

setQueryData([untypedTag], (data) => {
expectTypeOf(data).toEqualTypeOf<unknown>()
return 'foo'
setQueryData(userTag, (data) => {
expectTypeOf(data).toEqualTypeOf<{ id: number }>()
return data
})

setQueryData([numberTag], (data) => {
expectTypeOf(data).toEqualTypeOf<number>()
return 2
})
// ancestor tag is still locked at the type level
// @ts-expect-error - sharedTag has data: never
setQueryData(sharedTag, (data) => {
expectTypeOf(data).toEqualTypeOf<never>()

// this is kinda interesting, no matter the data the return type is the union :thinking:
// so there's not really a type safe way to update multiple queries at once
setQueryData([numberTag, stringTag], (data) => {
expectTypeOf(data).toEqualTypeOf<number | string>()
return 'foo'
return 'could be corrupting'
})
})

setQueryData([untypedTag, stringTag, numberTag], (data) => {
expectTypeOf(data).toEqualTypeOf<unknown>()
return 'foo'
})
test('descendants nest arbitrarily deep', () => {
const { setQueryData } = createQueryClient()
const sharedTag = tag()
const userTag = sharedTag.add<{ id: number }>()
const userAvatarTag = userTag.add<{ id: number, url: string }>()

// @ts-expect-error - number tag not assignable to string action
setQueryData(numberTag, (data) => {
expectTypeOf(data).toEqualTypeOf<number>()
return 'string'
setQueryData(userAvatarTag, (data) => {
expectTypeOf(data).toEqualTypeOf<{ id: number, url: string }>()
return data
})

// @ts-expect-error - number tag not assignable to string action
setQueryData([numberTag, stringTag], (data) => {
expectTypeOf(data).toEqualTypeOf<number | string>()
return []
setQueryData(userTag, (data) => {
expectTypeOf(data).toEqualTypeOf<{ id: number }>()
return data
})
})

Expand Down Expand Up @@ -252,12 +260,14 @@ describe('refreshQueryData', () => {
test('tags', () => {
const { refreshQueryData } = createQueryClient()

const numberTag = tag<number>()
const stringTag = tag<string>()
const sharedTag = tag()
const numberTag = sharedTag.add<number>()
const stringTag = sharedTag.add<string>()
const action = (param: number) => param

refreshQueryData(sharedTag)
refreshQueryData(numberTag)
refreshQueryData([numberTag, stringTag])
refreshQueryData(stringTag)
refreshQueryData(action)
refreshQueryData(action, [2])

Expand Down
48 changes: 19 additions & 29 deletions src/createQueryClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -562,22 +562,18 @@ describe('setQueryData', () => {

await vi.runOnlyPendingTimersAsync()

setQueryData(stringTag, () => {
return 'bar'
})

setQueryData(numberTag, () => {
return 2
})
setQueryData(stringTag, () => 'bar')
setQueryData(numberTag, () => 2)

expect(stringQuery.data).toBe('bar')
expect(numberQuery.data).toBe(2)
})

test('tags', async () => {
test('descendant tag setter only matches that descendant\'s queries', async () => {
const { setQueryData, query } = createQueryClient()
const stringTag = tag<string>()
const numberTag = tag<number>()
const sharedTag = tag()
const stringTag = sharedTag.add<string>()
const numberTag = sharedTag.add<number>()

const stringAction = () => 'foo'
const numberAction = () => 1
Expand All @@ -587,16 +583,10 @@ describe('setQueryData', () => {

await vi.runOnlyPendingTimersAsync()

setQueryData([stringTag], () => {
return 'bar'
})
setQueryData(stringTag, (data) => data + '-bar')

setQueryData([numberTag], () => {
return 2
})

expect(stringQuery.data).toBe('bar')
expect(numberQuery.data).toBe(2)
expect(stringQuery.data).toBe('foo-bar')
expect(numberQuery.data).toBe(1)
})

test('action', async () => {
Expand Down Expand Up @@ -656,8 +646,8 @@ describe('refreshQueryData', () => {

const numberAction = vi.fn()
const stringAction = vi.fn()
const numberTag = tag<number>()
const stringTag = tag<string>()
const numberTag = tag()
const stringTag = tag()

query(numberAction, [], { tags: [numberTag] })
query(stringAction, [], { tags: [stringTag] })
Expand Down Expand Up @@ -795,7 +785,7 @@ describe('mutate', () => {
[undefined],
])('refreshes tagged queries: %s', async (refreshQueryData) => {
const { mutate, query } = createQueryClient()
const numberTag = tag<number>()
const numberTag = tag()
const queryAction = vi.fn()
const mutationAction = vi.fn()

Expand All @@ -817,7 +807,7 @@ describe('mutate', () => {

test('does not refresh tagged queries if refreshQueryData is false', async () => {
const { mutate, query } = createQueryClient()
const numberTag = tag<number>()
const numberTag = tag()
const queryAction = vi.fn()
const mutationAction = vi.fn()

Expand All @@ -839,7 +829,7 @@ describe('mutate', () => {

test('does not refresh tagged queries if the action throws an error', async () => {
const { mutate, query } = createQueryClient()
const numberTag = tag<number>()
const numberTag = tag()
const queryAction = vi.fn()
const mutationAction = vi.fn(() => {
throw new Error()
Expand Down Expand Up @@ -1047,7 +1037,7 @@ describe('useMutation', () => {
test('setQueryDataBefore and setQueryDataAfter are called when the mutation is executed', async () => {
const { useMutation, query } = createQueryClient()
const { promise, resolve } = Promise.withResolvers<void>()
const numberTag = tag<number>()
const numberTag = tag<void>()
const queryAction = vi.fn()
const mutationAction = vi.fn(() => promise)
const setQueryDataBefore = vi.fn()
Expand Down Expand Up @@ -1306,8 +1296,8 @@ describe('defineMutation', () => {
const { promise, resolve } = Promise.withResolvers<void>()
const mutationPayload = 1
const mutationAction = (value: number) => promise.then(() => value)
const tagA = tag()
const tagB = tag()
const tagA = tag<number>()
const tagB = tag<number>()
const queryAResponse = 1
const queryBResponse = 1
const queryAAction = () => queryAResponse
Expand Down Expand Up @@ -1627,8 +1617,8 @@ describe('defineMutation', () => {
const { promise, resolve } = Promise.withResolvers<void>()
const mutationPayload = 1
const mutationAction = (value: number) => promise.then(() => value)
const tagA = tag()
const tagB = tag()
const tagA = tag<number>()
const tagB = tag<number>()
const queryAResponse = 1
const queryBResponse = 1
const queryAAction = () => queryAResponse
Expand Down
20 changes: 10 additions & 10 deletions src/createQueryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from './types/client'
import { createQueryGroups } from './createQueryGroups'
import { createUseQuery } from './createUseQuery'
import { isQueryTag, isQueryTags, QueryTag } from './types/tags'
import { isQueryTag, QueryTag } from './types/tags'
import { isArray } from './utilities/arrays'
import { assertNever } from './utilities/assert'
import { QueryGroup } from './createQueryGroup'
Expand Down Expand Up @@ -59,7 +59,7 @@ export function createQueryClient(options?: ClientOptions): QueryClient {
}

const setQueryData: SetQueryData = (
param1: QueryTag | QueryTag[] | QueryAction,
param1: QueryTag | QueryAction,
param2: Parameters<QueryAction> | QueryDataSetter,
param3?: QueryDataSetter,
): void => {
Expand All @@ -72,10 +72,10 @@ export function createQueryClient(options?: ClientOptions): QueryClient {
})
}

if (isQueryTag(param1) || isQueryTags(param1)) {
const tags = param1
if (isQueryTag(param1)) {
const queryTag = param1
const setter = param2 as QueryDataSetter
const groups = getQueryGroups(tags)
const groups = getQueryGroups(queryTag)

setDataForGroups(groups, setter)

Expand Down Expand Up @@ -107,12 +107,12 @@ export function createQueryClient(options?: ClientOptions): QueryClient {
}

const refreshQueryData: RefreshQueryData = (
param1: QueryTag | QueryTag[] | QueryAction,
param1: QueryTag | QueryAction,
param2?: Parameters<QueryAction>,
): void => {
if (isQueryTag(param1) || isQueryTags(param1)) {
const tags = param1
const groups = getQueryGroups(tags)
if (isQueryTag(param1)) {
const queryTag = param1
const groups = getQueryGroups(queryTag)

groups.forEach((group) => {
group.execute()
Expand All @@ -133,7 +133,7 @@ export function createQueryClient(options?: ClientOptions): QueryClient {
return
}

assertNever(param1, 'Invalid arguments given to setQueryData')
assertNever(param1, 'Invalid arguments given to refreshQueryData')
}

const mutate: MutationFunction = (action, parameters, options) => {
Expand Down
14 changes: 5 additions & 9 deletions src/createQueryGroup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,31 +244,27 @@ describe('given group with tags', () => {
test('can check if it has a tag', async () => {
const group = createQueryGroup(vi.fn(), [])
const tag1 = tag()
const tag2 = tag((value: string) => value)
const tag2 = tag<string>()

expect(group.hasTag(tag1)).toBe(false)

const query1 = group.createQuery({ tags: [tag1] })
const query2 = group.createQuery({ tags: [tag2('foo')] })
const query2 = group.createQuery({ tags: [tag2] })

// need executed to happen for tag factories
await vi.advanceTimersByTimeAsync(0)

expect(group.hasTag(tag1)).toBe(true)
expect(group.hasTag(tag2('foo'))).toBe(true)
expect(group.hasTag(tag2('bar'))).toBe(false)
expect(group.hasTag(tag2)).toBe(true)

query1.dispose()

expect(group.hasTag(tag1)).toBe(false)
expect(group.hasTag(tag2('foo'))).toBe(true)
expect(group.hasTag(tag2('bar'))).toBe(false)
expect(group.hasTag(tag2)).toBe(true)

query2.dispose()

expect(group.hasTag(tag1)).toBe(false)
expect(group.hasTag(tag2('foo'))).toBe(false)
expect(group.hasTag(tag2('bar'))).toBe(false)
expect(group.hasTag(tag2)).toBe(false)
})
})

Expand Down
Loading
Loading