from __future__ import annotations from dataclasses import dataclass from typing import Any from database import ReviewDatabase def require_user_id(value: int) -> int: user_id = int(value) if user_id <= 0: raise ValueError("A positive account owner is required") return user_id @dataclass(frozen=True) class SQLiteAlertRepository: database: ReviewDatabase def save_alert(self, user_id: int, *args: Any, **kwargs: Any) -> int: return self.database.save_alert(require_user_id(user_id), *args, **kwargs) def list_alerts( self, user_id: int, as_of: str, unread_only: bool = False, limit: int = 100, ) -> list[dict[str, Any]]: return self.database.list_alerts( require_user_id(user_id), as_of, unread_only, limit ) def count_unread_alerts(self, user_id: int, as_of: str) -> int: return self.database.count_unread_alerts(require_user_id(user_id), as_of) def mark_alert_read(self, user_id: int, alert_id: int) -> bool: return self.database.mark_alert_read(require_user_id(user_id), alert_id) def mark_all_alerts_read(self, user_id: int, as_of: str) -> int: return self.database.mark_all_alerts_read(require_user_id(user_id), as_of) def delete_alert(self, user_id: int, alert_id: int) -> bool: return self.database.delete_alert(require_user_id(user_id), alert_id) @dataclass(frozen=True) class SQLiteTradeJournalRepository: database: ReviewDatabase def save_trade_entry(self, user_id: int, *args: Any, **kwargs: Any) -> int: return self.database.save_trade_entry(require_user_id(user_id), *args, **kwargs) def list_trade_entries( self, user_id: int, start_date: str = "", end_date: str = "", code: str = "", limit: int = 300, ) -> list[dict[str, Any]]: return self.database.list_trade_entries( require_user_id(user_id), start_date, end_date, code, limit ) def delete_trade_entry(self, user_id: int, trade_id: int) -> bool: return self.database.delete_trade_entry(require_user_id(user_id), trade_id) @dataclass(frozen=True) class SQLiteStrategyTrackingRepository: database: ReviewDatabase def save_strategy_tracks( self, user_id: int, run_id: int, selection_date: str, strategy_name: str, candidates: list[dict[str, Any]], ) -> int: return self.database.save_strategy_tracks( require_user_id(user_id), run_id, selection_date, strategy_name, candidates ) def get_screener_run(self, user_id: int, run_id: int) -> dict[str, Any] | None: owner_id = int(user_id) if owner_id < 0: raise ValueError("Account owner cannot be negative") return self.database.get_screener_run(owner_id, run_id) def delete_strategy_track(self, user_id: int, track_id: int) -> bool: return self.database.delete_strategy_track(require_user_id(user_id), track_id) def list_strategy_tracks( self, user_id: int, limit_batches: int = 12, ) -> list[dict[str, Any]]: return self.database.list_strategy_tracks( require_user_id(user_id), limit_batches ) def load_tracking_bars( self, targets: list[tuple[str, str]], limit: int = 5, ) -> dict[tuple[str, str], list[dict[str, Any]]]: return self.database.load_tracking_bars(targets, limit) @dataclass(frozen=True) class RepositoryBundle: alerts: SQLiteAlertRepository trades: SQLiteTradeJournalRepository strategy_tracking: SQLiteStrategyTrackingRepository def build_repository_bundle(database: ReviewDatabase) -> RepositoryBundle: return RepositoryBundle( alerts=SQLiteAlertRepository(database), trades=SQLiteTradeJournalRepository(database), strategy_tracking=SQLiteStrategyTrackingRepository(database), )