From 3675f78a238ecfed8cb678d8db4f9d0eeac72f61 Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Tue, 4 Jul 2023 07:29:25 +1000 Subject: [PATCH 1/7] refactor: Accept stores other than writable --- packages/svelte-query/src/createBaseQuery.ts | 6 +++--- packages/svelte-query/src/createMutation.ts | 6 +++--- packages/svelte-query/src/createQueries.ts | 10 +++++----- packages/svelte-query/src/types.ts | 8 ++++---- packages/svelte-query/src/utils.ts | 12 ++++++------ 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/svelte-query/src/createBaseQuery.ts b/packages/svelte-query/src/createBaseQuery.ts index 0a23085284..a14322e32d 100644 --- a/packages/svelte-query/src/createBaseQuery.ts +++ b/packages/svelte-query/src/createBaseQuery.ts @@ -1,9 +1,9 @@ -import { derived, get, readable, writable } from 'svelte/store' +import { derived, get, readable } from 'svelte/store' import { notifyManager } from '@tanstack/query-core' import type { QueryClient, QueryKey, QueryObserver } from '@tanstack/query-core' import type { CreateBaseQueryOptions, CreateBaseQueryResult } from './types' import { useQueryClient } from './useQueryClient' -import { isWritable } from './utils' +import { isSvelteStore } from './utils' export function createBaseQuery< TQueryFnData, @@ -24,7 +24,7 @@ export function createBaseQuery< ): CreateBaseQueryResult { const client = useQueryClient(queryClient) - const optionsStore = isWritable(options) ? options : writable(options) + const optionsStore = isSvelteStore(options) ? options : readable(options) const defaultedOptionsStore = derived(optionsStore, ($options) => { const defaultedOptions = client.defaultQueryOptions($options) diff --git a/packages/svelte-query/src/createMutation.ts b/packages/svelte-query/src/createMutation.ts index 58004ea29a..cd12e1eff8 100644 --- a/packages/svelte-query/src/createMutation.ts +++ b/packages/svelte-query/src/createMutation.ts @@ -1,4 +1,4 @@ -import { readable, derived, writable, get } from 'svelte/store' +import { readable, derived, get } from 'svelte/store' import type { QueryClient, DefaultError } from '@tanstack/query-core' import { MutationObserver, notifyManager } from '@tanstack/query-core' import type { @@ -7,7 +7,7 @@ import type { CreateMutationResult, } from './types' import { useQueryClient } from './useQueryClient' -import { isWritable } from './utils' +import { isSvelteStore } from './utils' export function createMutation< TData = unknown, @@ -20,7 +20,7 @@ export function createMutation< ): CreateMutationResult { const client = useQueryClient(queryClient) - const optionsStore = isWritable(options) ? options : writable(options) + const optionsStore = isSvelteStore(options) ? options : readable(options) const observer = new MutationObserver( client, diff --git a/packages/svelte-query/src/createQueries.ts b/packages/svelte-query/src/createQueries.ts index 7d8c7c3169..9863fd14bf 100644 --- a/packages/svelte-query/src/createQueries.ts +++ b/packages/svelte-query/src/createQueries.ts @@ -9,10 +9,10 @@ import type { QueryObserverOptions, } from '@tanstack/query-core' import { notifyManager, QueriesObserver } from '@tanstack/query-core' -import { derived, get, readable, writable, type Readable } from 'svelte/store' -import type { WritableOrVal } from './types' +import { derived, get, readable, type Readable } from 'svelte/store' +import type { StoreOrVal } from './types' import { useQueryClient } from './useQueryClient' -import { isWritable } from './utils' +import { isSvelteStore } from './utils' // This defines the `CreateQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`. // `placeholderData` function does not have a parameter @@ -168,7 +168,7 @@ export function createQueries< queries, ...options }: { - queries: WritableOrVal<[...QueriesOptions]> + queries: StoreOrVal<[...QueriesOptions]> combine?: (result: QueriesResults) => TCombinedResult }, queryClient?: QueryClient, @@ -176,7 +176,7 @@ export function createQueries< const client = useQueryClient(queryClient) // const isRestoring = useIsRestoring() - const queriesStore = isWritable(queries) ? queries : writable(queries) + const queriesStore = isSvelteStore(queries) ? queries : readable(queries) const defaultedQueriesStore = derived(queriesStore, ($queries) => { return $queries.map((opts) => { diff --git a/packages/svelte-query/src/types.ts b/packages/svelte-query/src/types.ts index 39a058586e..3e9f6d6351 100644 --- a/packages/svelte-query/src/types.ts +++ b/packages/svelte-query/src/types.ts @@ -13,7 +13,7 @@ import type { import type { Readable, Writable } from 'svelte/store' /** Allows a type to be either the base object or a store of that object */ -export type WritableOrVal = T | Writable +export type StoreOrVal = T | Readable | Writable /** Options for createBaseQuery */ export type CreateBaseQueryOptions< @@ -22,7 +22,7 @@ export type CreateBaseQueryOptions< TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, -> = WritableOrVal< +> = StoreOrVal< QueryObserverOptions > @@ -54,7 +54,7 @@ export type CreateInfiniteQueryOptions< TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, TPageParam = unknown, -> = WritableOrVal< +> = StoreOrVal< InfiniteQueryObserverOptions< TQueryFnData, TError, @@ -89,7 +89,7 @@ export type CreateMutationOptions< TError = DefaultError, TVariables = void, TContext = unknown, -> = WritableOrVal< +> = StoreOrVal< Omit< MutationObserverOptions, '_defaulted' | 'variables' diff --git a/packages/svelte-query/src/utils.ts b/packages/svelte-query/src/utils.ts index 8ce19a7f43..68140eda2c 100644 --- a/packages/svelte-query/src/utils.ts +++ b/packages/svelte-query/src/utils.ts @@ -1,8 +1,8 @@ -import type { Writable } from 'svelte/store' -import type { WritableOrVal } from './types' +import type { Readable } from 'svelte/store' +import type { StoreOrVal } from './types' -export function isWritable( - obj: WritableOrVal, -): obj is Writable { - return 'subscribe' in obj && 'set' in obj && 'update' in obj +export function isSvelteStore( + obj: StoreOrVal, +): obj is Readable { + return 'subscribe' in obj } From ed68d92082a258f625b8ceaaa73d73014797df16 Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Tue, 4 Jul 2023 07:31:25 +1000 Subject: [PATCH 2/7] Cleanup Readable type import --- packages/svelte-query/src/createQueries.ts | 3 ++- packages/svelte-query/src/useIsFetching.ts | 3 ++- packages/svelte-query/src/useIsMutating.ts | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/svelte-query/src/createQueries.ts b/packages/svelte-query/src/createQueries.ts index 9863fd14bf..203e6d81ee 100644 --- a/packages/svelte-query/src/createQueries.ts +++ b/packages/svelte-query/src/createQueries.ts @@ -9,7 +9,8 @@ import type { QueryObserverOptions, } from '@tanstack/query-core' import { notifyManager, QueriesObserver } from '@tanstack/query-core' -import { derived, get, readable, type Readable } from 'svelte/store' +import { derived, get, readable } from 'svelte/store' +import type { Readable } from 'svelte/store' import type { StoreOrVal } from './types' import { useQueryClient } from './useQueryClient' import { isSvelteStore } from './utils' diff --git a/packages/svelte-query/src/useIsFetching.ts b/packages/svelte-query/src/useIsFetching.ts index 86d5e2b23f..c6089b76b1 100644 --- a/packages/svelte-query/src/useIsFetching.ts +++ b/packages/svelte-query/src/useIsFetching.ts @@ -3,7 +3,8 @@ import { type QueryClient, notifyManager, } from '@tanstack/query-core' -import { type Readable, readable } from 'svelte/store' +import { readable } from 'svelte/store' +import type { Readable } from 'svelte/store' import { useQueryClient } from './useQueryClient' export function useIsFetching( diff --git a/packages/svelte-query/src/useIsMutating.ts b/packages/svelte-query/src/useIsMutating.ts index c4293fa744..4aa231c873 100644 --- a/packages/svelte-query/src/useIsMutating.ts +++ b/packages/svelte-query/src/useIsMutating.ts @@ -3,7 +3,8 @@ import { type QueryClient, notifyManager, } from '@tanstack/query-core' -import { type Readable, readable } from 'svelte/store' +import { readable } from 'svelte/store' +import type { Readable } from 'svelte/store' import { useQueryClient } from './useQueryClient' export function useIsMutating( From 5a15ed3c9d3e43c2bb765ded064f5563facd3f9c Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:14:56 +1000 Subject: [PATCH 3/7] Add tests --- .../src/__tests__/createQuery.test.ts | 55 +++++++++++++++++-- packages/svelte-query/vite.config.ts | 1 + 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/packages/svelte-query/src/__tests__/createQuery.test.ts b/packages/svelte-query/src/__tests__/createQuery.test.ts index 47460e3d06..e9acadd577 100644 --- a/packages/svelte-query/src/__tests__/createQuery.test.ts +++ b/packages/svelte-query/src/__tests__/createQuery.test.ts @@ -1,12 +1,12 @@ -import { describe, it, expect } from 'vitest' +import { describe, expect, test } from 'vitest' import { render, waitFor } from '@testing-library/svelte' -import { writable } from 'svelte/store' +import { derived, writable } from 'svelte/store' import CreateQuery from './CreateQuery.svelte' import { sleep } from './utils' import type { CreateQueryOptions } from '../types' describe('createQuery', () => { - it('Render and wait for success', async () => { + test('Render and wait for success', async () => { const rendered = render(CreateQuery, { props: { options: { @@ -28,8 +28,8 @@ describe('createQuery', () => { }) }) - it('should keep previous data when returned as placeholder data', async () => { - const options: CreateQueryOptions = writable({ + test('Keep previous data when returned as placeholder data', async () => { + const options = writable({ queryKey: ['test', [1]], queryFn: async ({ queryKey }) => { await sleep(10) @@ -38,7 +38,8 @@ describe('createQuery', () => { return ids.map((id) => ({ id })) }, placeholderData: (previousData: { id: number }[]) => previousData, - }) + }) satisfies CreateQueryOptions + const rendered = render(CreateQuery, { props: { options } }) await waitFor(() => { @@ -63,4 +64,46 @@ describe('createQuery', () => { expect(rendered.queryByText('id: 2')).toBeInTheDocument() }) }) + + test('Accept a writable store for options', async () => { + const optionsStore = writable({ + queryKey: ['test'], + queryFn: async () => { + await sleep(10) + return 'Success' + }, + }) satisfies CreateQueryOptions + + const rendered = render(CreateQuery, { + props: { + options: optionsStore, + } + }) + + await waitFor(() => { + expect(rendered.getByText('Success')).toBeInTheDocument() + }) + }) + + test('Accept a derived store for options', async () => { + const writableStore = writable("test"); + + const derivedStore = derived(writableStore, ($store) => ({ + queryKey: [$store], + queryFn: async () => { + await sleep(10) + return 'Success' + }, + })) satisfies CreateQueryOptions + + const rendered = render(CreateQuery, { + props: { + options: derivedStore, + } + }) + + await waitFor(() => { + expect(rendered.getByText('Success')).toBeInTheDocument() + }) + }) }) diff --git a/packages/svelte-query/vite.config.ts b/packages/svelte-query/vite.config.ts index ea042a0513..fdbb3a56f1 100644 --- a/packages/svelte-query/vite.config.ts +++ b/packages/svelte-query/vite.config.ts @@ -6,6 +6,7 @@ export default defineConfig({ test: { name: 'svelte-query', watch: false, + globals: true, coverage: { provider: 'istanbul' }, environment: 'jsdom', include: ['src/**/*.{test,spec}.{js,ts}'], From 32ce67cf1129274ad1e9d55acb3fbd2a27a1224b Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:17:06 +1000 Subject: [PATCH 4/7] Stricter isSvelteStore check --- .../svelte-query/src/__tests__/createQuery.test.ts | 12 ++++++------ packages/svelte-query/src/utils.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/svelte-query/src/__tests__/createQuery.test.ts b/packages/svelte-query/src/__tests__/createQuery.test.ts index e9acadd577..47be18395d 100644 --- a/packages/svelte-query/src/__tests__/createQuery.test.ts +++ b/packages/svelte-query/src/__tests__/createQuery.test.ts @@ -39,7 +39,7 @@ describe('createQuery', () => { }, placeholderData: (previousData: { id: number }[]) => previousData, }) satisfies CreateQueryOptions - + const rendered = render(CreateQuery, { props: { options } }) await waitFor(() => { @@ -73,11 +73,11 @@ describe('createQuery', () => { return 'Success' }, }) satisfies CreateQueryOptions - + const rendered = render(CreateQuery, { props: { options: optionsStore, - } + }, }) await waitFor(() => { @@ -86,7 +86,7 @@ describe('createQuery', () => { }) test('Accept a derived store for options', async () => { - const writableStore = writable("test"); + const writableStore = writable('test') const derivedStore = derived(writableStore, ($store) => ({ queryKey: [$store], @@ -95,11 +95,11 @@ describe('createQuery', () => { return 'Success' }, })) satisfies CreateQueryOptions - + const rendered = render(CreateQuery, { props: { options: derivedStore, - } + }, }) await waitFor(() => { diff --git a/packages/svelte-query/src/utils.ts b/packages/svelte-query/src/utils.ts index 68140eda2c..eb86225694 100644 --- a/packages/svelte-query/src/utils.ts +++ b/packages/svelte-query/src/utils.ts @@ -4,5 +4,5 @@ import type { StoreOrVal } from './types' export function isSvelteStore( obj: StoreOrVal, ): obj is Readable { - return 'subscribe' in obj + return 'subscribe' in obj && typeof obj.subscribe === 'function' } From 4f1cfe59aa67ebf90bb38ef8ccad30f7450ff799 Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:23:20 +1000 Subject: [PATCH 5/7] Update docs --- docs/svelte/reactivity.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/svelte/reactivity.md b/docs/svelte/reactivity.md index 6d7b3fdc33..ade2ace5e8 100644 --- a/docs/svelte/reactivity.md +++ b/docs/svelte/reactivity.md @@ -3,7 +3,7 @@ id: reactivity title: Reactivity --- -Svelte uses a compiler to build your code which optimises rendering. By default, variables will run once, unless they are referenced in your markup. To be able to react to changes in options you need to use [stores](https://svelte.dev/tutorial/writable-stores). +Svelte uses a compiler to build your code which optimises rendering. By default, variables will run once, unless they are referenced in your markup. To be able to react to changes in options you need to use [stores](https://svelte.dev/docs/svelte-store). In the below example, the `refetchInterval` option is set from the variable `intervalMs`, which is edited by the input field. However, as the query is not told it should react to changes in `intervalMs`, `refetchInterval` will not change when the input value changes. @@ -30,6 +30,7 @@ To solve this, create a store for the options and use it as input for the query. ```markdown - + ``` From b08d332b540e2ed315abbaa9c644cc1ff6e7965c Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:26:45 +1000 Subject: [PATCH 6/7] Fix input bind --- docs/svelte/reactivity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/svelte/reactivity.md b/docs/svelte/reactivity.md index ade2ace5e8..c4c8a105f9 100644 --- a/docs/svelte/reactivity.md +++ b/docs/svelte/reactivity.md @@ -43,5 +43,5 @@ To solve this, create a store for the options and use it as input for the query. const query = createQuery(queryOptions) - + ``` From 9aee3ae550a895e9690508f84d47f426855f0a8f Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:31:12 +1000 Subject: [PATCH 7/7] Add testing-library cleanup --- packages/svelte-query/vite.config.ts | 1 - packages/svelte-query/vitest.setup.ts | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/svelte-query/vite.config.ts b/packages/svelte-query/vite.config.ts index fdbb3a56f1..ea042a0513 100644 --- a/packages/svelte-query/vite.config.ts +++ b/packages/svelte-query/vite.config.ts @@ -6,7 +6,6 @@ export default defineConfig({ test: { name: 'svelte-query', watch: false, - globals: true, coverage: { provider: 'istanbul' }, environment: 'jsdom', include: ['src/**/*.{test,spec}.{js,ts}'], diff --git a/packages/svelte-query/vitest.setup.ts b/packages/svelte-query/vitest.setup.ts index d263e51f4f..7f489d28ba 100644 --- a/packages/svelte-query/vitest.setup.ts +++ b/packages/svelte-query/vitest.setup.ts @@ -1,4 +1,7 @@ import matchers from '@testing-library/jest-dom/matchers' -import { expect } from 'vitest' +import { cleanup } from '@testing-library/svelte' +import { afterEach, expect } from 'vitest' expect.extend(matchers) + +afterEach(() => cleanup())