use sqlx::PgPool; use uuid::Uuid; use crate::model::{Station, StationSignal}; pub async fn list_stations( pool: &PgPool, line_code: Option<&str>, ) -> Result, sqlx::Error> { match line_code { Some(line) => { sqlx::query_as::<_, Station>( r#"SELECT * FROM station WHERE line_code = $1 ORDER BY code"#, ) .bind(line) .fetch_all(pool) .await } None => { sqlx::query_as::<_, Station>(r#"SELECT * FROM station ORDER BY code"#) .fetch_all(pool) .await } } } pub async fn get_station_by_id( pool: &PgPool, station_id: Uuid, ) -> Result, sqlx::Error> { sqlx::query_as::<_, Station>(r#"SELECT * FROM station WHERE id = $1"#) .bind(station_id) .fetch_optional(pool) .await } pub async fn get_station_by_code( pool: &PgPool, code: &str, ) -> Result, sqlx::Error> { sqlx::query_as::<_, Station>(r#"SELECT * FROM station WHERE code = $1"#) .bind(code) .fetch_optional(pool) .await } pub struct CreateStationParams<'a> { pub code: &'a str, pub name: &'a str, pub line_code: Option<&'a str>, pub segment_code: Option<&'a str>, pub station_type: &'a str, pub enabled: bool, pub description: Option<&'a str>, } pub async fn create_station( pool: &PgPool, params: CreateStationParams<'_>, ) -> Result { let station_id = Uuid::new_v4(); sqlx::query( r#" INSERT INTO station ( id, code, name, line_code, segment_code, station_type, enabled, description ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) "#, ) .bind(station_id) .bind(params.code) .bind(params.name) .bind(params.line_code) .bind(params.segment_code) .bind(params.station_type) .bind(params.enabled) .bind(params.description) .execute(pool) .await?; Ok(station_id) } pub struct UpdateStationParams<'a> { pub code: Option<&'a str>, pub name: Option<&'a str>, pub line_code: Option<&'a str>, pub segment_code: Option<&'a str>, pub station_type: Option<&'a str>, pub enabled: Option, pub description: Option<&'a str>, } pub async fn update_station( pool: &PgPool, station_id: Uuid, params: UpdateStationParams<'_>, ) -> Result { let result = sqlx::query( r#" UPDATE station SET code = COALESCE($2, code), name = COALESCE($3, name), line_code = COALESCE($4, line_code), segment_code = COALESCE($5, segment_code), station_type = COALESCE($6, station_type), enabled = COALESCE($7, enabled), description = COALESCE($8, description), updated_at = NOW() WHERE id = $1 "#, ) .bind(station_id) .bind(params.code) .bind(params.name) .bind(params.line_code) .bind(params.segment_code) .bind(params.station_type) .bind(params.enabled) .bind(params.description) .execute(pool) .await?; Ok(result.rows_affected() > 0) } pub async fn delete_station(pool: &PgPool, station_id: Uuid) -> Result { let result = sqlx::query(r#"DELETE FROM station WHERE id = $1"#) .bind(station_id) .execute(pool) .await?; Ok(result.rows_affected() > 0) } pub async fn list_station_signals( pool: &PgPool, station_id: Uuid, ) -> Result, sqlx::Error> { sqlx::query_as::<_, StationSignal>( r#"SELECT * FROM station_signal WHERE station_id = $1 ORDER BY signal_role"#, ) .bind(station_id) .fetch_all(pool) .await } pub struct UpsertStationSignalParams { pub signal_role: String, pub point_id: Option, pub derived_from_role: Option, pub invert_value: bool, } pub async fn upsert_station_signal( pool: &PgPool, station_id: Uuid, params: UpsertStationSignalParams, ) -> Result { sqlx::query_as::<_, StationSignal>( r#" INSERT INTO station_signal ( station_id, signal_role, point_id, derived_from_role, invert_value ) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (station_id, signal_role) DO UPDATE SET point_id = EXCLUDED.point_id, derived_from_role = EXCLUDED.derived_from_role, invert_value = EXCLUDED.invert_value, updated_at = NOW() RETURNING * "#, ) .bind(station_id) .bind(¶ms.signal_role) .bind(params.point_id) .bind(¶ms.derived_from_role) .bind(params.invert_value) .fetch_one(pool) .await } pub async fn delete_station_signal( pool: &PgPool, station_id: Uuid, signal_role: &str, ) -> Result { let result = sqlx::query(r#"DELETE FROM station_signal WHERE station_id = $1 AND signal_role = $2"#) .bind(station_id) .bind(signal_role) .execute(pool) .await?; Ok(result.rows_affected() > 0) }