use chrono::NaiveDate; use serde::Serialize; use sqlx::SqlitePool; #[derive(Serialize, Clone)] pub struct PlannedEvent { id: i64, name: String, planned_amount_cox: i64, allow_guests: bool, trip_details_id: i64, planned_starting_time: String, max_people: i64, day: String, notes: Option, } #[derive(Serialize)] pub struct PlannedEventWithUser { #[serde(flatten)] planned_event: PlannedEvent, cox_needed: bool, cox: Vec, rower: Vec, } //TODO: move to appropriate place #[derive(Serialize)] pub struct Registration { pub name: String, pub registered_at: String, } impl PlannedEvent { pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option { sqlx::query_as!( Self, " SELECT planned_event.id, name, planned_amount_cox, allow_guests, trip_details_id, planned_starting_time, max_people, day, notes FROM planned_event INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id WHERE planned_event.id like ? ", id ) .fetch_one(db) .await .ok() } pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec { let day = format!("{day}"); let events = sqlx::query_as!( PlannedEvent, "SELECT planned_event.id, name, planned_amount_cox, allow_guests, trip_details_id, planned_starting_time, max_people, day, notes FROM planned_event INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id WHERE day=?", day ) .fetch_all(db) .await .unwrap(); //TODO: fixme let mut ret = Vec::new(); for event in events { let cox = event.get_all_cox(db).await; ret.push(PlannedEventWithUser { planned_event: event.clone(), cox_needed: event.planned_amount_cox > cox.len() as i64, cox, rower: event.get_all_rower(db).await, }); } ret } async fn get_all_cox(&self, db: &SqlitePool) -> Vec { sqlx::query_as!( Registration, " SELECT (SELECT name FROM user WHERE cox_id = id) as name, (SELECT created_at FROM user WHERE cox_id = id) as registered_at FROM trip WHERE planned_event_id = ? ", self.id ) .fetch_all(db) .await .unwrap() //Okay, as PlannedEvent can only be created with proper DB backing } async fn get_all_rower(&self, db: &SqlitePool) -> 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 planned_event WHERE id = ?) ", self.id ) .fetch_all(db) .await .unwrap() //Okay, as PlannedEvent can only be created with proper DB backing } pub async fn create( db: &SqlitePool, name: String, planned_amount_cox: i32, allow_guests: bool, trip_details_id: i64, ) { sqlx::query!( "INSERT INTO planned_event(name, planned_amount_cox, allow_guests, trip_details_id) VALUES(?, ?, ?, ?)", name, planned_amount_cox, allow_guests, trip_details_id ) .execute(db) .await .unwrap(); //TODO: fixme } pub async fn delete(&self, db: &SqlitePool) { sqlx::query!("DELETE FROM planned_event WHERE id = ?", self.id) .execute(db) .await .unwrap(); //Okay, as PlannedEvent can only be created with proper DB backing } } #[cfg(test)] mod test { use crate::testdb; use super::PlannedEvent; use chrono::NaiveDate; use sqlx::SqlitePool; #[sqlx::test] fn test_get_day() { let pool = testdb!(); let res = PlannedEvent::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await; assert_eq!(res.len(), 1); } #[sqlx::test] fn test_create() { let pool = testdb!(); PlannedEvent::create(&pool, "new-event".into(), 2, false, 1).await; let res = PlannedEvent::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await; assert_eq!(res.len(), 2); } #[sqlx::test] fn test_delete() { let pool = testdb!(); let planned_event = PlannedEvent::find_by_id(&pool, 1).await.unwrap(); planned_event.delete(&pool).await; let res = PlannedEvent::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await; assert_eq!(res.len(), 0); } }