feat: SQL Explorer with PostgreSQL schema browser and pre-built queries
The SQL Explorer was querying Trino which has zero tables. Rewrote to use PostgreSQL directly: Backend: - GET /api/analytics/pg-schema: returns all public tables with column names, types, and nullability from information_schema - POST /api/analytics/pg-query: read-only SQL execution against PostgreSQL with SELECT-only enforcement, auto LIMIT, and descriptive error messages for syntax/table/query errors Frontend: - Schema browser shows all PostgreSQL tables with columns and types - Click a table name → generates SELECT * FROM table LIMIT 100 - Pre-built Queries section with 12 seeded queries covering companies, recommendations, trends, market prices, documents, global events, trading decisions, ingestion health, reserve pool, sector exposure - User-saved queries shown separately with delete buttons - Chart builder, Monaco editor, and save functionality preserved Migration 021: seeds 12 pre-built saved queries
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
-- Seed pre-built saved queries for the SQL Explorer
|
||||
INSERT INTO saved_queries (name, description, sql_text) VALUES
|
||||
('Company Overview', 'All tracked companies with sector and status',
|
||||
'SELECT ticker, legal_name, sector, active, created_at FROM companies ORDER BY ticker'),
|
||||
|
||||
('Recent Recommendations', 'Latest buy/sell recommendations with confidence',
|
||||
'SELECT ticker, action, confidence, mode, risk_classification, generated_at FROM recommendations WHERE action IN (''buy'', ''sell'') ORDER BY generated_at DESC LIMIT 50'),
|
||||
|
||||
('High Confidence Buys', 'Buy recommendations with confidence >= 0.75',
|
||||
'SELECT ticker, confidence, mode, thesis, generated_at FROM recommendations WHERE action = ''buy'' AND confidence >= 0.75 ORDER BY confidence DESC LIMIT 50'),
|
||||
|
||||
('Trend Windows Summary', 'Current trend direction and strength by ticker',
|
||||
'SELECT entity_id AS ticker, window, trend_direction, trend_strength, confidence FROM trend_windows ORDER BY trend_strength DESC LIMIT 100'),
|
||||
|
||||
('Market Prices', 'Latest close prices for tracked companies',
|
||||
'SELECT DISTINCT ON (ticker) ticker, (data->>''c'')::float AS close, (data->>''o'')::float AS open, (data->>''h'')::float AS high, (data->>''l'')::float AS low, (data->>''v'')::float AS volume, captured_at FROM market_snapshots WHERE snapshot_type = ''bar'' ORDER BY ticker, captured_at DESC'),
|
||||
|
||||
('Document Counts by Type', 'Count of documents by type and status',
|
||||
'SELECT document_type, status, count(*) FROM documents GROUP BY document_type, status ORDER BY document_type, count(*) DESC'),
|
||||
|
||||
('Global Events', 'Recent macro events with severity',
|
||||
'SELECT severity, LEFT(summary, 100) AS summary, event_types, affected_sectors, created_at FROM global_events ORDER BY created_at DESC LIMIT 30'),
|
||||
|
||||
('Trading Decisions', 'Recent trading engine decisions',
|
||||
'SELECT ticker, decision, skip_reason, computed_position_size, computed_share_quantity, risk_tier_at_decision, created_at FROM trading_decisions ORDER BY created_at DESC LIMIT 50'),
|
||||
|
||||
('Ingestion Health', 'Source ingestion run stats (last 24h)',
|
||||
'SELECT s.source_type, s.source_name, count(*) AS runs, count(*) FILTER (WHERE ir.status = ''completed'') AS completed, count(*) FILTER (WHERE ir.status = ''failed'') AS failed FROM ingestion_runs ir JOIN sources s ON ir.source_id = s.id WHERE ir.started_at > NOW() - INTERVAL ''24 hours'' GROUP BY s.source_type, s.source_name ORDER BY failed DESC, runs DESC'),
|
||||
|
||||
('Reserve Pool Ledger', 'Reserve pool transaction history',
|
||||
'SELECT amount, balance_after, trigger_type, notes, created_at FROM reserve_pool_ledger ORDER BY created_at DESC LIMIT 30'),
|
||||
|
||||
('Sector Exposure', 'Market value by sector from positions',
|
||||
'SELECT c.sector, count(*) AS positions, sum((ms.data->>''c'')::float) AS total_close_price FROM companies c JOIN market_snapshots ms ON c.ticker = ms.ticker WHERE ms.snapshot_type = ''bar'' GROUP BY c.sector ORDER BY total_close_price DESC'),
|
||||
|
||||
('Source Coverage Matrix', 'Active sources per company',
|
||||
'SELECT c.ticker, c.legal_name, count(*) FILTER (WHERE s.source_type = ''market_api'') AS market, count(*) FILTER (WHERE s.source_type = ''news_api'') AS news, count(*) FILTER (WHERE s.source_type = ''filings_api'') AS filings, count(*) AS total FROM companies c LEFT JOIN sources s ON c.id = s.company_id AND s.active = TRUE WHERE c.active = TRUE GROUP BY c.ticker, c.legal_name ORDER BY c.ticker')
|
||||
ON CONFLICT DO NOTHING;
|
||||
Reference in New Issue
Block a user