bulltrackers-module 1.0.731 → 1.0.732

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.
@@ -3,8 +3,10 @@
3
3
  * UPDATED: Injects verification and rankings data into context globally and locally.
4
4
  * UPDATED: Added support for historical ranking data in both Standard and Meta contexts.
5
5
  * UPDATED: Added support for 'series' data (historical root data or computation results) in Global Data.
6
+ * UPDATED: Added 'utils.fetchLatest' to support on-demand BigQuery fallback.
6
7
  */
7
8
  const mathLayer = require('../layers/index');
9
+ const DataLoader = require('../utils/data_loader'); // [NEW] Import DataLoader
8
10
  const { LEGACY_MAPPING } = require('../topology/HashManager');
9
11
 
10
12
  class ContextFactory {
@@ -67,6 +69,14 @@ class ContextFactory {
67
69
  computed: computedDependencies || {},
68
70
  previousComputed: previousComputedDependencies || {},
69
71
  meta: metadata, config, deps,
72
+
73
+ // [NEW] UTILS FOR ON-DEMAND FETCHING
74
+ utils: {
75
+ fetchLatest: async (rootType, lookbackDays) => {
76
+ return DataLoader.fetchLatestRootData(config, deps, rootType, userId, userType, lookbackDays);
77
+ }
78
+ },
79
+
70
80
  globalData: {
71
81
  rankings: allRankings || [],
72
82
  rankingsYesterday: allRankingsYesterday || [],
@@ -82,6 +92,7 @@ class ContextFactory {
82
92
  }
83
93
 
84
94
  static buildMetaContext(options) {
95
+ // ... (No changes needed for MetaContext yet)
85
96
  const {
86
97
  dateStr,
87
98
  metadata,
@@ -123,7 +134,7 @@ class ContextFactory {
123
134
  watchlistMembership: watchlistMembership || {},
124
135
  alertHistory: alertHistory || {},
125
136
  series: seriesData || {},
126
- piMasterList: piMasterList || {} // <--- ADDED TO GLOBAL DATA
137
+ piMasterList: piMasterList || {}
127
138
  }
128
139
  };
129
140
  }
@@ -25,6 +25,84 @@ const {
25
25
  } = require('../../core/utils/bigquery_utils');
26
26
 
27
27
  const { normalizeName } = require('./utils');
28
+ const { BigQuery } = require('@google-cloud/bigquery'); // [NEW] Import BigQuery Client
29
+
30
+ // [NEW] Map root types to likely BQ tables (Configuration should ideally override this)
31
+ const ROOT_TABLE_MAP = {
32
+ portfolio: 'data-platform.feature_store.portfolios',
33
+ history: 'data-platform.feature_store.trade_history'
34
+ };
35
+
36
+ const bigquery = new BigQuery();
37
+
38
+ // =============================================================================
39
+ // [NEW] ON-DEMAND LATEST DATA FETCHER
40
+ // =============================================================================
41
+ /**
42
+ * Fetches the latest available root data for a specific user from BigQuery.
43
+ * Used as a fallback when 'today's' data is missing due to outages.
44
+ * @param {object} config - System config
45
+ * @param {object} deps - Dependencies
46
+ * @param {string} rootType - 'portfolio' or 'history'
47
+ * @param {string} userId - The user ID (CID)
48
+ * @param {string} userType - The user type (e.g. POPULAR_INVESTOR)
49
+ * @param {number} lookbackDays - How far back to search (default 7)
50
+ */
51
+ exports.fetchLatestRootData = async (config, deps, rootType, userId, userType, lookbackDays = 7) => {
52
+ const { logger } = deps;
53
+ const tableName = config.bigQuery?.tables?.[rootType] || ROOT_TABLE_MAP[rootType];
54
+
55
+ if (!tableName) {
56
+ logger.log('WARN', `[DataLoader] No BigQuery table mapped for rootType '${rootType}'`);
57
+ return null;
58
+ }
59
+
60
+ try {
61
+ // Construct Dynamic Query to get the Last Available Record
62
+ // Assumes schema: CustomerId, Date, UserType, and a payload column (e.g. PortfolioData/HistoryData)
63
+ // We select * to get the payload wrapper.
64
+ const query = `
65
+ SELECT *
66
+ FROM \`${tableName}\`
67
+ WHERE CustomerId = @userId
68
+ AND Date >= DATE_SUB(CURRENT_DATE(), INTERVAL @lookbackDays DAY)
69
+ ORDER BY Date DESC
70
+ LIMIT 1
71
+ `;
72
+
73
+ const options = {
74
+ query: query,
75
+ params: { userId: String(userId), lookbackDays: lookbackDays }
76
+ };
77
+
78
+ const [rows] = await bigquery.query(options);
79
+
80
+ if (rows && rows.length > 0) {
81
+ const record = rows[0];
82
+ const dateFound = record.Date ? record.Date.value || record.Date : 'unknown';
83
+ logger.log('INFO', `[DataLoader] 🔄 Fetched LATEST ${rootType} for ${userId} from ${dateFound}`);
84
+
85
+ // Normalize result to match stream format
86
+ // Assumes the payload is either the whole row or nested in a specific column like 'portfolio_data'
87
+ // We return the payload with _userType injected.
88
+ let payload = record;
89
+ if (rootType === 'portfolio' && record.portfolio_data) payload = record.portfolio_data;
90
+ if (rootType === 'history' && record.history_data) payload = record.history_data;
91
+
92
+ return {
93
+ ...payload,
94
+ _userType: userType || record.UserType,
95
+ _isFallback: true,
96
+ _fetchedAt: new Date().toISOString()
97
+ };
98
+ }
99
+
100
+ return null;
101
+ } catch (e) {
102
+ logger.log('ERROR', `[DataLoader] Failed to fetch latest ${rootType} for ${userId}: ${e.message}`);
103
+ return null;
104
+ }
105
+ };
28
106
 
29
107
  // =============================================================================
30
108
  // 1. PORTFOLIOS
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.731",
3
+ "version": "1.0.732",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -38,24 +38,25 @@
38
38
  "finance"
39
39
  ],
40
40
  "dependencies": {
41
+ "@google-cloud/bigquery": "^7.9.4",
41
42
  "@google-cloud/firestore": "^7.11.3",
42
43
  "@google-cloud/monitoring": "latest",
43
44
  "@google-cloud/pubsub": "latest",
45
+ "@google-cloud/storage": "^7.18.0",
46
+ "@google-cloud/tasks": "^5.0.0",
44
47
  "aiden-shared-calculations-unified": "^1.0.110",
45
48
  "cors": "^2.8.5",
46
49
  "dotenv": "latest",
47
50
  "express": "^4.19.2",
48
51
  "express-rate-limit": "^8.2.1",
52
+ "firebase-admin": "^13.6.0",
49
53
  "google-auth-library": "^10.5.0",
50
54
  "graphviz": "latest",
51
55
  "node-graphviz": "^0.1.1",
52
56
  "p-limit": "^3.1.0",
53
57
  "require-all": "^3.0.0",
54
58
  "sharedsetup": "latest",
55
- "zod": "^4.3.5",
56
- "@google-cloud/storage": "^7.18.0",
57
- "@google-cloud/bigquery": "^7.3.0",
58
- "@google-cloud/tasks": "^5.0.0"
59
+ "zod": "^4.3.5"
59
60
  },
60
61
  "devDependencies": {
61
62
  "bulltracker-deployer": "file:../bulltracker-deployer"