mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 14:05:24 +02:00
Optimize data processing performance with memoization
This commit is contained in:
+31
-12
@@ -65,8 +65,12 @@ const MONTH_MAP: Record<string, string> = {
|
||||
};
|
||||
|
||||
// Robust Month Normalizer
|
||||
const monthCache: Record<string, string> = {};
|
||||
|
||||
const normalizeMonth = (rawMonth: string): string => {
|
||||
if (!rawMonth) return '';
|
||||
if (monthCache[rawMonth]) return monthCache[rawMonth];
|
||||
|
||||
let m = String(rawMonth).trim().toLowerCase();
|
||||
|
||||
// 0. Check for Excel Serial Date (e.g. 45544 -> Sep)
|
||||
@@ -82,7 +86,10 @@ const normalizeMonth = (rawMonth: string): string => {
|
||||
}
|
||||
|
||||
// 1. Direct Map Lookup (Handles "jan", "enero", "sep", etc.)
|
||||
if (MONTH_MAP[m]) return MONTH_MAP[m];
|
||||
if (MONTH_MAP[m]) {
|
||||
monthCache[rawMonth] = MONTH_MAP[m];
|
||||
return MONTH_MAP[m];
|
||||
}
|
||||
|
||||
// 2. Handle numeric months "01", "1", "01-2023"
|
||||
// If it's a full date string like "2023-04-01" or "01/04/2023"
|
||||
@@ -125,6 +132,7 @@ const normalizeMonth = (rawMonth: string): string => {
|
||||
}
|
||||
}
|
||||
|
||||
monthCache[rawMonth] = rawMonth;
|
||||
return rawMonth; // Return as-is if all else fails
|
||||
};
|
||||
|
||||
@@ -508,16 +516,25 @@ export const mergeSalesAndAdsData = (
|
||||
trafficData?: TrafficRecord[],
|
||||
velocityMap?: Map<string, number>
|
||||
): CombinedKPIs[] => {
|
||||
const stringCache: Record<string, string> = {};
|
||||
const getNorm = (s: string) => {
|
||||
if (!s) return '';
|
||||
if (stringCache[s]) return stringCache[s];
|
||||
const v = s.trim().toUpperCase();
|
||||
stringCache[s] = v;
|
||||
return v;
|
||||
};
|
||||
|
||||
// Key for both sales and ads: ASIN|Customer|Year|Week
|
||||
const createKey = (asin: string, customer: string, year: number, week: number) =>
|
||||
`${asin.trim().toUpperCase()}|${customer.trim().toUpperCase()}|${year}|${week}`;
|
||||
`${getNorm(asin)}|${getNorm(customer)}|${year}|${week}`;
|
||||
|
||||
// Build traffic lookup map - Use a more efficient key
|
||||
const trafficMap = new Map<string, number>();
|
||||
if (trafficData) {
|
||||
for (let i = 0; i < trafficData.length; i++) {
|
||||
const t = trafficData[i];
|
||||
const key = `${t.asin.trim().toUpperCase()}|${t.country.trim().toUpperCase()}|${t.year}|${t.week}`;
|
||||
const key = `${getNorm(t.asin)}|${getNorm(t.country)}|${t.year}|${t.week}`;
|
||||
trafficMap.set(key, (trafficMap.get(key) || 0) + (t.glanceViews || 0));
|
||||
}
|
||||
}
|
||||
@@ -544,8 +561,8 @@ export const mergeSalesAndAdsData = (
|
||||
const weekNum = sale.week || 0;
|
||||
if (weekNum === 0) continue;
|
||||
|
||||
const asinUpper = sale.asin.trim().toUpperCase();
|
||||
const key = `${asinUpper}|${sale.customer.trim().toUpperCase()}|${sale.year}|${weekNum}`;
|
||||
const asinUpper = getNorm(sale.asin);
|
||||
const key = `${asinUpper}|${getNorm(sale.customer)}|${sale.year}|${weekNum}`;
|
||||
|
||||
// If no global map provided, build it on the fly
|
||||
if (!asinMetadataMap) {
|
||||
@@ -585,7 +602,7 @@ export const mergeSalesAndAdsData = (
|
||||
const adsMap = new Map<string, AdsRecord>();
|
||||
for (let i = 0; i < adsData.length; i++) {
|
||||
const ad = adsData[i];
|
||||
const key = `${ad.asin.trim().toUpperCase()}|${ad.country.trim().toUpperCase()}|${ad.year}|${ad.week}`;
|
||||
const key = `${getNorm(ad.asin)}|${getNorm(ad.country)}|${ad.year}|${ad.week}`;
|
||||
const existing = adsMap.get(key);
|
||||
if (existing) {
|
||||
existing.cost += ad.cost;
|
||||
@@ -633,7 +650,7 @@ export const mergeSalesAndAdsData = (
|
||||
month: sale.month,
|
||||
week: sale.week,
|
||||
year: sale.year,
|
||||
asin: sale.asin.trim().toUpperCase(),
|
||||
asin: getNorm(sale.asin),
|
||||
title: sale.title,
|
||||
line: sale.line,
|
||||
sku: sale.sku,
|
||||
@@ -663,7 +680,7 @@ export const mergeSalesAndAdsData = (
|
||||
// 5. Add ads-only records - use provided metadata for line/title
|
||||
adsMap.forEach((ad, key) => {
|
||||
if (!processedKeys.has(key)) {
|
||||
const asin = ad.asin.trim().toUpperCase();
|
||||
const asin = getNorm(ad.asin);
|
||||
const meta = asinMetadata.get(asin);
|
||||
const avgWeeklySales = velocityMap?.get(asin) || 0;
|
||||
|
||||
@@ -1299,10 +1316,12 @@ export const pivotSalesData = (data: any[], dimensions: string[] = ['title', 'cu
|
||||
data.forEach(record => {
|
||||
// Group by Dynamic Dimensions
|
||||
// Use a fallback for 'customer' dimension as some records use 'marketplace'
|
||||
const keyParts = dimensions.map(dim => {
|
||||
if (dim === 'customer') return String(record.customer || record.marketplace || '');
|
||||
return String(record[dim] || '');
|
||||
});
|
||||
const keyParts = new Array(dimensions.length);
|
||||
for (let i = 0; i < dimensions.length; i++) {
|
||||
const dim = dimensions[i];
|
||||
if (dim === 'customer') keyParts[i] = String(record.customer || record.marketplace || '');
|
||||
else keyParts[i] = String(record[dim] || '');
|
||||
}
|
||||
const key = keyParts.join('||');
|
||||
|
||||
if (!map.has(key)) {
|
||||
|
||||
Reference in New Issue
Block a user