@carbonorm/carbonnode 3.10.0 → 4.0.0
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/dist/api/C6Constants.d.ts +20 -0
- package/dist/api/orm/builders/ConditionBuilder.d.ts +8 -0
- package/dist/api/orm/builders/JoinBuilder.d.ts +9 -0
- package/dist/api/orm/queries/PostQueryBuilder.d.ts +1 -1
- package/dist/api/restOrm.d.ts +4 -4
- package/dist/api/types/ormInterfaces.d.ts +32 -12
- package/dist/api/utils/cacheManager.d.ts +7 -8
- package/dist/index.cjs.js +566 -142
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +562 -141
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/cacheManager.test.ts +67 -0
- package/src/__tests__/expressServer.e2e.test.ts +104 -2
- package/src/__tests__/fixtures/c6.fixture.ts +5 -0
- package/src/__tests__/httpExecutorSingular.e2e.test.ts +35 -4
- package/src/__tests__/sakila-db/C6.js +1 -1
- package/src/__tests__/sakila-db/C6.ts +1 -1
- package/src/__tests__/sqlBuilders.complex.test.ts +85 -0
- package/src/__tests__/sqlBuilders.test.ts +28 -0
- package/src/api/C6Constants.ts +12 -2
- package/src/api/axiosInstance.ts +29 -0
- package/src/api/executors/HttpExecutor.ts +73 -97
- package/src/api/handlers/ExpressHandler.ts +30 -7
- package/src/api/orm/builders/ConditionBuilder.ts +227 -0
- package/src/api/orm/builders/JoinBuilder.ts +150 -1
- package/src/api/orm/queries/PostQueryBuilder.ts +4 -2
- package/src/api/orm/queries/SelectQueryBuilder.ts +5 -0
- package/src/api/orm/queries/UpdateQueryBuilder.ts +3 -1
- package/src/api/types/ormInterfaces.ts +32 -18
- package/src/api/utils/cacheManager.ts +75 -34
- package/src/api/utils/testHelpers.ts +5 -3
- package/src/variables/isNode.ts +1 -8
|
@@ -5,12 +5,159 @@ import {resolveDerivedTable, isDerivedTableKey} from "../queryHelpers";
|
|
|
5
5
|
|
|
6
6
|
export abstract class JoinBuilder<G extends OrmGenerics> extends ConditionBuilder<G>{
|
|
7
7
|
|
|
8
|
+
private indexHintCache?: Map<string, string>;
|
|
9
|
+
|
|
8
10
|
protected createSelectBuilder(
|
|
9
11
|
_request: any
|
|
10
12
|
): { build(table: string, isSubSelect: boolean): { sql: string; params: any[] | Record<string, any> } } {
|
|
11
13
|
throw new Error('Subclasses must implement createSelectBuilder to support derived table serialization.');
|
|
12
14
|
}
|
|
13
15
|
|
|
16
|
+
protected resetIndexHints(): void {
|
|
17
|
+
this.indexHintCache = undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private normalizeIndexHintKey(key: string): string {
|
|
21
|
+
return key
|
|
22
|
+
.replace(/`/g, '')
|
|
23
|
+
.replace(/_/g, ' ')
|
|
24
|
+
.trim()
|
|
25
|
+
.replace(/\s+/g, ' ')
|
|
26
|
+
.toUpperCase();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private normalizeHintTargetKey(target: string): string {
|
|
30
|
+
return target.replace(/`/g, '').trim();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private hasIndexHintKeys(obj: Record<string, any>): boolean {
|
|
34
|
+
const keys = Object.keys(obj ?? {});
|
|
35
|
+
if (!keys.length) return false;
|
|
36
|
+
|
|
37
|
+
const forceKey = this.normalizeIndexHintKey(C6C.FORCE_INDEX);
|
|
38
|
+
const useKey = this.normalizeIndexHintKey(C6C.USE_INDEX);
|
|
39
|
+
const ignoreKey = this.normalizeIndexHintKey(C6C.IGNORE_INDEX);
|
|
40
|
+
|
|
41
|
+
return keys.some(key => {
|
|
42
|
+
const normalized = this.normalizeIndexHintKey(key);
|
|
43
|
+
return normalized === forceKey || normalized === useKey || normalized === ignoreKey;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private normalizeHintSpec(spec: any): Record<string, any> | undefined {
|
|
48
|
+
if (spec instanceof Map) {
|
|
49
|
+
spec = Object.fromEntries(spec);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (Array.isArray(spec) || typeof spec === 'string') {
|
|
53
|
+
return { [C6C.FORCE_INDEX]: spec } as Record<string, any>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!spec || typeof spec !== 'object') {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!this.hasIndexHintKeys(spec as Record<string, any>)) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return spec as Record<string, any>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private formatIndexHintClause(spec: any): string {
|
|
68
|
+
const normalizedSpec = this.normalizeHintSpec(spec);
|
|
69
|
+
if (!normalizedSpec) return '';
|
|
70
|
+
|
|
71
|
+
const clauses: string[] = [];
|
|
72
|
+
const forceKey = this.normalizeIndexHintKey(C6C.FORCE_INDEX);
|
|
73
|
+
const useKey = this.normalizeIndexHintKey(C6C.USE_INDEX);
|
|
74
|
+
const ignoreKey = this.normalizeIndexHintKey(C6C.IGNORE_INDEX);
|
|
75
|
+
|
|
76
|
+
const pushClause = (keyword: string, rawValue: any) => {
|
|
77
|
+
const values = Array.isArray(rawValue) ? rawValue : [rawValue];
|
|
78
|
+
const indexes = values
|
|
79
|
+
.map(value => String(value ?? '').trim())
|
|
80
|
+
.filter(Boolean)
|
|
81
|
+
.map(value => `\`${value.replace(/`/g, '``')}\``);
|
|
82
|
+
if (!indexes.length) return;
|
|
83
|
+
clauses.push(`${keyword} (${indexes.join(', ')})`);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
for (const [key, rawValue] of Object.entries(normalizedSpec)) {
|
|
87
|
+
const normalizedKey = this.normalizeIndexHintKey(key);
|
|
88
|
+
if (normalizedKey === forceKey) {
|
|
89
|
+
pushClause('FORCE INDEX', rawValue);
|
|
90
|
+
} else if (normalizedKey === useKey) {
|
|
91
|
+
pushClause('USE INDEX', rawValue);
|
|
92
|
+
} else if (normalizedKey === ignoreKey) {
|
|
93
|
+
pushClause('IGNORE INDEX', rawValue);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return clauses.join(' ');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private normalizeIndexHints(raw: any): Map<string, string> | undefined {
|
|
101
|
+
if (raw instanceof Map) {
|
|
102
|
+
raw = Object.fromEntries(raw);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const cache = new Map<string, string>();
|
|
106
|
+
|
|
107
|
+
const addEntry = (target: string, spec: any) => {
|
|
108
|
+
const clause = this.formatIndexHintClause(spec);
|
|
109
|
+
if (!clause) return;
|
|
110
|
+
const normalizedTarget = target === '__base__'
|
|
111
|
+
? '__base__'
|
|
112
|
+
: this.normalizeHintTargetKey(target);
|
|
113
|
+
cache.set(normalizedTarget, clause);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
if (Array.isArray(raw) || typeof raw === 'string') {
|
|
117
|
+
addEntry('__base__', raw);
|
|
118
|
+
} else if (raw && typeof raw === 'object') {
|
|
119
|
+
if (this.hasIndexHintKeys(raw as Record<string, any>)) {
|
|
120
|
+
addEntry('__base__', raw);
|
|
121
|
+
} else {
|
|
122
|
+
for (const [key, value] of Object.entries(raw as Record<string, any>)) {
|
|
123
|
+
const normalizedKey = this.normalizeHintTargetKey(key);
|
|
124
|
+
if (!normalizedKey) continue;
|
|
125
|
+
addEntry(normalizedKey, value);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return cache.size ? cache : undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
protected getIndexHintClause(table: string, alias?: string): string {
|
|
134
|
+
if (!this.indexHintCache) {
|
|
135
|
+
const rawHints = (this.request as unknown as Record<string, any> | undefined)?.[C6C.INDEX_HINTS];
|
|
136
|
+
this.indexHintCache = this.normalizeIndexHints(rawHints);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const hints = this.indexHintCache;
|
|
140
|
+
if (!hints || hints.size === 0) return '';
|
|
141
|
+
|
|
142
|
+
const normalizedTable = this.normalizeHintTargetKey(table);
|
|
143
|
+
const normalizedAlias = alias ? this.normalizeHintTargetKey(alias) : undefined;
|
|
144
|
+
|
|
145
|
+
const candidates = [
|
|
146
|
+
normalizedAlias,
|
|
147
|
+
normalizedAlias ? `${normalizedTable} ${normalizedAlias}` : undefined,
|
|
148
|
+
normalizedTable,
|
|
149
|
+
'__base__',
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
for (const candidate of candidates) {
|
|
153
|
+
if (!candidate) continue;
|
|
154
|
+
const clause = hints.get(candidate);
|
|
155
|
+
if (clause) return clause;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return '';
|
|
159
|
+
}
|
|
160
|
+
|
|
14
161
|
buildJoinClauses(joinArgs: any, params: any[] | Record<string, any>): string {
|
|
15
162
|
let sql = '';
|
|
16
163
|
|
|
@@ -79,7 +226,9 @@ export abstract class JoinBuilder<G extends OrmGenerics> extends ConditionBuilde
|
|
|
79
226
|
if (alias) {
|
|
80
227
|
this.registerAlias(alias, table);
|
|
81
228
|
}
|
|
82
|
-
const
|
|
229
|
+
const hintClause = this.getIndexHintClause(table, alias);
|
|
230
|
+
const baseJoinSql = alias ? `\`${table}\` AS \`${alias}\`` : `\`${table}\``;
|
|
231
|
+
const joinSql = hintClause ? `${baseJoinSql} ${hintClause}` : baseJoinSql;
|
|
83
232
|
const onClause = this.buildBooleanJoinedConditions(conditions, true, params);
|
|
84
233
|
sql += ` ${joinKind} JOIN ${joinSql}`;
|
|
85
234
|
if (onClause) {
|
|
@@ -18,13 +18,15 @@ export class PostQueryBuilder<G extends OrmGenerics> extends ConditionBuilder<G>
|
|
|
18
18
|
const verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
|
|
19
19
|
const body = verb in this.request ? this.request[verb] : this.request;
|
|
20
20
|
const keys = Object.keys(body);
|
|
21
|
-
const params: any[] = []
|
|
21
|
+
const params: any[] | Record<string, any> = this.useNamedParams ? {} : [];
|
|
22
22
|
const placeholders: string[] = []
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
for (const key of keys) {
|
|
26
26
|
const value = body[key];
|
|
27
|
-
const
|
|
27
|
+
const trimmed = this.trimTablePrefix(table, key);
|
|
28
|
+
const qualified = `${table}.${trimmed}`;
|
|
29
|
+
const placeholder = this.serializeUpdateValue(value, params, qualified);
|
|
28
30
|
placeholders.push(placeholder);
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -16,6 +16,7 @@ export class SelectQueryBuilder<G extends OrmGenerics> extends PaginationBuilder
|
|
|
16
16
|
// reset any previously collected SELECT aliases (from AggregateBuilder)
|
|
17
17
|
// @ts-ignore
|
|
18
18
|
if (this.selectAliases && this.selectAliases.clear) this.selectAliases.clear();
|
|
19
|
+
this.resetIndexHints();
|
|
19
20
|
const args = this.request;
|
|
20
21
|
this.initAlias(table, args.JOIN);
|
|
21
22
|
const params = this.useNamedParams ? {} : [];
|
|
@@ -25,6 +26,10 @@ export class SelectQueryBuilder<G extends OrmGenerics> extends PaginationBuilder
|
|
|
25
26
|
.join(', ');
|
|
26
27
|
|
|
27
28
|
let sql = `SELECT ${selectFields} FROM \`${table}\``;
|
|
29
|
+
const baseIndexHint = this.getIndexHintClause(table);
|
|
30
|
+
if (baseIndexHint) {
|
|
31
|
+
sql += ` ${baseIndexHint}`;
|
|
32
|
+
}
|
|
28
33
|
|
|
29
34
|
if (args.JOIN) {
|
|
30
35
|
sql += this.buildJoinClauses(args.JOIN, params);
|
|
@@ -39,7 +39,9 @@ export class UpdateQueryBuilder<G extends OrmGenerics> extends PaginationBuilder
|
|
|
39
39
|
.map(([col, val]) => {
|
|
40
40
|
const trimmed = this.trimTablePrefix(table, col);
|
|
41
41
|
const qualified = `${table}.${trimmed}`;
|
|
42
|
-
|
|
42
|
+
this.assertValidIdentifier(qualified, 'UPDATE SET');
|
|
43
|
+
const rightSql = this.serializeUpdateValue(val, params, qualified);
|
|
44
|
+
return `\`${trimmed}\` = ${rightSql}`;
|
|
43
45
|
});
|
|
44
46
|
|
|
45
47
|
sql += ` SET ${setClauses.join(', ')}`;
|
|
@@ -97,7 +97,13 @@ export type RequestQueryBody<
|
|
|
97
97
|
export interface iCacheAPI<ResponseDataType = any> {
|
|
98
98
|
requestArgumentsSerialized: string;
|
|
99
99
|
request: AxiosPromise<ResponseDataType>;
|
|
100
|
-
response?: AxiosResponse
|
|
100
|
+
response?: AxiosResponse & {
|
|
101
|
+
__carbonTiming?: {
|
|
102
|
+
start: number;
|
|
103
|
+
end: number;
|
|
104
|
+
duration: number;
|
|
105
|
+
}
|
|
106
|
+
},
|
|
101
107
|
final?: boolean;
|
|
102
108
|
}
|
|
103
109
|
|
|
@@ -105,40 +111,48 @@ export interface iChangeC6Data {
|
|
|
105
111
|
rowCount: number;
|
|
106
112
|
}
|
|
107
113
|
|
|
108
|
-
|
|
114
|
+
// New discriminated REST response type based on HTTP method
|
|
115
|
+
export type C6RestResponse<
|
|
116
|
+
Method extends iRestMethods,
|
|
117
|
+
RestData extends { [key: string]: any },
|
|
118
|
+
Overrides = {}
|
|
119
|
+
> = {
|
|
120
|
+
rest: Method extends 'GET' ? Modify<RestData, Overrides>[] : Modify<RestData, Overrides>;
|
|
121
|
+
session?: any;
|
|
122
|
+
sql?: any;
|
|
123
|
+
} & (Method extends 'GET'
|
|
124
|
+
? { next?: () => Promise<DetermineResponseDataType<'GET', RestData, Overrides>> }
|
|
125
|
+
: {});
|
|
126
|
+
|
|
127
|
+
export interface iC6RestResponse<RestData> {
|
|
128
|
+
// Backwards compatibility: base interface for rest/sql/session (singular)
|
|
129
|
+
rest: RestData;
|
|
130
|
+
session?: any;
|
|
131
|
+
sql?: any;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface iDeleteC6RestResponse<RestData extends { [key: string]: any; }, RequestData = any> extends iChangeC6Data, C6RestResponse<'DELETE', RestData> {
|
|
109
135
|
deleted: boolean | number | string | RequestData;
|
|
110
136
|
}
|
|
111
137
|
|
|
112
|
-
export interface iPostC6RestResponse<RestData
|
|
138
|
+
export interface iPostC6RestResponse<RestData extends { [key: string]: any; }> extends C6RestResponse<'POST', RestData> {
|
|
113
139
|
created: boolean | number | string;
|
|
114
140
|
}
|
|
115
141
|
|
|
116
|
-
export interface iPutC6RestResponse<RestData
|
|
142
|
+
export interface iPutC6RestResponse<RestData extends { [key: string]: any; }, RequestData = any> extends iChangeC6Data, C6RestResponse<'PUT', RestData> {
|
|
117
143
|
updated: boolean | number | string | RequestData;
|
|
118
144
|
}
|
|
119
145
|
|
|
120
|
-
export interface iC6RestResponse<RestData> {
|
|
121
|
-
rest: RestData;
|
|
122
|
-
session?: any;
|
|
123
|
-
sql?: any;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
146
|
export interface iGetC6RestResponse<
|
|
127
147
|
ResponseDataType extends { [key: string]: any },
|
|
128
148
|
ResponseDataOverrides = {}
|
|
129
|
-
> extends
|
|
130
|
-
// TODO - We removed Modify<ResponseDataType, ResponseDataOverrides> |
|
|
131
|
-
Modify<ResponseDataType, ResponseDataOverrides>[]
|
|
132
|
-
> {
|
|
133
|
-
next?: () => Promise<DetermineResponseDataType<"GET", ResponseDataType, ResponseDataOverrides>>;
|
|
134
|
-
}
|
|
149
|
+
> extends C6RestResponse<'GET', ResponseDataType, ResponseDataOverrides> {}
|
|
135
150
|
|
|
136
151
|
export type DetermineResponseDataType<
|
|
137
152
|
Method extends iRestMethods,
|
|
138
153
|
RestTableInterface extends { [key: string]: any },
|
|
139
154
|
ResponseDataOverrides = {}
|
|
140
|
-
> =
|
|
141
|
-
(Method extends 'POST'
|
|
155
|
+
> = (Method extends 'POST'
|
|
142
156
|
? iPostC6RestResponse<RestTableInterface>
|
|
143
157
|
: Method extends 'GET'
|
|
144
158
|
? iGetC6RestResponse<RestTableInterface, ResponseDataOverrides>
|
|
@@ -1,46 +1,87 @@
|
|
|
1
|
-
import {AxiosPromise} from "axios";
|
|
1
|
+
import { AxiosPromise } from "axios";
|
|
2
2
|
import { iCacheAPI } from "../types/ormInterfaces";
|
|
3
3
|
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
4
|
+
// -----------------------------------------------------------------------------
|
|
5
|
+
// Cache Storage
|
|
6
|
+
// -----------------------------------------------------------------------------
|
|
7
|
+
export const apiRequestCache = new Map<string, iCacheAPI>();
|
|
8
|
+
export const userCustomClearCache: (() => void)[] = [];
|
|
9
|
+
|
|
10
|
+
// -----------------------------------------------------------------------------
|
|
11
|
+
// Cache Key Generator (safe, fixed-size ~40 chars)
|
|
12
|
+
// -----------------------------------------------------------------------------
|
|
13
|
+
// -----------------------------------------------------------------------------
|
|
14
|
+
// Browser-safe deterministic hash (FNV-1a)
|
|
15
|
+
// -----------------------------------------------------------------------------
|
|
16
|
+
function fnv1a(str: string): string {
|
|
17
|
+
let h = 0x811c9dc5;
|
|
18
|
+
for (let i = 0; i < str.length; i++) {
|
|
19
|
+
h ^= str.charCodeAt(i);
|
|
20
|
+
h = (h * 0x01000193) >>> 0;
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
-
userCustomClearCache.map((f) => 'function' === typeof f && f());
|
|
23
|
-
|
|
24
|
-
userCustomClearCache = apiRequestCache = []
|
|
25
|
-
|
|
22
|
+
return h.toString(16);
|
|
26
23
|
}
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
function makeCacheKey(
|
|
26
|
+
method: string,
|
|
27
|
+
tableName: string | string[],
|
|
28
|
+
requestData: unknown,
|
|
29
|
+
): string {
|
|
30
|
+
const raw = JSON.stringify([method, tableName, requestData]);
|
|
31
|
+
return fnv1a(raw);
|
|
32
|
+
}
|
|
33
33
|
|
|
34
|
+
// -----------------------------------------------------------------------------
|
|
35
|
+
// Clear Cache (no shared-array bugs)
|
|
36
|
+
// -----------------------------------------------------------------------------
|
|
37
|
+
export function clearCache(props?: { ignoreWarning?: boolean }): void {
|
|
38
|
+
if (!props?.ignoreWarning) {
|
|
39
|
+
console.warn(
|
|
40
|
+
"The REST API clearCache should only be used with extreme care!",
|
|
41
|
+
);
|
|
34
42
|
}
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
for (const fn of userCustomClearCache) {
|
|
45
|
+
try {
|
|
46
|
+
fn();
|
|
47
|
+
} catch {}
|
|
48
|
+
}
|
|
41
49
|
|
|
42
|
-
|
|
50
|
+
apiRequestCache.clear();
|
|
51
|
+
}
|
|
43
52
|
|
|
44
|
-
|
|
53
|
+
// -----------------------------------------------------------------------------
|
|
54
|
+
// Check Cache (dedupe via hashed key)
|
|
55
|
+
// -----------------------------------------------------------------------------
|
|
56
|
+
export function checkCache<ResponseDataType = any>(
|
|
57
|
+
method: string,
|
|
58
|
+
tableName: string | string[],
|
|
59
|
+
requestData: any,
|
|
60
|
+
): AxiosPromise<ResponseDataType> | false {
|
|
61
|
+
const key = makeCacheKey(method, tableName, requestData);
|
|
62
|
+
const cached = apiRequestCache.get(key);
|
|
63
|
+
|
|
64
|
+
if (!cached) return false;
|
|
65
|
+
|
|
66
|
+
console.groupCollapsed(
|
|
67
|
+
`%c API cache hit for ${method} ${tableName}`,
|
|
68
|
+
"color:#0c0",
|
|
69
|
+
);
|
|
70
|
+
console.log("Request Data:", requestData);
|
|
71
|
+
console.groupEnd();
|
|
72
|
+
|
|
73
|
+
return cached.request;
|
|
74
|
+
}
|
|
45
75
|
|
|
76
|
+
// -----------------------------------------------------------------------------
|
|
77
|
+
// Store Cache Entry (drop-in compatible)
|
|
78
|
+
// -----------------------------------------------------------------------------
|
|
79
|
+
export function setCache<ResponseDataType = any>(
|
|
80
|
+
method: string,
|
|
81
|
+
tableName: string | string[],
|
|
82
|
+
requestData: any,
|
|
83
|
+
cacheEntry: iCacheAPI<ResponseDataType>,
|
|
84
|
+
): void {
|
|
85
|
+
const key = makeCacheKey(method, tableName, requestData);
|
|
86
|
+
apiRequestCache.set(key, cacheEntry);
|
|
46
87
|
}
|
|
@@ -2,13 +2,15 @@ import {apiRequestCache} from "./cacheManager";
|
|
|
2
2
|
|
|
3
3
|
export function checkAllRequestsComplete(): true | (string[]) {
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const cacheEntries = Array.from(apiRequestCache.values())
|
|
6
|
+
|
|
7
|
+
const stillRunning = cacheEntries.filter((cache) => undefined === cache.response)
|
|
6
8
|
|
|
7
9
|
if (stillRunning.length !== 0) {
|
|
8
10
|
|
|
9
11
|
if (document === null || document === undefined) {
|
|
10
12
|
|
|
11
|
-
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(
|
|
13
|
+
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(cacheEntries) + ')')
|
|
12
14
|
|
|
13
15
|
}
|
|
14
16
|
|
|
@@ -21,4 +23,4 @@ export function checkAllRequestsComplete(): true | (string[]) {
|
|
|
21
23
|
|
|
22
24
|
return true
|
|
23
25
|
|
|
24
|
-
}
|
|
26
|
+
}
|
package/src/variables/isNode.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
const isNode = () => {
|
|
2
|
-
|
|
3
|
-
console.log('Checking if running in Node.js environment...');
|
|
4
|
-
|
|
5
|
-
const isNodeEnv = typeof process !== 'undefined' && !!process.versions?.node;
|
|
6
|
-
|
|
7
|
-
console.log(`Is Node.js environment: ${isNodeEnv}`);
|
|
8
|
-
|
|
9
|
-
return isNodeEnv;
|
|
2
|
+
return typeof process !== 'undefined' && !!process.versions?.node;
|
|
10
3
|
}
|
|
11
4
|
|
|
12
5
|
export default isNode;
|