complexqa_frontend_core 1.18.5 → 1.18.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ApiAbstractClass } from "./api_abstract_class.js";
|
|
2
|
+
import { resolveCachedSearch } from "./cache/api_search_cache.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
*
|
|
@@ -9,6 +10,9 @@ export class ApiAbstractReferenceClass extends ApiAbstractClass
|
|
|
9
10
|
|
|
10
11
|
api_prefix = 'api';
|
|
11
12
|
|
|
13
|
+
/** @type {boolean} */
|
|
14
|
+
search_cache_enabled = true;
|
|
15
|
+
|
|
12
16
|
/**
|
|
13
17
|
*
|
|
14
18
|
* @version v.1.0 (03/06/2026)
|
|
@@ -16,7 +20,7 @@ export class ApiAbstractReferenceClass extends ApiAbstractClass
|
|
|
16
20
|
*/
|
|
17
21
|
constructor(options)
|
|
18
22
|
{
|
|
19
|
-
super();
|
|
23
|
+
super(options);
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
|
|
@@ -31,6 +35,22 @@ export class ApiAbstractReferenceClass extends ApiAbstractClass
|
|
|
31
35
|
* @param {?object|undefined} payload.response
|
|
32
36
|
*/
|
|
33
37
|
async search(payload = {})
|
|
38
|
+
{
|
|
39
|
+
return resolveCachedSearch(
|
|
40
|
+
this,
|
|
41
|
+
'search',
|
|
42
|
+
payload,
|
|
43
|
+
(p) => this.executeSearch(p),
|
|
44
|
+
{ useCache: this.search_cache_enabled },
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {object|typeFOR} payload
|
|
51
|
+
* @returns {Promise<{response: *, payload: *}>}
|
|
52
|
+
*/
|
|
53
|
+
async executeSearch(payload = {})
|
|
34
54
|
{
|
|
35
55
|
if (!this.module_prefix)
|
|
36
56
|
{
|
|
@@ -50,7 +70,7 @@ export class ApiAbstractReferenceClass extends ApiAbstractClass
|
|
|
50
70
|
|
|
51
71
|
return {
|
|
52
72
|
response: response,
|
|
53
|
-
payload : payload
|
|
73
|
+
payload : payload,
|
|
54
74
|
};
|
|
55
75
|
}
|
|
56
76
|
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { clone_object } from "../../utils/utils.js";
|
|
2
|
+
import { MemoryCacheStore } from "./memory_cache_store.js";
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_SEARCH_CACHE_TTL_MS = 4 * 60 * 60 * 1000;
|
|
5
|
+
|
|
6
|
+
let cacheStore = new MemoryCacheStore();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* DI: подмена хранилища кеша (например, persistent/store с TTL).
|
|
10
|
+
*
|
|
11
|
+
* @param {MemoryCacheStore} store
|
|
12
|
+
*/
|
|
13
|
+
export function setApiSearchCacheStore(store)
|
|
14
|
+
{
|
|
15
|
+
cacheStore = store;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @returns {MemoryCacheStore}
|
|
21
|
+
*/
|
|
22
|
+
export function getApiSearchCacheStore()
|
|
23
|
+
{
|
|
24
|
+
return cacheStore;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {object} apiInstance
|
|
30
|
+
* @param {string} methodName
|
|
31
|
+
* @returns {string}
|
|
32
|
+
*/
|
|
33
|
+
export function buildSearchCacheKey(apiInstance, methodName = 'search')
|
|
34
|
+
{
|
|
35
|
+
return `${ apiInstance?.constructor?.name || 'Api' }.${ methodName }`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Дефолтный запрос: без фильтров и без options.
|
|
41
|
+
*
|
|
42
|
+
* @param {object|false|undefined} payload
|
|
43
|
+
* @returns {boolean}
|
|
44
|
+
*/
|
|
45
|
+
export function isDefaultSearchPayload(payload)
|
|
46
|
+
{
|
|
47
|
+
const filters = payload?.filters ?? payload?.filter ?? [];
|
|
48
|
+
|
|
49
|
+
if (!Array.isArray(filters) || filters.length > 0)
|
|
50
|
+
{
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const options = payload?.options;
|
|
55
|
+
|
|
56
|
+
if (options === false || options == null)
|
|
57
|
+
{
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (typeof options === 'object' && Object.keys(options).length === 0)
|
|
62
|
+
{
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {object} apiInstance
|
|
72
|
+
* @param {string} methodName
|
|
73
|
+
* @param {object|false|undefined} payload
|
|
74
|
+
* @param {Function} searchFn
|
|
75
|
+
* @param {object} [config]
|
|
76
|
+
* @param {boolean} [config.useCache]
|
|
77
|
+
* @param {number} [config.ttlMs]
|
|
78
|
+
* @returns {Promise<*>}
|
|
79
|
+
*/
|
|
80
|
+
export async function resolveCachedSearch(
|
|
81
|
+
apiInstance,
|
|
82
|
+
methodName,
|
|
83
|
+
payload,
|
|
84
|
+
searchFn,
|
|
85
|
+
config = {},
|
|
86
|
+
)
|
|
87
|
+
{
|
|
88
|
+
const {
|
|
89
|
+
useCache = false,
|
|
90
|
+
ttlMs = DEFAULT_SEARCH_CACHE_TTL_MS,
|
|
91
|
+
} = config;
|
|
92
|
+
|
|
93
|
+
if (!useCache || !isDefaultSearchPayload(payload))
|
|
94
|
+
{
|
|
95
|
+
return searchFn(payload);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const cacheKey = buildSearchCacheKey(apiInstance, methodName);
|
|
99
|
+
const cached = cacheStore.get(cacheKey);
|
|
100
|
+
|
|
101
|
+
if (cached !== undefined)
|
|
102
|
+
{
|
|
103
|
+
return Promise.resolve(clone_object(cached));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const result = await searchFn(payload);
|
|
107
|
+
cacheStore.set(cacheKey, clone_object(result), ttlMs);
|
|
108
|
+
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Простое in-memory key-value хранилище с TTL.
|
|
3
|
+
*
|
|
4
|
+
* @version v.1.0 (13/06/2026)
|
|
5
|
+
*/
|
|
6
|
+
export class MemoryCacheStore
|
|
7
|
+
{
|
|
8
|
+
constructor()
|
|
9
|
+
{
|
|
10
|
+
this._entries = new Map();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {string} key
|
|
16
|
+
* @returns {*|undefined}
|
|
17
|
+
*/
|
|
18
|
+
get(key)
|
|
19
|
+
{
|
|
20
|
+
const entry = this._entries.get(key);
|
|
21
|
+
|
|
22
|
+
if (!entry)
|
|
23
|
+
{
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (entry.expiresAt <= Date.now())
|
|
28
|
+
{
|
|
29
|
+
this._entries.delete(key);
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return entry.value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {string} key
|
|
39
|
+
* @param {*} value
|
|
40
|
+
* @param {number} ttlMs
|
|
41
|
+
*/
|
|
42
|
+
set(key, value, ttlMs)
|
|
43
|
+
{
|
|
44
|
+
this._entries.set(key, {
|
|
45
|
+
value,
|
|
46
|
+
expiresAt: Date.now() + ttlMs,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {string} key
|
|
53
|
+
*/
|
|
54
|
+
delete(key)
|
|
55
|
+
{
|
|
56
|
+
this._entries.delete(key);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
clear()
|
|
61
|
+
{
|
|
62
|
+
this._entries.clear();
|
|
63
|
+
}
|
|
64
|
+
}
|