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