Fix financial taxonomy snapshot normalization
This commit is contained in:
98
lib/financials/page-merge.ts
Normal file
98
lib/financials/page-merge.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import type {
|
||||
CompanyFinancialStatementsResponse
|
||||
} from '@/lib/types';
|
||||
|
||||
export function mergeDetailMaps(
|
||||
base: CompanyFinancialStatementsResponse['statementDetails'],
|
||||
next: CompanyFinancialStatementsResponse['statementDetails']
|
||||
) {
|
||||
if (!base) {
|
||||
return next;
|
||||
}
|
||||
|
||||
if (!next) {
|
||||
return base;
|
||||
}
|
||||
|
||||
const merged: NonNullable<CompanyFinancialStatementsResponse['statementDetails']> = structuredClone(base);
|
||||
for (const [surfaceKey, detailRows] of Object.entries(next)) {
|
||||
const existingRows = merged[surfaceKey] ?? [];
|
||||
const rowMap = new Map(existingRows.map((row) => [row.key, row]));
|
||||
|
||||
for (const detailRow of detailRows) {
|
||||
const existing = rowMap.get(detailRow.key);
|
||||
if (!existing) {
|
||||
rowMap.set(detailRow.key, structuredClone(detailRow));
|
||||
continue;
|
||||
}
|
||||
|
||||
existing.values = {
|
||||
...existing.values,
|
||||
...detailRow.values
|
||||
};
|
||||
existing.sourceFactIds = [...new Set([...(existing.sourceFactIds ?? []), ...(detailRow.sourceFactIds ?? [])])];
|
||||
existing.dimensionsSummary = [...new Set([...(existing.dimensionsSummary ?? []), ...(detailRow.dimensionsSummary ?? [])])];
|
||||
}
|
||||
|
||||
merged[surfaceKey] = [...rowMap.values()];
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function mergeFinancialPages(
|
||||
base: CompanyFinancialStatementsResponse | null,
|
||||
next: CompanyFinancialStatementsResponse
|
||||
) {
|
||||
if (!base) {
|
||||
return next;
|
||||
}
|
||||
|
||||
const periods = [...base.periods, ...next.periods]
|
||||
.filter((period, index, list) => list.findIndex((item) => item.id === period.id) === index)
|
||||
.sort((left, right) => Date.parse(left.periodEnd ?? left.filingDate) - Date.parse(right.periodEnd ?? right.filingDate));
|
||||
|
||||
const mergeRows = <T extends { key: string; values: Record<string, number | null> }>(rows: T[]) => {
|
||||
const map = new Map<string, T>();
|
||||
for (const row of rows) {
|
||||
const existing = map.get(row.key);
|
||||
if (!existing) {
|
||||
map.set(row.key, structuredClone(row));
|
||||
continue;
|
||||
}
|
||||
|
||||
existing.values = {
|
||||
...existing.values,
|
||||
...row.values
|
||||
};
|
||||
}
|
||||
|
||||
return [...map.values()];
|
||||
};
|
||||
|
||||
return {
|
||||
...next,
|
||||
periods,
|
||||
statementRows: next.statementRows && base.statementRows
|
||||
? {
|
||||
faithful: mergeRows([...(base.statementRows.faithful ?? []), ...(next.statementRows.faithful ?? [])]),
|
||||
standardized: mergeRows([...(base.statementRows.standardized ?? []), ...(next.statementRows.standardized ?? [])])
|
||||
}
|
||||
: next.statementRows,
|
||||
statementDetails: mergeDetailMaps(base.statementDetails, next.statementDetails),
|
||||
ratioRows: next.ratioRows && base.ratioRows
|
||||
? mergeRows([...(base.ratioRows ?? []), ...(next.ratioRows ?? [])])
|
||||
: next.ratioRows,
|
||||
kpiRows: next.kpiRows && base.kpiRows
|
||||
? mergeRows([...(base.kpiRows ?? []), ...(next.kpiRows ?? [])])
|
||||
: next.kpiRows,
|
||||
trendSeries: next.trendSeries,
|
||||
categories: next.categories,
|
||||
dimensionBreakdown: next.dimensionBreakdown ?? base.dimensionBreakdown
|
||||
};
|
||||
}
|
||||
|
||||
export const __financialPageMergeInternals = {
|
||||
mergeDetailMaps,
|
||||
mergeFinancialPages
|
||||
};
|
||||
Reference in New Issue
Block a user