use crate::model::user::User; use chrono::Datelike; use serde::Serialize; use sqlx::{FromRow, Row, SqlitePool}; #[derive(FromRow, Serialize, Clone)] pub struct Stat { name: String, rowed_km: i32, } impl Stat { pub async fn boats(db: &SqlitePool, year: Option) -> Vec { let year = match year { Some(year) => year, None => chrono::Utc::now().year(), }; //TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server) sqlx::query(&format!( " SELECT (SELECT name FROM boat WHERE id=logbook.boat_id) as name, CAST(SUM(distance_in_km) AS INTEGER) AS rowed_km FROM logbook WHERE arrival LIKE '{year}-%' GROUP BY boat_id ORDER BY rowed_km DESC; ") ) .fetch_all(db) .await .unwrap() .into_iter() .map(|row| Stat { name: row.get("name"), rowed_km: row.get("rowed_km"), }) .collect() } pub async fn guest(db: &SqlitePool, year: Option) -> Stat { let year = match year { Some(year) => year, None => chrono::Utc::now().year(), }; //TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server) let rowed_km = sqlx::query(&format!( " SELECT SUM((b.amount_seats - COALESCE(m.member_count, 0)) * l.distance_in_km) as total_guest_km FROM logbook l JOIN boat b ON l.boat_id = b.id LEFT JOIN ( SELECT logbook_id, COUNT(*) as member_count FROM rower GROUP BY logbook_id ) m ON l.id = m.logbook_id WHERE l.distance_in_km IS NOT NULL AND l.arrival LIKE '{year}-%' AND b.name != 'Externes Boot'; " )) .fetch_one(db) .await .unwrap() .get::(0) as i32; let rowed_km_guests = sqlx::query(&format!( " SELECT CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km FROM user u INNER JOIN rower r ON u.id = r.rower_id INNER JOIN logbook l ON r.logbook_id = l.id INNER JOIN user_role ur ON u.id = ur.user_id INNER JOIN role ro ON ur.role_id = ro.id WHERE ro.name = 'scheckbuch' AND l.distance_in_km IS NOT NULL AND l.arrival LIKE '{year}-%'; " )) .fetch_one(db) .await .unwrap() .get::(0) as i32; Stat { name: "Gäste".into(), rowed_km: rowed_km + rowed_km_guests, } } pub async fn people(db: &SqlitePool, year: Option) -> Vec { let year = match year { Some(year) => year, None => chrono::Utc::now().year(), }; //TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server) sqlx::query(&format!( " SELECT u.name, CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km FROM ( SELECT * FROM user WHERE id NOT IN ( SELECT user_id FROM user_role JOIN role ON user_role.role_id = role.id WHERE role.name = 'scheckbuch' ) ) u INNER JOIN rower r ON u.id = r.rower_id INNER JOIN logbook l ON r.logbook_id = l.id WHERE l.distance_in_km IS NOT NULL AND l.arrival LIKE '{year}-%' GROUP BY u.name ORDER BY rowed_km DESC; " )) .fetch_all(db) .await .unwrap() .into_iter() .map(|row| Stat { name: row.get("name"), rowed_km: row.get("rowed_km"), }) .collect() } } #[derive(Debug, Serialize)] pub struct PersonalStat { date: String, km: i32, } pub async fn get_personal(db: &SqlitePool, user: &User) -> Vec { sqlx::query(&format!( " SELECT departure_date as date, SUM(total_distance) OVER (ORDER BY departure_date) as km FROM ( SELECT date(l.departure) as departure_date, COALESCE(SUM(l.distance_in_km),0) as total_distance FROM logbook l LEFT JOIN rower r ON l.id = r.logbook_id WHERE l.shipmaster = {0} OR r.rower_id = {0} GROUP BY departure_date ) as subquery ORDER BY departure_date; ", user.id )) .fetch_all(db) .await .unwrap() .into_iter() .map(|row| PersonalStat { date: row.get("date"), km: row.get("km"), }) .collect() }