UNPKG

rx-query

Version:
215 lines 8.98 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.query = void 0; const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); const cache_1 = require("./cache"); const config_1 = require("./config"); const key_1 = require("./key"); const mutate_1 = require("./mutate"); function query(key, ...inputs) { const { query, queryParam, queryConfig } = parseInput(inputs); const retryCondition = createRetryCondition(queryConfig); const retryDelay = createRetryDelay(queryConfig); const invokeQuery = (loadingStatus, queryParameters) => { const invoke = (retries) => { return query(queryParameters).pipe((0, operators_1.map)((data) => { return { status: 'success', data: data, }; }), (0, operators_1.catchError)((error) => { return (0, rxjs_1.of)({ status: 'error', error, retries, }); })); }; const mutateQuery = (data, updater) => { const cacheKey = (0, key_1.createQueryKey)(key, queryParameters); const mutate$ = queryConfig.mutator(data, { queryParameters, cacheKey }); if ((0, rxjs_1.isObservable)(mutate$)) { mutate$ .pipe((0, operators_1.map)((newData) => () => (0, mutate_1.mutateSuccess)(cacheKey, newData)), (0, operators_1.take)(1), (0, operators_1.startWith)(() => (0, mutate_1.mutateOptimistic)(cacheKey, updater || data))) .subscribe({ next: (evt) => evt(), error: (errorData) => (0, mutate_1.mutateError)(cacheKey, errorData), }); return; } (0, mutate_1.mutateSuccess)(cacheKey, mutate$); }; const callResult$ = (0, rxjs_1.defer)(() => invoke(0).pipe((0, operators_1.expand)((result) => { if (result.status === 'error' && retryCondition(result.retries || 0, result.error)) { return (0, rxjs_1.timer)(retryDelay(result.retries || 0)).pipe((0, operators_1.concatMap)(() => invoke((result.retries || 0) + 1)), // retry internally // for consumers we're still loading (0, operators_1.startWith)({ ...result, status: loadingStatus, })); } return rxjs_1.EMPTY; }), // prevents that there's multiple emits in the same tick // for when the status is swapped from error to loading (to retry) (0, operators_1.debounceTime)(0), (0, operators_1.map)((r) => { return { ...r, mutate: mutateQuery, }; }))); return callResult$; }; return (0, rxjs_1.defer)(() => { const params$ = paramsTrigger(queryConfig, queryParam, key, invokeQuery); const focus$ = focusTrigger(queryConfig, queryParam, key, invokeQuery); const reconnect$ = reconnectTrigger(queryConfig, queryParam, key, invokeQuery); const interval$ = intervalTrigger(queryConfig, queryParam, key, invokeQuery); const triggersSubscription = (0, rxjs_1.merge)(params$, focus$, reconnect$, interval$) .pipe((0, operators_1.observeOn)(rxjs_1.asyncScheduler)) .subscribe({ next: (c) => cache_1.revalidate.next(c), }); return cache_1.queryCache.pipe((0, operators_1.withLatestFrom)(params$), (0, operators_1.map)(([c, k]) => c[k.key]), (0, operators_1.filter)((v) => !!v && // exclude state changes that are unimportant to the consumer !['query-unsubscribe', 'group-unsubscribe'].includes(v.trigger)), (0, operators_1.map)((v) => v.groupState.result), (0, operators_1.distinctUntilChanged)(), patchDataWithPreviousData(queryConfig.keepPreviousData), (0, operators_1.finalize)(() => { params$.pipe((0, operators_1.take)(1)).subscribe({ next: (params) => { cache_1.revalidate.next({ ...params, trigger: 'query-unsubscribe', }); }, }); triggersSubscription.unsubscribe(); })); }); } exports.query = query; function createRetryDelay(queryConfig) { return typeof queryConfig.retryDelay === 'number' ? () => queryConfig.retryDelay : queryConfig.retryDelay || (() => 0); } function createRetryCondition(queryConfig) { return typeof queryConfig.retries === 'number' ? (n) => n < (queryConfig.retries || 0) : queryConfig.retries || (() => false); } function paramsTrigger(queryConfig, queryParam, key, invokeQuery) { return queryParam.pipe((0, operators_1.startWith)(undefined), (0, operators_1.distinctUntilChanged)((a, b) => JSON.stringify(a) === JSON.stringify(b)), (0, operators_1.pairwise)(), (0, operators_1.concatMap)(([previous, params]) => { const revalidates = []; if (previous !== undefined) { const unsubscribe = { key: (0, key_1.createQueryKey)(key, previous), query: invokeQuery, trigger: 'query-unsubscribe', params: previous, config: queryConfig, }; revalidates.push(unsubscribe); } const init = { key: (0, key_1.createQueryKey)(key, params), query: invokeQuery, trigger: 'query-subscribe', params, config: queryConfig, }; revalidates.push(init); return revalidates; })); } function intervalTrigger(queryConfig, queryParam, key, invokeQuery) { return queryConfig.refetchInterval !== Infinity ? ((0, rxjs_1.isObservable)(queryConfig.refetchInterval) ? queryConfig.refetchInterval : (0, rxjs_1.interval)(queryConfig.refetchInterval)).pipe((0, operators_1.withLatestFrom)(queryParam), (0, operators_1.map)(([_, params]) => { const interval = { key: (0, key_1.createQueryKey)(key, params), query: invokeQuery, trigger: 'interval', params, config: queryConfig, }; return interval; })) : rxjs_1.NEVER; } function focusTrigger(queryConfig, queryParam, key, invokeQuery) { return queryConfig.refetchOnWindowFocus ? (0, rxjs_1.fromEvent)(window, 'focus').pipe((0, operators_1.withLatestFrom)(queryParam), (0, operators_1.map)(([_, params]) => { const focused = { key: (0, key_1.createQueryKey)(key, params), query: invokeQuery, trigger: 'focus', params, config: queryConfig, }; return focused; })) : rxjs_1.NEVER; } function reconnectTrigger(queryConfig, queryParam, key, invokeQuery) { return queryConfig.refetchOnReconnect ? (0, rxjs_1.fromEvent)(window, 'online').pipe((0, operators_1.withLatestFrom)(queryParam), (0, operators_1.map)(([_, params]) => { const reconnected = { key: (0, key_1.createQueryKey)(key, params), query: invokeQuery, trigger: 'reconnect', params, config: queryConfig, }; return reconnected; })) : rxjs_1.NEVER; } function parseInput(inputs) { const [firstInput, secondInput, thirdInput] = inputs; const hasParamInput = typeof firstInput !== 'function'; const queryParam = hasParamInput ? (0, rxjs_1.isObservable)(firstInput) ? firstInput : (0, rxjs_1.of)(firstInput) : (0, rxjs_1.of)(null); const query = (typeof firstInput === 'function' ? firstInput : secondInput); const inputConfig = (hasParamInput ? thirdInput : secondInput); const queryConfig = { ...(0, config_1.getQueryConfig)(), ...inputConfig, }; return { query, queryParam: queryParam.pipe((0, operators_1.shareReplay)({ refCount: true, bufferSize: 1, })), queryConfig, }; } function patchDataWithPreviousData(keepPreviousData) { let data; return (source) => { if (!keepPreviousData) return source; return source.pipe((0, operators_1.map)((value) => { if (data !== undefined && value.data === undefined && value.status === 'loading') { return { ...value, data, status: 'refreshing', }; } data = value.data; return value; })); }; } //# sourceMappingURL=query.js.map