Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions src/core/cache/async/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*!
* V4Fire Core
* https://github.com/V4Fire/Core
*
* Released under the MIT license
* https://github.com/V4Fire/Core/blob/master/LICENSE
*/

import type { ClearFilter } from 'core/cache/interface';

/**
* Base interface for an async cache data structure
*
* @typeparam V - value type
* @typeparam K - key type (`string` by default)
*/
export default interface AsyncCache<V = unknown, K = string> {
/**
* Number of elements within the cache
*/
readonly size: Promise<number>;

/**
* Returns true if a value by the specified key exists in the cache
* @param key
*/
has(key: K): Promise<boolean>;

/**
* Returns a value from the cache by the specified key
* @param key
*/
get(key: K): Promise<CanUndef<V>>;

/**
* Saves a value to the cache by the specified key
*
* @param key
* @param value
* @param opts
*/
set(key: K, value: V, opts?: {}): Promise<V>;

/**
* Removes a value from the cache by the specified key
* @param key
*/
remove(key: K): Promise<CanUndef<V>>;

/**
* Clears the cache by the specified filter and returns a map of removed keys
* @param [filter] - filter for removing (if not specified, then all cache values will be removed)
*/
clear(filter?: ClearFilter<V, K>): Promise<Map<K, V>>;

/**
* Returns an iterator by the cache keys
*/
[Symbol.asyncIterator](): Promise<AsyncIterableIterator<K> | IterableIterator<K>>;

/**
* Returns an iterator by the cache keys
*/
keys(): Promise<AsyncIterableIterator<K> | IterableIterator<K>>;

/**
* Returns an iterator by the cache values
*/
values(): Promise<AsyncIterableIterator<V> | IterableIterator<V>>;

/**
* Returns an iterator from the cache that produces pairs of keys and values
*/
entries(): Promise<AsyncIterableIterator<[K, V]> | IterableIterator<[K, V]>>;
}
1 change: 1 addition & 0 deletions src/core/cache/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
export * from 'core/cache/interface';

export { default as AbstractCache } from 'core/cache/interface';
export { default as AbstractAsyncCache } from 'core/cache/async/interface';
export { default as Cache } from 'core/cache/simple';
export { default as RestrictedCache } from 'core/cache/restricted';
export { default as NeverCache } from 'core/cache/never';
6 changes: 4 additions & 2 deletions src/core/request/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import config from 'config';
import { memoize } from 'core/promise/sync';
import { toQueryString } from 'core/url';

import { Cache, RestrictedCache, NeverCache, AbstractCache } from 'core/cache';
import { Cache, RestrictedCache, NeverCache, AbstractCache, AbstractAsyncCache } from 'core/cache';
import type { AsyncStorage } from 'core/kv-storage';

import engine from 'core/request/engines';
Expand Down Expand Up @@ -44,7 +44,9 @@ export const
caches = new Set<AbstractCache>(),
pendingCache = new Cache<RequestResponse>();

export const cache: Record<Exclude<CacheStrategy, AbstractCache | Promise<AbstractCache>>, AbstractCache> = {
export const cache: Record<Exclude<
CacheStrategy, AbstractCache | Promise<AbstractCache> | AbstractAsyncCache
>, AbstractCache> = {
queue: new RestrictedCache(),
forever: new Cache(),
never: new NeverCache()
Expand Down
5 changes: 3 additions & 2 deletions src/core/request/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable max-lines-per-function */
/*!
* V4Fire Core
* https://github.com/V4Fire/Core
Expand Down Expand Up @@ -250,7 +251,7 @@ function request<D = unknown>(
fromCache = false;

if (cacheKey != null && ctx.canCache) {
if (ctx.pendingCache.has(cacheKey)) {
if (await ctx.pendingCache.has(cacheKey)) {
try {
const
res = await ctx.pendingCache.get(cacheKey);
Expand All @@ -277,7 +278,7 @@ function request<D = unknown>(
})));
}

fromCache = await AbortablePromise.resolve(ctx.cache.has(cacheKey), requestPromise);
fromCache = await AbortablePromise.resolve(await ctx.cache.has(cacheKey), requestPromise);
}

let
Expand Down
7 changes: 5 additions & 2 deletions src/core/request/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import type { EventEmitter2 as EventEmitter } from 'eventemitter2';
import type { AbstractCache } from 'core/cache';
import type { AbstractCache, AbstractAsyncCache } from 'core/cache';

import type Data from 'core/data';
import type { ModelMethod } from 'core/data';
Expand Down Expand Up @@ -43,7 +43,8 @@ export type CacheStrategy =
'forever' |
'never' |
AbstractCache |
Promise<AbstractCache>;
Promise<AbstractCache> |
AbstractAsyncCache;

export type CacheType =
'memory' |
Expand Down Expand Up @@ -392,6 +393,8 @@ export interface CreateRequestOptions<D = unknown> {
*/
cacheTTL?: number;

customRequestCacheKey?(url: string): string;

/**
* Enables support of offline caching.
* By default, a request can only be taken from a cache if there is no network.
Expand Down
4 changes: 4 additions & 0 deletions src/core/request/modules/context/modules/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export default class RequestContext<D = unknown> extends Super<D> {
* @param url
*/
getRequestKey(url: string): string {
if (this.customRequestCacheKey) {
return this.customRequestCacheKey(url);
}

const
p = this.params,
cacheId = p.cacheId ?? '',
Expand Down
6 changes: 6 additions & 0 deletions src/core/request/modules/context/modules/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ export default class RequestContext<D = unknown> {
*/
readonly params!: NormalizedCreateRequestOptions<D>;

readonly customRequestCacheKey?: (url:string) => string;

/**
* Alias for `params.query`
* @alias
Expand Down Expand Up @@ -217,6 +219,10 @@ export default class RequestContext<D = unknown> {
delete p.offlineCache;
}

if (p.customRequestCacheKey) {
this.customRequestCacheKey = p.customRequestCacheKey;
}

this.isReady = (async () => {
// eslint-disable-next-line require-atomic-updates
cacheAPI = await cacheAPI;
Expand Down
Loading