99 lines
3.0 KiB
TypeScript
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
|
|
};
|