Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/@christian/remote-rainbow-store'…
Browse files Browse the repository at this point in the history
… into @christian/query-store-token-search
  • Loading branch information
christianbaroni committed Jan 10, 2025
2 parents 367f988 + cd887a1 commit 0f96d10
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 34 deletions.
54 changes: 25 additions & 29 deletions src/state/internal/createQueryStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { StateCreator, StoreApi, UseBoundStore, create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
import { IS_DEV } from '@/env';
import { RainbowError, logger } from '@/logger';
import { time } from '@/utils';
import { RainbowPersistConfig, createRainbowStore, omitStoreMethods } from './createRainbowStore';
import { $, AttachValue, SignalFunction, Unsubscribe, attachValueSubscriptionMap } from './signal';

Expand Down Expand Up @@ -353,16 +354,6 @@ const SHOULD_PERSIST_INTERNAL_STATE_MAP: Record<string, boolean> = {

const ABORT_ERROR = new Error('[createQueryStore: AbortError] Fetch interrupted');

export const time = {
seconds: (n: number) => n * 1000,
minutes: (n: number) => time.seconds(n * 60),
hours: (n: number) => time.minutes(n * 60),
days: (n: number) => time.hours(n * 24),
weeks: (n: number) => time.days(n * 7),
infinity: Infinity,
zero: 0,
};

const MIN_STALE_TIME = time.seconds(5);

export function createQueryStore<
Expand Down Expand Up @@ -530,7 +521,7 @@ export function createQueryStore<

const baseMethods = {
async fetch(params: TParams | undefined, options: FetchOptions | undefined) {
const { enabled, status } = get();
const { enabled, error, status } = get();

if (!options?.force && !enabled) return null;

Expand Down Expand Up @@ -563,26 +554,26 @@ export function createQueryStore<
if (!activeRefetchTimeout && subscriptionCount > 0 && staleTime !== 0 && staleTime !== Infinity) {
scheduleNextFetch(effectiveParams, options);
}
if (enableLogs) console.log('[💾 Returning Cached Data 💾] for queryKey: ', currentQueryKey);
if (enableLogs) console.log('[💾 Returning Cached Data 💾] for params:', JSON.stringify(effectiveParams));
if (keepPreviousData && storeQueryKey !== currentQueryKey) set(state => ({ ...state, queryKey: currentQueryKey }));
return cacheEntry?.data ?? null;
}
}

if (!skipStoreUpdates) {
set(state => ({ ...state, error: null, status: QueryStatuses.Loading }));
if (error || !isLoading) set(state => ({ ...state, error: null, status: QueryStatuses.Loading }));
activeFetch = { key: currentQueryKey };
}

const fetchOperation = async () => {
try {
if (enableLogs) console.log('[🔄 Fetching 🔄] for queryKey: ', currentQueryKey, ':: params: ', effectiveParams);
if (enableLogs) console.log('[🔄 Fetching 🔄] for params:', JSON.stringify(effectiveParams));
const rawResult = await (abortInterruptedFetches && !skipStoreUpdates
? fetchWithAbortControl(effectiveParams)
: fetcher(effectiveParams, null));

const lastFetchedAt = Date.now();
if (enableLogs) console.log('[✅ Fetch Successful ✅] for queryKey: ', currentQueryKey);
if (enableLogs) console.log('[✅ Fetch Successful ✅] for params:', JSON.stringify(effectiveParams));

let transformedData: TData;
try {
Expand All @@ -594,7 +585,7 @@ export function createQueryStore<
}

if (skipStoreUpdates) {
if (enableLogs) console.log('[🥷 Successful Parallel Fetch 🥷] for queryKey: ', currentQueryKey);
if (enableLogs) console.log('[🥷 Successful Parallel Fetch 🥷] for params:', JSON.stringify(effectiveParams));
return transformedData;
}

Expand All @@ -610,9 +601,9 @@ export function createQueryStore<
if (!setData && !disableCache) {
if (enableLogs)
console.log(
'[💾 Setting Cache 💾] for queryKey: ',
currentQueryKey,
'Has previous data? ',
'[💾 Setting Cache 💾] for params:',
JSON.stringify(effectiveParams),
'| Has previous data?:',
!!newState.queryCache[currentQueryKey]?.data
);
newState.queryCache = {
Expand All @@ -625,7 +616,7 @@ export function createQueryStore<
},
};
} else if (setData) {
if (enableLogs) console.log('[💾 Setting Data 💾] for queryKey: ', currentQueryKey);
if (enableLogs) console.log('[💾 Setting Data 💾] for params:\n', JSON.stringify(effectiveParams));
setData({
data: transformedData,
params: effectiveParams,
Expand Down Expand Up @@ -670,7 +661,7 @@ export function createQueryStore<
return transformedData ?? null;
} catch (error) {
if (error === ABORT_ERROR) {
if (enableLogs) console.log('[❌ Fetch Aborted ❌] for queryKey: ', currentQueryKey);
if (enableLogs) console.log('[❌ Fetch Aborted ❌] for params:', JSON.stringify(effectiveParams));
return null;
}

Expand Down Expand Up @@ -820,7 +811,7 @@ export function createQueryStore<
const currentParams = getCurrentResolvedParams();
const currentKey = state.queryKey;
if (currentKey !== lastFetchKey || state.isStale()) {
state.fetch(currentParams, undefined);
state.fetch(currentParams);
} else {
scheduleNextFetch(currentParams, undefined);
}
Expand All @@ -836,18 +827,23 @@ export function createQueryStore<
fetchAfterParamCreation = true;
return;
}
const { enabled, fetch, isStale, subscriptionCount } = get();
const currentParams = getCurrentResolvedParams();
const currentQueryKey = getQueryKey(currentParams);
const { enabled, fetch, isStale, queryKey: storeQueryKey, subscriptionCount } = get();

if (!enabled || (subscriptionCount !== 1 && !disableAutoRefetching)) return;

if (subscriptionCount === 1) {
const currentParams = getCurrentResolvedParams();
const currentQueryKey = getQueryKey(currentParams);

set(state => ({ ...state, queryKey: currentQueryKey }));
if (storeQueryKey !== currentQueryKey) set(state => ({ ...state, queryKey: currentQueryKey }));

if ((subscriptionCount === 1 || disableAutoRefetching) && enabled) {
if (isStale() || !get().queryCache[currentQueryKey]?.lastFetchedAt) {
if (isStale()) {
fetch(currentParams);
} else {
scheduleNextFetch(currentParams, undefined);
}
} else if (disableAutoRefetching) {
fetch();
}
};

Expand Down Expand Up @@ -953,8 +949,8 @@ export function createQueryStore<
const unsub = subscribeFn(() => {
const newVal = attachVal.value;
if (!equal(oldVal, newVal)) {
if (enableLogs) console.log('[🌀 Param Change 🌀] -', k, '- [Old]:', `${oldVal?.toString()},`, '[New]:', newVal?.toString());
oldVal = newVal;
if (enableLogs) console.log('[🌀 Param Change 🌀] Param changed:', k, ':: Old value:', oldVal, ':: New value:', newVal);
onParamChange();
}
});
Expand Down
10 changes: 6 additions & 4 deletions src/state/internal/createRainbowStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { debounce } from 'lodash';
import { MMKV } from 'react-native-mmkv';
import { StateCreator, create } from 'zustand';
import { PersistOptions, PersistStorage, StorageValue, persist, subscribeWithSelector } from 'zustand/middleware';
import { IS_IOS } from '@/env';
import { RainbowError, logger } from '@/logger';

const PERSIST_RATE_LIMIT_MS = 3000;
import { time } from '@/utils';

const rainbowStorage = new MMKV({ id: 'rainbow-storage' });

Expand Down Expand Up @@ -40,7 +40,7 @@ export interface RainbowPersistConfig<S, PersistedState = Partial<S>> {
serializer?: (state: StorageValue<PersistedState>['state'], version: StorageValue<PersistedState>['version']) => string;
/**
* The throttle rate for the persist operation in milliseconds.
* @default time.seconds(3)
* @default iOS: time.seconds(3) | Android: time.seconds(5)
*/
persistThrottleMs?: number;
/**
Expand Down Expand Up @@ -107,6 +107,8 @@ interface LazyPersistParams<S, PersistedState extends Partial<S>> {
value: StorageValue<S> | StorageValue<PersistedState>;
}

const DEFAULT_PERSIST_THROTTLE_MS = IS_IOS ? time.seconds(3) : time.seconds(5);

/**
* Creates a persist storage object for the Rainbow store.
* @param config - The configuration options for the persistable Rainbow store.
Expand All @@ -117,7 +119,7 @@ function createPersistStorage<S, PersistedState extends Partial<S>>(config: Rain
const {
deserializer = serializedState => defaultDeserializeState<PersistedState>(serializedState, enableMapSetHandling),
serializer = (state, version) => defaultSerializeState<PersistedState>(state, version, enableMapSetHandling),
persistThrottleMs = PERSIST_RATE_LIMIT_MS,
persistThrottleMs = DEFAULT_PERSIST_THROTTLE_MS,
storageKey,
version = 0,
} = config;
Expand Down
3 changes: 2 additions & 1 deletion src/state/internal/tests/QueryStoreTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
// import { ParsedAssetsDictByChain } from '@/__swaps__/types/assets';
// import { AddressAssetsReceivedMessage } from '@/__swaps__/types/refraction';
// import { useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';
// import { createQueryStore, time } from '../createQueryStore';
// import { time } from '@/utils';
// import { createQueryStore } from '../createQueryStore';
// import { createRainbowStore } from '../createRainbowStore';

// const ENABLE_LOGS = false;
Expand Down
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ export { default as withSpeed } from './withSpeed';
export { default as FallbackIcon } from './CoinIcons/FallbackIcon';
export { default as getExchangeIconUrl } from './getExchangeIconUrl';
export { resolveFirstRejectLast } from './resolveFirstRejectLast';
export { time } from './time';
40 changes: 40 additions & 0 deletions src/utils/time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
type TimeInMs = number;
type TimeUtils = {
/** Convert seconds to milliseconds */
seconds: (seconds: number) => TimeInMs;
/** Convert minutes to milliseconds */
minutes: (minutes: number) => TimeInMs;
/** Convert hours to milliseconds */
hours: (hours: number) => TimeInMs;
/** Convert days to milliseconds */
days: (days: number) => TimeInMs;
/** Convert weeks to milliseconds */
weeks: (weeks: number) => TimeInMs;
/** Represents infinite time */
infinity: typeof Infinity;
/** Represents zero time */
zero: 0;
};

/**
* Utility object for time conversions and helpers.
* All methods convert the input unit to milliseconds.
* @example
* time.seconds(5) // 5 seconds
* time.minutes(2) // 2 minutes
* time.hours(1) // 1 hour
* time.days(5) // 5 days
* time.weeks(2) // 2 weeks
* ––
* time.infinity // Infinity
* time.zero // 0
*/
export const time: TimeUtils = {
seconds: seconds => seconds * 1000,
minutes: minutes => time.seconds(minutes * 60),
hours: hours => time.minutes(hours * 60),
days: days => time.hours(days * 24),
weeks: weeks => time.days(weeks * 7),
infinity: Infinity,
zero: 0,
};

0 comments on commit 0f96d10

Please sign in to comment.