Skip to content

Commit a39bddd

Browse files
committed
chore(core): update query-core
1 parent 84c6428 commit a39bddd

File tree

9 files changed

+112
-70
lines changed

9 files changed

+112
-70
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@sveltestack/svelte-query",
33
"private": false,
4-
"version": "1.0.6",
4+
"version": "1.0.7",
55
"description": "Hooks for managing, caching and syncing asynchronous and remote data in Svelte",
66
"license": "MIT",
77
"svelte": "svelte/index.js",

src/queryCore/core/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export { CancelledError } from './retryer'
12
export { QueryCache } from './queryCache'
23
export { QueryClient } from './queryClient'
34
export { QueryObserver } from './queryObserver'
@@ -14,6 +15,5 @@ export { isCancelledError } from './retryer'
1415

1516
// Types
1617
export * from './types'
17-
export type { CancelledError } from './retryer'
1818
export type { Query as QueryCore } from './query'
1919
export type { Logger } from './logger'

src/queryCore/core/infiniteQueryBehavior.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export function infiniteQueryBehavior<
1717
const oldPages = context.state.data?.pages || []
1818
const oldPageParams = context.state.data?.pageParams || []
1919
let newPageParams = oldPageParams
20+
let cancelled = false
2021

2122
// Get query function
2223
const queryFn =
@@ -29,6 +30,10 @@ export function infiniteQueryBehavior<
2930
param?: unknown,
3031
previous?: boolean
3132
): Promise<unknown[]> => {
33+
if (cancelled) {
34+
return Promise.reject('Cancelled')
35+
}
36+
3237
if (typeof param === 'undefined' && !manual && pages.length) {
3338
return Promise.resolve(pages)
3439
}
@@ -38,11 +43,7 @@ export function infiniteQueryBehavior<
3843
pageParam: param,
3944
}
4045

41-
let cancelFn: undefined | (() => any)
4246
const queryFnResult = queryFn(queryFnContext)
43-
if ((queryFnResult as any).cancel) {
44-
cancelFn = (queryFnResult as any).cancel
45-
}
4647

4748
const promise = Promise.resolve(queryFnResult).then(page => {
4849
newPageParams = previous
@@ -51,15 +52,15 @@ export function infiniteQueryBehavior<
5152
return previous ? [page, ...pages] : [...pages, page]
5253
})
5354

54-
if (cancelFn) {
55+
if (isCancelable(queryFnResult)) {
5556
const promiseAsAny = promise as any
56-
promiseAsAny.cancel = cancelFn
57+
promiseAsAny.cancel = queryFnResult.cancel
5758
}
5859

5960
return promise
6061
}
6162

62-
let promise
63+
let promise: Promise<unknown[]>
6364

6465
// Fetch first page?
6566
if (!oldPages.length) {
@@ -109,9 +110,13 @@ export function infiniteQueryBehavior<
109110
pageParams: newPageParams,
110111
}))
111112

112-
if (isCancelable(promise)) {
113-
const finalPromiseAsAny = finalPromise as any
114-
finalPromiseAsAny.cancel = promise.cancel
113+
const finalPromiseAsAny = finalPromise as any
114+
115+
finalPromiseAsAny.cancel = () => {
116+
cancelled = true
117+
if (isCancelable(promise)) {
118+
promise.cancel()
119+
}
115120
}
116121

117122
return finalPromise

src/queryCore/core/mutationObserver.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ export class MutationObserver<
116116

117117
this.currentMutation = this.client.getMutationCache().build(this.client, {
118118
...this.options,
119-
variables: variables ?? this.options.variables,
119+
variables:
120+
typeof variables !== 'undefined' ? variables : this.options.variables,
120121
})
121122

122123
this.currentMutation.addObserver(this)

src/queryCore/core/onlineManager.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,14 @@ class OnlineManager extends Subscribable {
4545
return this.online
4646
}
4747

48-
return navigator.onLine === undefined || navigator.onLine
48+
if (
49+
typeof navigator === 'undefined' ||
50+
typeof navigator.onLine === 'undefined'
51+
) {
52+
return true
53+
}
54+
55+
return navigator.onLine
4956
}
5057

