@memberjunction/core 6.1.5 → 6.1.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/dist/generic/baseEngine.d.ts +21 -0
- package/dist/generic/baseEngine.d.ts.map +1 -1
- package/dist/generic/baseEngine.js +60 -5
- package/dist/generic/baseEngine.js.map +1 -1
- package/dist/generic/baseEntity.d.ts +2 -1
- package/dist/generic/baseEntity.d.ts.map +1 -1
- package/dist/generic/baseEntity.js +3 -4
- package/dist/generic/baseEntity.js.map +1 -1
- package/dist/generic/databaseProviderBase.d.ts +41 -8
- package/dist/generic/databaseProviderBase.d.ts.map +1 -1
- package/dist/generic/databaseProviderBase.js +107 -42
- package/dist/generic/databaseProviderBase.js.map +1 -1
- package/dist/generic/entityRecordNameCache.d.ts +48 -0
- package/dist/generic/entityRecordNameCache.d.ts.map +1 -0
- package/dist/generic/entityRecordNameCache.js +92 -0
- package/dist/generic/entityRecordNameCache.js.map +1 -0
- package/dist/generic/interfaces.d.ts +39 -4
- package/dist/generic/interfaces.d.ts.map +1 -1
- package/dist/generic/interfaces.js.map +1 -1
- package/dist/generic/localCacheManager.d.ts +105 -11
- package/dist/generic/localCacheManager.d.ts.map +1 -1
- package/dist/generic/localCacheManager.js +221 -40
- package/dist/generic/localCacheManager.js.map +1 -1
- package/dist/generic/providerBase.d.ts +18 -22
- package/dist/generic/providerBase.d.ts.map +1 -1
- package/dist/generic/providerBase.js +26 -103
- package/dist/generic/providerBase.js.map +1 -1
- package/dist/generic/queryInfo.d.ts +14 -2
- package/dist/generic/queryInfo.d.ts.map +1 -1
- package/dist/generic/queryInfo.js +18 -5
- package/dist/generic/queryInfo.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -6,7 +6,7 @@ import { ComputeRRF } from "./scoring/ReciprocalRankFusion.js";
|
|
|
6
6
|
import { LocalCacheManager } from "./localCacheManager.js";
|
|
7
7
|
import { ApplicationInfo } from "../generic/applicationInfo.js";
|
|
8
8
|
import { AuditLogTypeInfo, AuthorizationInfo, AuthorizationRoleInfo, RoleInfo, RowLevelSecurityFilterInfo, UserInfo } from "./securityInfo.js";
|
|
9
|
-
import { MJGlobal, MJEventType, NormalizeUUID, UUIDsEqual,
|
|
9
|
+
import { MJGlobal, MJEventType, NormalizeUUID, UUIDsEqual, EscapeSQLString, ordinalCompare } from "@memberjunction/global";
|
|
10
10
|
import { FindReferencedIdentifiers } from "@memberjunction/sql-dialect";
|
|
11
11
|
import { TelemetryManager } from "./telemetryManager.js";
|
|
12
12
|
import { LogDebug, LogError, LogStatus, LogStatusEx } from "./logging.js";
|
|
@@ -186,10 +186,6 @@ export class ProviderBase {
|
|
|
186
186
|
this._localMetadata = new AllMetadata();
|
|
187
187
|
this._entityMapByName = new Map();
|
|
188
188
|
this._entityMapByID = new Map();
|
|
189
|
-
// Bounded LRU (unlike its siblings above, this cache holds one entry per distinct
|
|
190
|
-
// *record* touched via Load()/Save()/LoadFromData() — not per entity definition — so
|
|
191
|
-
// it can't be reset on metadata refresh; it needs its own eviction policy.
|
|
192
|
-
this._entityRecordNameCache = new MJLruCache({ maxSize: 10000, ttlMs: 60 * 60 * 1000 });
|
|
193
189
|
this._refresh = false;
|
|
194
190
|
/** Single-flight guard for the full metadata reload in {@link Config} — see the comment there. */
|
|
195
191
|
this._metadataReloadInFlight = null;
|
|
@@ -591,124 +587,49 @@ export class ProviderBase {
|
|
|
591
587
|
return false;
|
|
592
588
|
}
|
|
593
589
|
/**
|
|
594
|
-
*
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
*
|
|
601
|
-
* Use this for synchronous contexts (like template rendering) where you can't await GetEntityRecordName().
|
|
590
|
+
* Returns a record's name for synchronous display code, or `undefined` when it is not at hand.
|
|
591
|
+
*
|
|
592
|
+
* This provider keeps no record names, so without `loadIfNeeded` the answer is always
|
|
593
|
+
* `undefined`. A provider that serves a single user (`GraphQLDataProvider`) overrides the
|
|
594
|
+
* record-name methods with a cache; one shared by several users must not, since a name can be
|
|
595
|
+
* withheld from some of them.
|
|
596
|
+
*
|
|
602
597
|
* @param entityName - The name of the entity
|
|
603
598
|
* @param compositeKey - The primary key value(s) for the record
|
|
604
|
-
* @param loadIfNeeded -
|
|
605
|
-
* @returns The
|
|
599
|
+
* @param loadIfNeeded - Look the name up when it is not cached
|
|
600
|
+
* @returns The display name, or undefined if not cached and not looked up
|
|
606
601
|
*/
|
|
607
602
|
async GetCachedRecordName(entityName, compositeKey, loadIfNeeded) {
|
|
608
|
-
|
|
609
|
-
if (!cachedEntry && loadIfNeeded) {
|
|
610
|
-
cachedEntry = await this.GetEntityRecordName(entityName, compositeKey);
|
|
611
|
-
}
|
|
612
|
-
return cachedEntry;
|
|
603
|
+
return loadIfNeeded ? this.GetEntityRecordName(entityName, compositeKey) : undefined;
|
|
613
604
|
}
|
|
614
605
|
/**
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
* @param entityName - The name of the entity
|
|
618
|
-
* @param compositeKey - The primary key value(s) for the record
|
|
619
|
-
* @param recordName - The display name to cache
|
|
606
|
+
* Offers a record's name for later synchronous retrieval. `BaseEntity` calls it after every
|
|
607
|
+
* Load(), LoadFromData() and Save(). Ignored here; see {@link GetCachedRecordName}.
|
|
620
608
|
*/
|
|
621
609
|
SetCachedRecordName(entityName, compositeKey, recordName) {
|
|
622
|
-
this
|
|
610
|
+
// Intentionally empty: this provider keeps no record names.
|
|
623
611
|
}
|
|
624
612
|
/**
|
|
625
|
-
* Gets the display name for a single entity record
|
|
613
|
+
* Gets the display name for a single entity record.
|
|
626
614
|
* Uses the entity's IsNameField or falls back to 'Name' field if available.
|
|
627
615
|
* @param entityName - The name of the entity
|
|
628
616
|
* @param compositeKey - The primary key value(s) for the record
|
|
629
|
-
* @param contextUser -
|
|
630
|
-
* @param forceRefresh -
|
|
631
|
-
* @returns The display name of the record or
|
|
617
|
+
* @param contextUser - The acting user; field- and row-level security are applied for them
|
|
618
|
+
* @param forceRefresh - Bypass any cache. This provider has none, so it always looks up.
|
|
619
|
+
* @returns The display name of the record, or an empty string if not found or not readable
|
|
632
620
|
*/
|
|
633
621
|
async GetEntityRecordName(entityName, compositeKey, contextUser, forceRefresh = false) {
|
|
634
|
-
|
|
635
|
-
// Check cache unless forceRefresh
|
|
636
|
-
if (!forceRefresh) {
|
|
637
|
-
const cached = this._entityRecordNameCache.Get(cacheKey);
|
|
638
|
-
if (cached !== undefined) {
|
|
639
|
-
return cached;
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
// Fetch from database via provider-specific implementation
|
|
643
|
-
const name = await this.InternalGetEntityRecordName(entityName, compositeKey, contextUser);
|
|
644
|
-
if (name) {
|
|
645
|
-
this._entityRecordNameCache.Set(cacheKey, name);
|
|
646
|
-
}
|
|
647
|
-
return name;
|
|
622
|
+
return this.InternalGetEntityRecordName(entityName, compositeKey, contextUser);
|
|
648
623
|
}
|
|
649
624
|
/**
|
|
650
|
-
* Gets display names for multiple entity records in a single operation
|
|
651
|
-
* More efficient than multiple GetEntityRecordName calls.
|
|
625
|
+
* Gets display names for multiple entity records in a single operation.
|
|
652
626
|
* @param info - Array of entity/key pairs to lookup
|
|
653
|
-
* @param contextUser -
|
|
654
|
-
* @param forceRefresh -
|
|
627
|
+
* @param contextUser - The acting user; field- and row-level security are applied for them
|
|
628
|
+
* @param forceRefresh - Bypass any cache. This provider has none, so it always looks up.
|
|
655
629
|
* @returns Array of results with names and status for each requested record
|
|
656
630
|
*/
|
|
657
631
|
async GetEntityRecordNames(info, contextUser, forceRefresh = false) {
|
|
658
|
-
|
|
659
|
-
// Check cache for each item, collect uncached items
|
|
660
|
-
const results = [];
|
|
661
|
-
const uncachedInfo = [];
|
|
662
|
-
const uncachedIndexes = [];
|
|
663
|
-
for (let i = 0; i < info.length; i++) {
|
|
664
|
-
const item = info[i];
|
|
665
|
-
const cacheKey = this.getCacheKey(item.EntityName, item.CompositeKey);
|
|
666
|
-
const cached = this._entityRecordNameCache.Get(cacheKey);
|
|
667
|
-
if (cached !== undefined) {
|
|
668
|
-
// Cache hit
|
|
669
|
-
results[i] = {
|
|
670
|
-
EntityName: item.EntityName,
|
|
671
|
-
CompositeKey: item.CompositeKey,
|
|
672
|
-
Status: 'cached',
|
|
673
|
-
Success: true,
|
|
674
|
-
RecordName: cached
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
else {
|
|
678
|
-
// Cache miss - need to fetch
|
|
679
|
-
uncachedInfo.push(item);
|
|
680
|
-
uncachedIndexes.push(i);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
// Fetch uncached items from database
|
|
684
|
-
if (uncachedInfo.length > 0) {
|
|
685
|
-
const uncachedResults = await this.InternalGetEntityRecordNames(uncachedInfo, contextUser);
|
|
686
|
-
// Merge results and update cache
|
|
687
|
-
for (let i = 0; i < uncachedResults.length; i++) {
|
|
688
|
-
const result = uncachedResults[i];
|
|
689
|
-
const originalIndex = uncachedIndexes[i];
|
|
690
|
-
results[originalIndex] = result;
|
|
691
|
-
// Cache successful results
|
|
692
|
-
if (result.Success && result.RecordName) {
|
|
693
|
-
const cacheKey = this.getCacheKey(result.EntityName, result.CompositeKey);
|
|
694
|
-
this._entityRecordNameCache.Set(cacheKey, result.RecordName);
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
return results;
|
|
699
|
-
}
|
|
700
|
-
else {
|
|
701
|
-
// Force refresh - bypass cache entirely
|
|
702
|
-
const results = await this.InternalGetEntityRecordNames(info, contextUser);
|
|
703
|
-
// Update cache with fresh results
|
|
704
|
-
for (const result of results) {
|
|
705
|
-
if (result.Success && result.RecordName) {
|
|
706
|
-
const cacheKey = this.getCacheKey(result.EntityName, result.CompositeKey);
|
|
707
|
-
this._entityRecordNameCache.Set(cacheKey, result.RecordName);
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
return results;
|
|
711
|
-
}
|
|
632
|
+
return this.InternalGetEntityRecordNames(info, contextUser);
|
|
712
633
|
}
|
|
713
634
|
// ========================================================================
|
|
714
635
|
// PUBLIC API METHODS - Orchestrate Pre → Cache → Internal → Post flow
|
|
@@ -1779,7 +1700,9 @@ export class ProviderBase {
|
|
|
1779
1700
|
resolvable: true,
|
|
1780
1701
|
// No user (client-side / trusted single-user context) ⇒ nothing to authorize against;
|
|
1781
1702
|
// the gate only consults `authorized` when a contextUser is present.
|
|
1782
|
-
|
|
1703
|
+
// This provider's permissions, not the global provider's: a client connection that is not
|
|
1704
|
+
// the global one may have no global provider at all, or one holding another server's.
|
|
1705
|
+
authorized: !user || qInfo.UserCanRun(user, this),
|
|
1783
1706
|
categoryPath: qInfo.CategoryPath,
|
|
1784
1707
|
queryName: qInfo.Name
|
|
1785
1708
|
};
|