OpportunityRadar / db /database.py
3v324v23's picture
fix(db): resolve SqliteError at startup by improving path detection and initialization robustness
24fbf8d
Raw
History Blame Contribute Delete
3.47 kB
"""SQLite database connection and table initialization for OpportunityRadar."""
import sqlite3
import os
from pathlib import Path
from loguru import logger
DB_PATH = Path(os.getenv("DATABASE_PATH", str(Path(__file__).resolve().parent.parent / "opportunityradar.db")))
def get_connection():
"""Create and return a SQLite connection with row factory enabled.
Returns:
sqlite3.Connection: A connection to the local SQLite database.
"""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
return conn
def init_db():
"""Create the sources, snapshots, and student_profiles tables if they do not already exist.
This is safe to call multiple times — it uses IF NOT EXISTS and checks column existence.
"""
# Ensure parent directory exists (critical if a custom DATABASE_PATH is used in a volume)
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
logger.info("Initializing database at {}", DB_PATH)
conn = get_connection()
cursor = conn.cursor()
# --- 1. Create Tables (Base Schema) ---
# Sources table
cursor.execute("""
CREATE TABLE IF NOT EXISTS sources (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
url TEXT NOT NULL UNIQUE,
css_selector TEXT NOT NULL,
is_js_rendered BOOLEAN DEFAULT 0,
active BOOLEAN DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
""")
# Snapshots table
cursor.execute("""
CREATE TABLE IF NOT EXISTS snapshots (
id INTEGER PRIMARY KEY AUTOINCREMENT,
source_id INTEGER NOT NULL,
content_hash TEXT NOT NULL,
raw_content TEXT,
checked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
changed BOOLEAN DEFAULT 0,
FOREIGN KEY (source_id) REFERENCES sources(id)
);
""")
# Student Profiles table
cursor.execute("""
CREATE TABLE IF NOT EXISTS student_profiles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE NOT NULL,
name TEXT,
branch TEXT NOT NULL,
year INTEGER NOT NULL,
college TEXT,
update_count INTEGER DEFAULT 0,
verified BOOLEAN DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
""")
# --- 2. Migrations (Updates to Existing Tables) ---
# Sources: Add category and tags
cursor = conn.execute("PRAGMA table_info(sources)")
columns = [row[1] for row in cursor.fetchall()]
if "category" not in columns:
conn.execute("ALTER TABLE sources ADD COLUMN category TEXT DEFAULT 'general'")
logger.info("Added category column to sources table")
if "tags" not in columns:
conn.execute("ALTER TABLE sources ADD COLUMN tags TEXT DEFAULT '[\"all\"]'")
logger.info("Added tags column to sources table")
# Student Profiles: Add update_count (for users who already had the table from V2)
cursor = conn.execute("PRAGMA table_info(student_profiles)")
columns = [row[1] for row in cursor.fetchall()]
if "update_count" not in columns:
conn.execute("ALTER TABLE student_profiles ADD COLUMN update_count INTEGER DEFAULT 0")
logger.info("Added update_count column to student_profiles table")
conn.commit()
conn.close()
logger.info("Database initialized at {}", DB_PATH)