use log::{info, trace}; use sqlx::migrate::Migrator; use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; use sqlx::{Pool, Sqlite}; use std::str::FromStr; use crate::db::errors::DatabaseError; use crate::db::model_utils::Period; use crate::types::ScheduleUid; mod controllers; pub mod errors; mod model_utils; mod relays; mod schedules; mod tag; pub use controllers::DbController; pub use relays::DbRelay; pub use schedules::{DbPeriods, DbSchedule}; pub use tag::DbTag; static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations" pub async fn run_migrations(pool: &Pool<Sqlite>) { info!("Running migrations"); MIGRATOR.run(pool).await.expect("Failed to run migrations."); } async fn init_schedule( pool: &Pool<Sqlite>, uid: &ScheduleUid, name: &str, periods: DbPeriods, ) -> Result<(), DatabaseError> { trace!("Initializing schedule {:?}", name); match DbSchedule::get_by_uid(&mut pool.acquire().await.unwrap(), uid).await { Ok(_) => Ok(()), Err(err) => match err { DatabaseError::NotFound => { trace!("Schedule {:?} not found, inserting", name); sqlx::query_as!( DbSchedule, "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", uid, name, periods, ) .fetch_optional(pool) .await? .ok_or(DatabaseError::InsertGetError) .map(|_| ()) } _ => Err(err), }, } } pub async fn init(db: &str) -> Pool<Sqlite> { let options = SqliteConnectOptions::from_str(db) .expect("Error parsing database path") .create_if_missing(true); let pool: Pool<Sqlite> = SqlitePoolOptions::new() .acquire_timeout(std::time::Duration::from_secs(1)) .max_connections(5) .connect_with(options) .await .expect("Error connecting to database"); run_migrations(&pool).await; init_schedule(&pool, &ScheduleUid::Off, "Off", DbPeriods(vec![])) .await .expect("Error initializing schedule Off"); init_schedule( &pool, &ScheduleUid::On, "On", DbPeriods(vec![Period::new_on()]), ) .await .expect("Error initializing schedule On"); pool }