5158
private setDefaultEventListener() {

src/queryCore/core/query.ts

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export class Query<
135135
private cache: QueryCache
136136
private promise?: Promise<TData>
137137
private gcTimeout?: number
138-
private retryer?: Retryer<unknown, TError>
138+
private retryer?: Retryer<TData, TError>
139139
private observers: QueryObserver<any, any, any, any>[]
140140
private defaultOptions?: QueryOptions<TQueryFnData, TError, TData>
141141

@@ -388,28 +388,21 @@ export class Query<
388388

389389
// Try to fetch the data
390390
this.retryer = new Retryer({
391-
fn: context.fetchFn,
392-
onFail: () => {
393-
this.dispatch({ type: 'failed' })
394-
},
395-
onPause: () => {
396-
this.dispatch({ type: 'pause' })
397-
},
398-
onContinue: () => {
399-
this.dispatch({ type: 'continue' })
400-
},
401-
retry: context.options.retry,
402-
retryDelay: context.options.retryDelay,
403-
})
391+
fn: context.fetchFn as () => TData,
392+
onSuccess: data => {
393+
this.setData(data as TData)
404394

405-
this.promise = this.retryer.promise
406-
.then(data => this.setData(data as TData))
407-
.catch(error => {
408-
// Set error state if needed
395+
// Remove query after fetching if cache time is 0
396+
if (this.cacheTime === 0) {
397+
this.optionalRemove()
398+
}
399+
},
400+
onError: error => {
401+
// Optimistically update state if needed
409402
if (!(isCancelledError(error) && error.silent)) {
410403
this.dispatch({
411404
type: 'error',
412-
error,
405+
error: error as TError,
413406
})
414407
}
415408

@@ -427,18 +420,21 @@ export class Query<
427420
if (this.cacheTime === 0) {
428421
this.optionalRemove()
429422
}
423+
},
424+
onFail: () => {
425+
this.dispatch({ type: 'failed' })
426+
},
427+
onPause: () => {
428+
this.dispatch({ type: 'pause' })
429+
},
430+
onContinue: () => {
431+
this.dispatch({ type: 'continue' })
432+
},
433+
retry: context.options.retry,
434+
retryDelay: context.options.retryDelay,
435+
})
430436

431-
// Propagate error
432-
throw error
433-
})
434-
.then(data => {
435-
// Remove query after fetching if cache time is 0
436-
if (this.cacheTime === 0) {
437-
this.optionalRemove()
438-
}
439-
440-
return data
441-
})
437+
this.promise = this.retryer.promise
442438

443439
return this.promise
444440
}

src/queryCore/core/queryCache.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
109109
arg2?: QueryFilters
110110
): Query<TQueryFnData, TError, TData> | undefined {
111111
const [filters] = parseFilterArgs(arg1, arg2)
112+
113+
if (typeof filters.exact === 'undefined') {
114+
filters.exact = true
115+
}
116+
112117
return this.queries.find(query => matchQuery(filters, query))
113118
}
114119

