| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- """
- Database Schema and Initialization
- Defines SQLite database schema for storing analysis data.
- Handles database creation and migrations.
- """
- import sqlite3
- import logging
- from pathlib import Path
- from typing import Optional
- logger = logging.getLogger(__name__)
- def get_schema_version() -> int:
- """Get the current schema version."""
- return 1
- def get_database_schema() -> str:
- """
- Get SQL schema for database initialization.
-
- Returns:
- str: SQL schema definition
- """
- return """
- -- Analyses table: stores basic analysis information
- CREATE TABLE IF NOT EXISTS analyses (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- report_id TEXT UNIQUE NOT NULL,
- timestamp DATETIME NOT NULL,
- device_id TEXT NOT NULL,
- overall_grade TEXT,
- grade_description TEXT,
- processing_time REAL,
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP
- );
- -- Analysis inputs table: stores input files information
- CREATE TABLE IF NOT EXISTS analysis_inputs (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- analysis_id INTEGER NOT NULL,
- input_type TEXT NOT NULL,
- original_path TEXT NOT NULL,
- saved_path TEXT NOT NULL,
- file_size INTEGER,
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
- FOREIGN KEY (analysis_id) REFERENCES analyses(id) ON DELETE CASCADE
- );
- -- Analysis results table: stores model predictions and results
- CREATE TABLE IF NOT EXISTS analysis_results (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- analysis_id INTEGER NOT NULL,
- model_type TEXT NOT NULL,
- predicted_class TEXT,
- confidence REAL,
- probabilities TEXT,
- processing_time REAL,
- metadata TEXT,
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
- FOREIGN KEY (analysis_id) REFERENCES analyses(id) ON DELETE CASCADE
- );
- -- Analysis visualizations table: stores visualization image metadata
- CREATE TABLE IF NOT EXISTS analysis_visualizations (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- analysis_id INTEGER NOT NULL,
- visualization_type TEXT NOT NULL,
- file_path TEXT NOT NULL,
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
- FOREIGN KEY (analysis_id) REFERENCES analyses(id) ON DELETE CASCADE
- );
- -- Create indexes for common queries
- CREATE INDEX IF NOT EXISTS idx_analyses_report_id ON analyses(report_id);
- CREATE INDEX IF NOT EXISTS idx_analyses_created_at ON analyses(created_at);
- CREATE INDEX IF NOT EXISTS idx_analysis_inputs_analysis_id ON analysis_inputs(analysis_id);
- CREATE INDEX IF NOT EXISTS idx_analysis_results_analysis_id ON analysis_results(analysis_id);
- CREATE INDEX IF NOT EXISTS idx_analysis_visualizations_analysis_id ON analysis_visualizations(analysis_id);
- """
- def init_database(db_path: Path) -> bool:
- """
- Initialize the database with schema.
-
- Args:
- db_path: Path to the database file
-
- Returns:
- bool: True if initialization successful, False otherwise
- """
- try:
- # Ensure parent directory exists
- db_path.parent.mkdir(parents=True, exist_ok=True)
-
- # Connect to database
- conn = sqlite3.connect(str(db_path))
- cursor = conn.cursor()
-
- # Execute schema
- cursor.executescript(get_database_schema())
-
- # Create metadata table to track schema version
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS schema_version (
- version INTEGER PRIMARY KEY,
- updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
- )
- """)
-
- # Check if version exists
- cursor.execute("SELECT version FROM schema_version LIMIT 1")
- result = cursor.fetchone()
-
- if not result:
- # Insert initial version
- cursor.execute("INSERT INTO schema_version (version) VALUES (?)", (get_schema_version(),))
-
- conn.commit()
- conn.close()
-
- logger.info(f"Database initialized successfully: {db_path}")
- return True
-
- except Exception as e:
- logger.error(f"Error initializing database: {e}")
- return False
- def get_database_connection(db_path: Path) -> Optional[sqlite3.Connection]:
- """
- Get a connection to the database.
-
- Args:
- db_path: Path to the database file
-
- Returns:
- sqlite3.Connection or None if connection failed
- """
- try:
- # Initialize database if doesn't exist
- if not db_path.exists():
- init_database(db_path)
-
- # Enable foreign keys
- conn = sqlite3.connect(str(db_path))
- conn.execute("PRAGMA foreign_keys = ON")
-
- # Use Row factory for easier dict-like access
- conn.row_factory = sqlite3.Row
-
- return conn
-
- except Exception as e:
- logger.error(f"Error connecting to database: {e}")
- return None
- def close_database_connection(conn: sqlite3.Connection) -> None:
- """
- Close a database connection.
-
- Args:
- conn: Connection to close
- """
- try:
- if conn:
- conn.close()
- except Exception as e:
- logger.error(f"Error closing database connection: {e}")
|