Files
Neon-Desk/lib/financials/page-merge.ts

99 lines
3.0 KiB
TypeScript

import type {
CompanyFinancialStatementsResponse
} from '@/lib/types';
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
};