@tanstack/solid-query
Advanced tools
Comparing version 5.0.0-beta.20 to 5.0.0-beta.21
260
build/dev.js
import { notifyManager, QueryClient as QueryClient$1, MutationObserver, QueriesObserver, hydrate, QueryObserver, InfiniteQueryObserver } from '@tanstack/query-core'; | ||
export * from '@tanstack/query-core'; | ||
import { batch, createContext, useContext, onMount, onCleanup, createMemo, createSignal, createComputed, on, createResource } from 'solid-js'; | ||
import { batch, createContext, useContext, createRenderEffect, onCleanup, createMemo, createSignal, createComputed, on, mergeProps, createResource, onMount, untrack } from 'solid-js'; | ||
import { createComponent, isServer } from 'solid-js/web'; | ||
@@ -23,13 +23,13 @@ import { createStore, unwrap, reconcile } from 'solid-js/store'; | ||
} | ||
return client; | ||
return client(); | ||
}; | ||
var QueryClientProvider = (props) => { | ||
onMount(() => { | ||
createRenderEffect((unmount) => { | ||
unmount?.(); | ||
props.client.mount(); | ||
return props.client.unmount.bind(props.client); | ||
}); | ||
onCleanup(() => props.client.unmount()); | ||
return createComponent(QueryClientContext.Provider, { | ||
get value() { | ||
return props.client; | ||
}, | ||
value: () => props.client, | ||
get children() { | ||
@@ -48,2 +48,5 @@ return props.children; | ||
} | ||
var IsRestoringContext = createContext(() => false); | ||
var useIsRestoring = () => useContext(IsRestoringContext); | ||
var IsRestoringProvider = IsRestoringContext.Provider; | ||
@@ -82,17 +85,27 @@ // src/createBaseQuery.ts | ||
const client = createMemo(() => useQueryClient(queryClient?.())); | ||
const defaultedOptions = client().defaultQueryOptions(options()); | ||
defaultedOptions._optimisticResults = "optimistic"; | ||
defaultedOptions.structuralSharing = false; | ||
if (isServer) { | ||
defaultedOptions.retry = false; | ||
defaultedOptions.throwOnError = true; | ||
} | ||
const observer = new Observer(client(), defaultedOptions); | ||
const isRestoring = useIsRestoring(); | ||
const defaultedOptions = createMemo( | ||
() => mergeProps(client().defaultQueryOptions(options()), { | ||
get _optimisticResults() { | ||
return isRestoring() ? "isRestoring" : "optimistic"; | ||
}, | ||
structuralSharing: false, | ||
...isServer && { retry: false, throwOnError: true } | ||
}) | ||
); | ||
const [observer, setObserver] = createSignal( | ||
new Observer(client(), untrack(defaultedOptions)) | ||
); | ||
createComputed( | ||
on(client, (c) => setObserver(new Observer(c, defaultedOptions())), { | ||
defer: true | ||
}) | ||
); | ||
const [state, setState] = createStore( | ||
observer.getOptimisticResult(defaultedOptions) | ||
observer().getOptimisticResult(defaultedOptions()) | ||
); | ||
const createServerSubscriber = (resolve, reject) => { | ||
return observer.subscribe((result) => { | ||
return observer().subscribe((result) => { | ||
notifyManager.batchCalls(() => { | ||
const query = observer.getCurrentQuery(); | ||
const query = observer().getCurrentQuery(); | ||
const unwrappedResult = hydrateableObserverResult(query, result); | ||
@@ -108,24 +121,17 @@ if (unwrappedResult.isError) { | ||
const createClientSubscriber = () => { | ||
return observer.subscribe((result) => { | ||
const obs = observer(); | ||
return obs.subscribe((result) => { | ||
notifyManager.batchCalls(() => { | ||
const reconcileOptions = observer.options.reconcile; | ||
if (queryResource()?.data && result.data && !queryResource.loading) { | ||
setState((store) => { | ||
return reconcileFn( | ||
store, | ||
result, | ||
reconcileOptions === void 0 ? "id" : reconcileOptions | ||
); | ||
}); | ||
const reconcileOptions = obs.options.reconcile; | ||
setState((store) => { | ||
return reconcileFn( | ||
store, | ||
result, | ||
reconcileOptions === void 0 ? "id" : reconcileOptions | ||
); | ||
}); | ||
if (queryResource()?.data && result.data && !queryResource.loading && isRestoring()) | ||
mutate(state); | ||
} else { | ||
setState((store) => { | ||
return reconcileFn( | ||
store, | ||
result, | ||
reconcileOptions === void 0 ? "id" : reconcileOptions | ||
); | ||
}); | ||
else | ||
refetch(); | ||
} | ||
})(); | ||
@@ -137,12 +143,11 @@ }); | ||
() => { | ||
const obs = observer(); | ||
return new Promise((resolve, reject) => { | ||
if (isServer) { | ||
if (isServer) | ||
unsubscribe = createServerSubscriber(resolve, reject); | ||
} else { | ||
if (!unsubscribe) { | ||
unsubscribe = createClientSubscriber(); | ||
} | ||
} | ||
if (!state.isLoading) { | ||
const query = observer.getCurrentQuery(); | ||
else if (!unsubscribe && !isRestoring()) | ||
unsubscribe = createClientSubscriber(); | ||
obs.updateResult(); | ||
if (!state.isLoading && !isRestoring()) { | ||
const query = obs.getCurrentQuery(); | ||
resolve(hydrateableObserverResult(query, state)); | ||
@@ -155,3 +160,5 @@ } | ||
// If initialData is provided, we resolve the resource immediately | ||
ssrLoadFrom: options().initialData ? "initial" : "server", | ||
get ssrLoadFrom() { | ||
return options().initialData ? "initial" : "server"; | ||
}, | ||
get deferStream() { | ||
@@ -169,2 +176,3 @@ return options().deferStream; | ||
onHydrated(_k, info) { | ||
const defaultOptions = defaultedOptions(); | ||
if (info.value) { | ||
@@ -174,4 +182,4 @@ hydrate(client(), { | ||
{ | ||
queryKey: defaultedOptions.queryKey, | ||
queryHash: defaultedOptions.queryHash, | ||
queryKey: defaultOptions.queryKey, | ||
queryHash: defaultOptions.queryHash, | ||
state: info.value | ||
@@ -182,14 +190,27 @@ } | ||
} | ||
if (!unsubscribe) { | ||
const newOptions = { ...defaultedOptions }; | ||
if (defaultedOptions.staleTime || !defaultedOptions.initialData) { | ||
newOptions.refetchOnMount = false; | ||
} | ||
observer.setOptions(newOptions); | ||
setState(observer.getOptimisticResult(newOptions)); | ||
unsubscribe = createClientSubscriber(); | ||
if (unsubscribe) | ||
return; | ||
const newOptions = { ...defaultOptions }; | ||
if (defaultOptions.staleTime || !defaultOptions.initialData) { | ||
newOptions.refetchOnMount = false; | ||
} | ||
observer().setOptions(newOptions); | ||
setState(observer().getOptimisticResult(newOptions)); | ||
unsubscribe = createClientSubscriber(); | ||
} | ||
} | ||
); | ||
createComputed( | ||
on( | ||
[isRestoring, observer], | ||
([restoring]) => { | ||
const unsub = unsubscribe; | ||
queueMicrotask(() => unsub?.()); | ||
unsubscribe = null; | ||
if (!restoring) | ||
refetch(); | ||
}, | ||
{ defer: true } | ||
) | ||
); | ||
onCleanup(() => { | ||
@@ -203,4 +224,7 @@ if (unsubscribe) { | ||
on( | ||
() => client().defaultQueryOptions(options()), | ||
() => observer.setOptions(client().defaultQueryOptions(options())), | ||
[observer, defaultedOptions], | ||
([obs, opts]) => { | ||
obs.setOptions(opts); | ||
setState(obs.getOptimisticResult(opts)); | ||
}, | ||
{ | ||
@@ -217,5 +241,6 @@ // Defer because we don't need to trigger on first render | ||
() => { | ||
if (state.isError && !state.isFetching && shouldThrowError(observer.options.throwOnError, [ | ||
const obs = observer(); | ||
if (state.isError && !state.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [ | ||
state.error, | ||
observer.getCurrentQuery() | ||
obs.getCurrentQuery() | ||
])) { | ||
@@ -266,5 +291,5 @@ throw state.error; | ||
function createMutation(options, queryClient) { | ||
const client = useQueryClient(queryClient?.()); | ||
const client = createMemo(() => useQueryClient(queryClient?.())); | ||
const observer = new MutationObserver( | ||
client, | ||
client(), | ||
options() | ||
@@ -318,11 +343,16 @@ ); | ||
function createQueries(queriesOptions, queryClient) { | ||
const client = useQueryClient(queryClient?.()); | ||
const defaultedQueries = queriesOptions().queries.map((options) => { | ||
const defaultedOptions = client.defaultQueryOptions(options); | ||
defaultedOptions._optimisticResults = "optimistic"; | ||
return defaultedOptions; | ||
}); | ||
const client = createMemo(() => useQueryClient(queryClient?.())); | ||
const isRestoring = useIsRestoring(); | ||
const defaultedQueries = createMemo( | ||
() => queriesOptions().queries.map( | ||
(options) => mergeProps(client().defaultQueryOptions(options), { | ||
get _optimisticResults() { | ||
return isRestoring() ? "isRestoring" : "optimistic"; | ||
} | ||
}) | ||
) | ||
); | ||
const observer = new QueriesObserver( | ||
client, | ||
defaultedQueries, | ||
client(), | ||
defaultedQueries(), | ||
queriesOptions().combine ? { | ||
@@ -333,18 +363,71 @@ combine: queriesOptions().combine | ||
const [state, setState] = createStore( | ||
observer.getOptimisticResult(defaultedQueries)[1]() | ||
observer.getOptimisticResult(defaultedQueries())[1]() | ||
); | ||
const unsubscribe = observer.subscribe((result) => { | ||
notifyManager.batchCalls(() => { | ||
setState(unwrap(result)); | ||
})(); | ||
createRenderEffect( | ||
on( | ||
() => queriesOptions().queries.length, | ||
() => setState(observer.getOptimisticResult(defaultedQueries())[1]()) | ||
) | ||
); | ||
const dataResources = createMemo( | ||
on( | ||
() => state.length, | ||
() => state.map((queryRes) => { | ||
const dataPromise = () => new Promise((resolve) => { | ||
if (queryRes.isFetching && queryRes.isLoading) | ||
return; | ||
resolve(unwrap(queryRes.data)); | ||
}); | ||
return createResource(dataPromise); | ||
}) | ||
) | ||
); | ||
batch(() => { | ||
const dataResources_ = dataResources(); | ||
for (let index = 0; index < dataResources_.length; index++) { | ||
const dataResource = dataResources_[index]; | ||
dataResource[1].mutate(() => unwrap(state[index].data)); | ||
dataResource[1].refetch(); | ||
} | ||
}); | ||
let taskQueue = []; | ||
const subscribeToObserver = () => observer.subscribe((result) => { | ||
taskQueue.push(() => { | ||
batch(() => { | ||
const dataResources_ = dataResources(); | ||
for (let index = 0; index < dataResources_.length; index++) { | ||
const dataResource = dataResources_[index]; | ||
const unwrappedResult = { ...unwrap(result[index]) }; | ||
setState(index, unwrap(unwrappedResult)); | ||
dataResource[1].mutate(() => unwrap(state[index].data)); | ||
dataResource[1].refetch(); | ||
} | ||
}); | ||
}); | ||
queueMicrotask(() => { | ||
const taskToRun = taskQueue.pop(); | ||
if (taskToRun) | ||
taskToRun(); | ||
taskQueue = []; | ||
}); | ||
}); | ||
let unsubscribe = () => void 0; | ||
createComputed((cleanup) => { | ||
cleanup?.(); | ||
unsubscribe = isRestoring() ? () => void 0 : subscribeToObserver(); | ||
return () => queueMicrotask(unsubscribe); | ||
}); | ||
onCleanup(unsubscribe); | ||
onMount(() => { | ||
observer.setQueries( | ||
defaultedQueries(), | ||
queriesOptions().combine ? { | ||
combine: queriesOptions().combine | ||
} : void 0, | ||
{ listeners: false } | ||
); | ||
}); | ||
createComputed(() => { | ||
const updatedQueries = queriesOptions().queries.map((options) => { | ||
const defaultedOptions = client.defaultQueryOptions(options); | ||
defaultedOptions._optimisticResults = "optimistic"; | ||
return defaultedOptions; | ||
}); | ||
observer.setQueries( | ||
updatedQueries, | ||
defaultedQueries(), | ||
queriesOptions().combine ? { | ||
@@ -356,5 +439,18 @@ combine: queriesOptions().combine | ||
}); | ||
return state; | ||
const handler = (index) => ({ | ||
get(target, prop) { | ||
if (prop === "data") { | ||
return dataResources()[index][0](); | ||
} | ||
return Reflect.get(target, prop); | ||
} | ||
}); | ||
const getProxies = () => state.map((s, index) => { | ||
return new Proxy(s, handler(index)); | ||
}); | ||
const [proxifiedState, setProxifiedState] = createStore(getProxies()); | ||
createRenderEffect(() => setProxifiedState(getProxies())); | ||
return proxifiedState; | ||
} | ||
export { QueryClient, QueryClientContext, QueryClientProvider, createInfiniteQuery, createMutation, createQueries, createQuery, queryOptions, useIsFetching, useIsMutating, useQueryClient }; | ||
export { IsRestoringProvider, QueryClient, QueryClientContext, QueryClientProvider, createInfiniteQuery, createMutation, createQueries, createQuery, queryOptions, useIsFetching, useIsMutating, useIsRestoring, useQueryClient }; |
@@ -5,2 +5,3 @@ import { DefaultError, QueryKey, QueryObserverOptions as QueryObserverOptions$1, InfiniteQueryObserverOptions as InfiniteQueryObserverOptions$1, DefaultOptions as DefaultOptions$1, QueryClientConfig as QueryClientConfig$1, QueryClient as QueryClient$1, WithRequired, QueryObserverResult, DefinedQueryObserverResult, InfiniteQueryObserverResult, MutationObserverOptions, MutateFunction, MutationObserverResult, QueryFilters, InfiniteData, MutationFilters, QueriesPlaceholderDataFunction, QueryFunction } from '@tanstack/query-core'; | ||
import { JSX, Accessor } from 'solid-js'; | ||
import * as solid_js_types_reactive_signal from 'solid-js/types/reactive/signal'; | ||
@@ -78,3 +79,3 @@ interface QueryObserverOptions<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, TPageParam = never> extends Omit<QueryObserverOptions$1<TQueryFnData, TError, TData, TQueryData, TQueryKey, TPageParam>, 'structuralSharing'> { | ||
declare const QueryClientContext: solid_js.Context<QueryClient | undefined>; | ||
declare const QueryClientContext: solid_js.Context<(() => QueryClient) | undefined>; | ||
declare const useQueryClient: (queryClient?: QueryClient) => QueryClient; | ||
@@ -139,3 +140,3 @@ type QueryClientProviderProps = { | ||
type QueriesResults<T extends Array<any>, Result extends Array<any> = [], Depth extends ReadonlyArray<number> = []> = Depth['length'] extends MAXIMUM_DEPTH ? Array<CreateQueryResult> : T extends [] ? [] : T extends [infer Head] ? [...Result, GetResults<Head>] : T extends [infer Head, ...infer Tail] ? QueriesResults<[...Tail], [...Result, GetResults<Head>], [...Depth, 1]> : T extends Array<CreateQueryOptionsForCreateQueries<infer TQueryFnData, infer TError, infer TData, any>> ? Array<CreateQueryResult<unknown extends TData ? TQueryFnData : TData, unknown extends TError ? DefaultError : TError>> : Array<CreateQueryResult>; | ||
declare function createQueries<T extends Array<any>, TCombinedResult = QueriesResults<T>>(queriesOptions: Accessor<{ | ||
declare function createQueries<T extends Array<any>, TCombinedResult extends QueriesResults<T> = QueriesResults<T>>(queriesOptions: Accessor<{ | ||
queries: readonly [...QueriesOptions<T>]; | ||
@@ -145,2 +146,5 @@ combine?: (result: QueriesResults<T>) => TCombinedResult; | ||
export { CreateBaseMutationResult, CreateBaseQueryOptions, CreateBaseQueryResult, CreateInfiniteQueryOptions, CreateInfiniteQueryResult, CreateMutateAsyncFunction, CreateMutateFunction, CreateMutationOptions, CreateMutationResult, CreateQueryOptions, CreateQueryResult, DefaultOptions, DefinedCreateBaseQueryResult, DefinedCreateQueryResult, FunctionedParams, InfiniteQueryObserverOptions, QueryClient, QueryClientConfig, QueryClientContext, QueryClientProvider, QueryClientProviderProps, QueryObserverOptions, SolidInfiniteQueryOptions, SolidMutationOptions, SolidQueryOptions, createInfiniteQuery, createMutation, createQueries, createQuery, queryOptions, useIsFetching, useIsMutating, useQueryClient }; | ||
declare const useIsRestoring: () => Accessor<boolean>; | ||
declare const IsRestoringProvider: solid_js_types_reactive_signal.ContextProviderComponent<Accessor<boolean>>; | ||
export { CreateBaseMutationResult, CreateBaseQueryOptions, CreateBaseQueryResult, CreateInfiniteQueryOptions, CreateInfiniteQueryResult, CreateMutateAsyncFunction, CreateMutateFunction, CreateMutationOptions, CreateMutationResult, CreateQueryOptions, CreateQueryResult, DefaultOptions, DefinedCreateBaseQueryResult, DefinedCreateQueryResult, FunctionedParams, InfiniteQueryObserverOptions, IsRestoringProvider, QueryClient, QueryClientConfig, QueryClientContext, QueryClientProvider, QueryClientProviderProps, QueryObserverOptions, SolidInfiniteQueryOptions, SolidMutationOptions, SolidQueryOptions, createInfiniteQuery, createMutation, createQueries, createQuery, queryOptions, useIsFetching, useIsMutating, useIsRestoring, useQueryClient }; |
import { notifyManager, QueryClient as QueryClient$1, MutationObserver, QueriesObserver, hydrate, QueryObserver, InfiniteQueryObserver } from '@tanstack/query-core'; | ||
export * from '@tanstack/query-core'; | ||
import { batch, createContext, useContext, onMount, onCleanup, createMemo, createSignal, createComputed, on, createResource } from 'solid-js'; | ||
import { batch, createContext, useContext, createRenderEffect, onCleanup, createMemo, createSignal, createComputed, on, mergeProps, createResource, onMount, untrack } from 'solid-js'; | ||
import { createComponent, isServer } from 'solid-js/web'; | ||
@@ -23,13 +23,13 @@ import { createStore, unwrap, reconcile } from 'solid-js/store'; | ||
} | ||
return client; | ||
return client(); | ||
}; | ||
var QueryClientProvider = (props) => { | ||
onMount(() => { | ||
createRenderEffect((unmount) => { | ||
unmount?.(); | ||
props.client.mount(); | ||
return props.client.unmount.bind(props.client); | ||
}); | ||
onCleanup(() => props.client.unmount()); | ||
return createComponent(QueryClientContext.Provider, { | ||
get value() { | ||
return props.client; | ||
}, | ||
value: () => props.client, | ||
get children() { | ||
@@ -48,2 +48,5 @@ return props.children; | ||
} | ||
var IsRestoringContext = createContext(() => false); | ||
var useIsRestoring = () => useContext(IsRestoringContext); | ||
var IsRestoringProvider = IsRestoringContext.Provider; | ||
@@ -82,17 +85,27 @@ // src/createBaseQuery.ts | ||
const client = createMemo(() => useQueryClient(queryClient?.())); | ||
const defaultedOptions = client().defaultQueryOptions(options()); | ||
defaultedOptions._optimisticResults = "optimistic"; | ||
defaultedOptions.structuralSharing = false; | ||
if (isServer) { | ||
defaultedOptions.retry = false; | ||
defaultedOptions.throwOnError = true; | ||
} | ||
const observer = new Observer(client(), defaultedOptions); | ||
const isRestoring = useIsRestoring(); | ||
const defaultedOptions = createMemo( | ||
() => mergeProps(client().defaultQueryOptions(options()), { | ||
get _optimisticResults() { | ||
return isRestoring() ? "isRestoring" : "optimistic"; | ||
}, | ||
structuralSharing: false, | ||
...isServer && { retry: false, throwOnError: true } | ||
}) | ||
); | ||
const [observer, setObserver] = createSignal( | ||
new Observer(client(), untrack(defaultedOptions)) | ||
); | ||
createComputed( | ||
on(client, (c) => setObserver(new Observer(c, defaultedOptions())), { | ||
defer: true | ||
}) | ||
); | ||
const [state, setState] = createStore( | ||
observer.getOptimisticResult(defaultedOptions) | ||
observer().getOptimisticResult(defaultedOptions()) | ||
); | ||
const createServerSubscriber = (resolve, reject) => { | ||
return observer.subscribe((result) => { | ||
return observer().subscribe((result) => { | ||
notifyManager.batchCalls(() => { | ||
const query = observer.getCurrentQuery(); | ||
const query = observer().getCurrentQuery(); | ||
const unwrappedResult = hydrateableObserverResult(query, result); | ||
@@ -108,24 +121,17 @@ if (unwrappedResult.isError) { | ||
const createClientSubscriber = () => { | ||
return observer.subscribe((result) => { | ||
const obs = observer(); | ||
return obs.subscribe((result) => { | ||
notifyManager.batchCalls(() => { | ||
const reconcileOptions = observer.options.reconcile; | ||
if (queryResource()?.data && result.data && !queryResource.loading) { | ||
setState((store) => { | ||
return reconcileFn( | ||
store, | ||
result, | ||
reconcileOptions === void 0 ? "id" : reconcileOptions | ||
); | ||
}); | ||
const reconcileOptions = obs.options.reconcile; | ||
setState((store) => { | ||
return reconcileFn( | ||
store, | ||
result, | ||
reconcileOptions === void 0 ? "id" : reconcileOptions | ||
); | ||
}); | ||
if (queryResource()?.data && result.data && !queryResource.loading && isRestoring()) | ||
mutate(state); | ||
} else { | ||
setState((store) => { | ||
return reconcileFn( | ||
store, | ||
result, | ||
reconcileOptions === void 0 ? "id" : reconcileOptions | ||
); | ||
}); | ||
else | ||
refetch(); | ||
} | ||
})(); | ||
@@ -137,12 +143,11 @@ }); | ||
() => { | ||
const obs = observer(); | ||
return new Promise((resolve, reject) => { | ||
if (isServer) { | ||
if (isServer) | ||
unsubscribe = createServerSubscriber(resolve, reject); | ||
} else { | ||
if (!unsubscribe) { | ||
unsubscribe = createClientSubscriber(); | ||
} | ||
} | ||
if (!state.isLoading) { | ||
const query = observer.getCurrentQuery(); | ||
else if (!unsubscribe && !isRestoring()) | ||
unsubscribe = createClientSubscriber(); | ||
obs.updateResult(); | ||
if (!state.isLoading && !isRestoring()) { | ||
const query = obs.getCurrentQuery(); | ||
resolve(hydrateableObserverResult(query, state)); | ||
@@ -155,3 +160,5 @@ } | ||
// If initialData is provided, we resolve the resource immediately | ||
ssrLoadFrom: options().initialData ? "initial" : "server", | ||
get ssrLoadFrom() { | ||
return options().initialData ? "initial" : "server"; | ||
}, | ||
get deferStream() { | ||
@@ -169,2 +176,3 @@ return options().deferStream; | ||
onHydrated(_k, info) { | ||
const defaultOptions = defaultedOptions(); | ||
if (info.value) { | ||
@@ -174,4 +182,4 @@ hydrate(client(), { | ||
{ | ||
queryKey: defaultedOptions.queryKey, | ||
queryHash: defaultedOptions.queryHash, | ||
queryKey: defaultOptions.queryKey, | ||
queryHash: defaultOptions.queryHash, | ||
state: info.value | ||
@@ -182,14 +190,27 @@ } | ||
} | ||
if (!unsubscribe) { | ||
const newOptions = { ...defaultedOptions }; | ||
if (defaultedOptions.staleTime || !defaultedOptions.initialData) { | ||
newOptions.refetchOnMount = false; | ||
} | ||
observer.setOptions(newOptions); | ||
setState(observer.getOptimisticResult(newOptions)); | ||
unsubscribe = createClientSubscriber(); | ||
if (unsubscribe) | ||
return; | ||
const newOptions = { ...defaultOptions }; | ||
if (defaultOptions.staleTime || !defaultOptions.initialData) { | ||
newOptions.refetchOnMount = false; | ||
} | ||
observer().setOptions(newOptions); | ||
setState(observer().getOptimisticResult(newOptions)); | ||
unsubscribe = createClientSubscriber(); | ||
} | ||
} | ||
); | ||
createComputed( | ||
on( | ||
[isRestoring, observer], | ||
([restoring]) => { | ||
const unsub = unsubscribe; | ||
queueMicrotask(() => unsub?.()); | ||
unsubscribe = null; | ||
if (!restoring) | ||
refetch(); | ||
}, | ||
{ defer: true } | ||
) | ||
); | ||
onCleanup(() => { | ||
@@ -203,4 +224,7 @@ if (unsubscribe) { | ||
on( | ||
() => client().defaultQueryOptions(options()), | ||
() => observer.setOptions(client().defaultQueryOptions(options())), | ||
[observer, defaultedOptions], | ||
([obs, opts]) => { | ||
obs.setOptions(opts); | ||
setState(obs.getOptimisticResult(opts)); | ||
}, | ||
{ | ||
@@ -217,5 +241,6 @@ // Defer because we don't need to trigger on first render | ||
() => { | ||
if (state.isError && !state.isFetching && shouldThrowError(observer.options.throwOnError, [ | ||
const obs = observer(); | ||
if (state.isError && !state.isFetching && !isRestoring() && shouldThrowError(obs.options.throwOnError, [ | ||
state.error, | ||
observer.getCurrentQuery() | ||
obs.getCurrentQuery() | ||
])) { | ||
@@ -266,5 +291,5 @@ throw state.error; | ||
function createMutation(options, queryClient) { | ||
const client = useQueryClient(queryClient?.()); | ||
const client = createMemo(() => useQueryClient(queryClient?.())); | ||
const observer = new MutationObserver( | ||
client, | ||
client(), | ||
options() | ||
@@ -318,11 +343,16 @@ ); | ||
function createQueries(queriesOptions, queryClient) { | ||
const client = useQueryClient(queryClient?.()); | ||
const defaultedQueries = queriesOptions().queries.map((options) => { | ||
const defaultedOptions = client.defaultQueryOptions(options); | ||
defaultedOptions._optimisticResults = "optimistic"; | ||
return defaultedOptions; | ||
}); | ||
const client = createMemo(() => useQueryClient(queryClient?.())); | ||
const isRestoring = useIsRestoring(); | ||
const defaultedQueries = createMemo( | ||
() => queriesOptions().queries.map( | ||
(options) => mergeProps(client().defaultQueryOptions(options), { | ||
get _optimisticResults() { | ||
return isRestoring() ? "isRestoring" : "optimistic"; | ||
} | ||
}) | ||
) | ||
); | ||
const observer = new QueriesObserver( | ||
client, | ||
defaultedQueries, | ||
client(), | ||
defaultedQueries(), | ||
queriesOptions().combine ? { | ||
@@ -333,18 +363,71 @@ combine: queriesOptions().combine | ||
const [state, setState] = createStore( | ||
observer.getOptimisticResult(defaultedQueries)[1]() | ||
observer.getOptimisticResult(defaultedQueries())[1]() | ||
); | ||
const unsubscribe = observer.subscribe((result) => { | ||
notifyManager.batchCalls(() => { | ||
setState(unwrap(result)); | ||
})(); | ||
createRenderEffect( | ||
on( | ||
() => queriesOptions().queries.length, | ||
() => setState(observer.getOptimisticResult(defaultedQueries())[1]()) | ||
) | ||
); | ||
const dataResources = createMemo( | ||
on( | ||
() => state.length, | ||
() => state.map((queryRes) => { | ||
const dataPromise = () => new Promise((resolve) => { | ||
if (queryRes.isFetching && queryRes.isLoading) | ||
return; | ||
resolve(unwrap(queryRes.data)); | ||
}); | ||
return createResource(dataPromise); | ||
}) | ||
) | ||
); | ||
batch(() => { | ||
const dataResources_ = dataResources(); | ||
for (let index = 0; index < dataResources_.length; index++) { | ||
const dataResource = dataResources_[index]; | ||
dataResource[1].mutate(() => unwrap(state[index].data)); | ||
dataResource[1].refetch(); | ||
} | ||
}); | ||
let taskQueue = []; | ||
const subscribeToObserver = () => observer.subscribe((result) => { | ||
taskQueue.push(() => { | ||
batch(() => { | ||
const dataResources_ = dataResources(); | ||
for (let index = 0; index < dataResources_.length; index++) { | ||
const dataResource = dataResources_[index]; | ||
const unwrappedResult = { ...unwrap(result[index]) }; | ||
setState(index, unwrap(unwrappedResult)); | ||
dataResource[1].mutate(() => unwrap(state[index].data)); | ||
dataResource[1].refetch(); | ||
} | ||
}); | ||
}); | ||
queueMicrotask(() => { | ||
const taskToRun = taskQueue.pop(); | ||
if (taskToRun) | ||
taskToRun(); | ||
taskQueue = []; | ||
}); | ||
}); | ||
let unsubscribe = () => void 0; | ||
createComputed((cleanup) => { | ||
cleanup?.(); | ||
unsubscribe = isRestoring() ? () => void 0 : subscribeToObserver(); | ||
return () => queueMicrotask(unsubscribe); | ||
}); | ||
onCleanup(unsubscribe); | ||
onMount(() => { | ||
observer.setQueries( | ||
defaultedQueries(), | ||
queriesOptions().combine ? { | ||
combine: queriesOptions().combine | ||
} : void 0, | ||
{ listeners: false } | ||
); | ||
}); | ||
createComputed(() => { | ||
const updatedQueries = queriesOptions().queries.map((options) => { | ||
const defaultedOptions = client.defaultQueryOptions(options); | ||
defaultedOptions._optimisticResults = "optimistic"; | ||
return defaultedOptions; | ||
}); | ||
observer.setQueries( | ||
updatedQueries, | ||
defaultedQueries(), | ||
queriesOptions().combine ? { | ||
@@ -356,5 +439,18 @@ combine: queriesOptions().combine | ||
}); | ||
return state; | ||
const handler = (index) => ({ | ||
get(target, prop) { | ||
if (prop === "data") { | ||
return dataResources()[index][0](); | ||
} | ||
return Reflect.get(target, prop); | ||
} | ||
}); | ||
const getProxies = () => state.map((s, index) => { | ||
return new Proxy(s, handler(index)); | ||
}); | ||
const [proxifiedState, setProxifiedState] = createStore(getProxies()); | ||
createRenderEffect(() => setProxifiedState(getProxies())); | ||
return proxifiedState; | ||
} | ||
export { QueryClient, QueryClientContext, QueryClientProvider, createInfiniteQuery, createMutation, createQueries, createQuery, queryOptions, useIsFetching, useIsMutating, useQueryClient }; | ||
export { IsRestoringProvider, QueryClient, QueryClientContext, QueryClientProvider, createInfiniteQuery, createMutation, createQueries, createQuery, queryOptions, useIsFetching, useIsMutating, useIsRestoring, useQueryClient }; |
{ | ||
"name": "@tanstack/solid-query", | ||
"version": "5.0.0-beta.20", | ||
"version": "5.0.0-beta.21", | ||
"description": "Primitives for managing, caching and syncing asynchronous and remote data in Solid", | ||
@@ -5,0 +5,0 @@ "author": "tannerlinsley", |
@@ -11,4 +11,7 @@ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ | ||
createResource, | ||
createSignal, | ||
mergeProps, | ||
on, | ||
onCleanup, | ||
untrack, | ||
} from 'solid-js' | ||
@@ -18,2 +21,3 @@ import { createStore, reconcile, unwrap } from 'solid-js/store' | ||
import { shouldThrowError } from './utils' | ||
import { useIsRestoring } from './isRestoring' | ||
import type { CreateBaseQueryOptions } from './types' | ||
@@ -109,14 +113,27 @@ import type { Accessor } from 'solid-js' | ||
const client = createMemo(() => useQueryClient(queryClient?.())) | ||
const isRestoring = useIsRestoring() | ||
const defaultedOptions = client().defaultQueryOptions(options()) | ||
defaultedOptions._optimisticResults = 'optimistic' | ||
defaultedOptions.structuralSharing = false | ||
if (isServer) { | ||
defaultedOptions.retry = false | ||
defaultedOptions.throwOnError = true | ||
} | ||
const observer = new Observer(client(), defaultedOptions) | ||
const defaultedOptions = createMemo(() => | ||
mergeProps(client().defaultQueryOptions(options()), { | ||
get _optimisticResults() { | ||
return isRestoring() ? 'isRestoring' : 'optimistic' | ||
}, | ||
structuralSharing: false, | ||
...(isServer && { retry: false, throwOnError: true }), | ||
}), | ||
) | ||
const [observer, setObserver] = createSignal( | ||
new Observer(client(), untrack(defaultedOptions)), | ||
) | ||
// we set the value in a computed because `createMemo` | ||
// returns undefined during transitions | ||
createComputed( | ||
on(client, (c) => setObserver(new Observer(c, defaultedOptions())), { | ||
defer: true, | ||
}), | ||
) | ||
const [state, setState] = createStore<QueryObserverResult<TData, TError>>( | ||
observer.getOptimisticResult(defaultedOptions), | ||
observer().getOptimisticResult(defaultedOptions()), | ||
) | ||
@@ -130,5 +147,5 @@ | ||
) => { | ||
return observer.subscribe((result) => { | ||
return observer().subscribe((result) => { | ||
notifyManager.batchCalls(() => { | ||
const query = observer.getCurrentQuery() | ||
const query = observer().getCurrentQuery() | ||
const unwrappedResult = hydrateableObserverResult(query, result) | ||
@@ -146,28 +163,26 @@ | ||
const createClientSubscriber = () => { | ||
return observer.subscribe((result) => { | ||
const obs = observer() | ||
return obs.subscribe((result) => { | ||
notifyManager.batchCalls(() => { | ||
// @ts-expect-error - This will error because the reconcile option does not | ||
// exist on the query-core QueryObserverResult type | ||
const reconcileOptions = observer.options.reconcile | ||
const reconcileOptions = obs.options.reconcile | ||
setState((store) => { | ||
return reconcileFn( | ||
store, | ||
result, | ||
reconcileOptions === undefined ? 'id' : reconcileOptions, | ||
) | ||
}) | ||
// If the query has data we dont suspend but instead mutate the resource | ||
// This could happen when placeholderData/initialData is defined | ||
if (queryResource()?.data && result.data && !queryResource.loading) { | ||
setState((store) => { | ||
return reconcileFn( | ||
store, | ||
result, | ||
reconcileOptions === undefined ? 'id' : reconcileOptions, | ||
) | ||
}) | ||
if ( | ||
queryResource()?.data && | ||
result.data && | ||
!queryResource.loading && | ||
isRestoring() | ||
) | ||
mutate(state) | ||
} else { | ||
setState((store) => { | ||
return reconcileFn( | ||
store, | ||
result, | ||
reconcileOptions === undefined ? 'id' : reconcileOptions, | ||
) | ||
}) | ||
refetch() | ||
} | ||
else refetch() | ||
})() | ||
@@ -186,13 +201,12 @@ }) | ||
() => { | ||
const obs = observer() | ||
return new Promise((resolve, reject) => { | ||
if (isServer) { | ||
unsubscribe = createServerSubscriber(resolve, reject) | ||
} else { | ||
if (!unsubscribe) { | ||
unsubscribe = createClientSubscriber() | ||
} | ||
} | ||
if (isServer) unsubscribe = createServerSubscriber(resolve, reject) | ||
else if (!unsubscribe && !isRestoring()) | ||
unsubscribe = createClientSubscriber() | ||
if (!state.isLoading) { | ||
const query = observer.getCurrentQuery() | ||
obs.updateResult() | ||
if (!state.isLoading && !isRestoring()) { | ||
const query = obs.getCurrentQuery() | ||
resolve(hydrateableObserverResult(query, state)) | ||
@@ -206,3 +220,5 @@ } | ||
// If initialData is provided, we resolve the resource immediately | ||
ssrLoadFrom: options().initialData ? 'initial' : 'server', | ||
get ssrLoadFrom() { | ||
return options().initialData ? 'initial' : 'server' | ||
}, | ||
@@ -222,2 +238,3 @@ get deferStream() { | ||
onHydrated(_k, info) { | ||
const defaultOptions = defaultedOptions() | ||
if (info.value) { | ||
@@ -227,4 +244,4 @@ hydrate(client(), { | ||
{ | ||
queryKey: defaultedOptions.queryKey, | ||
queryHash: defaultedOptions.queryHash, | ||
queryKey: defaultOptions.queryKey, | ||
queryHash: defaultOptions.queryHash, | ||
state: info.value, | ||
@@ -236,17 +253,16 @@ }, | ||
if (!unsubscribe) { | ||
/** | ||
* Do not refetch query on mount if query was fetched on server, | ||
* even if `staleTime` is not set. | ||
*/ | ||
const newOptions = { ...defaultedOptions } | ||
if (defaultedOptions.staleTime || !defaultedOptions.initialData) { | ||
newOptions.refetchOnMount = false | ||
} | ||
// Setting the options as an immutable object to prevent | ||
// wonky behavior with observer subscriptions | ||
observer.setOptions(newOptions) | ||
setState(observer.getOptimisticResult(newOptions)) | ||
unsubscribe = createClientSubscriber() | ||
if (unsubscribe) return | ||
/** | ||
* Do not refetch query on mount if query was fetched on server, | ||
* even if `staleTime` is not set. | ||
*/ | ||
const newOptions = { ...defaultOptions } | ||
if (defaultOptions.staleTime || !defaultOptions.initialData) { | ||
newOptions.refetchOnMount = false | ||
} | ||
// Setting the options as an immutable object to prevent | ||
// wonky behavior with observer subscriptions | ||
observer().setOptions(newOptions) | ||
setState(observer().getOptimisticResult(newOptions)) | ||
unsubscribe = createClientSubscriber() | ||
}, | ||
@@ -256,2 +272,15 @@ }, | ||
createComputed( | ||
on( | ||
[isRestoring, observer], | ||
([restoring]) => { | ||
const unsub = unsubscribe | ||
queueMicrotask(() => unsub?.()) | ||
unsubscribe = null | ||
if (!restoring) refetch() | ||
}, | ||
{ defer: true }, | ||
), | ||
) | ||
onCleanup(() => { | ||
@@ -266,4 +295,7 @@ if (unsubscribe) { | ||
on( | ||
() => client().defaultQueryOptions(options()), | ||
() => observer.setOptions(client().defaultQueryOptions(options())), | ||
[observer, defaultedOptions], | ||
([obs, opts]) => { | ||
obs.setOptions(opts) | ||
setState(obs.getOptimisticResult(opts)) | ||
}, | ||
{ | ||
@@ -281,8 +313,10 @@ // Defer because we don't need to trigger on first render | ||
() => { | ||
const obs = observer() | ||
if ( | ||
state.isError && | ||
!state.isFetching && | ||
shouldThrowError(observer.options.throwOnError, [ | ||
!isRestoring() && | ||
shouldThrowError(obs.options.throwOnError, [ | ||
state.error, | ||
observer.getCurrentQuery(), | ||
obs.getCurrentQuery(), | ||
]) | ||
@@ -289,0 +323,0 @@ ) { |
import { MutationObserver } from '@tanstack/query-core' | ||
import { createComputed, on, onCleanup } from 'solid-js' | ||
import { createComputed, createMemo, on, onCleanup } from 'solid-js' | ||
import { createStore } from 'solid-js/store' | ||
@@ -25,6 +25,6 @@ import { useQueryClient } from './QueryClientProvider' | ||
): CreateMutationResult<TData, TError, TVariables, TContext> { | ||
const client = useQueryClient(queryClient?.()) | ||
const client = createMemo(() => useQueryClient(queryClient?.())) | ||
const observer = new MutationObserver<TData, TError, TVariables, TContext>( | ||
client, | ||
client(), | ||
options(), | ||
@@ -31,0 +31,0 @@ ) |
@@ -1,5 +0,17 @@ | ||
import { QueriesObserver, notifyManager } from '@tanstack/query-core' | ||
import { createComputed, onCleanup } from 'solid-js' | ||
import { QueriesObserver } from '@tanstack/query-core' | ||
import { createStore, unwrap } from 'solid-js/store' | ||
import { | ||
batch, | ||
createComputed, | ||
createMemo, | ||
createRenderEffect, | ||
createResource, | ||
mergeProps, | ||
on, | ||
onCleanup, | ||
onMount, | ||
} from 'solid-js' | ||
import { useQueryClient } from './QueryClientProvider' | ||
import { useIsRestoring } from './isRestoring' | ||
import type { CreateQueryResult, SolidQueryOptions } from './types' | ||
import type { Accessor } from 'solid-js' | ||
@@ -13,4 +25,4 @@ import type { QueryClient } from './QueryClient' | ||
QueryKey, | ||
QueryObserverResult, | ||
} from '@tanstack/query-core' | ||
import type { CreateQueryResult, SolidQueryOptions } from './types' | ||
@@ -163,3 +175,3 @@ // This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`. | ||
T extends Array<any>, | ||
TCombinedResult = QueriesResults<T>, | ||
TCombinedResult extends QueriesResults<T> = QueriesResults<T>, | ||
>( | ||
@@ -172,13 +184,18 @@ queriesOptions: Accessor<{ | ||
): TCombinedResult { | ||
const client = useQueryClient(queryClient?.()) | ||
const client = createMemo(() => useQueryClient(queryClient?.())) | ||
const isRestoring = useIsRestoring() | ||
const defaultedQueries = queriesOptions().queries.map((options) => { | ||
const defaultedOptions = client.defaultQueryOptions(options) | ||
defaultedOptions._optimisticResults = 'optimistic' | ||
return defaultedOptions | ||
}) | ||
const defaultedQueries = createMemo(() => | ||
queriesOptions().queries.map((options) => | ||
mergeProps(client().defaultQueryOptions(options), { | ||
get _optimisticResults() { | ||
return isRestoring() ? 'isRestoring' : 'optimistic' | ||
}, | ||
}), | ||
), | ||
) | ||
const observer = new QueriesObserver( | ||
client, | ||
defaultedQueries, | ||
client(), | ||
defaultedQueries(), | ||
queriesOptions().combine | ||
@@ -191,23 +208,85 @@ ? ({ | ||
// @ts-expect-error - Types issue with solid-js createStore | ||
const [state, setState] = createStore<TCombinedResult>( | ||
observer.getOptimisticResult(defaultedQueries)[1](), | ||
observer.getOptimisticResult(defaultedQueries())[1](), | ||
) | ||
const unsubscribe = observer.subscribe((result) => { | ||
notifyManager.batchCalls(() => { | ||
setState(unwrap(result) as unknown as TCombinedResult) | ||
})() | ||
createRenderEffect( | ||
on( | ||
() => queriesOptions().queries.length, | ||
() => setState(observer.getOptimisticResult(defaultedQueries())[1]()), | ||
), | ||
) | ||
const dataResources = createMemo( | ||
on( | ||
() => state.length, | ||
() => | ||
state.map((queryRes) => { | ||
const dataPromise = () => | ||
new Promise((resolve) => { | ||
if (queryRes.isFetching && queryRes.isLoading) return | ||
resolve(unwrap(queryRes.data)) | ||
}) | ||
return createResource(dataPromise) | ||
}), | ||
), | ||
) | ||
batch(() => { | ||
const dataResources_ = dataResources() | ||
for (let index = 0; index < dataResources_.length; index++) { | ||
const dataResource = dataResources_[index]! | ||
dataResource[1].mutate(() => unwrap(state[index]!.data)) | ||
dataResource[1].refetch() | ||
} | ||
}) | ||
let taskQueue: Array<() => void> = [] | ||
const subscribeToObserver = () => | ||
observer.subscribe((result) => { | ||
taskQueue.push(() => { | ||
batch(() => { | ||
const dataResources_ = dataResources() | ||
for (let index = 0; index < dataResources_.length; index++) { | ||
const dataResource = dataResources_[index]! | ||
const unwrappedResult = { ...unwrap(result[index]!) } | ||
// @ts-expect-error typescript pedantry regarding the possible range of index | ||
setState(index, unwrap(unwrappedResult)) | ||
dataResource[1].mutate(() => unwrap(state[index]!.data)) | ||
dataResource[1].refetch() | ||
} | ||
}) | ||
}) | ||
queueMicrotask(() => { | ||
const taskToRun = taskQueue.pop() | ||
if (taskToRun) taskToRun() | ||
taskQueue = [] | ||
}) | ||
}) | ||
let unsubscribe: () => void = () => undefined | ||
createComputed<() => void>((cleanup) => { | ||
cleanup?.() | ||
unsubscribe = isRestoring() ? () => undefined : subscribeToObserver() | ||
// cleanup needs to be scheduled after synchronous effects take place | ||
return () => queueMicrotask(unsubscribe) | ||
}) | ||
onCleanup(unsubscribe) | ||
onMount(() => { | ||
observer.setQueries( | ||
defaultedQueries(), | ||
queriesOptions().combine | ||
? ({ | ||
combine: queriesOptions().combine, | ||
} as QueriesObserverOptions<TCombinedResult>) | ||
: undefined, | ||
{ listeners: false }, | ||
) | ||
}) | ||
createComputed(() => { | ||
const updatedQueries = queriesOptions().queries.map((options) => { | ||
const defaultedOptions = client.defaultQueryOptions(options) | ||
defaultedOptions._optimisticResults = 'optimistic' | ||
return defaultedOptions | ||
}) | ||
observer.setQueries( | ||
updatedQueries, | ||
defaultedQueries(), | ||
queriesOptions().combine | ||
@@ -222,3 +301,20 @@ ? ({ | ||
return state | ||
const handler = (index: number) => ({ | ||
get(target: QueryObserverResult, prop: keyof QueryObserverResult): any { | ||
if (prop === 'data') { | ||
return dataResources()[index]![0]() | ||
} | ||
return Reflect.get(target, prop) | ||
}, | ||
}) | ||
const getProxies = () => | ||
state.map((s, index) => { | ||
return new Proxy(s, handler(index)) | ||
}) | ||
const [proxifiedState, setProxifiedState] = createStore(getProxies()) | ||
createRenderEffect(() => setProxifiedState(getProxies())) | ||
return proxifiedState as TCombinedResult | ||
} |
@@ -30,1 +30,2 @@ /* istanbul ignore file */ | ||
export { createQueries } from './createQueries' | ||
export { useIsRestoring, IsRestoringProvider } from './isRestoring' |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
436385
34
13337