rx-query
Version:
215 lines • 8.98 kB
JavaScript
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
;