@memberjunction/core 5.11.0 → 5.13.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/generic/QueryCache.d.ts +41 -7
- package/dist/generic/QueryCache.d.ts.map +1 -1
- package/dist/generic/QueryCache.js +146 -12
- package/dist/generic/QueryCache.js.map +1 -1
- package/dist/generic/QueryCacheManager.d.ts +105 -0
- package/dist/generic/QueryCacheManager.d.ts.map +1 -0
- package/dist/generic/QueryCacheManager.js +314 -0
- package/dist/generic/QueryCacheManager.js.map +1 -0
- package/dist/generic/baseEntity.js +2 -2
- package/dist/generic/baseEntity.js.map +1 -1
- package/dist/generic/dataHooks.d.ts +56 -0
- package/dist/generic/dataHooks.d.ts.map +1 -0
- package/dist/generic/dataHooks.js +56 -0
- package/dist/generic/dataHooks.js.map +1 -0
- package/dist/generic/interfaces.d.ts +10 -0
- package/dist/generic/interfaces.d.ts.map +1 -1
- package/dist/generic/interfaces.js.map +1 -1
- package/dist/generic/providerBase.js +3 -3
- package/dist/generic/providerBase.js.map +1 -1
- package/dist/generic/queryCompositionEngine.d.ts +7 -0
- package/dist/generic/queryCompositionEngine.d.ts.map +1 -1
- package/dist/generic/queryCompositionEngine.js +41 -5
- package/dist/generic/queryCompositionEngine.js.map +1 -1
- package/dist/generic/queryInfoInterfaces.d.ts +6 -0
- package/dist/generic/queryInfoInterfaces.d.ts.map +1 -1
- package/dist/generic/queryPagingEngine.d.ts +110 -0
- package/dist/generic/queryPagingEngine.d.ts.map +1 -0
- package/dist/generic/queryPagingEngine.js +335 -0
- package/dist/generic/queryPagingEngine.js.map +1 -0
- package/dist/generic/runQuery.d.ts +8 -0
- package/dist/generic/runQuery.d.ts.map +1 -1
- package/dist/generic/runQuery.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/generic/hookRegistry.d.ts +0 -83
- package/dist/generic/hookRegistry.d.ts.map +0 -1
- package/dist/generic/hookRegistry.js +0 -87
- package/dist/generic/hookRegistry.js.map +0 -1
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { LocalCacheManager } from './localCacheManager.js';
|
|
2
|
+
import { Metadata } from './metadata.js';
|
|
3
|
+
import { LogStatus } from './logging.js';
|
|
4
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
5
|
+
/**
|
|
6
|
+
* Wrapper around LocalCacheManager that translates query-specific caching concerns
|
|
7
|
+
* (paging, count, ad-hoc keys, dependency invalidation, entity-change awareness)
|
|
8
|
+
* into LocalCacheManager's generic RunQueryCache methods.
|
|
9
|
+
*
|
|
10
|
+
* Replaces the standalone QueryCache class so that query result caching participates
|
|
11
|
+
* in LCM's unified eviction, TTL, statistics, and optional Redis persistence.
|
|
12
|
+
*
|
|
13
|
+
* ## IMPORTANT — Caching is intentionally BYPASSED for now
|
|
14
|
+
*
|
|
15
|
+
* All Get/Set methods are wired up but short-circuit to no-ops. The reason:
|
|
16
|
+
*
|
|
17
|
+
* Query results cannot be reliably invalidated today. Unlike RunView caching (which
|
|
18
|
+
* tracks individual entities and can invalidate on any row-level mutation), queries
|
|
19
|
+
* are arbitrary SQL that may join, filter, or aggregate across many tables. The
|
|
20
|
+
* `QueryEntity` table maps queries to the entities they reference, but those mappings
|
|
21
|
+
* are LLM-discovered and not guaranteed to be complete. A TTL-only strategy risks
|
|
22
|
+
* serving stale data when the underlying rows change before the TTL expires.
|
|
23
|
+
*
|
|
24
|
+
* The full caching implementation is preserved below so that when we have a reliable
|
|
25
|
+
* invalidation strategy (e.g., entity mutation hooks that can confidently evict all
|
|
26
|
+
* affected query caches with complete QueryEntity coverage), we can enable caching
|
|
27
|
+
* by removing the early returns at the top of each method. Until then, every query
|
|
28
|
+
* execution hits the database to guarantee fresh results.
|
|
29
|
+
*/
|
|
30
|
+
export class QueryCacheManager {
|
|
31
|
+
constructor(connectionPrefix) {
|
|
32
|
+
/** Tracks cache timestamps per fingerprint for computing CacheTTLRemaining */
|
|
33
|
+
this._cacheTimestamps = new Map();
|
|
34
|
+
/** Reverse index: normalized entity name → set of fingerprints that depend on it */
|
|
35
|
+
this._queryEntityIndex = new Map();
|
|
36
|
+
this._connectionPrefix = connectionPrefix;
|
|
37
|
+
}
|
|
38
|
+
get LCM() {
|
|
39
|
+
return LocalCacheManager.Instance;
|
|
40
|
+
}
|
|
41
|
+
// ── Fingerprint generation ──────────────────────────────────────────────
|
|
42
|
+
Fingerprint(queryId, queryName, params) {
|
|
43
|
+
return this.LCM.GenerateRunQueryFingerprint(queryId, queryName, params, this._connectionPrefix);
|
|
44
|
+
}
|
|
45
|
+
PagedFingerprint(queryId, queryName, params, startRow, maxRows) {
|
|
46
|
+
return `${this.Fingerprint(queryId, queryName, params)}|page:${startRow}:${maxRows}`;
|
|
47
|
+
}
|
|
48
|
+
CountFingerprint(queryId, queryName, params) {
|
|
49
|
+
return `${this.Fingerprint(queryId, queryName, params)}|count`;
|
|
50
|
+
}
|
|
51
|
+
AdhocFingerprint(sql) {
|
|
52
|
+
return `_adhoc_|_|${QueryCacheManager.Fnv1aHash(sql)}|${this._connectionPrefix}`;
|
|
53
|
+
}
|
|
54
|
+
// ── Full-result cache ───────────────────────────────────────────────────
|
|
55
|
+
/**
|
|
56
|
+
* Retrieves cached full (unpaginated) results for a saved query.
|
|
57
|
+
* Returns null on miss or if caching is disabled.
|
|
58
|
+
*/
|
|
59
|
+
async Get(query, params) {
|
|
60
|
+
// BYPASSED — see class-level comment for rationale
|
|
61
|
+
return null;
|
|
62
|
+
/* When caching is enabled, uncomment the block below:
|
|
63
|
+
if (!query.CacheConfig?.enabled) return null;
|
|
64
|
+
|
|
65
|
+
const fp = this.Fingerprint(query.ID, query.Name, params);
|
|
66
|
+
const cached = await this.LCM.GetRunQueryResult(fp);
|
|
67
|
+
if (!cached) return null;
|
|
68
|
+
|
|
69
|
+
const ttlRemainingMs = this.computeTTLRemaining(fp, query.CacheConfig.ttlMinutes);
|
|
70
|
+
return { results: cached.results, ttlRemainingMs };
|
|
71
|
+
*/
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Stores full (unpaginated) query results in the cache.
|
|
75
|
+
*/
|
|
76
|
+
async Set(query, params, results) {
|
|
77
|
+
// BYPASSED — see class-level comment for rationale
|
|
78
|
+
return;
|
|
79
|
+
/* When caching is enabled, uncomment the block below:
|
|
80
|
+
const config = query.CacheConfig;
|
|
81
|
+
if (!config?.enabled) return;
|
|
82
|
+
|
|
83
|
+
const fp = this.Fingerprint(query.ID, query.Name, params);
|
|
84
|
+
const ttlMs = config.ttlMinutes * 60 * 1000;
|
|
85
|
+
|
|
86
|
+
await this.LCM.SetRunQueryResult(
|
|
87
|
+
fp, query.Name, results,
|
|
88
|
+
new Date().toISOString(),
|
|
89
|
+
results.length, query.ID, ttlMs,
|
|
90
|
+
);
|
|
91
|
+
this._cacheTimestamps.set(fp, Date.now());
|
|
92
|
+
this.RegisterEntityDependencies(fp, query);
|
|
93
|
+
*/
|
|
94
|
+
}
|
|
95
|
+
// ── Paged cache ─────────────────────────────────────────────────────────
|
|
96
|
+
/**
|
|
97
|
+
* Retrieves cached results for a specific page of a paged query.
|
|
98
|
+
*/
|
|
99
|
+
async GetPaged(query, params, startRow, maxRows) {
|
|
100
|
+
// BYPASSED — see class-level comment for rationale
|
|
101
|
+
return null;
|
|
102
|
+
/* When caching is enabled, uncomment the block below:
|
|
103
|
+
if (!query.CacheConfig?.enabled) return null;
|
|
104
|
+
|
|
105
|
+
const fp = this.PagedFingerprint(query.ID, query.Name, params, startRow, maxRows);
|
|
106
|
+
const cached = await this.LCM.GetRunQueryResult(fp);
|
|
107
|
+
if (!cached) return null;
|
|
108
|
+
|
|
109
|
+
const ttlRemainingMs = this.computeTTLRemaining(fp, query.CacheConfig.ttlMinutes);
|
|
110
|
+
return { results: cached.results, ttlRemainingMs };
|
|
111
|
+
*/
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Stores results for a specific page in the cache.
|
|
115
|
+
*/
|
|
116
|
+
async SetPaged(query, params, startRow, maxRows, results) {
|
|
117
|
+
// BYPASSED — see class-level comment for rationale
|
|
118
|
+
return;
|
|
119
|
+
/* When caching is enabled, uncomment the block below:
|
|
120
|
+
const config = query.CacheConfig;
|
|
121
|
+
if (!config?.enabled) return;
|
|
122
|
+
|
|
123
|
+
const fp = this.PagedFingerprint(query.ID, query.Name, params, startRow, maxRows);
|
|
124
|
+
const ttlMs = config.ttlMinutes * 60 * 1000;
|
|
125
|
+
const displayName = `${query.Name} [page ${startRow}+${maxRows}]`;
|
|
126
|
+
|
|
127
|
+
await this.LCM.SetRunQueryResult(
|
|
128
|
+
fp, displayName, results,
|
|
129
|
+
new Date().toISOString(), results.length, query.ID, ttlMs,
|
|
130
|
+
);
|
|
131
|
+
this._cacheTimestamps.set(fp, Date.now());
|
|
132
|
+
this.RegisterEntityDependencies(fp, query);
|
|
133
|
+
*/
|
|
134
|
+
}
|
|
135
|
+
// ── Count cache ─────────────────────────────────────────────────────────
|
|
136
|
+
/**
|
|
137
|
+
* Retrieves a cached TotalRowCount for a query + params combination.
|
|
138
|
+
*/
|
|
139
|
+
async GetTotalRowCount(query, params) {
|
|
140
|
+
// BYPASSED — see class-level comment for rationale
|
|
141
|
+
return null;
|
|
142
|
+
/* When caching is enabled, uncomment the block below:
|
|
143
|
+
if (!query.CacheConfig?.enabled) return null;
|
|
144
|
+
|
|
145
|
+
const fp = this.CountFingerprint(query.ID, query.Name, params);
|
|
146
|
+
const cached = await this.LCM.GetRunQueryResult(fp);
|
|
147
|
+
if (!cached) return null;
|
|
148
|
+
|
|
149
|
+
const row = cached.results[0] as { TotalRowCount: number } | undefined;
|
|
150
|
+
return row?.TotalRowCount ?? null;
|
|
151
|
+
*/
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Stores a TotalRowCount value in the cache, encoded as a single-row result.
|
|
155
|
+
*/
|
|
156
|
+
async SetTotalRowCount(query, params, count) {
|
|
157
|
+
// BYPASSED — see class-level comment for rationale
|
|
158
|
+
return;
|
|
159
|
+
/* When caching is enabled, uncomment the block below:
|
|
160
|
+
const config = query.CacheConfig;
|
|
161
|
+
if (!config?.enabled) return;
|
|
162
|
+
|
|
163
|
+
const fp = this.CountFingerprint(query.ID, query.Name, params);
|
|
164
|
+
const ttlMs = config.ttlMinutes * 60 * 1000;
|
|
165
|
+
|
|
166
|
+
await this.LCM.SetRunQueryResult(
|
|
167
|
+
fp, `${query.Name} [count]`, [{ TotalRowCount: count }],
|
|
168
|
+
new Date().toISOString(), 1, query.ID, ttlMs,
|
|
169
|
+
);
|
|
170
|
+
this._cacheTimestamps.set(fp, Date.now());
|
|
171
|
+
*/
|
|
172
|
+
}
|
|
173
|
+
// ── Ad-hoc cache ────────────────────────────────────────────────────────
|
|
174
|
+
/**
|
|
175
|
+
* Retrieves cached results for an ad-hoc SQL query.
|
|
176
|
+
*/
|
|
177
|
+
async GetAdhoc(sql, ttlMinutes) {
|
|
178
|
+
// BYPASSED — see class-level comment for rationale
|
|
179
|
+
return null;
|
|
180
|
+
/* When caching is enabled, uncomment the block below:
|
|
181
|
+
if (ttlMinutes <= 0) return null;
|
|
182
|
+
|
|
183
|
+
const fp = this.AdhocFingerprint(sql);
|
|
184
|
+
const cached = await this.LCM.GetRunQueryResult(fp);
|
|
185
|
+
return cached ? { results: cached.results } : null;
|
|
186
|
+
*/
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Stores ad-hoc SQL query results in the cache.
|
|
190
|
+
*/
|
|
191
|
+
async SetAdhoc(sql, ttlMinutes, results) {
|
|
192
|
+
// BYPASSED — see class-level comment for rationale
|
|
193
|
+
return;
|
|
194
|
+
/* When caching is enabled, uncomment the block below:
|
|
195
|
+
if (ttlMinutes <= 0) return;
|
|
196
|
+
|
|
197
|
+
const fp = this.AdhocFingerprint(sql);
|
|
198
|
+
const ttlMs = ttlMinutes * 60 * 1000;
|
|
199
|
+
|
|
200
|
+
await this.LCM.SetRunQueryResult(
|
|
201
|
+
fp, 'Ad-Hoc Query', results,
|
|
202
|
+
new Date().toISOString(), results.length, undefined, ttlMs,
|
|
203
|
+
);
|
|
204
|
+
this._cacheTimestamps.set(fp, Date.now());
|
|
205
|
+
*/
|
|
206
|
+
}
|
|
207
|
+
// ── Invalidation ────────────────────────────────────────────────────────
|
|
208
|
+
/**
|
|
209
|
+
* Invalidates all cache entries (full, paged, count) for a single query by name.
|
|
210
|
+
*/
|
|
211
|
+
async InvalidateQuery(queryName) {
|
|
212
|
+
// No-op while caching is bypassed, but safe to call unconditionally
|
|
213
|
+
await this.LCM.InvalidateQueryCaches(queryName);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Invalidates cache entries for a query and all queries that transitively depend on it.
|
|
217
|
+
*/
|
|
218
|
+
async InvalidateWithDependents(query, visited = new Set()) {
|
|
219
|
+
// No-op while caching is bypassed (nothing in cache to invalidate),
|
|
220
|
+
// but the traversal logic is preserved for when caching is enabled.
|
|
221
|
+
if (visited.has(query.ID))
|
|
222
|
+
return;
|
|
223
|
+
visited.add(query.ID);
|
|
224
|
+
await this.LCM.InvalidateQueryCaches(query.Name);
|
|
225
|
+
const dependents = query.Dependents;
|
|
226
|
+
if (dependents && dependents.length > 0) {
|
|
227
|
+
for (const dep of dependents) {
|
|
228
|
+
const depQuery = this.FindQueryById(dep.QueryID);
|
|
229
|
+
if (depQuery) {
|
|
230
|
+
await this.InvalidateWithDependents(depQuery, visited);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// ── Entity-change invalidation ──────────────────────────────────────────
|
|
236
|
+
/**
|
|
237
|
+
* Called when an entity changes (save/delete). Invalidates all query cache entries
|
|
238
|
+
* that depend on the changed entity via QueryEntity mappings.
|
|
239
|
+
*
|
|
240
|
+
* While caching is bypassed the reverse index will always be empty, so this is
|
|
241
|
+
* effectively a no-op. Kept wired up so enabling caching requires no caller changes.
|
|
242
|
+
*/
|
|
243
|
+
async HandleEntityChange(entityName) {
|
|
244
|
+
const normalized = entityName.trim().toLowerCase();
|
|
245
|
+
const fingerprints = this._queryEntityIndex.get(normalized);
|
|
246
|
+
if (!fingerprints || fingerprints.size === 0)
|
|
247
|
+
return;
|
|
248
|
+
const fpArray = [...fingerprints];
|
|
249
|
+
for (const fp of fpArray) {
|
|
250
|
+
await this.LCM.InvalidateRunQueryResult(fp);
|
|
251
|
+
this._cacheTimestamps.delete(fp);
|
|
252
|
+
}
|
|
253
|
+
fingerprints.clear();
|
|
254
|
+
LogStatus(`QueryCacheManager: invalidated ${fpArray.length} cache entries for entity "${entityName}"`);
|
|
255
|
+
}
|
|
256
|
+
// ── Entity dependency registration (private) ────────────────────────────
|
|
257
|
+
RegisterEntityDependencies(fingerprint, query) {
|
|
258
|
+
const entityNames = this.GetTransitiveEntityDependencies(query);
|
|
259
|
+
for (const name of entityNames) {
|
|
260
|
+
const normalized = name.trim().toLowerCase();
|
|
261
|
+
if (!this._queryEntityIndex.has(normalized)) {
|
|
262
|
+
this._queryEntityIndex.set(normalized, new Set());
|
|
263
|
+
}
|
|
264
|
+
this._queryEntityIndex.get(normalized).add(fingerprint);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
GetTransitiveEntityDependencies(query, visited = new Set()) {
|
|
268
|
+
if (visited.has(query.ID))
|
|
269
|
+
return [];
|
|
270
|
+
visited.add(query.ID);
|
|
271
|
+
const entities = [];
|
|
272
|
+
// Direct entity mappings from QueryEntity table
|
|
273
|
+
const queryEntities = query.Entities;
|
|
274
|
+
if (queryEntities) {
|
|
275
|
+
for (const qe of queryEntities) {
|
|
276
|
+
if (qe.Entity) {
|
|
277
|
+
entities.push(qe.Entity);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// Walk composition dependencies for transitive entity mappings
|
|
282
|
+
const dependencies = query.Dependencies;
|
|
283
|
+
if (dependencies) {
|
|
284
|
+
for (const dep of dependencies) {
|
|
285
|
+
const depQuery = this.FindQueryById(dep.DependsOnQueryID);
|
|
286
|
+
if (depQuery) {
|
|
287
|
+
entities.push(...this.GetTransitiveEntityDependencies(depQuery, visited));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return [...new Set(entities)];
|
|
292
|
+
}
|
|
293
|
+
// ── Helpers ─────────────────────────────────────────────────────────────
|
|
294
|
+
FindQueryById(queryId) {
|
|
295
|
+
return Metadata.Provider.Queries.find((q) => UUIDsEqual(q.ID, queryId));
|
|
296
|
+
}
|
|
297
|
+
computeTTLRemaining(fingerprint, ttlMinutes) {
|
|
298
|
+
const cachedAt = this._cacheTimestamps.get(fingerprint) ?? 0;
|
|
299
|
+
const ttlMs = ttlMinutes * 60 * 1000;
|
|
300
|
+
return Math.max(0, (cachedAt + ttlMs) - Date.now());
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* FNV-1a 32-bit hash — fast, deterministic, good distribution for cache keys.
|
|
304
|
+
*/
|
|
305
|
+
static Fnv1aHash(input) {
|
|
306
|
+
let hash = 0x811c9dc5; // FNV offset basis
|
|
307
|
+
for (let i = 0; i < input.length; i++) {
|
|
308
|
+
hash ^= input.charCodeAt(i);
|
|
309
|
+
hash = (hash * 0x01000193) >>> 0; // FNV prime, keep as uint32
|
|
310
|
+
}
|
|
311
|
+
return hash.toString(16);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=QueryCacheManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryCacheManager.js","sourceRoot":"","sources":["../../src/generic/QueryCacheManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MJEventType, MJGlobal, uuidv4, UUIDsEqual, WarningManager } from '@memberjunction/global';
|
|
2
|
-
import {
|
|
2
|
+
import { GetDataHooks } from './dataHooks.js';
|
|
3
3
|
import { EntityFieldInfo, EntityInfo, EntityFieldTSType, EntityPermissionType, RecordChange, ValidationErrorInfo, ValidationResult } from './entityInfo.js';
|
|
4
4
|
import { EntityDeleteOptions, EntitySaveOptions, ProviderType } from './interfaces.js';
|
|
5
5
|
import { Metadata } from './metadata.js';
|
|
@@ -1775,7 +1775,7 @@ export class BaseEntity {
|
|
|
1775
1775
|
* (error message), the save is rejected by throwing an Error.
|
|
1776
1776
|
*/
|
|
1777
1777
|
async RunPreSaveHooks() {
|
|
1778
|
-
const preSaveHooks =
|
|
1778
|
+
const preSaveHooks = GetDataHooks('PreSave');
|
|
1779
1779
|
for (const hook of preSaveHooks) {
|
|
1780
1780
|
const hookResult = await hook(this, this.ActiveUser);
|
|
1781
1781
|
if (hookResult === false) {
|