@memberjunction/core 3.3.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/__tests__/mocks/TestMetadataProvider.d.ts +45 -0
- package/dist/__tests__/mocks/TestMetadataProvider.d.ts.map +1 -0
- package/dist/__tests__/mocks/TestMetadataProvider.js +217 -0
- package/dist/__tests__/mocks/TestMetadataProvider.js.map +1 -0
- package/dist/__tests__/providerBase.concurrency.test.d.ts +10 -0
- package/dist/__tests__/providerBase.concurrency.test.d.ts.map +1 -0
- package/dist/__tests__/providerBase.concurrency.test.js +253 -0
- package/dist/__tests__/providerBase.concurrency.test.js.map +1 -0
- package/dist/__tests__/providerBase.refresh.test.d.ts +10 -0
- package/dist/__tests__/providerBase.refresh.test.d.ts.map +1 -0
- package/dist/__tests__/providerBase.refresh.test.js +161 -0
- package/dist/__tests__/providerBase.refresh.test.js.map +1 -0
- package/dist/__tests__/setup.d.ts +5 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +17 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/generic/InMemoryLocalStorageProvider.d.ts +1 -1
- package/dist/generic/InMemoryLocalStorageProvider.js +2 -6
- package/dist/generic/InMemoryLocalStorageProvider.js.map +1 -1
- package/dist/generic/QueryCache.d.ts +1 -1
- package/dist/generic/QueryCache.js +6 -10
- package/dist/generic/QueryCache.js.map +1 -1
- package/dist/generic/QueryCacheConfig.js +1 -2
- package/dist/generic/RegisterForStartup.d.ts +2 -2
- package/dist/generic/RegisterForStartup.js +7 -12
- package/dist/generic/RegisterForStartup.js.map +1 -1
- package/dist/generic/applicationInfo.d.ts +3 -3
- package/dist/generic/applicationInfo.js +4 -10
- package/dist/generic/applicationInfo.js.map +1 -1
- package/dist/generic/authEvaluator.d.ts +1 -1
- package/dist/generic/authEvaluator.js +4 -8
- package/dist/generic/authEvaluator.js.map +1 -1
- package/dist/generic/authTypes.js +1 -4
- package/dist/generic/authTypes.js.map +1 -1
- package/dist/generic/baseEngine.d.ts +5 -5
- package/dist/generic/baseEngine.js +51 -56
- package/dist/generic/baseEngine.js.map +1 -1
- package/dist/generic/baseEngineRegistry.js +13 -17
- package/dist/generic/baseEngineRegistry.js.map +1 -1
- package/dist/generic/baseEntity.d.ts +5 -5
- package/dist/generic/baseEntity.js +103 -113
- package/dist/generic/baseEntity.js.map +1 -1
- package/dist/generic/baseInfo.js +3 -7
- package/dist/generic/baseInfo.js.map +1 -1
- package/dist/generic/compositeKey.d.ts +2 -2
- package/dist/generic/compositeKey.js +5 -11
- package/dist/generic/compositeKey.js.map +1 -1
- package/dist/generic/databaseProviderBase.d.ts +2 -2
- package/dist/generic/databaseProviderBase.js +2 -6
- package/dist/generic/databaseProviderBase.js.map +1 -1
- package/dist/generic/entityInfo.d.ts +74 -5
- package/dist/generic/entityInfo.d.ts.map +1 -1
- package/dist/generic/entityInfo.js +138 -105
- package/dist/generic/entityInfo.js.map +1 -1
- package/dist/generic/explorerNavigationItem.d.ts +1 -1
- package/dist/generic/explorerNavigationItem.js +2 -6
- package/dist/generic/explorerNavigationItem.js.map +1 -1
- package/dist/generic/graphqlTypeNames.d.ts +1 -1
- package/dist/generic/graphqlTypeNames.js +4 -9
- package/dist/generic/graphqlTypeNames.js.map +1 -1
- package/dist/generic/interfaces.d.ts +51 -12
- package/dist/generic/interfaces.d.ts.map +1 -1
- package/dist/generic/interfaces.js +15 -30
- package/dist/generic/interfaces.js.map +1 -1
- package/dist/generic/libraryInfo.d.ts +1 -1
- package/dist/generic/libraryInfo.js +2 -6
- package/dist/generic/libraryInfo.js.map +1 -1
- package/dist/generic/localCacheManager.d.ts +2 -2
- package/dist/generic/localCacheManager.js +44 -48
- package/dist/generic/localCacheManager.js.map +1 -1
- package/dist/generic/logging.d.ts.map +1 -1
- package/dist/generic/logging.js +54 -67
- package/dist/generic/logging.js.map +1 -1
- package/dist/generic/metadata.d.ts +10 -10
- package/dist/generic/metadata.js +17 -21
- package/dist/generic/metadata.js.map +1 -1
- package/dist/generic/metadataUtil.d.ts +1 -1
- package/dist/generic/metadataUtil.js +3 -7
- package/dist/generic/metadataUtil.js.map +1 -1
- package/dist/generic/providerBase.d.ts +18 -12
- package/dist/generic/providerBase.d.ts.map +1 -1
- package/dist/generic/providerBase.js +130 -130
- package/dist/generic/providerBase.js.map +1 -1
- package/dist/generic/queryInfo.d.ts +5 -5
- package/dist/generic/queryInfo.js +21 -30
- package/dist/generic/queryInfo.js.map +1 -1
- package/dist/generic/queryInfoInterfaces.js +1 -2
- package/dist/generic/queryInfoInterfaces.js.map +1 -1
- package/dist/generic/querySQLFilters.js +5 -10
- package/dist/generic/querySQLFilters.js.map +1 -1
- package/dist/generic/runQuery.d.ts +2 -2
- package/dist/generic/runQuery.js +5 -9
- package/dist/generic/runQuery.js.map +1 -1
- package/dist/generic/runQuerySQLFilterImplementations.d.ts +1 -1
- package/dist/generic/runQuerySQLFilterImplementations.js +4 -8
- package/dist/generic/runQuerySQLFilterImplementations.js.map +1 -1
- package/dist/generic/runReport.d.ts +2 -2
- package/dist/generic/runReport.js +5 -9
- package/dist/generic/runReport.js.map +1 -1
- package/dist/generic/securityInfo.d.ts +2 -2
- package/dist/generic/securityInfo.js +10 -20
- package/dist/generic/securityInfo.js.map +1 -1
- package/dist/generic/telemetryManager.js +20 -32
- package/dist/generic/telemetryManager.js.map +1 -1
- package/dist/generic/transactionGroup.d.ts +1 -1
- package/dist/generic/transactionGroup.d.ts.map +1 -1
- package/dist/generic/transactionGroup.js +11 -19
- package/dist/generic/transactionGroup.js.map +1 -1
- package/dist/generic/util.js +15 -31
- package/dist/generic/util.js.map +1 -1
- package/dist/index.d.ts +34 -34
- package/dist/index.js +45 -63
- package/dist/index.js.map +1 -1
- package/dist/views/runView.d.ts +3 -3
- package/dist/views/runView.js +6 -11
- package/dist/views/runView.js.map +1 -1
- package/dist/views/viewInfo.d.ts +3 -3
- package/dist/views/viewInfo.js +10 -17
- package/dist/views/viewInfo.js.map +1 -1
- package/package.json +11 -10
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const compositeKey_1 = require("./compositeKey");
|
|
17
|
-
const explorerNavigationItem_1 = require("./explorerNavigationItem");
|
|
18
|
-
const metadata_1 = require("./metadata");
|
|
19
|
-
const runView_1 = require("../views/runView");
|
|
1
|
+
import { BaseEntity } from "./baseEntity.js";
|
|
2
|
+
import { EntityDocumentTypeInfo, EntityInfo } from "./entityInfo.js";
|
|
3
|
+
import { AllMetadata } from "./interfaces.js";
|
|
4
|
+
import { LocalCacheManager } from "./localCacheManager.js";
|
|
5
|
+
import { ApplicationInfo } from "../generic/applicationInfo.js";
|
|
6
|
+
import { AuditLogTypeInfo, AuthorizationInfo, RoleInfo, RowLevelSecurityFilterInfo, UserInfo } from "./securityInfo.js";
|
|
7
|
+
import { MJGlobal } from "@memberjunction/global";
|
|
8
|
+
import { TelemetryManager } from "./telemetryManager.js";
|
|
9
|
+
import { LogError, LogStatus } from "./logging.js";
|
|
10
|
+
import { QueryCategoryInfo, QueryFieldInfo, QueryInfo, QueryPermissionInfo, QueryEntityInfo, QueryParameterInfo } from "./queryInfo.js";
|
|
11
|
+
import { LibraryInfo } from "./libraryInfo.js";
|
|
12
|
+
import { CompositeKey } from "./compositeKey.js";
|
|
13
|
+
import { ExplorerNavigationItem } from "./explorerNavigationItem.js";
|
|
14
|
+
import { Metadata } from "./metadata.js";
|
|
15
|
+
import { RunView } from "../views/runView.js";
|
|
20
16
|
/**
|
|
21
17
|
* Creates a new instance of AllMetadata from a simple object.
|
|
22
18
|
* Handles deserialization and proper instantiation of all metadata classes.
|
|
@@ -24,17 +20,16 @@ const runView_1 = require("../views/runView");
|
|
|
24
20
|
* @param md - The metadata provider for context
|
|
25
21
|
* @returns A fully populated AllMetadata instance with proper type instances
|
|
26
22
|
*/
|
|
27
|
-
function MetadataFromSimpleObject(data, md) {
|
|
23
|
+
export function MetadataFromSimpleObject(data, md) {
|
|
28
24
|
try {
|
|
29
25
|
const newObject = MetadataFromSimpleObjectWithoutUser(data, md);
|
|
30
|
-
newObject.CurrentUser = data.CurrentUser ? new
|
|
26
|
+
newObject.CurrentUser = data.CurrentUser ? new UserInfo(md, data.CurrentUser) : null;
|
|
31
27
|
return newObject;
|
|
32
28
|
}
|
|
33
29
|
catch (e) {
|
|
34
|
-
|
|
30
|
+
LogError(e);
|
|
35
31
|
}
|
|
36
32
|
}
|
|
37
|
-
exports.MetadataFromSimpleObject = MetadataFromSimpleObject;
|
|
38
33
|
/**
|
|
39
34
|
* Creates a new instance of AllMetadata from a simple object, but does NOT set the CurrentUser property
|
|
40
35
|
* Handles deserialization and proper instantiation of all metadata classes.
|
|
@@ -42,11 +37,11 @@ exports.MetadataFromSimpleObject = MetadataFromSimpleObject;
|
|
|
42
37
|
* @param md - The metadata provider for context
|
|
43
38
|
* @returns A fully populated AllMetadata instance with proper type instances
|
|
44
39
|
*/
|
|
45
|
-
function MetadataFromSimpleObjectWithoutUser(data, md) {
|
|
40
|
+
export function MetadataFromSimpleObjectWithoutUser(data, md) {
|
|
46
41
|
try {
|
|
47
|
-
const returnMetadata = new
|
|
42
|
+
const returnMetadata = new AllMetadata();
|
|
48
43
|
// now iterate through the AllMetadataMapping array and construct the return type
|
|
49
|
-
for (let m of
|
|
44
|
+
for (let m of AllMetadataArrays) {
|
|
50
45
|
let simpleKey = m.key;
|
|
51
46
|
if (!data.hasOwnProperty(simpleKey)) {
|
|
52
47
|
simpleKey = simpleKey.substring(3); // remove the All prefix
|
|
@@ -62,41 +57,40 @@ function MetadataFromSimpleObjectWithoutUser(data, md) {
|
|
|
62
57
|
return returnMetadata;
|
|
63
58
|
}
|
|
64
59
|
catch (e) {
|
|
65
|
-
|
|
60
|
+
LogError(e);
|
|
66
61
|
}
|
|
67
62
|
}
|
|
68
|
-
exports.MetadataFromSimpleObjectWithoutUser = MetadataFromSimpleObjectWithoutUser;
|
|
69
63
|
/**
|
|
70
64
|
* This is a list of all metadata classes that are used in the AllMetadata class.
|
|
71
65
|
* Used to automatically determine the class type when deserializing the metadata and
|
|
72
66
|
* for iterating through all metadata collections.
|
|
73
67
|
* Each entry maps a property key to its corresponding class constructor.
|
|
74
68
|
*/
|
|
75
|
-
|
|
76
|
-
{ key: 'AllEntities', class:
|
|
77
|
-
{ key: 'AllApplications', class:
|
|
78
|
-
{ key: 'AllRoles', class:
|
|
79
|
-
{ key: 'AllRowLevelSecurityFilters', class:
|
|
80
|
-
{ key: 'AllAuditLogTypes', class:
|
|
81
|
-
{ key: 'AllAuthorizations', class:
|
|
82
|
-
{ key: 'AllQueryCategories', class:
|
|
83
|
-
{ key: 'AllQueries', class:
|
|
84
|
-
{ key: 'AllQueryFields', class:
|
|
85
|
-
{ key: 'AllQueryPermissions', class:
|
|
86
|
-
{ key: 'AllQueryEntities', class:
|
|
87
|
-
{ key: 'AllQueryParameters', class:
|
|
88
|
-
{ key: 'AllEntityDocumentTypes', class:
|
|
89
|
-
{ key: 'AllLibraries', class:
|
|
90
|
-
{ key: 'AllExplorerNavigationItems', class:
|
|
69
|
+
export const AllMetadataArrays = [
|
|
70
|
+
{ key: 'AllEntities', class: EntityInfo },
|
|
71
|
+
{ key: 'AllApplications', class: ApplicationInfo },
|
|
72
|
+
{ key: 'AllRoles', class: RoleInfo },
|
|
73
|
+
{ key: 'AllRowLevelSecurityFilters', class: RowLevelSecurityFilterInfo },
|
|
74
|
+
{ key: 'AllAuditLogTypes', class: AuditLogTypeInfo },
|
|
75
|
+
{ key: 'AllAuthorizations', class: AuthorizationInfo },
|
|
76
|
+
{ key: 'AllQueryCategories', class: QueryCategoryInfo },
|
|
77
|
+
{ key: 'AllQueries', class: QueryInfo },
|
|
78
|
+
{ key: 'AllQueryFields', class: QueryFieldInfo },
|
|
79
|
+
{ key: 'AllQueryPermissions', class: QueryPermissionInfo },
|
|
80
|
+
{ key: 'AllQueryEntities', class: QueryEntityInfo },
|
|
81
|
+
{ key: 'AllQueryParameters', class: QueryParameterInfo },
|
|
82
|
+
{ key: 'AllEntityDocumentTypes', class: EntityDocumentTypeInfo },
|
|
83
|
+
{ key: 'AllLibraries', class: LibraryInfo },
|
|
84
|
+
{ key: 'AllExplorerNavigationItems', class: ExplorerNavigationItem }
|
|
91
85
|
];
|
|
92
86
|
/**
|
|
93
87
|
* Base class for all metadata providers in MemberJunction.
|
|
94
88
|
* Implements common functionality for metadata caching, refresh, and dataset management.
|
|
95
89
|
* Subclasses must implement abstract methods for provider-specific operations.
|
|
96
90
|
*/
|
|
97
|
-
class ProviderBase {
|
|
91
|
+
export class ProviderBase {
|
|
98
92
|
constructor() {
|
|
99
|
-
this._localMetadata = new
|
|
93
|
+
this._localMetadata = new AllMetadata();
|
|
100
94
|
this._refresh = false;
|
|
101
95
|
this._cachedVisibleExplorerNavigationItems = null;
|
|
102
96
|
}
|
|
@@ -135,7 +129,7 @@ class ProviderBase {
|
|
|
135
129
|
// Check for cached results - if all are cached, end telemetry and return early
|
|
136
130
|
if (preResult.allCached && preResult.cachedResults) {
|
|
137
131
|
const totalResults = preResult.cachedResults.reduce((sum, r) => sum + (r.Results?.length ?? 0), 0);
|
|
138
|
-
|
|
132
|
+
TelemetryManager.Instance.EndEvent(preResult.telemetryEventId, {
|
|
139
133
|
cacheHit: true,
|
|
140
134
|
allCached: true,
|
|
141
135
|
batchSize: params.length,
|
|
@@ -166,7 +160,7 @@ class ProviderBase {
|
|
|
166
160
|
const preResult = await this.PreRunQuery(params, contextUser);
|
|
167
161
|
// Check for cached result - end telemetry with cache hit info
|
|
168
162
|
if (preResult.cachedResult) {
|
|
169
|
-
|
|
163
|
+
TelemetryManager.Instance.EndEvent(preResult.telemetryEventId, {
|
|
170
164
|
cacheHit: true,
|
|
171
165
|
cacheStatus: preResult.cacheStatus,
|
|
172
166
|
resultCount: preResult.cachedResult.Results?.length ?? 0
|
|
@@ -192,7 +186,7 @@ class ProviderBase {
|
|
|
192
186
|
// Check for cached results - if all are cached, end telemetry and return early
|
|
193
187
|
if (preResult.allCached && preResult.cachedResults) {
|
|
194
188
|
const totalResults = preResult.cachedResults.reduce((sum, r) => sum + (r.Results?.length ?? 0), 0);
|
|
195
|
-
|
|
189
|
+
TelemetryManager.Instance.EndEvent(preResult.telemetryEventId, {
|
|
196
190
|
cacheHit: true,
|
|
197
191
|
allCached: true,
|
|
198
192
|
batchSize: params.length,
|
|
@@ -218,12 +212,12 @@ class ProviderBase {
|
|
|
218
212
|
* @param callerName
|
|
219
213
|
*/
|
|
220
214
|
async EntityStatusCheck(params, callerName) {
|
|
221
|
-
const entityName = await
|
|
215
|
+
const entityName = await RunView.GetEntityNameFromRunViewParams(params, this);
|
|
222
216
|
const entity = this.Entities.find(e => e.Name.trim().toLowerCase() === entityName?.trim().toLowerCase());
|
|
223
217
|
if (!entity) {
|
|
224
218
|
throw new Error(`Entity ${entityName} not found in metadata`);
|
|
225
219
|
}
|
|
226
|
-
|
|
220
|
+
EntityInfo.AssertEntityActiveStatus(entity, callerName);
|
|
227
221
|
}
|
|
228
222
|
// Type aliases for cleaner code
|
|
229
223
|
get PreRunViewResult() { return this._preRunViewResultType; }
|
|
@@ -244,7 +238,7 @@ class ProviderBase {
|
|
|
244
238
|
const preViewStart = performance.now();
|
|
245
239
|
// Start telemetry tracking
|
|
246
240
|
const telemetryStart = performance.now();
|
|
247
|
-
const telemetryEventId =
|
|
241
|
+
const telemetryEventId = TelemetryManager.Instance.StartEvent('RunView', 'ProviderBase.RunView', {
|
|
248
242
|
EntityName: params.EntityName,
|
|
249
243
|
ViewID: params.ViewID,
|
|
250
244
|
ViewName: params.ViewName,
|
|
@@ -275,9 +269,9 @@ class ProviderBase {
|
|
|
275
269
|
let cacheStatus = 'disabled';
|
|
276
270
|
let cachedResult;
|
|
277
271
|
let fingerprint;
|
|
278
|
-
if (params.CacheLocal &&
|
|
279
|
-
fingerprint =
|
|
280
|
-
const cached = await
|
|
272
|
+
if (params.CacheLocal && LocalCacheManager.Instance.IsInitialized) {
|
|
273
|
+
fingerprint = LocalCacheManager.Instance.GenerateRunViewFingerprint(params, this.InstanceConnectionString);
|
|
274
|
+
const cached = await LocalCacheManager.Instance.GetRunViewResult(fingerprint);
|
|
281
275
|
if (cached) {
|
|
282
276
|
// Reconstruct RunViewResult from cached data
|
|
283
277
|
cachedResult = {
|
|
@@ -299,7 +293,7 @@ class ProviderBase {
|
|
|
299
293
|
const cacheCheckTime = performance.now() - cacheCheckStart;
|
|
300
294
|
const totalPreTime = performance.now() - preViewStart;
|
|
301
295
|
if (totalPreTime > 50) {
|
|
302
|
-
|
|
296
|
+
LogStatus(`[PERF-PRE] PreRunView ${params.EntityName}: ${totalPreTime.toFixed(1)}ms (telemetry=${telemetryTime.toFixed(1)}ms, entityCheck=${entityCheckTime.toFixed(1)}ms, entityLookup=${entityLookupTime.toFixed(1)}ms, cache=${cacheCheckTime.toFixed(1)}ms)`);
|
|
303
297
|
}
|
|
304
298
|
return {
|
|
305
299
|
telemetryEventId,
|
|
@@ -318,7 +312,7 @@ class ProviderBase {
|
|
|
318
312
|
async PreRunViews(params, contextUser) {
|
|
319
313
|
// Start telemetry tracking for batch operation
|
|
320
314
|
const fromEngine = params.some(p => p._fromEngine);
|
|
321
|
-
const telemetryEventId =
|
|
315
|
+
const telemetryEventId = TelemetryManager.Instance.StartEvent('RunView', 'ProviderBase.RunViews', {
|
|
322
316
|
BatchSize: params.length,
|
|
323
317
|
Entities: params.map(p => p.EntityName || p.ViewName || p.ViewID).filter(Boolean),
|
|
324
318
|
_fromEngine: fromEngine
|
|
@@ -326,7 +320,7 @@ class ProviderBase {
|
|
|
326
320
|
// Check if any params have CacheLocal enabled - smart caching is always used when caching locally
|
|
327
321
|
const useSmartCacheCheck = params.some(p => p.CacheLocal);
|
|
328
322
|
// If local caching is enabled, use smart cache check flow
|
|
329
|
-
if (useSmartCacheCheck &&
|
|
323
|
+
if (useSmartCacheCheck && LocalCacheManager.Instance.IsInitialized) {
|
|
330
324
|
return this.prepareSmartCacheCheckParams(params, telemetryEventId, contextUser);
|
|
331
325
|
}
|
|
332
326
|
// Traditional caching flow
|
|
@@ -347,9 +341,9 @@ class ProviderBase {
|
|
|
347
341
|
param.Fields = entity.Fields.map(f => f.Name);
|
|
348
342
|
}
|
|
349
343
|
// Check local cache if enabled
|
|
350
|
-
if (param.CacheLocal &&
|
|
351
|
-
const fingerprint =
|
|
352
|
-
const cached = await
|
|
344
|
+
if (param.CacheLocal && LocalCacheManager.Instance.IsInitialized) {
|
|
345
|
+
const fingerprint = LocalCacheManager.Instance.GenerateRunViewFingerprint(param, this.InstanceConnectionString);
|
|
346
|
+
const cached = await LocalCacheManager.Instance.GetRunViewResult(fingerprint);
|
|
353
347
|
if (cached) {
|
|
354
348
|
const cachedViewResult = {
|
|
355
349
|
Success: true,
|
|
@@ -404,9 +398,9 @@ class ProviderBase {
|
|
|
404
398
|
}
|
|
405
399
|
// Build the cache check param with optional cache status
|
|
406
400
|
let cacheStatus;
|
|
407
|
-
if (param.CacheLocal &&
|
|
408
|
-
const fingerprint =
|
|
409
|
-
const cached = await
|
|
401
|
+
if (param.CacheLocal && LocalCacheManager.Instance.IsInitialized) {
|
|
402
|
+
const fingerprint = LocalCacheManager.Instance.GenerateRunViewFingerprint(param, this.InstanceConnectionString);
|
|
403
|
+
const cached = await LocalCacheManager.Instance.GetRunViewResult(fingerprint);
|
|
410
404
|
if (cached) {
|
|
411
405
|
cacheStatus = {
|
|
412
406
|
maxUpdatedAt: cached.maxUpdatedAt,
|
|
@@ -442,8 +436,8 @@ class ProviderBase {
|
|
|
442
436
|
const response = await provider.RunViewsWithCacheCheck(preResult.smartCacheCheckParams, contextUser);
|
|
443
437
|
if (!response.success) {
|
|
444
438
|
// If the smart cache check failed, log and return empty results
|
|
445
|
-
|
|
446
|
-
|
|
439
|
+
LogError(`SmartCacheCheck failed: ${response.errorMessage}`);
|
|
440
|
+
TelemetryManager.Instance.EndEvent(preResult.telemetryEventId, {
|
|
447
441
|
smartCacheCheck: true,
|
|
448
442
|
success: false,
|
|
449
443
|
errorMessage: response.errorMessage
|
|
@@ -471,7 +465,7 @@ class ProviderBase {
|
|
|
471
465
|
cacheMisses++;
|
|
472
466
|
}
|
|
473
467
|
// End telemetry
|
|
474
|
-
|
|
468
|
+
TelemetryManager.Instance.EndEvent(preResult.telemetryEventId, {
|
|
475
469
|
smartCacheCheck: true,
|
|
476
470
|
success: true,
|
|
477
471
|
cacheHits,
|
|
@@ -503,8 +497,8 @@ class ProviderBase {
|
|
|
503
497
|
}
|
|
504
498
|
if (checkResult.status === 'current') {
|
|
505
499
|
// Cache is current - use cached data
|
|
506
|
-
const fingerprint =
|
|
507
|
-
const cached = await
|
|
500
|
+
const fingerprint = LocalCacheManager.Instance.GenerateRunViewFingerprint(param, this.InstanceConnectionString);
|
|
501
|
+
const cached = await LocalCacheManager.Instance.GetRunViewResult(fingerprint);
|
|
508
502
|
if (cached) {
|
|
509
503
|
const cachedResult = {
|
|
510
504
|
Success: true,
|
|
@@ -539,13 +533,13 @@ class ProviderBase {
|
|
|
539
533
|
}
|
|
540
534
|
else if (checkResult.status === 'differential') {
|
|
541
535
|
// Cache is stale but we have differential data - merge with cached data
|
|
542
|
-
const fingerprint =
|
|
536
|
+
const fingerprint = LocalCacheManager.Instance.GenerateRunViewFingerprint(param, this.InstanceConnectionString);
|
|
543
537
|
// Get entity info for primary key field name
|
|
544
538
|
const entity = this.Entities.find(e => e.Name.trim().toLowerCase() === param.EntityName?.trim().toLowerCase());
|
|
545
539
|
const primaryKeyFieldName = entity?.FirstPrimaryKey?.Name || 'ID';
|
|
546
540
|
// Apply differential update to cache
|
|
547
|
-
if (param.CacheLocal && checkResult.differentialData &&
|
|
548
|
-
const merged = await
|
|
541
|
+
if (param.CacheLocal && checkResult.differentialData && LocalCacheManager.Instance.IsInitialized) {
|
|
542
|
+
const merged = await LocalCacheManager.Instance.ApplyDifferentialUpdate(fingerprint, param, checkResult.differentialData.updatedRows, checkResult.differentialData.deletedRecordIDs, primaryKeyFieldName, checkResult.maxUpdatedAt || new Date().toISOString(), checkResult.rowCount || 0, checkResult.aggregateResults // Pass fresh aggregate results (can't be differentially computed)
|
|
549
543
|
);
|
|
550
544
|
if (merged) {
|
|
551
545
|
const mergedResult = {
|
|
@@ -584,12 +578,12 @@ class ProviderBase {
|
|
|
584
578
|
AggregateResults: checkResult.aggregateResults // Include fresh aggregate results
|
|
585
579
|
};
|
|
586
580
|
// Update the local cache with fresh data (don't await - fire and forget for performance)
|
|
587
|
-
if (param.CacheLocal && checkResult.maxUpdatedAt &&
|
|
588
|
-
const fingerprint =
|
|
581
|
+
if (param.CacheLocal && checkResult.maxUpdatedAt && LocalCacheManager.Instance.IsInitialized) {
|
|
582
|
+
const fingerprint = LocalCacheManager.Instance.GenerateRunViewFingerprint(param, this.InstanceConnectionString);
|
|
589
583
|
// Note: We don't await here to avoid blocking the response
|
|
590
584
|
// Cache update happens in background
|
|
591
|
-
|
|
592
|
-
).catch(e =>
|
|
585
|
+
LocalCacheManager.Instance.SetRunViewResult(fingerprint, param, checkResult.results || [], checkResult.maxUpdatedAt, checkResult.aggregateResults // Include aggregate results in cache
|
|
586
|
+
).catch(e => LogError(`Failed to update cache: ${e}`));
|
|
593
587
|
}
|
|
594
588
|
// Transform to entity objects if needed
|
|
595
589
|
await this.TransformSimpleObjectToEntityObject(param, freshResult, contextUser);
|
|
@@ -621,7 +615,7 @@ class ProviderBase {
|
|
|
621
615
|
*/
|
|
622
616
|
async PreRunQuery(params, contextUser) {
|
|
623
617
|
// Start telemetry tracking
|
|
624
|
-
const telemetryEventId =
|
|
618
|
+
const telemetryEventId = TelemetryManager.Instance.StartEvent('RunQuery', 'ProviderBase.RunQuery', {
|
|
625
619
|
QueryID: params.QueryID,
|
|
626
620
|
QueryName: params.QueryName,
|
|
627
621
|
CategoryPath: params.CategoryPath,
|
|
@@ -648,7 +642,7 @@ class ProviderBase {
|
|
|
648
642
|
*/
|
|
649
643
|
async PreRunQueries(params, contextUser) {
|
|
650
644
|
// Start telemetry tracking for batch operation
|
|
651
|
-
const telemetryEventId =
|
|
645
|
+
const telemetryEventId = TelemetryManager.Instance.StartEvent('RunQuery', 'ProviderBase.RunQueries', {
|
|
652
646
|
BatchSize: params.length,
|
|
653
647
|
Queries: params.map(p => p.QueryName || p.QueryID).filter(Boolean)
|
|
654
648
|
}, contextUser?.ID);
|
|
@@ -676,15 +670,15 @@ class ProviderBase {
|
|
|
676
670
|
// Transform the result set into BaseEntity-derived objects, if needed
|
|
677
671
|
await this.TransformSimpleObjectToEntityObject(params, result, contextUser);
|
|
678
672
|
// Store in local cache if enabled and we have a successful result
|
|
679
|
-
if (params.CacheLocal && result.Success && preResult.fingerprint &&
|
|
673
|
+
if (params.CacheLocal && result.Success && preResult.fingerprint && LocalCacheManager.Instance.IsInitialized) {
|
|
680
674
|
// Extract maxUpdatedAt from results if available
|
|
681
675
|
const maxUpdatedAt = this.extractMaxUpdatedAt(result.Results);
|
|
682
|
-
await
|
|
676
|
+
await LocalCacheManager.Instance.SetRunViewResult(preResult.fingerprint, params, result.Results, maxUpdatedAt, result.AggregateResults // Include aggregate results in cache
|
|
683
677
|
);
|
|
684
678
|
}
|
|
685
679
|
// End telemetry tracking with cache miss info
|
|
686
680
|
if (preResult.telemetryEventId) {
|
|
687
|
-
|
|
681
|
+
TelemetryManager.Instance.EndEvent(preResult.telemetryEventId, {
|
|
688
682
|
cacheHit: false,
|
|
689
683
|
cacheStatus: preResult.cacheStatus,
|
|
690
684
|
resultCount: result.Results?.length ?? 0,
|
|
@@ -706,10 +700,10 @@ class ProviderBase {
|
|
|
706
700
|
for (let i = 0; i < results.length; i++) {
|
|
707
701
|
promises.push(this.TransformSimpleObjectToEntityObject(params[i], results[i], contextUser));
|
|
708
702
|
// Store in local cache if enabled
|
|
709
|
-
if (params[i].CacheLocal && results[i].Success &&
|
|
710
|
-
const fingerprint =
|
|
703
|
+
if (params[i].CacheLocal && results[i].Success && LocalCacheManager.Instance.IsInitialized) {
|
|
704
|
+
const fingerprint = LocalCacheManager.Instance.GenerateRunViewFingerprint(params[i], this.InstanceConnectionString);
|
|
711
705
|
const maxUpdatedAt = this.extractMaxUpdatedAt(results[i].Results);
|
|
712
|
-
promises.push(
|
|
706
|
+
promises.push(LocalCacheManager.Instance.SetRunViewResult(fingerprint, params[i], results[i].Results, maxUpdatedAt, results[i].AggregateResults // Include aggregate results in cache
|
|
713
707
|
));
|
|
714
708
|
}
|
|
715
709
|
}
|
|
@@ -720,7 +714,7 @@ class ProviderBase {
|
|
|
720
714
|
const cachedCount = preResult.cacheStatusMap
|
|
721
715
|
? [...preResult.cacheStatusMap.values()].filter(s => s.status === 'hit').length
|
|
722
716
|
: 0;
|
|
723
|
-
|
|
717
|
+
TelemetryManager.Instance.EndEvent(preResult.telemetryEventId, {
|
|
724
718
|
cacheHit: false,
|
|
725
719
|
allCached: false,
|
|
726
720
|
batchSize: params.length,
|
|
@@ -742,7 +736,7 @@ class ProviderBase {
|
|
|
742
736
|
// Query caching is handled internally by the provider
|
|
743
737
|
// End telemetry tracking with cache miss info
|
|
744
738
|
if (preResult.telemetryEventId) {
|
|
745
|
-
|
|
739
|
+
TelemetryManager.Instance.EndEvent(preResult.telemetryEventId, {
|
|
746
740
|
cacheHit: false,
|
|
747
741
|
cacheStatus: preResult.cacheStatus,
|
|
748
742
|
resultCount: result.Results?.length ?? 0,
|
|
@@ -766,7 +760,7 @@ class ProviderBase {
|
|
|
766
760
|
const cachedCount = preResult.cacheStatusMap
|
|
767
761
|
? [...preResult.cacheStatusMap.values()].filter(s => s.status === 'hit').length
|
|
768
762
|
: 0;
|
|
769
|
-
|
|
763
|
+
TelemetryManager.Instance.EndEvent(preResult.telemetryEventId, {
|
|
770
764
|
cacheHit: false,
|
|
771
765
|
allCached: false,
|
|
772
766
|
batchSize: params.length,
|
|
@@ -856,7 +850,7 @@ class ProviderBase {
|
|
|
856
850
|
*/
|
|
857
851
|
async PreProcessRunView(params, contextUser) {
|
|
858
852
|
// Start telemetry tracking
|
|
859
|
-
const eventId =
|
|
853
|
+
const eventId = TelemetryManager.Instance.StartEvent('RunView', 'ProviderBase.RunView', {
|
|
860
854
|
EntityName: params.EntityName,
|
|
861
855
|
ViewID: params.ViewID,
|
|
862
856
|
ViewName: params.ViewName,
|
|
@@ -892,7 +886,7 @@ class ProviderBase {
|
|
|
892
886
|
// End telemetry tracking
|
|
893
887
|
const eventId = params._telemetryEventId;
|
|
894
888
|
if (eventId) {
|
|
895
|
-
|
|
889
|
+
TelemetryManager.Instance.EndEvent(eventId);
|
|
896
890
|
delete params._telemetryEventId;
|
|
897
891
|
}
|
|
898
892
|
}
|
|
@@ -906,7 +900,7 @@ class ProviderBase {
|
|
|
906
900
|
async PreProcessRunViews(params, contextUser) {
|
|
907
901
|
// Start telemetry tracking for batch operation
|
|
908
902
|
const fromEngine = params.some(p => p._fromEngine);
|
|
909
|
-
const eventId =
|
|
903
|
+
const eventId = TelemetryManager.Instance.StartEvent('RunView', 'ProviderBase.RunViews', {
|
|
910
904
|
BatchSize: params.length,
|
|
911
905
|
Entities: params.map(p => p.EntityName || p.ViewName || p.ViewID).filter(Boolean),
|
|
912
906
|
_fromEngine: fromEngine
|
|
@@ -950,7 +944,7 @@ class ProviderBase {
|
|
|
950
944
|
// End telemetry tracking for batch operation
|
|
951
945
|
const eventId = params[0]._telemetryBatchEventId;
|
|
952
946
|
if (eventId) {
|
|
953
|
-
|
|
947
|
+
TelemetryManager.Instance.EndEvent(eventId);
|
|
954
948
|
delete params[0]._telemetryBatchEventId;
|
|
955
949
|
}
|
|
956
950
|
}
|
|
@@ -967,7 +961,7 @@ class ProviderBase {
|
|
|
967
961
|
// we need to transform each of the items in the result set into a BaseEntity-derived object
|
|
968
962
|
// Create entities and load data in parallel for better performance
|
|
969
963
|
const entityPromises = result.Results.map(async (item) => {
|
|
970
|
-
if (item instanceof
|
|
964
|
+
if (item instanceof BaseEntity || (typeof item.Save === 'function')) {
|
|
971
965
|
// the second check is a "duck-typing" check in case we have different runtime
|
|
972
966
|
// loading sources where the instanceof will fail
|
|
973
967
|
return item;
|
|
@@ -998,7 +992,7 @@ class ProviderBase {
|
|
|
998
992
|
this._ConfigData = data;
|
|
999
993
|
// first, let's check to see if we have an existing Metadata.Provider registered, if so
|
|
1000
994
|
// unless our data.IgnoreExistingMetadata is set to true, we will not refresh the metadata
|
|
1001
|
-
if (
|
|
995
|
+
if (Metadata.Provider && !data.IgnoreExistingMetadata) {
|
|
1002
996
|
// we have an existing globally registered provider AND we are not
|
|
1003
997
|
// requested to ignore the existing metadata, so we will not refresh it
|
|
1004
998
|
if (this.CopyMetadataFromGlobalProvider()) {
|
|
@@ -1015,7 +1009,7 @@ class ProviderBase {
|
|
|
1015
1009
|
const start = new Date().getTime();
|
|
1016
1010
|
const res = await this.GetAllMetadata(providerToUse);
|
|
1017
1011
|
const end = new Date().getTime();
|
|
1018
|
-
|
|
1012
|
+
LogStatus(`GetAllMetadata() took ${end - start} ms`);
|
|
1019
1013
|
if (res) {
|
|
1020
1014
|
// Atomic swap via UpdateLocalMetadata: single property assignment is atomic in JavaScript
|
|
1021
1015
|
// Readers now see new metadata instead of old
|
|
@@ -1027,7 +1021,7 @@ class ProviderBase {
|
|
|
1027
1021
|
}
|
|
1028
1022
|
else {
|
|
1029
1023
|
// GetAllMetadata failed - log error but keep existing metadata
|
|
1030
|
-
|
|
1024
|
+
LogError('GetAllMetadata() returned undefined - metadata not updated');
|
|
1031
1025
|
}
|
|
1032
1026
|
}
|
|
1033
1027
|
return true;
|
|
@@ -1046,14 +1040,14 @@ class ProviderBase {
|
|
|
1046
1040
|
*/
|
|
1047
1041
|
CopyMetadataFromGlobalProvider() {
|
|
1048
1042
|
try {
|
|
1049
|
-
if (
|
|
1050
|
-
this._localMetadata = this.CloneAllMetadata(
|
|
1043
|
+
if (Metadata.Provider && Metadata.Provider !== this && Metadata.Provider.AllMetadata) {
|
|
1044
|
+
this._localMetadata = this.CloneAllMetadata(Metadata.Provider.AllMetadata);
|
|
1051
1045
|
return true;
|
|
1052
1046
|
}
|
|
1053
1047
|
return false;
|
|
1054
1048
|
}
|
|
1055
1049
|
catch (e) {
|
|
1056
|
-
|
|
1050
|
+
LogError(`Failed to copy metadata from global provider: ${e.message}`);
|
|
1057
1051
|
return false; // if we fail to copy the metadata, we will return false
|
|
1058
1052
|
}
|
|
1059
1053
|
}
|
|
@@ -1077,7 +1071,7 @@ class ProviderBase {
|
|
|
1077
1071
|
if (excludeSchemaList && excludeSchemaList.length > 0 && excludeSchemaList.indexOf(mjcSchema) !== -1) {
|
|
1078
1072
|
const index = excludeSchemaList.indexOf(mjcSchema);
|
|
1079
1073
|
excludeSchemaList.splice(index, 1);
|
|
1080
|
-
|
|
1074
|
+
LogStatus(`Removed MJ Core schema (${mjcSchema}) from ExcludeSchemas list because it is required for the API to function correctly`);
|
|
1081
1075
|
}
|
|
1082
1076
|
let schemaFilter = '';
|
|
1083
1077
|
if (includeSchemaList && includeSchemaList.length > 0) {
|
|
@@ -1092,6 +1086,7 @@ class ProviderBase {
|
|
|
1092
1086
|
}
|
|
1093
1087
|
return f;
|
|
1094
1088
|
}
|
|
1089
|
+
static { this._mjMetadataDatasetName = 'MJ_Metadata'; }
|
|
1095
1090
|
/**
|
|
1096
1091
|
* Retrieves all metadata from the server and constructs typed instances.
|
|
1097
1092
|
* Uses the MJ_Metadata dataset for efficient bulk loading.
|
|
@@ -1103,10 +1098,10 @@ class ProviderBase {
|
|
|
1103
1098
|
//const start1 = new Date().getTime();
|
|
1104
1099
|
const f = this.BuildDatasetFilterFromConfig();
|
|
1105
1100
|
// Get the dataset and cache it for anyone else who wants to use it
|
|
1106
|
-
const d = await this.GetDatasetByName(
|
|
1101
|
+
const d = await this.GetDatasetByName(ProviderBase._mjMetadataDatasetName, f.length > 0 ? f : null, this.CurrentUser, providerToUse);
|
|
1107
1102
|
if (d && d.Success) {
|
|
1108
1103
|
// cache the dataset for anyone who wants to use it
|
|
1109
|
-
await this.CacheDataset(
|
|
1104
|
+
await this.CacheDataset(ProviderBase._mjMetadataDatasetName, f.length > 0 ? f : null, d);
|
|
1110
1105
|
// got the results, let's build our response in the format we need
|
|
1111
1106
|
const simpleMetadata = {};
|
|
1112
1107
|
for (let r of d.Results) {
|
|
@@ -1118,7 +1113,7 @@ class ProviderBase {
|
|
|
1118
1113
|
simpleMetadata.AllApplications = simpleMetadata.Applications.map((a) => {
|
|
1119
1114
|
a.ApplicationEntities = simpleMetadata.ApplicationEntities.filter((ae) => ae.ApplicationID === a.ID);
|
|
1120
1115
|
a.ApplicationSettings = simpleMetadata.ApplicationSettings.filter((as) => as.ApplicationID === a.ID);
|
|
1121
|
-
return new
|
|
1116
|
+
return new ApplicationInfo(a, this);
|
|
1122
1117
|
});
|
|
1123
1118
|
// now we need to construct our return type. The way the return type works, which is an instance of AllMetadata, we have to
|
|
1124
1119
|
// construst each item so it contains an array of the correct type. This is because the AllMetadata class has an array of each type of metadata
|
|
@@ -1129,11 +1124,11 @@ class ProviderBase {
|
|
|
1129
1124
|
return returnMetadata;
|
|
1130
1125
|
}
|
|
1131
1126
|
else {
|
|
1132
|
-
|
|
1127
|
+
LogError('GetAllMetadata() - Error getting metadata from server' + (d ? ': ' + d.Status : ''));
|
|
1133
1128
|
}
|
|
1134
1129
|
}
|
|
1135
1130
|
catch (e) {
|
|
1136
|
-
|
|
1131
|
+
LogError(e);
|
|
1137
1132
|
}
|
|
1138
1133
|
}
|
|
1139
1134
|
/**
|
|
@@ -1162,7 +1157,7 @@ class ProviderBase {
|
|
|
1162
1157
|
e.EntityPermissions = permissions.filter(p => p.EntityID === e.ID);
|
|
1163
1158
|
e.EntityRelationships = relationships.filter(r => r.EntityID === e.ID);
|
|
1164
1159
|
e.EntitySettings = settings.filter(s => s.EntityID === e.ID);
|
|
1165
|
-
result.push(new
|
|
1160
|
+
result.push(new EntityInfo(e));
|
|
1166
1161
|
}
|
|
1167
1162
|
return result;
|
|
1168
1163
|
}
|
|
@@ -1333,7 +1328,7 @@ class ProviderBase {
|
|
|
1333
1328
|
// Determine which overload was called
|
|
1334
1329
|
let actualLoadKey;
|
|
1335
1330
|
let actualContextUser;
|
|
1336
|
-
if (loadKeyOrContextUser instanceof
|
|
1331
|
+
if (loadKeyOrContextUser instanceof CompositeKey) {
|
|
1337
1332
|
// Second overload: entityName, loadKey, contextUser
|
|
1338
1333
|
actualLoadKey = loadKeyOrContextUser;
|
|
1339
1334
|
actualContextUser = contextUser;
|
|
@@ -1352,7 +1347,7 @@ class ProviderBase {
|
|
|
1352
1347
|
// Use the MJGlobal Class Factory to do our object instantiation - we do NOT use metadata for this anymore, doesn't work well to have file paths with node dynamically at runtime
|
|
1353
1348
|
// type reference registration by any module via MJ Global is the way to go as it is reliable across all platforms.
|
|
1354
1349
|
try {
|
|
1355
|
-
const newObject =
|
|
1350
|
+
const newObject = MJGlobal.Instance.ClassFactory.CreateInstance(BaseEntity, entityName, entity, this);
|
|
1356
1351
|
await newObject.Config(actualContextUser);
|
|
1357
1352
|
if (actualLoadKey) {
|
|
1358
1353
|
// Load existing record
|
|
@@ -1369,7 +1364,7 @@ class ProviderBase {
|
|
|
1369
1364
|
return newObject;
|
|
1370
1365
|
}
|
|
1371
1366
|
catch (e) {
|
|
1372
|
-
|
|
1367
|
+
LogError(e);
|
|
1373
1368
|
throw new Error(`Entity ${entityName} could not be instantiated via MJGlobal Class Factory. Make sure you have registered the class reference with MJGlobal.Instance.ClassFactory.Register(). ALSO, make sure you call LoadGeneratedEntities() from the GeneratedEntities project within your project as tree-shaking sometimes removes subclasses and could be causing this error!`);
|
|
1374
1369
|
}
|
|
1375
1370
|
}
|
|
@@ -1377,7 +1372,7 @@ class ProviderBase {
|
|
|
1377
1372
|
throw new Error(`Entity ${entityName} not found in metadata`);
|
|
1378
1373
|
}
|
|
1379
1374
|
catch (ex) {
|
|
1380
|
-
|
|
1375
|
+
LogError(ex);
|
|
1381
1376
|
return null;
|
|
1382
1377
|
}
|
|
1383
1378
|
}
|
|
@@ -1406,7 +1401,7 @@ class ProviderBase {
|
|
|
1406
1401
|
return result;
|
|
1407
1402
|
}
|
|
1408
1403
|
catch (e) {
|
|
1409
|
-
|
|
1404
|
+
LogError(e);
|
|
1410
1405
|
throw e;
|
|
1411
1406
|
}
|
|
1412
1407
|
}
|
|
@@ -1557,7 +1552,7 @@ class ProviderBase {
|
|
|
1557
1552
|
* @returns
|
|
1558
1553
|
*/
|
|
1559
1554
|
GetDatasetCacheKey(datasetName, itemFilters) {
|
|
1560
|
-
return this.LocalStoragePrefix +
|
|
1555
|
+
return this.LocalStoragePrefix + ProviderBase.localStorageRootKey + this.InstanceConnectionString + '__DATASET__' + datasetName + this.ConvertItemFiltersToUniqueKey(itemFilters);
|
|
1561
1556
|
}
|
|
1562
1557
|
/**
|
|
1563
1558
|
* Converts dataset item filters into a unique string key for caching.
|
|
@@ -1608,7 +1603,7 @@ class ProviderBase {
|
|
|
1608
1603
|
*/
|
|
1609
1604
|
async GetLatestMetadataUpdates(providerToUse) {
|
|
1610
1605
|
const f = this.BuildDatasetFilterFromConfig();
|
|
1611
|
-
const d = await this.GetDatasetStatusByName(
|
|
1606
|
+
const d = await this.GetDatasetStatusByName(ProviderBase._mjMetadataDatasetName, f.length > 0 ? f : null, this.CurrentUser, providerToUse);
|
|
1612
1607
|
if (d && d.Success) {
|
|
1613
1608
|
const ret = d.EntityUpdateDates.map(e => {
|
|
1614
1609
|
return {
|
|
@@ -1699,6 +1694,14 @@ class ProviderBase {
|
|
|
1699
1694
|
UpdateLocalMetadata(res) {
|
|
1700
1695
|
this._localMetadata = res;
|
|
1701
1696
|
}
|
|
1697
|
+
/**
|
|
1698
|
+
* Returns the filesystem provider for the current environment.
|
|
1699
|
+
* Default implementation returns null (no filesystem access).
|
|
1700
|
+
* Server-side providers should override this to return a NodeFileSystemProvider.
|
|
1701
|
+
*/
|
|
1702
|
+
get FileSystemProvider() {
|
|
1703
|
+
return null;
|
|
1704
|
+
}
|
|
1702
1705
|
/**
|
|
1703
1706
|
* Loads metadata from local storage if available.
|
|
1704
1707
|
* Deserializes and reconstructs typed metadata objects.
|
|
@@ -1708,8 +1711,8 @@ class ProviderBase {
|
|
|
1708
1711
|
const ls = this.LocalStorageProvider;
|
|
1709
1712
|
if (ls) {
|
|
1710
1713
|
// execution environment supports local storage, use it
|
|
1711
|
-
this._latestLocalMetadataTimestamps = JSON.parse(await ls.GetItem(this.LocalStoragePrefix +
|
|
1712
|
-
const temp = JSON.parse(await ls.GetItem(this.LocalStoragePrefix +
|
|
1714
|
+
this._latestLocalMetadataTimestamps = JSON.parse(await ls.GetItem(this.LocalStoragePrefix + ProviderBase.localStorageTimestampsKey));
|
|
1715
|
+
const temp = JSON.parse(await ls.GetItem(this.LocalStoragePrefix + ProviderBase.localStorageAllMetadataKey)); // we now have a simple object for all the metadata
|
|
1713
1716
|
if (temp) {
|
|
1714
1717
|
// we have local metadata
|
|
1715
1718
|
const metadata = MetadataFromSimpleObject(temp, this); // create a new object to start this up
|
|
@@ -1721,6 +1724,13 @@ class ProviderBase {
|
|
|
1721
1724
|
// some enviroments don't support local storage
|
|
1722
1725
|
}
|
|
1723
1726
|
}
|
|
1727
|
+
static { this.localStorageRootKey = '___MJCore_Metadata'; }
|
|
1728
|
+
static { this.localStorageTimestampsKey = this.localStorageRootKey + '_Timestamps'; }
|
|
1729
|
+
static { this.localStorageAllMetadataKey = this.localStorageRootKey + '_AllMetadata'; }
|
|
1730
|
+
static { this.localStorageKeys = [
|
|
1731
|
+
ProviderBase.localStorageTimestampsKey,
|
|
1732
|
+
ProviderBase.localStorageAllMetadataKey,
|
|
1733
|
+
]; }
|
|
1724
1734
|
/**
|
|
1725
1735
|
* This property will return the prefix to use for local storage keys. This is useful if you have multiple instances of a provider running in the same environment
|
|
1726
1736
|
* and you want to keep their local storage keys separate. The default implementation returns an empty string, but subclasses can override this to return a unique string
|
|
@@ -1738,14 +1748,14 @@ class ProviderBase {
|
|
|
1738
1748
|
const ls = this.LocalStorageProvider;
|
|
1739
1749
|
if (ls) {
|
|
1740
1750
|
// execution environment supports local storage, use it
|
|
1741
|
-
await ls.SetItem(this.LocalStoragePrefix +
|
|
1751
|
+
await ls.SetItem(this.LocalStoragePrefix + ProviderBase.localStorageTimestampsKey, JSON.stringify(this._latestLocalMetadataTimestamps));
|
|
1742
1752
|
// now persist the AllMetadata object
|
|
1743
|
-
await ls.SetItem(this.LocalStoragePrefix +
|
|
1753
|
+
await ls.SetItem(this.LocalStoragePrefix + ProviderBase.localStorageAllMetadataKey, JSON.stringify(this._localMetadata));
|
|
1744
1754
|
}
|
|
1745
1755
|
}
|
|
1746
1756
|
catch (e) {
|
|
1747
1757
|
// some enviroments don't support local storage
|
|
1748
|
-
|
|
1758
|
+
LogError(e);
|
|
1749
1759
|
}
|
|
1750
1760
|
}
|
|
1751
1761
|
/**
|
|
@@ -1755,24 +1765,14 @@ class ProviderBase {
|
|
|
1755
1765
|
async RemoveLocalMetadataFromStorage() {
|
|
1756
1766
|
try {
|
|
1757
1767
|
const ls = this.LocalStorageProvider;
|
|
1758
|
-
for (let i = 0; i <
|
|
1759
|
-
await ls.Remove(this.LocalStoragePrefix +
|
|
1768
|
+
for (let i = 0; i < ProviderBase.localStorageKeys.length; i++) {
|
|
1769
|
+
await ls.Remove(this.LocalStoragePrefix + ProviderBase.localStorageKeys[i]);
|
|
1760
1770
|
}
|
|
1761
1771
|
}
|
|
1762
1772
|
catch (e) {
|
|
1763
1773
|
// some enviroments don't support local storage
|
|
1764
|
-
|
|
1774
|
+
LogError(e);
|
|
1765
1775
|
}
|
|
1766
1776
|
}
|
|
1767
1777
|
}
|
|
1768
|
-
exports.ProviderBase = ProviderBase;
|
|
1769
|
-
_a = ProviderBase;
|
|
1770
|
-
ProviderBase._mjMetadataDatasetName = 'MJ_Metadata';
|
|
1771
|
-
ProviderBase.localStorageRootKey = '___MJCore_Metadata';
|
|
1772
|
-
ProviderBase.localStorageTimestampsKey = _a.localStorageRootKey + '_Timestamps';
|
|
1773
|
-
ProviderBase.localStorageAllMetadataKey = _a.localStorageRootKey + '_AllMetadata';
|
|
1774
|
-
ProviderBase.localStorageKeys = [
|
|
1775
|
-
_a.localStorageTimestampsKey,
|
|
1776
|
-
_a.localStorageAllMetadataKey,
|
|
1777
|
-
];
|
|
1778
1778
|
//# sourceMappingURL=providerBase.js.map
|