src/queryCore/core/queryObserver.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ export class QueryObserver<
4949
private currentQuery!: Query<TQueryFnData, TError, TQueryData>
5050
private currentResult!: QueryObserverResult<TData, TError>
5151
private currentResultState?: QueryState<TQueryData, TError>
52+
private previousOptions?: QueryObserverOptions<
53+
TQueryFnData,
54+
TError,
55+
TData,
56+
TQueryData
57+
>
5258
private previousQueryResult?: QueryObserverResult<TData, TError>
5359
private initialDataUpdateCount: number
5460
private initialErrorUpdateCount: number
@@ -155,8 +161,7 @@ export class QueryObserver<
155161
setOptions(
156162
options?: QueryObserverOptions<TQueryFnData, TError, TData, TQueryData>
157163
): void {
158-
const prevOptions = this.options
159-
164+
this.previousOptions = this.options
160165
this.options = this.client.defaultQueryObserverOptions(options)
161166

162167
if (
@@ -168,39 +173,49 @@ export class QueryObserver<
168173

169174
// Keep previous query key if the user does not supply one
170175
if (!this.options.queryKey) {
171-
this.options.queryKey = prevOptions.queryKey
176+
this.options.queryKey = this.previousOptions.queryKey
172177
}
173178

174179
const didUpdateQuery = this.updateQuery()
175180

176181
let optionalFetch
182+
let updateResult
177183
let updateStaleTimeout
178184
let updateRefetchInterval
179185

180-
// If we subscribed to a new query, optionally fetch and update intervals
186+
// If we subscribed to a new query, optionally fetch and update result and timers
181187
if (didUpdateQuery) {
182188
optionalFetch = true
189+
updateResult = true
183190
updateStaleTimeout = true
184191
updateRefetchInterval = true
185192
}
186193

187194
// Optionally fetch if the query became enabled
188-
if (this.options.enabled !== false && prevOptions.enabled === false) {
195+
if (
196+
this.options.enabled !== false &&
197+
this.previousOptions.enabled === false
198+
) {
189199
optionalFetch = true
190200
}
191201

202+
// Update result if the select function changed
203+
if (this.options.select !== this.previousOptions.select) {
204+
updateResult = true
205+
}
206+
192207
// Update stale interval if needed
193208
if (
194-
this.options.enabled !== prevOptions.enabled ||
195-
this.options.staleTime !== prevOptions.staleTime
209+
this.options.enabled !== this.previousOptions.enabled ||
210+
this.options.staleTime !== this.previousOptions.staleTime
196211
) {
197212
updateStaleTimeout = true
198213
}
199214

200215
// Update refetch interval if needed
201216
if (
202-
this.options.enabled !== prevOptions.enabled ||
203-
this.options.refetchInterval !== prevOptions.refetchInterval
217+
this.options.enabled !== this.previousOptions.enabled ||
218+
this.options.refetchInterval !== this.previousOptions.refetchInterval
204219
) {
205220
updateRefetchInterval = true
206221
}
@@ -212,8 +227,7 @@ export class QueryObserver<
212227
}
213228
}
214229

215-
// Update result when subscribing to a new query
216-
if (didUpdateQuery) {
230+
if (updateResult) {
217231
this.updateResult()
218232
}
219233

@@ -399,8 +413,12 @@ export class QueryObserver<
399413
}
400414
// Select data if needed
401415
else if (this.options.select && typeof state.data !== 'undefined') {
402-
// Use the previous select result if the query data did not change
403-
if (this.currentResult && state.data === this.currentResultState?.data) {
416+
// Use the previous select result if the query data and select function did not change
417+
if (
418+
this.currentResult &&
419+
state.data === this.currentResultState?.data &&
420+
this.options.select === this.previousOptions?.select
421+
) {
404422
data = this.currentResult.data
405423
} else {
406424
data = this.options.select(state.data)

src/queryCore/core/retryer.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { functionalUpdate, sleep } from './utils'
66

77
interface RetryerConfig<TData = unknown, TError = unknown> {
88
fn: () => TData | Promise<TData>
9+
onError?: (error: TError) => void
10+
onSuccess?: (data: TData) => void
911
onFail?: (failureCount: number, error: TError) => void
1012
onPause?: () => void
1113
onContinue?: () => void
@@ -88,15 +90,21 @@ export class Retryer<TData = unknown, TError = unknown> {
8890
})
8991

9092
const resolve = (value: any) => {
91-
this.isResolved = true
92-
continueFn?.()
93-
promiseResolve(value)
93+
if (!this.isResolved) {
94+
this.isResolved = true
95+
config.onSuccess?.(value)
96+
continueFn?.()
97+
promiseResolve(value)
98+
}
9499
}
95100

96101
const reject = (value: any) => {
97-
this.isResolved = true
98-
continueFn?.()
99-
promiseReject(value)
102+
if (!this.isResolved) {
103+
this.isResolved = true
104+
config.onError?.(value)
105+
continueFn?.()
106+
promiseReject(value)
107+
}
100108
}
101109

102110
const pause = () => {
@@ -129,13 +137,15 @@ export class Retryer<TData = unknown, TError = unknown> {
129137

130138
// Create callback to cancel this fetch
131139
cancelFn = cancelOptions => {
132-
reject(new CancelledError(cancelOptions))
133-
134-
// Cancel transport if supported
135-
if (isCancelable(promiseOrValue)) {
136-
try {
137-
promiseOrValue.cancel()
138-
} catch {}
140+
if (!this.isResolved) {
141+
reject(new CancelledError(cancelOptions))
142+
143+
// Cancel transport if supported
144+
if (isCancelable(promiseOrValue)) {
145+
try {
146+
promiseOrValue.cancel()
147+
} catch {}
148+
}
139149
}
140150
}
141151

0 commit comments

Comments
 (0)