From f3d35809e032a3231545020db893218425d474c3 Mon Sep 17 00:00:00 2001 From: kholstinin Date: Tue, 20 Aug 2024 19:16:12 +0500 Subject: [PATCH 1/7] feat: async cache --- src/core/cache/async/interface.ts | 75 +++++++++++++++++++++++++++++++ src/core/cache/index.ts | 1 + src/core/request/interface.ts | 5 ++- 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 src/core/cache/async/interface.ts diff --git a/src/core/cache/async/interface.ts b/src/core/cache/async/interface.ts new file mode 100644 index 000000000..821a909a8 --- /dev/null +++ b/src/core/cache/async/interface.ts @@ -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 { + /** + * Number of elements within the cache + */ + readonly size: Promise; + + /** + * Returns true if a value by the specified key exists in the cache + * @param key + */ + has(key: K): Promise; + + /** + * Returns a value from the cache by the specified key + * @param key + */ + get(key: K): Promise>; + + /** + * Saves a value to the cache by the specified key + * + * @param key + * @param value + * @param opts + */ + set(key: K, value: V, opts?: {}): Promise; + + /** + * Removes a value from the cache by the specified key + * @param key + */ + remove(key: K): Promise>; + + /** + * 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): Promise>; + + /** + * Returns an iterator by the cache keys + */ + [Symbol.asyncIterator](): AsyncIterableIterator; + + /** + * Returns an iterator by the cache keys + */ + keys(): AsyncIterableIterator; + + /** + * Returns an iterator by the cache values + */ + values(): AsyncIterableIterator; + + /** + * Returns an iterator from the cache that produces pairs of keys and values + */ + entries(): AsyncIterableIterator<[K, V]>; +} diff --git a/src/core/cache/index.ts b/src/core/cache/index.ts index 6c9da9f0e..12dffb09f 100644 --- a/src/core/cache/index.ts +++ b/src/core/cache/index.ts @@ -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'; diff --git a/src/core/request/interface.ts b/src/core/request/interface.ts index c9e0d2eea..dd2540876 100644 --- a/src/core/request/interface.ts +++ b/src/core/request/interface.ts @@ -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'; @@ -43,7 +43,8 @@ export type CacheStrategy = 'forever' | 'never' | AbstractCache | - Promise; + Promise | + AbstractAsyncCache; export type CacheType = 'memory' | From 5908fd6afbba7a82fd371525c10ae3afa1105e2a Mon Sep 17 00:00:00 2001 From: kholstinin Date: Tue, 20 Aug 2024 19:17:48 +0500 Subject: [PATCH 2/7] fix: ts --- src/core/request/const.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/request/const.ts b/src/core/request/const.ts index c8b45d068..6e0ca45ea 100644 --- a/src/core/request/const.ts +++ b/src/core/request/const.ts @@ -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'; @@ -44,7 +44,9 @@ export const caches = new Set(), pendingCache = new Cache(); -export const cache: Record>, AbstractCache> = { +export const cache: Record | AbstractAsyncCache +>, AbstractCache> = { queue: new RestrictedCache(), forever: new Cache(), never: new NeverCache() From 70f7e373cb8256971766194d3e6a858e92584b79 Mon Sep 17 00:00:00 2001 From: kholstinin Date: Tue, 20 Aug 2024 19:35:23 +0500 Subject: [PATCH 3/7] fix: typings of iterators --- src/core/cache/async/interface.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/cache/async/interface.ts b/src/core/cache/async/interface.ts index 821a909a8..c4b6fdb3d 100644 --- a/src/core/cache/async/interface.ts +++ b/src/core/cache/async/interface.ts @@ -56,20 +56,20 @@ export default interface AsyncCache { /** * Returns an iterator by the cache keys */ - [Symbol.asyncIterator](): AsyncIterableIterator; + [Symbol.asyncIterator](): Promise | IterableIterator>; /** * Returns an iterator by the cache keys */ - keys(): AsyncIterableIterator; + keys(): Promise | IterableIterator>; /** * Returns an iterator by the cache values */ - values(): AsyncIterableIterator; + values(): Promise | IterableIterator>; /** * Returns an iterator from the cache that produces pairs of keys and values */ - entries(): AsyncIterableIterator<[K, V]>; + entries(): Promise | IterableIterator<[K, V]>>; } From c3b57e5dc38e53ffd8c7fc98541a1a244e40a67d Mon Sep 17 00:00:00 2001 From: kholstinin Date: Tue, 20 Aug 2024 19:43:58 +0500 Subject: [PATCH 4/7] fix: async cache in request usage --- src/core/request/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/request/index.ts b/src/core/request/index.ts index 5ac4df7f5..828c16c52 100644 --- a/src/core/request/index.ts +++ b/src/core/request/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-lines-per-function */ /*! * V4Fire Core * https://github.com/V4Fire/Core @@ -250,7 +251,7 @@ function request( 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); @@ -277,7 +278,7 @@ function request( }))); } - fromCache = await AbortablePromise.resolve(ctx.cache.has(cacheKey), requestPromise); + fromCache = await AbortablePromise.resolve(await ctx.cache.has(cacheKey), requestPromise); } let From e6f126cd68b5f6cc172957bfc2d06bccfef09ab3 Mon Sep 17 00:00:00 2001 From: kholstinin Date: Mon, 26 Aug 2024 13:52:10 +0500 Subject: [PATCH 5/7] feat: disable protected on cache key --- src/core/request/modules/context/modules/params.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/request/modules/context/modules/params.ts b/src/core/request/modules/context/modules/params.ts index 8c69f3d0d..0c019f668 100644 --- a/src/core/request/modules/context/modules/params.ts +++ b/src/core/request/modules/context/modules/params.ts @@ -71,7 +71,7 @@ export default class RequestContext { /** * Sets a new string key to cache the request */ - protected set cacheKey(value: CanUndef) { + set cacheKey(value: CanUndef) { this[$$.cacheKey] = value; } From 00fb6fe9b2f8ace22f2efd486c3e5655da29d380 Mon Sep 17 00:00:00 2001 From: kholstinin Date: Mon, 26 Aug 2024 14:47:22 +0500 Subject: [PATCH 6/7] feat: possibility to override requestKey function --- src/core/request/interface.ts | 2 ++ src/core/request/modules/context/modules/methods.ts | 4 ++++ src/core/request/modules/context/modules/params.ts | 8 +++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/core/request/interface.ts b/src/core/request/interface.ts index dd2540876..ab7feb8a2 100644 --- a/src/core/request/interface.ts +++ b/src/core/request/interface.ts @@ -393,6 +393,8 @@ export interface CreateRequestOptions { */ 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. diff --git a/src/core/request/modules/context/modules/methods.ts b/src/core/request/modules/context/modules/methods.ts index 836026cbb..d12919f8b 100644 --- a/src/core/request/modules/context/modules/methods.ts +++ b/src/core/request/modules/context/modules/methods.ts @@ -24,6 +24,10 @@ export default class RequestContext extends Super { * @param url */ getRequestKey(url: string): string { + if (this.customRequestCacheKey) { + return this.customRequestCacheKey(url); + } + const p = this.params, cacheId = p.cacheId ?? '', diff --git a/src/core/request/modules/context/modules/params.ts b/src/core/request/modules/context/modules/params.ts index 0c019f668..2285566cb 100644 --- a/src/core/request/modules/context/modules/params.ts +++ b/src/core/request/modules/context/modules/params.ts @@ -71,7 +71,7 @@ export default class RequestContext { /** * Sets a new string key to cache the request */ - set cacheKey(value: CanUndef) { + protected set cacheKey(value: CanUndef) { this[$$.cacheKey] = value; } @@ -97,6 +97,8 @@ export default class RequestContext { */ readonly params!: NormalizedCreateRequestOptions; + readonly customRequestCacheKey?: (url:string) => string; + /** * Alias for `params.query` * @alias @@ -217,6 +219,10 @@ export default class RequestContext { delete p.offlineCache; } + if (p.customRequestCacheKey) { + this.customRequestCacheKey = p.customRequestCacheKey; + } + this.isReady = (async () => { // eslint-disable-next-line require-atomic-updates cacheAPI = await cacheAPI; From 014e40b52ae5822d96ef076b776fdc45e3fa6d8f Mon Sep 17 00:00:00 2001 From: kholstinin Date: Tue, 27 Aug 2024 20:36:54 +0500 Subject: [PATCH 7/7] fix: async cache type --- src/core/cache/async/interface.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/cache/async/interface.ts b/src/core/cache/async/interface.ts index c4b6fdb3d..966ff3a3d 100644 --- a/src/core/cache/async/interface.ts +++ b/src/core/cache/async/interface.ts @@ -66,7 +66,7 @@ export default interface AsyncCache { /** * Returns an iterator by the cache values */ - values(): Promise | IterableIterator>; + values(): Promise | IterableIterator>; /** * Returns an iterator from the cache that produces pairs of keys and values