Wire up the full data pipeline for the Rust TUI rewrite: - SQL schema creation for all 9 tables with correct types, FKs, and constraints - 20 async query functions (teams, players, cards, lineups, sync status, cache) - Config loading via figment integrated into main.rs startup flow - App struct now holds SqlitePool and Settings for screen access - Roster aggregate query and Lineup JSON helper methods - Added csv, sha2, regex crates for upcoming phases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
289 lines
8.2 KiB
Rust
289 lines
8.2 KiB
Rust
use chrono::NaiveDateTime;
|
|
use serde::{Deserialize, Serialize};
|
|
use sqlx::FromRow;
|
|
|
|
// =============================================================================
|
|
// Core Entities (synced from league API)
|
|
// =============================================================================
|
|
|
|
#[derive(Debug, FromRow, Serialize, Deserialize)]
|
|
pub struct Team {
|
|
pub id: i64,
|
|
pub abbrev: String,
|
|
pub short_name: String,
|
|
pub long_name: String,
|
|
pub season: i64,
|
|
pub manager1_name: Option<String>,
|
|
pub manager2_name: Option<String>,
|
|
pub gm_discord_id: Option<String>,
|
|
pub gm2_discord_id: Option<String>,
|
|
pub division_id: Option<i64>,
|
|
pub division_name: Option<String>,
|
|
pub league_abbrev: Option<String>,
|
|
pub thumbnail: Option<String>,
|
|
pub color: Option<String>,
|
|
pub dice_color: Option<String>,
|
|
pub stadium: Option<String>,
|
|
pub salary_cap: Option<f64>,
|
|
pub synced_at: Option<NaiveDateTime>,
|
|
}
|
|
|
|
#[derive(Debug, FromRow, Serialize, Deserialize)]
|
|
pub struct Player {
|
|
pub id: i64,
|
|
pub name: String,
|
|
pub season: i64,
|
|
pub team_id: Option<i64>,
|
|
pub swar: Option<f64>,
|
|
pub card_image: Option<String>,
|
|
pub card_image_alt: Option<String>,
|
|
pub headshot: Option<String>,
|
|
pub vanity_card: Option<String>,
|
|
pub pos_1: Option<String>,
|
|
pub pos_2: Option<String>,
|
|
pub pos_3: Option<String>,
|
|
pub pos_4: Option<String>,
|
|
pub pos_5: Option<String>,
|
|
pub pos_6: Option<String>,
|
|
pub pos_7: Option<String>,
|
|
pub pos_8: Option<String>,
|
|
pub hand: Option<String>,
|
|
pub injury_rating: Option<String>,
|
|
pub il_return: Option<String>,
|
|
pub demotion_week: Option<i64>,
|
|
pub strat_code: Option<String>,
|
|
pub bbref_id: Option<String>,
|
|
pub sbaplayer_id: Option<i64>,
|
|
pub last_game: Option<String>,
|
|
pub last_game2: Option<String>,
|
|
pub synced_at: Option<NaiveDateTime>,
|
|
}
|
|
|
|
impl Player {
|
|
pub fn positions(&self) -> Vec<&str> {
|
|
[
|
|
self.pos_1.as_deref(),
|
|
self.pos_2.as_deref(),
|
|
self.pos_3.as_deref(),
|
|
self.pos_4.as_deref(),
|
|
self.pos_5.as_deref(),
|
|
self.pos_6.as_deref(),
|
|
self.pos_7.as_deref(),
|
|
self.pos_8.as_deref(),
|
|
]
|
|
.into_iter()
|
|
.flatten()
|
|
.collect()
|
|
}
|
|
|
|
pub fn is_pitcher(&self) -> bool {
|
|
self.positions()
|
|
.iter()
|
|
.any(|p| matches!(*p, "SP" | "RP" | "CP"))
|
|
}
|
|
|
|
pub fn is_batter(&self) -> bool {
|
|
self.positions()
|
|
.iter()
|
|
.any(|p| matches!(*p, "C" | "1B" | "2B" | "3B" | "SS" | "LF" | "CF" | "RF" | "DH"))
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Card Data (imported from Strat-o-Matic)
|
|
// =============================================================================
|
|
|
|
#[derive(Debug, FromRow, Serialize, Deserialize)]
|
|
pub struct BatterCard {
|
|
pub id: i64,
|
|
pub player_id: i64,
|
|
// vs Left-Handed Pitchers
|
|
pub so_vlhp: f64,
|
|
pub bb_vlhp: f64,
|
|
pub hit_vlhp: f64,
|
|
pub ob_vlhp: f64,
|
|
pub tb_vlhp: f64,
|
|
pub hr_vlhp: f64,
|
|
pub dp_vlhp: f64,
|
|
// vs Right-Handed Pitchers
|
|
pub so_vrhp: f64,
|
|
pub bb_vrhp: f64,
|
|
pub hit_vrhp: f64,
|
|
pub ob_vrhp: f64,
|
|
pub tb_vrhp: f64,
|
|
pub hr_vrhp: f64,
|
|
pub dp_vrhp: f64,
|
|
// Ballpark modifiers
|
|
pub bphr_vlhp: f64,
|
|
pub bphr_vrhp: f64,
|
|
pub bp1b_vlhp: f64,
|
|
pub bp1b_vrhp: f64,
|
|
// Running game
|
|
pub stealing: Option<String>,
|
|
pub steal_rating: Option<String>,
|
|
pub speed: Option<i64>,
|
|
// Batting extras
|
|
pub bunt: Option<String>,
|
|
pub hit_run: Option<String>,
|
|
// Fielding
|
|
pub fielding: Option<String>,
|
|
// Catcher-specific
|
|
pub catcher_arm: Option<i64>,
|
|
pub catcher_pb: Option<i64>,
|
|
pub catcher_t: Option<i64>,
|
|
// Computed ratings
|
|
pub rating_vl: Option<f64>,
|
|
pub rating_vr: Option<f64>,
|
|
pub rating_overall: Option<f64>,
|
|
// Import metadata
|
|
pub imported_at: Option<NaiveDateTime>,
|
|
pub source: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, FromRow, Serialize, Deserialize)]
|
|
pub struct PitcherCard {
|
|
pub id: i64,
|
|
pub player_id: i64,
|
|
// vs Left-Handed Batters
|
|
pub so_vlhb: f64,
|
|
pub bb_vlhb: f64,
|
|
pub hit_vlhb: f64,
|
|
pub ob_vlhb: f64,
|
|
pub tb_vlhb: f64,
|
|
pub hr_vlhb: f64,
|
|
pub dp_vlhb: f64,
|
|
pub bphr_vlhb: f64,
|
|
pub bp1b_vlhb: f64,
|
|
// vs Right-Handed Batters
|
|
pub so_vrhb: f64,
|
|
pub bb_vrhb: f64,
|
|
pub hit_vrhb: f64,
|
|
pub ob_vrhb: f64,
|
|
pub tb_vrhb: f64,
|
|
pub hr_vrhb: f64,
|
|
pub dp_vrhb: f64,
|
|
pub bphr_vrhb: f64,
|
|
pub bp1b_vrhb: f64,
|
|
// Pitcher attributes
|
|
pub hold_rating: Option<i64>,
|
|
pub endurance_start: Option<i64>,
|
|
pub endurance_relief: Option<i64>,
|
|
pub endurance_close: Option<i64>,
|
|
pub fielding_range: Option<i64>,
|
|
pub fielding_error: Option<i64>,
|
|
pub wild_pitch: Option<i64>,
|
|
pub balk: Option<i64>,
|
|
pub batting_rating: Option<String>,
|
|
// Computed ratings
|
|
pub rating_vlhb: Option<f64>,
|
|
pub rating_vrhb: Option<f64>,
|
|
pub rating_overall: Option<f64>,
|
|
// Import metadata
|
|
pub imported_at: Option<NaiveDateTime>,
|
|
pub source: Option<String>,
|
|
}
|
|
|
|
// =============================================================================
|
|
// Transactions (synced from league API)
|
|
// =============================================================================
|
|
|
|
#[derive(Debug, FromRow, Serialize, Deserialize)]
|
|
pub struct Transaction {
|
|
pub id: i64,
|
|
pub season: i64,
|
|
pub week: i64,
|
|
pub move_id: String,
|
|
pub player_id: i64,
|
|
pub from_team_id: i64,
|
|
pub to_team_id: i64,
|
|
pub cancelled: bool,
|
|
pub frozen: bool,
|
|
pub synced_at: Option<NaiveDateTime>,
|
|
}
|
|
|
|
// =============================================================================
|
|
// Roster (aggregate view, not a DB table)
|
|
// =============================================================================
|
|
|
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
|
pub struct Roster {
|
|
pub majors: Vec<Player>,
|
|
pub minors: Vec<Player>,
|
|
pub il: Vec<Player>,
|
|
}
|
|
|
|
// =============================================================================
|
|
// User Data (local only)
|
|
// =============================================================================
|
|
|
|
#[derive(Debug, FromRow, Serialize, Deserialize)]
|
|
pub struct Lineup {
|
|
pub id: i64,
|
|
pub name: String,
|
|
pub description: Option<String>,
|
|
pub lineup_type: String,
|
|
pub batting_order: Option<String>, // JSON string
|
|
pub positions: Option<String>, // JSON string
|
|
pub starting_pitcher_id: Option<i64>,
|
|
pub created_at: Option<NaiveDateTime>,
|
|
pub updated_at: Option<NaiveDateTime>,
|
|
}
|
|
|
|
impl Lineup {
|
|
pub fn batting_order_vec(&self) -> Vec<i64> {
|
|
self.batting_order
|
|
.as_deref()
|
|
.and_then(|s| serde_json::from_str(s).ok())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
pub fn positions_map(&self) -> std::collections::HashMap<String, i64> {
|
|
self.positions
|
|
.as_deref()
|
|
.and_then(|s| serde_json::from_str(s).ok())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
pub fn set_batting_order(&mut self, order: &[i64]) {
|
|
self.batting_order = serde_json::to_string(order).ok();
|
|
}
|
|
|
|
pub fn set_positions(&mut self, positions: &std::collections::HashMap<String, i64>) {
|
|
self.positions = serde_json::to_string(positions).ok();
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, FromRow, Serialize, Deserialize)]
|
|
pub struct MatchupCache {
|
|
pub id: i64,
|
|
pub batter_id: i64,
|
|
pub pitcher_id: i64,
|
|
pub rating: f64,
|
|
pub tier: Option<String>,
|
|
pub details: Option<String>, // JSON string
|
|
pub computed_at: Option<NaiveDateTime>,
|
|
pub weights_hash: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, FromRow, Serialize, Deserialize)]
|
|
pub struct StandardizedScoreCache {
|
|
pub id: i64,
|
|
pub batter_card_id: Option<i64>,
|
|
pub pitcher_card_id: Option<i64>,
|
|
pub split: String,
|
|
pub total_score: f64,
|
|
pub stat_scores: String, // JSON string
|
|
pub computed_at: Option<NaiveDateTime>,
|
|
pub weights_hash: Option<String>,
|
|
pub league_stats_hash: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, FromRow, Serialize, Deserialize)]
|
|
pub struct SyncStatus {
|
|
pub id: i64,
|
|
pub entity_type: String,
|
|
pub last_sync: Option<NaiveDateTime>,
|
|
pub last_sync_count: Option<i64>,
|
|
pub last_error: Option<String>,
|
|
}
|