use chrono::NaiveDate; use serde::Serialize; use sqlx::SqlitePool; use super::planned_event::Registration; #[derive(Serialize, Clone)] pub struct Trip { id: i64, cox_id: i64, cox_name: String, trip_details_id: Option, planned_starting_time: String, max_people: i64, day: String, notes: Option, } #[derive(Serialize)] pub struct TripWithUser { #[serde(flatten)] trip: Trip, rower: Vec, } impl Trip { pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec { let day = format!("{day}"); let trips = sqlx::query_as!( Trip, " SELECT trip.id, cox_id, user.name as cox_name, trip_details_id, planned_starting_time, max_people, day, notes FROM trip INNER JOIN trip_details ON trip.trip_details_id = trip_details.id INNER JOIN user ON trip.cox_id = user.id WHERE day=? ", day ) .fetch_all(db) .await .unwrap(); //TODO: fixme let mut ret = Vec::new(); for trip in trips { ret.push(TripWithUser { trip: trip.clone(), rower: Self::get_all_rower_for_id(db, trip.id).await, }); } ret } async fn get_all_rower_for_id(db: &SqlitePool, trip_id: i64) -> Vec { sqlx::query_as!( Registration, " SELECT (SELECT name FROM user WHERE user_trip.user_id = user.id) as name, (SELECT created_at FROM user WHERE user_trip.user_id = user.id) as registered_at FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM trip WHERE id = ?)", trip_id ) .fetch_all(db) .await .unwrap() //TODO: fixme } /// Cox decides to create own trip. pub async fn new_own(db: &SqlitePool, cox_id: i64, trip_details_id: i64) { sqlx::query!( "INSERT INTO trip (cox_id, trip_details_id) VALUES(?, ?)", cox_id, trip_details_id ) .execute(db) .await .unwrap(); //TODO: fixme } /// Cox decides to help in a planned event. pub async fn new_join( db: &SqlitePool, cox_id: i64, planned_event_id: i64, ) -> Result<(), CoxHelpError> { let is_rower = sqlx::query!( "SELECT count(*) as amount FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM planned_event WHERE id = ?) AND user_id = ?", planned_event_id, cox_id ) .fetch_one(db) .await .unwrap(); if is_rower.amount > 0 { return Err(CoxHelpError::AlreadyRegisteredAsRower); } match sqlx::query!( "INSERT INTO trip (cox_id, planned_event_id) VALUES(?, ?)", cox_id, planned_event_id ) .execute(db) .await { Ok(_) => Ok(()), Err(_) => Err(CoxHelpError::AlreadyRegisteredAsCox), } } /// Cox decides to update own trip. pub async fn update_own( db: &SqlitePool, cox_id: i64, trip_id: i64, max_people: i32, notes: Option, ) -> Result<(), TripUpdateError> { if !Self::is_trip_from_user(db, cox_id, trip_id).await { return Err(TripUpdateError::NotYourTrip); } let trip_details = sqlx::query!( "SELECT trip_details_id as id FROM trip WHERE id = ?", trip_id ) .fetch_one(db) .await .unwrap(); //TODO: fixme let trip_details_id = match trip_details.id { Some(id) => id, None => { return Err(TripUpdateError::TripDoesNotExist); } }; sqlx::query!( "UPDATE trip_details SET max_people = ?, notes = ? WHERE id = ?", max_people, notes, trip_details_id ) .execute(db) .await .unwrap(); //TODO: fixme Ok(()) } pub async fn delete_by_planned_event_id(db: &SqlitePool, user_id: i64, planned_event_id: i64) { let _ = sqlx::query!( "DELETE FROM trip WHERE cox_id = ? AND planned_event_id = ?", user_id, planned_event_id ) .execute(db) .await .is_ok(); } pub(crate) async fn delete( db: &SqlitePool, user_id: i64, trip_id: i64, ) -> Result<(), TripDeleteError> { let registered_rower = Self::get_all_rower_for_id(db, trip_id).await; if registered_rower.is_empty() { return Err(TripDeleteError::SomebodyAlreadyRegistered); } if !Self::is_trip_from_user(db, user_id, trip_id).await { return Err(TripDeleteError::NotYourTrip); } sqlx::query!( "DELETE FROM trip WHERE cox_id = ? AND id = ?", user_id, trip_id ) .execute(db) .await .unwrap(); //TODO: fixme Ok(()) } async fn is_trip_from_user(db: &SqlitePool, user_id: i64, trip_id: i64) -> bool { let trip_cox = sqlx::query!("SELECT cox_id FROM trip WHERE id = ?", trip_id) .fetch_one(db) .await .unwrap(); //TODO: fixme trip_cox.cox_id == user_id } } pub enum CoxHelpError { AlreadyRegisteredAsRower, AlreadyRegisteredAsCox, } pub enum TripDeleteError { SomebodyAlreadyRegistered, NotYourTrip, } pub enum TripUpdateError { NotYourTrip, TripDoesNotExist, }