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,6 +1,6 @@
1
1
  {
2
2
  "name": "complexqa_frontend_core",
3
- "version": "1.18.5",
3
+ "version": "1.18.6",
4
4
  "description": "core of web ",
5
5
  "type": "module",
6
6
  "exports": {
@@ -17,6 +17,7 @@ export class ApiAbstractClass
17
17
  api_prefix = '';
18
18
  method;
19
19
  headers;
20
+ search_cache_enabled = false;
20
21
 
21
22
 
22
23
  /**
@@ -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,9 @@
1
+ export { MemoryCacheStore } from "./memory_cache_store.js";
2
+ export {
3
+ DEFAULT_SEARCH_CACHE_TTL_MS,
4
+ setApiSearchCacheStore,
5
+ getApiSearchCacheStore,
6
+ buildSearchCacheKey,
7
+ isDefaultSearchPayload,
8
+ resolveCachedSearch,
9
+ } from "./api_search_cache.js";
@@ -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
+ }