feat(financials-v2): add statement snapshot schema and shared types
This commit is contained in:
22
drizzle/0001_glossy_statement_snapshots.sql
Normal file
22
drizzle/0001_glossy_statement_snapshots.sql
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
CREATE TABLE `filing_statement_snapshot` (
|
||||||
|
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
`filing_id` integer NOT NULL,
|
||||||
|
`ticker` text NOT NULL,
|
||||||
|
`filing_date` text NOT NULL,
|
||||||
|
`filing_type` text NOT NULL,
|
||||||
|
`period_end` text,
|
||||||
|
`statement_bundle` text,
|
||||||
|
`standardized_bundle` text,
|
||||||
|
`dimension_bundle` text,
|
||||||
|
`parse_status` text NOT NULL,
|
||||||
|
`parse_error` text,
|
||||||
|
`source` text NOT NULL,
|
||||||
|
`created_at` text NOT NULL,
|
||||||
|
`updated_at` text NOT NULL,
|
||||||
|
FOREIGN KEY (`filing_id`) REFERENCES `filing`(`id`) ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `filing_stmt_filing_uidx` ON `filing_statement_snapshot` (`filing_id`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `filing_stmt_ticker_date_idx` ON `filing_statement_snapshot` (`ticker`,`filing_date`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `filing_stmt_date_idx` ON `filing_statement_snapshot` (`filing_date`);--> statement-breakpoint
|
||||||
|
CREATE INDEX `filing_stmt_status_idx` ON `filing_statement_snapshot` (`parse_status`);
|
||||||
@@ -8,6 +8,13 @@
|
|||||||
"when": 1772137733427,
|
"when": 1772137733427,
|
||||||
"tag": "0000_cold_silver_centurion",
|
"tag": "0000_cold_silver_centurion",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 1,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1772417400000,
|
||||||
|
"tag": "0001_glossy_statement_snapshots",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -40,6 +40,63 @@ type FilingAnalysis = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type FinancialStatementKind = 'income' | 'balance' | 'cash_flow' | 'equity' | 'comprehensive_income';
|
||||||
|
|
||||||
|
type FilingStatementPeriod = {
|
||||||
|
id: string;
|
||||||
|
filingId: number;
|
||||||
|
accessionNumber: string;
|
||||||
|
filingDate: string;
|
||||||
|
periodEnd: string | null;
|
||||||
|
filingType: '10-K' | '10-Q';
|
||||||
|
periodLabel: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type StatementValuesByPeriod = Record<string, number | null>;
|
||||||
|
|
||||||
|
type FilingFaithfulStatementSnapshotRow = {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
concept: string | null;
|
||||||
|
order: number;
|
||||||
|
depth: number;
|
||||||
|
isSubtotal: boolean;
|
||||||
|
values: StatementValuesByPeriod;
|
||||||
|
};
|
||||||
|
|
||||||
|
type StandardizedStatementSnapshotRow = {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
concept: string;
|
||||||
|
category: string;
|
||||||
|
sourceConcepts: string[];
|
||||||
|
values: StatementValuesByPeriod;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DimensionStatementSnapshotRow = {
|
||||||
|
rowKey: string;
|
||||||
|
concept: string | null;
|
||||||
|
periodId: string;
|
||||||
|
axis: string;
|
||||||
|
member: string;
|
||||||
|
value: number | null;
|
||||||
|
unit: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
type FilingStatementBundle = {
|
||||||
|
periods: FilingStatementPeriod[];
|
||||||
|
statements: Record<FinancialStatementKind, FilingFaithfulStatementSnapshotRow[]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type StandardizedStatementBundle = {
|
||||||
|
periods: FilingStatementPeriod[];
|
||||||
|
statements: Record<FinancialStatementKind, StandardizedStatementSnapshotRow[]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DimensionStatementBundle = {
|
||||||
|
statements: Record<FinancialStatementKind, DimensionStatementSnapshotRow[]>;
|
||||||
|
};
|
||||||
|
|
||||||
const authDateColumn = {
|
const authDateColumn = {
|
||||||
mode: 'timestamp_ms'
|
mode: 'timestamp_ms'
|
||||||
} as const;
|
} as const;
|
||||||
@@ -192,6 +249,28 @@ export const filing = sqliteTable('filing', {
|
|||||||
filingDateIndex: index('filing_date_idx').on(table.filing_date)
|
filingDateIndex: index('filing_date_idx').on(table.filing_date)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export const filingStatementSnapshot = sqliteTable('filing_statement_snapshot', {
|
||||||
|
id: integer('id').primaryKey({ autoIncrement: true }),
|
||||||
|
filing_id: integer('filing_id').notNull().references(() => filing.id, { onDelete: 'cascade' }),
|
||||||
|
ticker: text('ticker').notNull(),
|
||||||
|
filing_date: text('filing_date').notNull(),
|
||||||
|
filing_type: text('filing_type').$type<'10-K' | '10-Q'>().notNull(),
|
||||||
|
period_end: text('period_end'),
|
||||||
|
statement_bundle: text('statement_bundle', { mode: 'json' }).$type<FilingStatementBundle | null>(),
|
||||||
|
standardized_bundle: text('standardized_bundle', { mode: 'json' }).$type<StandardizedStatementBundle | null>(),
|
||||||
|
dimension_bundle: text('dimension_bundle', { mode: 'json' }).$type<DimensionStatementBundle | null>(),
|
||||||
|
parse_status: text('parse_status').$type<'ready' | 'partial' | 'failed'>().notNull(),
|
||||||
|
parse_error: text('parse_error'),
|
||||||
|
source: text('source').$type<'sec_filing_summary' | 'xbrl_instance' | 'companyfacts_fallback'>().notNull(),
|
||||||
|
created_at: text('created_at').notNull(),
|
||||||
|
updated_at: text('updated_at').notNull()
|
||||||
|
}, (table) => ({
|
||||||
|
filingStatementFilingUnique: uniqueIndex('filing_stmt_filing_uidx').on(table.filing_id),
|
||||||
|
filingStatementTickerDateIndex: index('filing_stmt_ticker_date_idx').on(table.ticker, table.filing_date),
|
||||||
|
filingStatementDateIndex: index('filing_stmt_date_idx').on(table.filing_date),
|
||||||
|
filingStatementStatusIndex: index('filing_stmt_status_idx').on(table.parse_status)
|
||||||
|
}));
|
||||||
|
|
||||||
export const filingLink = sqliteTable('filing_link', {
|
export const filingLink = sqliteTable('filing_link', {
|
||||||
id: integer('id').primaryKey({ autoIncrement: true }),
|
id: integer('id').primaryKey({ autoIncrement: true }),
|
||||||
filing_id: integer('filing_id').notNull().references(() => filing.id, { onDelete: 'cascade' }),
|
filing_id: integer('filing_id').notNull().references(() => filing.id, { onDelete: 'cascade' }),
|
||||||
@@ -250,6 +329,7 @@ export const appSchema = {
|
|||||||
watchlistItem,
|
watchlistItem,
|
||||||
holding,
|
holding,
|
||||||
filing,
|
filing,
|
||||||
|
filingStatementSnapshot,
|
||||||
filingLink,
|
filingLink,
|
||||||
taskRun,
|
taskRun,
|
||||||
portfolioInsight
|
portfolioInsight
|
||||||
|
|||||||
73
lib/types.ts
73
lib/types.ts
@@ -127,6 +127,79 @@ export type CompanyFinancialPoint = {
|
|||||||
debt: number | null;
|
debt: number | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type FinancialStatementMode = 'standardized' | 'filing_faithful';
|
||||||
|
export type FinancialStatementKind = 'income' | 'balance' | 'cash_flow' | 'equity' | 'comprehensive_income';
|
||||||
|
export type FinancialHistoryWindow = '10y' | 'all';
|
||||||
|
|
||||||
|
export type FinancialStatementPeriod = {
|
||||||
|
id: string;
|
||||||
|
filingId: number;
|
||||||
|
accessionNumber: string;
|
||||||
|
filingDate: string;
|
||||||
|
periodEnd: string | null;
|
||||||
|
filingType: Extract<Filing['filing_type'], '10-K' | '10-Q'>;
|
||||||
|
periodLabel: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type StandardizedStatementRow = {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
concept: string;
|
||||||
|
category: string;
|
||||||
|
sourceConcepts: string[];
|
||||||
|
values: Record<string, number | null>;
|
||||||
|
hasDimensions: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FilingFaithfulStatementRow = {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
concept: string | null;
|
||||||
|
order: number;
|
||||||
|
depth: number;
|
||||||
|
isSubtotal: boolean;
|
||||||
|
values: Record<string, number | null>;
|
||||||
|
hasDimensions: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DimensionBreakdownRow = {
|
||||||
|
rowKey: string;
|
||||||
|
concept: string | null;
|
||||||
|
periodId: string;
|
||||||
|
axis: string;
|
||||||
|
member: string;
|
||||||
|
value: number | null;
|
||||||
|
unit: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CompanyFinancialStatementsResponse = {
|
||||||
|
company: {
|
||||||
|
ticker: string;
|
||||||
|
companyName: string;
|
||||||
|
cik: string | null;
|
||||||
|
};
|
||||||
|
mode: FinancialStatementMode;
|
||||||
|
statement: FinancialStatementKind;
|
||||||
|
window: FinancialHistoryWindow;
|
||||||
|
periods: FinancialStatementPeriod[];
|
||||||
|
rows: StandardizedStatementRow[] | FilingFaithfulStatementRow[];
|
||||||
|
nextCursor: string | null;
|
||||||
|
coverage: {
|
||||||
|
filings: number;
|
||||||
|
rows: number;
|
||||||
|
dimensions: number;
|
||||||
|
};
|
||||||
|
dataSourceStatus: {
|
||||||
|
enabled: boolean;
|
||||||
|
hydratedFilings: number;
|
||||||
|
partialFilings: number;
|
||||||
|
failedFilings: number;
|
||||||
|
pendingFilings: number;
|
||||||
|
queuedSync: boolean;
|
||||||
|
};
|
||||||
|
dimensionBreakdown: Record<string, DimensionBreakdownRow[]> | null;
|
||||||
|
};
|
||||||
|
|
||||||
export type CompanyAiReport = {
|
export type CompanyAiReport = {
|
||||||
accessionNumber: string;
|
accessionNumber: string;
|
||||||
filingDate: string;
|
filingDate: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user