bulltrackers-module 1.0.701 → 1.0.703
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.
|
@@ -17,7 +17,8 @@ const {
|
|
|
17
17
|
loadWatchlistMembership: loadWatchlistMembershipData,
|
|
18
18
|
loadPIAlertHistory,
|
|
19
19
|
loadPIWatchlistData,
|
|
20
|
-
loadPopularInvestorMasterList
|
|
20
|
+
loadPopularInvestorMasterList,
|
|
21
|
+
loadDailyPortfolios // <--- IMPORTED
|
|
21
22
|
} = require('../utils/data_loader');
|
|
22
23
|
const { getAvailabilityWindow } = require('./AvailabilityChecker');
|
|
23
24
|
const zlib = require('zlib');
|
|
@@ -81,6 +82,12 @@ const LOADER_DEFINITIONS = {
|
|
|
81
82
|
// No collection key needed for direct implementation, but handled by fn
|
|
82
83
|
fn: loadPIWatchlistData,
|
|
83
84
|
isIdBased: true // Uses ID instead of Date
|
|
85
|
+
},
|
|
86
|
+
// <--- ADDED SUPPORT FOR PORTFOLIO SERIES
|
|
87
|
+
loadPortfolios: {
|
|
88
|
+
cache: 'portfolios',
|
|
89
|
+
fn: loadDailyPortfolios
|
|
90
|
+
// No configKey/flag ensures legacy loop (required for complex multi-collection fetch)
|
|
84
91
|
}
|
|
85
92
|
};
|
|
86
93
|
|
|
@@ -112,7 +119,8 @@ class CachedDataLoader {
|
|
|
112
119
|
// =========================================================================
|
|
113
120
|
// GENERIC LOADER HELPER
|
|
114
121
|
// =========================================================================
|
|
115
|
-
|
|
122
|
+
// [FIX] Accepts ...args to pass down filters (like requiredUserTypes)
|
|
123
|
+
async _loadGeneric(methodName, key, ...args) {
|
|
116
124
|
const def = LOADER_DEFINITIONS[methodName];
|
|
117
125
|
if (!def) throw new Error(`Unknown loader method: ${methodName}`);
|
|
118
126
|
|
|
@@ -125,7 +133,7 @@ class CachedDataLoader {
|
|
|
125
133
|
this.deps.logger?.log('INFO', `[CachedDataLoader] 📂 Loading '${def.cache}' from: ${collection}/${key}`);
|
|
126
134
|
}
|
|
127
135
|
|
|
128
|
-
const promise = def.fn(this.config, this.deps, key);
|
|
136
|
+
const promise = def.fn(this.config, this.deps, key, ...args);
|
|
129
137
|
cacheMap.set(key, promise);
|
|
130
138
|
return promise;
|
|
131
139
|
}
|
|
@@ -144,6 +152,8 @@ class CachedDataLoader {
|
|
|
144
152
|
async loadWatchlistMembership(dateStr) { return this._loadGeneric('loadWatchlistMembership', dateStr); }
|
|
145
153
|
async loadAlertHistory(dateStr) { return this._loadGeneric('loadAlertHistory' , dateStr); }
|
|
146
154
|
async loadPIWatchlistData(piCid) { return this._loadGeneric('loadPIWatchlistData' , String(piCid)); }
|
|
155
|
+
// <--- ADDED PORTFOLIOS ACCESSOR with extra arg
|
|
156
|
+
async loadPortfolios(dateStr, userTypes) { return this._loadGeneric('loadPortfolios', dateStr, userTypes); }
|
|
147
157
|
|
|
148
158
|
// =========================================================================
|
|
149
159
|
// SPECIALIZED LOADERS (Non-Standard Patterns)
|
|
@@ -195,13 +205,14 @@ class CachedDataLoader {
|
|
|
195
205
|
/**
|
|
196
206
|
* Optimistically loads data series using Batch Reads (db.getAll).
|
|
197
207
|
* Uses Availability Index to minimize costs.
|
|
208
|
+
* [FIX] Now accepts ...args to pass context (e.g. requiredUserTypes)
|
|
198
209
|
*/
|
|
199
|
-
async loadSeries(loaderMethod, dateStr, lookbackDays) {
|
|
210
|
+
async loadSeries(loaderMethod, dateStr, lookbackDays, ...args) {
|
|
200
211
|
const def = LOADER_DEFINITIONS[loaderMethod];
|
|
201
212
|
if (!def) throw new Error(`[CachedDataLoader] Unknown series method ${loaderMethod}`);
|
|
202
213
|
|
|
203
214
|
// Fallback to legacy loop if method isn't configured for batching (missing config/flag)
|
|
204
|
-
if (!def.configKey || !def.flag) return this._loadSeriesLegacy(loaderMethod, dateStr, lookbackDays);
|
|
215
|
+
if (!def.configKey || !def.flag) return this._loadSeriesLegacy(loaderMethod, dateStr, lookbackDays, ...args);
|
|
205
216
|
|
|
206
217
|
// 1. Calculate Date Range
|
|
207
218
|
const endDate = new Date(dateStr);
|
|
@@ -256,7 +267,7 @@ class CachedDataLoader {
|
|
|
256
267
|
});
|
|
257
268
|
} catch (err) {
|
|
258
269
|
console.warn(`[CachedDataLoader] Batch failed: ${err.message}. Legacy fallback.`);
|
|
259
|
-
return this._loadSeriesLegacy(loaderMethod, dateStr, lookbackDays);
|
|
270
|
+
return this._loadSeriesLegacy(loaderMethod, dateStr, lookbackDays, ...args);
|
|
260
271
|
}
|
|
261
272
|
}
|
|
262
273
|
|
|
@@ -268,7 +279,7 @@ class CachedDataLoader {
|
|
|
268
279
|
};
|
|
269
280
|
}
|
|
270
281
|
|
|
271
|
-
async _loadSeriesLegacy(loaderMethod, dateStr, lookbackDays) {
|
|
282
|
+
async _loadSeriesLegacy(loaderMethod, dateStr, lookbackDays, ...args) {
|
|
272
283
|
const results = {};
|
|
273
284
|
const promises = [];
|
|
274
285
|
const endDate = new Date(dateStr);
|
|
@@ -277,7 +288,8 @@ class CachedDataLoader {
|
|
|
277
288
|
const d = new Date(endDate);
|
|
278
289
|
d.setUTCDate(d.getUTCDate() - i);
|
|
279
290
|
const dStr = d.toISOString().slice(0, 10);
|
|
280
|
-
|
|
291
|
+
// [FIX] Pass args (e.g. requiredUserTypes) to the loader method
|
|
292
|
+
promises.push(this[loaderMethod](dStr, ...args).then(data => data ? results[dStr] = data : null).catch(() => null));
|
|
281
293
|
}
|
|
282
294
|
|
|
283
295
|
await Promise.all(promises);
|
|
@@ -392,6 +392,10 @@ async function loadSeriesData(loader, dateStr, calcs, config, deps) {
|
|
|
392
392
|
const rootReqs = {};
|
|
393
393
|
const depReqs = {}; // norm -> { days, originalName, category }
|
|
394
394
|
|
|
395
|
+
// [FIX] Calculate User Types here to pass to loadSeries
|
|
396
|
+
const requiredUserTypes = new Set(calcs.map(c => (c.userType || 'ALL').toUpperCase()));
|
|
397
|
+
const userTypeArray = requiredUserTypes.has('ALL') ? null : Array.from(requiredUserTypes);
|
|
398
|
+
|
|
395
399
|
calcs.forEach(c => {
|
|
396
400
|
if (c.manifest.rootDataSeries) {
|
|
397
401
|
Object.entries(c.manifest.rootDataSeries).forEach(([k, v]) => rootReqs[k] = Math.max(rootReqs[k]||0, v.lookback||v));
|
|
@@ -410,11 +414,17 @@ async function loadSeriesData(loader, dateStr, calcs, config, deps) {
|
|
|
410
414
|
const series = { root: {}, results: {} };
|
|
411
415
|
const rootMap = {
|
|
412
416
|
alerts: 'loadAlertHistory', insights: 'loadInsights', ratings: 'loadRatings',
|
|
413
|
-
watchlist: 'loadWatchlistMembership', rankings: 'loadRankings'
|
|
417
|
+
watchlist: 'loadWatchlistMembership', rankings: 'loadRankings',
|
|
418
|
+
// <--- ADDED MAPPING
|
|
419
|
+
portfolios: 'loadPortfolios'
|
|
414
420
|
};
|
|
415
421
|
|
|
416
422
|
await Promise.all(Object.entries(rootReqs).map(async ([key, days]) => {
|
|
417
|
-
if (rootMap[key])
|
|
423
|
+
if (rootMap[key]) {
|
|
424
|
+
// [FIX] Pass userTypeArray specifically if loading portfolios
|
|
425
|
+
const extraArgs = (key === 'portfolios') ? [userTypeArray] : [];
|
|
426
|
+
series.root[key] = (await loader.loadSeries(rootMap[key], dateStr, days, ...extraArgs)).data;
|
|
427
|
+
}
|
|
418
428
|
}));
|
|
419
429
|
|
|
420
430
|
// Build lookup from ALL computations using config.calculations
|
|
@@ -228,6 +228,19 @@ async function loadFullDayMap(config, deps, partRefs, dateString) {
|
|
|
228
228
|
return fullMap;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
/** Stage 3.5: Load Daily Portfolios (Wrapper for Series Loading) */
|
|
232
|
+
async function loadDailyPortfolios(config, deps, dateString, requiredUserTypes = null) {
|
|
233
|
+
// 1. GCS FAST PATH
|
|
234
|
+
const cached = await tryLoadFromGCS(config, dateString, 'portfolios', deps.logger);
|
|
235
|
+
if (cached) return cached;
|
|
236
|
+
|
|
237
|
+
// 2. FIRESTORE FALLBACK
|
|
238
|
+
// [FIX] Now passing requiredUserTypes to prevent fetching all users (e.g. NormalUserPortfolios)
|
|
239
|
+
const partRefs = await getPortfolioPartRefs(config, deps, dateString, requiredUserTypes);
|
|
240
|
+
if (partRefs.length === 0) return {};
|
|
241
|
+
return loadDataByRefs(config, deps, partRefs);
|
|
242
|
+
}
|
|
243
|
+
|
|
231
244
|
/** Stage 4: Load daily instrument insights */
|
|
232
245
|
async function loadDailyInsights(config, deps, dateString) {
|
|
233
246
|
const { db, logger, calculationUtils } = deps;
|
|
@@ -800,7 +813,8 @@ async function loadPopularInvestorMasterList(config, deps, dateString = null) {
|
|
|
800
813
|
module.exports = {
|
|
801
814
|
getPortfolioPartRefs,
|
|
802
815
|
loadDataByRefs,
|
|
803
|
-
loadFullDayMap,
|
|
816
|
+
loadFullDayMap,
|
|
817
|
+
loadDailyPortfolios,
|
|
804
818
|
loadDailyInsights,
|
|
805
819
|
loadDailySocialPostInsights,
|
|
806
820
|
getHistoryPartRefs,
|