bulltrackers-module 1.0.535 → 1.0.536
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/functions/computation-system/context/ContextFactory.js +4 -2
- package/functions/computation-system/data/AvailabilityChecker.js +4 -1
- package/functions/computation-system/data/CachedDataLoader.js +11 -2
- package/functions/computation-system/executors/StandardExecutor.js +6 -1
- package/functions/computation-system/layers/extractors.js +35 -1
- package/functions/computation-system/utils/data_loader.js +33 -1
- package/functions/root-data-indexer/index.js +13 -2
- package/package.json +1 -1
|
@@ -27,7 +27,8 @@ class ContextFactory {
|
|
|
27
27
|
allRankings, allRankingsYesterday, // Global rank lists
|
|
28
28
|
allVerifications,
|
|
29
29
|
// [NEW] New Root Data Types for Profile Metrics
|
|
30
|
-
ratings, pageViews, watchlistMembership, alertHistory
|
|
30
|
+
ratings, pageViews, watchlistMembership, alertHistory,
|
|
31
|
+
piMasterList, // [NEW]
|
|
31
32
|
} = options;
|
|
32
33
|
|
|
33
34
|
return {
|
|
@@ -56,7 +57,8 @@ class ContextFactory {
|
|
|
56
57
|
ratings: ratings || {},
|
|
57
58
|
pageViews: pageViews || {},
|
|
58
59
|
watchlistMembership: watchlistMembership || {},
|
|
59
|
-
alertHistory: alertHistory || {}
|
|
60
|
+
alertHistory: alertHistory || {},
|
|
61
|
+
piMasterList: piMasterList || {}, // [NEW]
|
|
60
62
|
}
|
|
61
63
|
};
|
|
62
64
|
}
|
|
@@ -229,7 +229,10 @@ async function checkRootDataAvailability(dateStr, config, dependencies, earliest
|
|
|
229
229
|
piRatings: !!details.piRatings,
|
|
230
230
|
piPageViews: !!details.piPageViews,
|
|
231
231
|
watchlistMembership: !!details.watchlistMembership,
|
|
232
|
-
piAlertHistory: !!details.piAlertHistory
|
|
232
|
+
piAlertHistory: !!details.piAlertHistory,
|
|
233
|
+
|
|
234
|
+
// [NEW] Global Helper Data
|
|
235
|
+
piMasterList: !!details.piMasterList
|
|
233
236
|
},
|
|
234
237
|
portfolioRefs: null,
|
|
235
238
|
historyRefs: null,
|
|
@@ -14,7 +14,8 @@ const {
|
|
|
14
14
|
loadPIRatings, // [NEW]
|
|
15
15
|
loadPIPageViews, // [NEW]
|
|
16
16
|
loadWatchlistMembership: loadWatchlistMembershipData, // [NEW] Renamed to avoid conflict
|
|
17
|
-
loadPIAlertHistory // [NEW]
|
|
17
|
+
loadPIAlertHistory, // [NEW]
|
|
18
|
+
loadPopularInvestorMasterList // [NEW]
|
|
18
19
|
} = require('../utils/data_loader');
|
|
19
20
|
const zlib = require('zlib');
|
|
20
21
|
|
|
@@ -31,7 +32,8 @@ class CachedDataLoader {
|
|
|
31
32
|
ratings: new Map(), // [NEW]
|
|
32
33
|
pageViews: new Map(), // [NEW]
|
|
33
34
|
watchlistMembership: new Map(), // [NEW]
|
|
34
|
-
alertHistory: new Map()
|
|
35
|
+
alertHistory: new Map(),// [NEW]
|
|
36
|
+
piMasterList: null // [NEW] Singleton cache (not date dependent)
|
|
35
37
|
};
|
|
36
38
|
}
|
|
37
39
|
|
|
@@ -141,6 +143,13 @@ class CachedDataLoader {
|
|
|
141
143
|
return {};
|
|
142
144
|
}
|
|
143
145
|
}
|
|
146
|
+
// [NEW] Load PI Master List (Global, Cached)
|
|
147
|
+
async loadPIMasterList() {
|
|
148
|
+
if (this.cache.piMasterList) return this.cache.piMasterList;
|
|
149
|
+
const data = await loadPopularInvestorMasterList(this.config, this.deps);
|
|
150
|
+
this.cache.piMasterList = data;
|
|
151
|
+
return data;
|
|
152
|
+
}
|
|
144
153
|
}
|
|
145
154
|
|
|
146
155
|
module.exports = { CachedDataLoader };
|
|
@@ -230,7 +230,9 @@ class StandardExecutor {
|
|
|
230
230
|
static async executePerUser(calcInstance, metadata, dateStr, portfolioData, yesterdayPortfolioData, historyData, computedDeps, prevDeps, config, deps, loader, stats, earliestDates) {
|
|
231
231
|
const { logger } = deps;
|
|
232
232
|
const targetUserType = metadata.userType;
|
|
233
|
+
// [NEW] Always load Global Helpers
|
|
233
234
|
const mappings = await loader.loadMappings();
|
|
235
|
+
const piMasterList = await loader.loadPIMasterList(); // [NEW] Loaded globally
|
|
234
236
|
const SCHEMAS = mathLayer.SCHEMAS;
|
|
235
237
|
|
|
236
238
|
// 1. Load Root Data
|
|
@@ -385,7 +387,10 @@ class StandardExecutor {
|
|
|
385
387
|
ratings: ratings || {},
|
|
386
388
|
pageViews: pageViews || {},
|
|
387
389
|
watchlistMembership: watchlistMembership || {},
|
|
388
|
-
alertHistory: alertHistory || {}
|
|
390
|
+
alertHistory: alertHistory || {},
|
|
391
|
+
|
|
392
|
+
// [NEW] Pass Master List
|
|
393
|
+
piMasterList,
|
|
389
394
|
});
|
|
390
395
|
|
|
391
396
|
if (metadata.requiresEarliestDataDate && earliestDates) {
|
|
@@ -947,6 +947,39 @@ class AlertHistoryExtractor {
|
|
|
947
947
|
}
|
|
948
948
|
}
|
|
949
949
|
|
|
950
|
+
/**
|
|
951
|
+
* [NEW] Extractor for Popular Investor Master List (Global Backup)
|
|
952
|
+
* Access via: context.globalData.piMasterList
|
|
953
|
+
*/
|
|
954
|
+
class PIMasterListExtractor {
|
|
955
|
+
/**
|
|
956
|
+
* Get the master record for a PI
|
|
957
|
+
* @param {Object} masterList - context.globalData.piMasterList
|
|
958
|
+
* @param {string} cid - The User CID
|
|
959
|
+
*/
|
|
960
|
+
static getRecord(masterList, cid) {
|
|
961
|
+
if (!masterList || !cid) return null;
|
|
962
|
+
return masterList[String(cid)] || null;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* Resolve Username from Master List
|
|
967
|
+
* @param {Object} masterList
|
|
968
|
+
* @param {string} cid
|
|
969
|
+
*/
|
|
970
|
+
static getUsername(masterList, cid) {
|
|
971
|
+
const record = this.getRecord(masterList, cid);
|
|
972
|
+
return record ? record.username : null;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* Check if CID exists in master list
|
|
977
|
+
*/
|
|
978
|
+
static exists(masterList, cid) {
|
|
979
|
+
return !!this.getRecord(masterList, cid);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
950
983
|
module.exports = {
|
|
951
984
|
DataExtractor,
|
|
952
985
|
priceExtractor,
|
|
@@ -962,5 +995,6 @@ module.exports = {
|
|
|
962
995
|
RatingsExtractor,
|
|
963
996
|
PageViewsExtractor,
|
|
964
997
|
WatchlistMembershipExtractor,
|
|
965
|
-
AlertHistoryExtractor
|
|
998
|
+
AlertHistoryExtractor,
|
|
999
|
+
PIMasterListExtractor
|
|
966
1000
|
};
|
|
@@ -774,6 +774,37 @@ async function loadPIAlertHistory(config, deps, dateString) {
|
|
|
774
774
|
}
|
|
775
775
|
}
|
|
776
776
|
|
|
777
|
+
// [NEW] Load Popular Investor Master List
|
|
778
|
+
async function loadPopularInvestorMasterList(config, deps) {
|
|
779
|
+
const { db, logger, calculationUtils } = deps;
|
|
780
|
+
const { withRetry } = calculationUtils;
|
|
781
|
+
|
|
782
|
+
// Default to 'system_state' collection, 'popular_investor_master_list' doc
|
|
783
|
+
const collectionName = config.piMasterListCollection || 'system_state';
|
|
784
|
+
const docId = config.piMasterListDocId || 'popular_investor_master_list';
|
|
785
|
+
|
|
786
|
+
logger.log('INFO', `Loading Popular Investor Master List from ${collectionName}/${docId}`);
|
|
787
|
+
|
|
788
|
+
try {
|
|
789
|
+
const docRef = db.collection(collectionName).doc(docId);
|
|
790
|
+
const docSnap = await withRetry(() => docRef.get(), 'getPIMasterList');
|
|
791
|
+
|
|
792
|
+
if (!docSnap.exists) {
|
|
793
|
+
logger.log('WARN', 'Popular Investor Master List not found.');
|
|
794
|
+
return {};
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
const data = tryDecompress(docSnap.data());
|
|
798
|
+
// Structure is { investors: { cid: { username, ... } } } or direct map { cid: { ... } }
|
|
799
|
+
// Based on user input, it looks like a direct map of CIDs or a field holding the map.
|
|
800
|
+
// We return the raw object which acts as the map.
|
|
801
|
+
return data.investors || data;
|
|
802
|
+
} catch (error) {
|
|
803
|
+
logger.log('ERROR', `Failed to load PI Master List: ${error.message}`);
|
|
804
|
+
return {};
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
777
808
|
module.exports = {
|
|
778
809
|
getPortfolioPartRefs,
|
|
779
810
|
loadDataByRefs,
|
|
@@ -791,5 +822,6 @@ module.exports = {
|
|
|
791
822
|
loadPIRatings,
|
|
792
823
|
loadPIPageViews,
|
|
793
824
|
loadWatchlistMembership,
|
|
794
|
-
loadPIAlertHistory
|
|
825
|
+
loadPIAlertHistory,
|
|
826
|
+
loadPopularInvestorMasterList // [NEW]
|
|
795
827
|
};
|
|
@@ -93,6 +93,7 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
93
93
|
piPageViews: collections.piPageViews || 'PIPageViewsData',
|
|
94
94
|
watchlistMembership: collections.watchlistMembership || 'WatchlistMembershipData',
|
|
95
95
|
piAlertHistory: collections.piAlertHistory || 'PIAlertHistoryData',
|
|
96
|
+
piMasterList: collections.piMasterList || 'system_state', // [NEW] Collection for master list
|
|
96
97
|
...collections // Allow overrides
|
|
97
98
|
};
|
|
98
99
|
|
|
@@ -237,7 +238,8 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
237
238
|
piRatings: false,
|
|
238
239
|
piPageViews: false,
|
|
239
240
|
watchlistMembership: false,
|
|
240
|
-
piAlertHistory: false
|
|
241
|
+
piAlertHistory: false,
|
|
242
|
+
piMasterList: false // [NEW] Flag for Master List
|
|
241
243
|
}
|
|
242
244
|
};
|
|
243
245
|
|
|
@@ -312,6 +314,10 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
312
314
|
// Path: PIAlertHistoryData/{YYYY-MM-DD}
|
|
313
315
|
const piAlertHistoryRef = db.collection(safeCollections.piAlertHistory).doc(dateStr);
|
|
314
316
|
|
|
317
|
+
// [NEW] Master List Ref (Single Global Document)
|
|
318
|
+
// Path: system_state/popular_investor_master_list
|
|
319
|
+
const piMasterListRef = db.collection(safeCollections.piMasterList).doc('popular_investor_master_list');
|
|
320
|
+
|
|
315
321
|
// 4. Social Data Checks - Use date tracking documents (NEW STRUCTURE)
|
|
316
322
|
// Single tracking documents at root level:
|
|
317
323
|
// - PopularInvestorSocialPostData/_dates -> fetchedDates.{date}
|
|
@@ -387,7 +393,8 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
387
393
|
piRatingsSnap,
|
|
388
394
|
piPageViewsSnap,
|
|
389
395
|
watchlistMembershipSnap,
|
|
390
|
-
piAlertHistorySnap
|
|
396
|
+
piAlertHistorySnap,
|
|
397
|
+
piMasterListSnap // [NEW]
|
|
391
398
|
] = await Promise.all([
|
|
392
399
|
checkAnyPartExists(normPortPartsRef),
|
|
393
400
|
checkAnyPartExists(specPortPartsRef),
|
|
@@ -396,6 +403,7 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
396
403
|
insightsRef.get(),
|
|
397
404
|
Promise.resolve(!genericSocialSnap.empty),
|
|
398
405
|
piRankingsRef.get(),
|
|
406
|
+
piMasterListRef.get(), // [NEW]
|
|
399
407
|
// Check new structure first, fallback to legacy
|
|
400
408
|
checkDateCollectionHasDocs(piPortfoliosCollectionRef).then(exists => exists || checkAnyPartExists(piPortfoliosPartsRef)),
|
|
401
409
|
checkAnyPartExists(piDeepPartsRef), // Legacy only
|
|
@@ -459,6 +467,9 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
459
467
|
availability.hasHistory = normHistExists || specHistExists || piHistExists || signedInHistExists;
|
|
460
468
|
availability.hasInsights = insightsSnap.exists;
|
|
461
469
|
availability.hasSocial = foundPISocial || foundSignedInSocial || genericSocialExists;
|
|
470
|
+
|
|
471
|
+
// [NEW] Assign Master List Availability
|
|
472
|
+
availability.details.piMasterList = piMasterListSnap.exists;
|
|
462
473
|
|
|
463
474
|
// Price Check
|
|
464
475
|
// Check if the target date exists in the price availability set
|