@@ -18,9 +18,11 @@ import type { CreateBaseQueryOptions } from './types'
1818import type { Accessor } from 'solid-js'
1919import type { QueryClient } from './QueryClient'
2020import type {
21+ Query ,
2122 QueryKey ,
2223 QueryObserver ,
2324 QueryObserverResult ,
25+ QueryState ,
2426} from '@tanstack/query-core'
2527
2628function reconcileFn < TData , TError > (
@@ -40,6 +42,49 @@ function reconcileFn<TData, TError>(
4042 return { ...result , data : newData } as typeof result
4143}
4244
45+ type HydrateableQueryState < TData , TError > = QueryObserverResult < TData , TError > &
46+ QueryState < TData , TError >
47+
48+ /**
49+ * Solid's `onHydrated` functionality will silently "fail" (hydrate with an empty object)
50+ * if the resource data is not serializable.
51+ */
52+ const hydrateableObserverResult = <
53+ TQueryFnData ,
54+ TError ,
55+ TData ,
56+ TQueryKey extends QueryKey ,
57+ T2 ,
58+ > (
59+ query : Query < TQueryFnData , TError , TData , TQueryKey > ,
60+ result : QueryObserverResult < T2 , TError > ,
61+ ) : HydrateableQueryState < T2 , TError > => {
62+ // Including the extra properties is only relevant on the server
63+ if ( ! isServer ) return result as HydrateableQueryState < T2 , TError >
64+
65+ return {
66+ ...unwrap ( result ) ,
67+
68+ // cast to refetch function should be safe, since we only remove it on the server,
69+ // and refetch is not relevant on the server
70+ refetch : undefined as unknown as HydrateableQueryState <
71+ T2 ,
72+ TError
73+ > [ 'refetch' ] ,
74+
75+ // hydrate() expects a QueryState object, which is similar but not
76+ // quite the same as a QueryObserverResult object. Thus, for now, we're
77+ // copying over the missing properties from state in order to support hydration
78+ dataUpdateCount : query . state . dataUpdateCount ,
79+ fetchFailureCount : query . state . fetchFailureCount ,
80+ isInvalidated : query . state . isInvalidated ,
81+
82+ // Unsetting these properties on the server since they might not be serializable
83+ fetchFailureReason : null ,
84+ fetchMeta : null ,
85+ }
86+ }
87+
4388// Base Query Function that is used to create the query.
4489export function createBaseQuery <
4590 TQueryFnData ,
@@ -54,6 +99,10 @@ export function createBaseQuery<
5499 Observer : typeof QueryObserver ,
55100 queryClient ?: Accessor < QueryClient > ,
56101) {
102+ type ResourceData =
103+ | HydrateableQueryState < TData , TError >
104+ | QueryObserverResult < TData , TError >
105+
57106 const client = createMemo ( ( ) => useQueryClient ( queryClient ?.( ) ) )
58107
59108 const defaultedOptions = client ( ) . defaultQueryOptions ( options ( ) )
@@ -71,41 +120,19 @@ export function createBaseQuery<
71120
72121 const createServerSubscriber = (
73122 resolve : (
74- data :
75- | QueryObserverResult < TData , TError >
76- | PromiseLike < QueryObserverResult < TData , TError > | undefined >
77- | undefined ,
123+ data : ResourceData | PromiseLike < ResourceData | undefined > | undefined ,
78124 ) => void ,
79125 reject : ( reason ?: any ) => void ,
80126 ) => {
81127 return observer . subscribe ( ( result ) => {
82128 notifyManager . batchCalls ( ( ) => {
83129 const query = observer . getCurrentQuery ( )
84- const { refetch, ...rest } = unwrap ( result )
85- const unwrappedResult = {
86- ...rest ,
87-
88- // hydrate() expects a QueryState object, which is similar but not
89- // quite the same as a QueryObserverResult object. Thus, for now, we're
90- // copying over the missing properties from state in order to support hydration
91- dataUpdateCount : query . state . dataUpdateCount ,
92- fetchFailureCount : query . state . fetchFailureCount ,
93- // Removing these properties since they might not be serializable
94- // fetchFailureReason: query.state.fetchFailureReason,
95- // fetchMeta: query.state.fetchMeta,
96- isInvalidated : query . state . isInvalidated ,
97- }
130+ const unwrappedResult = hydrateableObserverResult ( query , result )
98131
99132 if ( unwrappedResult . isError ) {
100- if ( process . env [ 'NODE_ENV' ] === 'development' ) {
101- console . error ( unwrappedResult . error )
102- }
103133 reject ( unwrappedResult . error )
104- }
105- if ( unwrappedResult . isSuccess ) {
106- // Use of any here is fine
107- // We cannot include refetch since it is not serializable
108- resolve ( unwrappedResult as any )
134+ } else {
135+ resolve ( unwrappedResult )
109136 }
110137 } ) ( )
111138 } )
@@ -148,7 +175,7 @@ export function createBaseQuery<
148175 let unsubscribe : ( ( ) => void ) | null = null
149176
150177 const [ queryResource , { refetch, mutate } ] = createResource <
151- QueryObserverResult < TData , TError > | undefined
178+ ResourceData | undefined
152179 > (
153180 ( ) => {
154181 return new Promise ( ( resolve , reject ) => {
@@ -159,8 +186,10 @@ export function createBaseQuery<
159186 unsubscribe = createClientSubscriber ( )
160187 }
161188 }
189+
162190 if ( ! state . isLoading ) {
163- resolve ( state )
191+ const query = observer . getCurrentQuery ( )
192+ resolve ( hydrateableObserverResult ( query , state ) )
164193 }
165194 } )
166195 } ,
0 commit comments