use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SymbolScore {
pub symbol_id: i64,
pub snapshot_id: i64,
pub stable_id: String,
pub score: f64,
pub rank: Option<i64>,
pub feature_loc: i64,
pub feature_fan_in: i64,
pub feature_fan_out: i64,
pub feature_complexity: i64,
pub feature_cfg_block_count: i64,
pub feature_cfg_edge_count: i64,
pub feature_conditional_density: f64,
pub feature_lifetime: i64,
pub feature_churn_count: i64,
pub scorer_version: String,
pub scored_at: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScorerFeature {
pub name: String,
pub weight: f64,
pub enabled: bool,
pub description: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScorerRun {
pub id: i64,
pub scorer_version: String,
pub started_at: i64,
pub completed_at: Option<i64>,
pub symbols_scored: i64,
pub feature_count: i64,
pub metadata: Option<String>,
}
pub fn ensure_schema(conn: &rusqlite::Connection) -> anyhow::Result<()> {
conn.execute(
"CREATE TABLE IF NOT EXISTS symbol_scores (
symbol_id INTEGER PRIMARY KEY,
snapshot_id INTEGER NOT NULL,
stable_id TEXT NOT NULL,
score REAL NOT NULL,
rank INTEGER,
feature_loc INTEGER NOT NULL DEFAULT 0,
feature_fan_in INTEGER NOT NULL DEFAULT 0,
feature_fan_out INTEGER NOT NULL DEFAULT 0,
feature_complexity INTEGER NOT NULL DEFAULT 0,
feature_cfg_block_count INTEGER NOT NULL DEFAULT 0,
feature_cfg_edge_count INTEGER NOT NULL DEFAULT 0,
feature_conditional_density REAL NOT NULL DEFAULT 0.0,
feature_lifetime INTEGER NOT NULL DEFAULT 0,
feature_churn_count INTEGER NOT NULL DEFAULT 0,
scorer_version TEXT NOT NULL,
scored_at INTEGER NOT NULL,
FOREIGN KEY (symbol_id) REFERENCES graph_entities(id) ON DELETE CASCADE,
FOREIGN KEY (snapshot_id) REFERENCES repo_snapshots(id) ON DELETE CASCADE
)",
[],
)
.map_err(|e| anyhow::anyhow!("create symbol_scores table: {}", e))?;
conn.execute(
"CREATE INDEX IF NOT EXISTS idx_symbol_scores_score ON symbol_scores(score DESC)",
[],
)
.map_err(|e| anyhow::anyhow!("create score index: {}", e))?;
conn.execute(
"CREATE INDEX IF NOT EXISTS idx_symbol_scores_stable ON symbol_scores(stable_id)",
[],
)
.map_err(|e| anyhow::anyhow!("create stable_id index: {}", e))?;
conn.execute(
"CREATE TABLE IF NOT EXISTS scorer_features (
name TEXT PRIMARY KEY,
weight REAL NOT NULL,
enabled INTEGER NOT NULL,
description TEXT
)",
[],
)
.map_err(|e| anyhow::anyhow!("create scorer_features table: {}", e))?;
conn.execute(
"CREATE TABLE IF NOT EXISTS scorer_runs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
scorer_version TEXT NOT NULL,
started_at INTEGER NOT NULL,
completed_at INTEGER,
symbols_scored INTEGER NOT NULL,
feature_count INTEGER NOT NULL,
metadata TEXT
)",
[],
)
.map_err(|e| anyhow::anyhow!("create scorer_runs table: {}", e))?;
Ok(())
}