import { randomUUID } from 'crypto'; import { DatabaseConnection } from '../db/index'; import { QueryBuilder } from '../utils/QueryBuilder'; import { sanitizeString, sanitizeDate } from '../utils/sanitizer'; import type { MarketCall, CreateCallInput, MarketCallRow } from '../types'; export class MarketCallRepository { constructor(private readonly db: DatabaseConnection) {} /** * Get all market calls, newest first. */ list(): (MarketCall & { createdAt: string })[] { const qb = new QueryBuilder('MARKET_CALLS_QUERIES.SELECT_ALL'); const rows = this.db.all(qb); return rows.map(MarketCallRepository.toCall); } /** * Get a single market call by ID. */ get(id: string): (MarketCall & { createdAt: string }) | null { const qb = new QueryBuilder('MARKET_CALLS_QUERIES.SELECT_BY_ID', [id]); const row = this.db.get(qb); return row ? MarketCallRepository.toCall(row) : null; } /** * Create a new market call with snapshot of current prices. */ create({ title, quarter, date, thesis, tickers, snapshot, }: CreateCallInput): MarketCall & { createdAt: string } { // Sanitize inputs const sanitizedTitle = sanitizeString(title, 'title', 255); const sanitizedQuarter = sanitizeString(quarter, 'quarter', 10); const sanitizedThesis = sanitizeString(thesis, 'thesis', 2000); const sanitizedDate = date ? sanitizeDate(date, 'date') : new Date().toISOString().slice(0, 10); const call = { id: randomUUID(), title: sanitizedTitle, quarter: sanitizedQuarter, date: sanitizedDate, thesis: sanitizedThesis, tickers: tickers ?? [], snapshot: snapshot ?? {}, createdAt: new Date().toISOString(), }; const qb = new QueryBuilder('MARKET_CALLS_QUERIES.INSERT', [ call.id, call.title, call.quarter, call.date, call.thesis, JSON.stringify(call.tickers), JSON.stringify(call.snapshot), call.createdAt, ]); this.db.run(qb); return call as MarketCall & { createdAt: string }; } /** * Delete a market call by ID. * Returns true if the call existed and was deleted, false otherwise. */ delete(id: string): boolean { const qb = new QueryBuilder('MARKET_CALLS_QUERIES.DELETE_BY_ID', [id]); const changes = this.db.run(qb); return changes > 0; } /** * Convert database row to domain object. */ private static toCall(row: MarketCallRow): MarketCall & { createdAt: string } { return { id: row.id, title: row.title, quarter: row.quarter, date: row.date, thesis: row.thesis, tickers: JSON.parse(row.tickers), snapshot: JSON.parse(row.snapshot), createdAt: row.created_at, } as MarketCall & { createdAt: string }; } }