bulltrackers-module 1.0.125 → 1.0.127
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.
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
const { FieldPath } = require('@google-cloud/firestore');
|
|
14
14
|
const {
|
|
15
15
|
getPortfolioPartRefs,
|
|
16
|
-
loadFullDayMap,
|
|
16
|
+
loadFullDayMap, // <-- Ensure loadFullDayMap is imported
|
|
17
17
|
loadDataByRefs,
|
|
18
18
|
loadDailyInsights,
|
|
19
|
-
loadDailySocialPostInsights
|
|
19
|
+
loadDailySocialPostInsights,
|
|
20
|
+
getHistoryPartRefs // <-- IMPORT NEW FUNCTION
|
|
20
21
|
} = require('../utils/data_loader.js');
|
|
21
22
|
|
|
22
23
|
const {
|
|
@@ -53,47 +54,53 @@ function checkRootDependencies(calcManifest, rootDataStatus) {
|
|
|
53
54
|
if (dep === 'portfolio' && !rootDataStatus.hasPortfolio) return false;
|
|
54
55
|
if (dep === 'insights' && !rootDataStatus.hasInsights) return false;
|
|
55
56
|
if (dep === 'social' && !rootDataStatus.hasSocial) return false;
|
|
57
|
+
if (dep === 'history' && !rootDataStatus.hasHistory) return false; // <-- ADDED THIS LINE
|
|
56
58
|
}
|
|
57
59
|
return true; // All dependencies were met
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
|
|
61
63
|
/**
|
|
62
|
-
* Checks if the root data (portfolios, insights, social) exists for a given day.
|
|
64
|
+
* Checks if the root data (portfolios, insights, social, history) exists for a given day.
|
|
63
65
|
* @param {string} dateStr - The date string to check (YYYY-MM-DD).
|
|
64
66
|
* @param {object} config - The computation system configuration object.
|
|
65
67
|
* @param {object} dependencies - Contains db, logger, calculationUtils.
|
|
66
|
-
* @returns {Promise<object>} { portfolioRefs, insightsData, socialData, hasPortfolio, hasInsights, hasSocial }
|
|
68
|
+
* @returns {Promise<object>} { portfolioRefs, insightsData, socialData, historyRefs, hasPortfolio, hasInsights, hasSocial, hasHistory }
|
|
67
69
|
*/
|
|
68
70
|
async function checkRootDataAvailability(dateStr, config, dependencies) {
|
|
69
71
|
const { logger } = dependencies;
|
|
70
72
|
logger.log('INFO', `[PassRunner] Checking root data availability for ${dateStr}...`);
|
|
71
73
|
|
|
72
74
|
try {
|
|
73
|
-
|
|
75
|
+
// --- MODIFIED: Add getHistoryPartRefs to the parallel load ---
|
|
76
|
+
const [portfolioRefs, insightsData, socialData, historyRefs] = await Promise.all([
|
|
74
77
|
getPortfolioPartRefs(config, dependencies, dateStr),
|
|
75
78
|
loadDailyInsights(config, dependencies, dateStr),
|
|
76
|
-
loadDailySocialPostInsights(config, dependencies, dateStr)
|
|
79
|
+
loadDailySocialPostInsights(config, dependencies, dateStr),
|
|
80
|
+
getHistoryPartRefs(config, dependencies, dateStr) // <-- ADD THIS
|
|
77
81
|
]);
|
|
78
82
|
|
|
79
83
|
const hasPortfolio = (portfolioRefs && portfolioRefs.length > 0);
|
|
80
84
|
const hasInsights = !!insightsData;
|
|
81
85
|
const hasSocial = !!socialData;
|
|
86
|
+
const hasHistory = (historyRefs && historyRefs.length > 0); // <-- ADD THIS
|
|
82
87
|
|
|
83
88
|
return {
|
|
84
89
|
portfolioRefs: portfolioRefs || [],
|
|
85
90
|
insightsData: insightsData || null,
|
|
86
91
|
socialData: socialData || null,
|
|
92
|
+
historyRefs: historyRefs || [], // <-- ADD THIS
|
|
87
93
|
hasPortfolio: hasPortfolio,
|
|
88
94
|
hasInsights: hasInsights,
|
|
89
|
-
hasSocial: hasSocial
|
|
95
|
+
hasSocial: hasSocial,
|
|
96
|
+
hasHistory: hasHistory // <-- ADD THIS
|
|
90
97
|
};
|
|
91
98
|
|
|
92
99
|
} catch (err) {
|
|
93
100
|
logger.log('ERROR', `[PassRunner] Error checking data availability for ${dateStr}`, { errorMessage: err.message });
|
|
94
101
|
return {
|
|
95
|
-
portfolioRefs: [], insightsData: null, socialData: null,
|
|
96
|
-
hasPortfolio: false, hasInsights: false, hasSocial: false
|
|
102
|
+
portfolioRefs: [], insightsData: null, socialData: null, historyRefs: [], // <-- ADD historyRefs
|
|
103
|
+
hasPortfolio: false, hasInsights: false, hasSocial: false, hasHistory: false // <-- ADD hasHistory
|
|
97
104
|
};
|
|
98
105
|
}
|
|
99
106
|
}
|
|
@@ -223,15 +230,16 @@ async function runComputationPass(config, dependencies, computationManifest) {
|
|
|
223
230
|
for (const dateStr of allExpectedDates) {
|
|
224
231
|
const dateToProcess = new Date(dateStr + 'T00:00:00Z');
|
|
225
232
|
|
|
226
|
-
// 1. Check for root data (portfolios, insights, social)
|
|
233
|
+
// 1. Check for root data (portfolios, insights, social, AND HISTORY)
|
|
227
234
|
const rootData = await checkRootDataAvailability(dateStr, config, dependencies);
|
|
228
235
|
const rootDataStatus = {
|
|
229
236
|
hasPortfolio: rootData.hasPortfolio,
|
|
230
237
|
hasInsights: rootData.hasInsights,
|
|
231
|
-
hasSocial: rootData.hasSocial
|
|
238
|
+
hasSocial: rootData.hasSocial,
|
|
239
|
+
hasHistory: rootData.hasHistory // <-- ADD THIS
|
|
232
240
|
};
|
|
233
241
|
|
|
234
|
-
if (!rootData.hasPortfolio && !rootData.hasInsights && !rootData.hasSocial) {
|
|
242
|
+
if (!rootData.hasPortfolio && !rootData.hasInsights && !rootData.hasSocial && !rootData.hasHistory) {
|
|
235
243
|
logger.log('WARN', `[PassRunner] Skipping Pass ${passToRun} for ${dateStr} due to missing all root data.`);
|
|
236
244
|
continue; // Skip to the next day
|
|
237
245
|
}
|
|
@@ -363,7 +371,9 @@ async function streamAndProcess(
|
|
|
363
371
|
todayInsights = null,
|
|
364
372
|
yesterdayInsights = null,
|
|
365
373
|
todaySocialPostInsights = null,
|
|
366
|
-
yesterdaySocialPostInsights = null
|
|
374
|
+
yesterdaySocialPostInsights = null,
|
|
375
|
+
todayHistoryData = null, // <-- ADD THIS
|
|
376
|
+
yesterdayHistoryData = null // <-- ADD THIS
|
|
367
377
|
) {
|
|
368
378
|
const { logger, calculationUtils } = dependencies;
|
|
369
379
|
logger.log('INFO', `[${passName}] Streaming ${todayRefs.length} 'today' part docs for ${dateStr}...`);
|
|
@@ -405,12 +415,16 @@ async function streamAndProcess(
|
|
|
405
415
|
const isHistoricalCalc = manifestCalc.isHistorical === true;
|
|
406
416
|
const isSpeculatorCalc = manifestCalc.category === 'speculators';
|
|
407
417
|
let processArgs;
|
|
418
|
+
|
|
419
|
+
// --- MODIFIED: Add history data to the context args ---
|
|
408
420
|
const allContextArgs = [
|
|
409
421
|
context,
|
|
410
422
|
todayInsights,
|
|
411
423
|
yesterdayInsights,
|
|
412
424
|
todaySocialPostInsights,
|
|
413
|
-
yesterdaySocialPostInsights
|
|
425
|
+
yesterdaySocialPostInsights,
|
|
426
|
+
todayHistoryData, // <-- ADD THIS
|
|
427
|
+
yesterdayHistoryData // <-- ADD THIS
|
|
414
428
|
];
|
|
415
429
|
|
|
416
430
|
if (isSocialOrInsights) {
|
|
@@ -447,7 +461,18 @@ async function streamAndProcess(
|
|
|
447
461
|
// Handle case where there are no users but we still need to run insights/social calcs
|
|
448
462
|
if (todayRefs.length === 0 && isFirstUser) {
|
|
449
463
|
logger.log('INFO', `[${passName}] No user portfolios found for ${dateStr}. Running insights/social calcs once.`);
|
|
450
|
-
|
|
464
|
+
|
|
465
|
+
// --- MODIFIED: Add null history data ---
|
|
466
|
+
const allContextArgs = [
|
|
467
|
+
context,
|
|
468
|
+
todayInsights,
|
|
469
|
+
yesterdayInsights,
|
|
470
|
+
todaySocialPostInsights,
|
|
471
|
+
yesterdaySocialPostInsights,
|
|
472
|
+
todayHistoryData, // <-- ADD THIS
|
|
473
|
+
yesterdayHistoryData // <-- ADD THIS
|
|
474
|
+
];
|
|
475
|
+
|
|
451
476
|
for (const calcName in state) {
|
|
452
477
|
const calc = state[calcName];
|
|
453
478
|
if (!calc || typeof calc.process !== 'function') continue;
|
|
@@ -474,23 +499,32 @@ async function runUnifiedComputation(dateToProcess, calculationsToRun, passName,
|
|
|
474
499
|
logger.log('INFO', `[${passName}] Starting run for ${dateStr} with ${calculationsToRun.length} calcs.`);
|
|
475
500
|
|
|
476
501
|
try {
|
|
502
|
+
// --- NEW: Get history root data from the orchestrator ---
|
|
477
503
|
const {
|
|
478
504
|
portfolioRefs: todayRefs,
|
|
479
505
|
insightsData: todayInsightsData,
|
|
480
|
-
socialData: todaySocialPostInsightsData
|
|
506
|
+
socialData: todaySocialPostInsightsData,
|
|
507
|
+
historyRefs: todayHistoryRefs // <-- ADD THIS
|
|
481
508
|
} = rootData;
|
|
482
509
|
|
|
483
510
|
let yesterdayPortfolios = {};
|
|
484
511
|
let yesterdayInsightsData = null;
|
|
485
512
|
let yesterdaySocialPostInsightsData = null;
|
|
513
|
+
let todayHistoryData = null; // <-- ADD THIS
|
|
514
|
+
let yesterdayHistoryData = null; // <-- ADD THIS
|
|
486
515
|
|
|
516
|
+
// --- MODIFIED: Add checks for history data ---
|
|
487
517
|
const requiresYesterdayPortfolio = calculationsToRun.some(c => c.isHistorical === true);
|
|
488
518
|
const requiresYesterdayInsights = calculationsToRun.some(c => c.class.prototype.process.toString().includes('yesterdayInsights'));
|
|
489
519
|
const requiresYesterdaySocialPosts = calculationsToRun.some(c => c.class.prototype.process.toString().includes('yesterdaySocialPostInsights'));
|
|
520
|
+
const requiresHistory = calculationsToRun.some(c => c.rootDataDependencies.includes('history'));
|
|
521
|
+
const requiresYesterdayHistory = calculationsToRun.some(c => c.isHistorical === true && c.class.prototype.process.toString().includes('yesterdayHistoryData'));
|
|
522
|
+
// --- END MODIFICATION ---
|
|
523
|
+
|
|
490
524
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
525
|
+
// --- (This block is now much larger, handling all "yesterday" and "history" data) ---
|
|
526
|
+
if (requiresYesterdayPortfolio || requiresYesterdayInsights || requiresYesterdaySocialPosts || requiresHistory || requiresYesterdayHistory) {
|
|
527
|
+
|
|
494
528
|
if(requiresYesterdayInsights) {
|
|
495
529
|
let daysAgo = 1; const maxLookback = 30;
|
|
496
530
|
while (!yesterdayInsightsData && daysAgo <= maxLookback) {
|
|
@@ -524,9 +558,32 @@ async function runUnifiedComputation(dateToProcess, calculationsToRun, passName,
|
|
|
524
558
|
logger.log('WARN', `[${passName}] Yesterday's (${prevStr}) portfolio data not found. Historical calcs requiring it will be skipped.`);
|
|
525
559
|
}
|
|
526
560
|
}
|
|
561
|
+
|
|
562
|
+
// --- NEW: Add logic to load Today's History Data (if needed) ---
|
|
563
|
+
if (requiresHistory && todayHistoryRefs.length > 0) {
|
|
564
|
+
logger.log('INFO', `[${passName}] Loading today's (${dateStr}) history map...`);
|
|
565
|
+
todayHistoryData = await loadFullDayMap(config, dependencies, todayHistoryRefs);
|
|
566
|
+
logger.log('INFO', `[${passName}] Loaded today's history map with ${Object.keys(todayHistoryData).length} users.`);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// --- NEW: Add logic to load Yesterday's History Data (if needed) ---
|
|
570
|
+
if (requiresYesterdayHistory) {
|
|
571
|
+
const prev = new Date(dateToProcess);
|
|
572
|
+
prev.setUTCDate(prev.getUTCDate() - 1);
|
|
573
|
+
const prevStr = prev.toISOString().slice(0, 10);
|
|
574
|
+
const yesterdayHistoryRefs = await getHistoryPartRefs(config, dependencies, prevStr);
|
|
575
|
+
if (yesterdayHistoryRefs.length > 0) {
|
|
576
|
+
yesterdayHistoryData = await loadFullDayMap(config, dependencies, yesterdayHistoryRefs);
|
|
577
|
+
logger.log('INFO', `[${passName}] Loaded yesterday's (${prevStr}) history map for historical calcs.`);
|
|
578
|
+
} else {
|
|
579
|
+
logger.log('WARN', `[${passName}] Yesterday's (${prevStr}) history data not found. Historical calcs requiring it will be skipped.`);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
527
582
|
}
|
|
528
583
|
|
|
529
584
|
const state = initializeCalculators(calculationsToRun, logger);
|
|
585
|
+
|
|
586
|
+
// --- MODIFIED: Pass new history data ---
|
|
530
587
|
await streamAndProcess(
|
|
531
588
|
dateStr,
|
|
532
589
|
todayRefs,
|
|
@@ -538,7 +595,9 @@ async function runUnifiedComputation(dateToProcess, calculationsToRun, passName,
|
|
|
538
595
|
todayInsightsData,
|
|
539
596
|
yesterdayInsightsData,
|
|
540
597
|
todaySocialPostInsightsData,
|
|
541
|
-
yesterdaySocialPostInsightsData
|
|
598
|
+
yesterdaySocialPostInsightsData,
|
|
599
|
+
todayHistoryData, // <-- ADD THIS
|
|
600
|
+
yesterdayHistoryData // <-- ADD THIS
|
|
542
601
|
);
|
|
543
602
|
|
|
544
603
|
let successCount = 0;
|
|
@@ -183,10 +183,60 @@ async function loadDailySocialPostInsights(config, dependencies, dateString) {
|
|
|
183
183
|
// --- END NEW ---
|
|
184
184
|
|
|
185
185
|
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* --- NEW ---
|
|
189
|
+
* Sub-pipe: pipe.computationSystem.dataLoader.getHistoryPartRefs
|
|
190
|
+
* @param {object} config - The computation system configuration object.
|
|
191
|
+
* @param {object} dependencies - Contains db, logger, calculationUtils.
|
|
192
|
+
* @param {string} dateString - The date in YYYY-MM-DD format.
|
|
193
|
+
* @returns {Promise<Firestore.DocumentReference[]>} An array of DocumentReferences.
|
|
194
|
+
*/
|
|
195
|
+
async function getHistoryPartRefs(config, dependencies, dateString) {
|
|
196
|
+
const { db, logger, calculationUtils } = dependencies;
|
|
197
|
+
const { withRetry } = calculationUtils;
|
|
198
|
+
|
|
199
|
+
logger.log('INFO', `Getting history part references for date: ${dateString}`);
|
|
200
|
+
const allPartRefs = [];
|
|
201
|
+
// --- MODIFIED: Use new history collection config keys ---
|
|
202
|
+
const collectionsToQuery = [config.normalUserHistoryCollection, config.speculatorHistoryCollection];
|
|
203
|
+
|
|
204
|
+
for (const collectionName of collectionsToQuery) {
|
|
205
|
+
if (!collectionName) { // Add a check in case config is missing
|
|
206
|
+
logger.log('WARN', `History collection name is undefined. Skipping.`);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const blockDocsQuery = db.collection(collectionName);
|
|
210
|
+
const blockDocRefs = await withRetry(
|
|
211
|
+
() => blockDocsQuery.listDocuments(),
|
|
212
|
+
`listDocuments(${collectionName})`
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
if (blockDocRefs.length === 0) {
|
|
216
|
+
logger.log('WARN', `No block documents found in collection: ${collectionName}`);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
for (const blockDocRef of blockDocRefs) {
|
|
221
|
+
const partsCollectionRef = blockDocRef.collection(config.snapshotsSubcollection).doc(dateString).collection(config.partsSubcollection);
|
|
222
|
+
const partDocs = await withRetry(
|
|
223
|
+
() => partsCollectionRef.listDocuments(),
|
|
224
|
+
`listDocuments(${partsCollectionRef.path})`
|
|
225
|
+
);
|
|
226
|
+
allPartRefs.push(...partDocs);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
logger.log('INFO', `Found ${allPartRefs.length} history part document references for ${dateString}.`);
|
|
231
|
+
return allPartRefs;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
|
|
186
235
|
module.exports = {
|
|
187
236
|
getPortfolioPartRefs,
|
|
188
237
|
loadDataByRefs,
|
|
189
238
|
loadFullDayMap,
|
|
190
239
|
loadDailyInsights,
|
|
191
240
|
loadDailySocialPostInsights,
|
|
241
|
+
getHistoryPartRefs, // <-- EXPORT NEW FUNCTION
|
|
192
242
|
};
|