238 lines
6.0 KiB
Rust
Raw Normal View History

2024-04-06 15:27:35 +02:00
use std::collections::HashMap;
2023-10-01 14:35:04 +02:00
use crate::model::user::User;
2023-11-18 12:21:37 +01:00
use chrono::Datelike;
2023-07-24 20:56:46 +02:00
use serde::Serialize;
2023-07-24 21:17:51 +02:00
use sqlx::{FromRow, Row, SqlitePool};
2023-07-24 20:56:46 +02:00
2024-04-06 18:55:38 +02:00
use super::boat::Boat;
2024-04-06 15:27:35 +02:00
#[derive(Serialize, Clone)]
pub struct BoatStat {
pot_years: Vec<i32>,
boats: Vec<SingleBoatStat>,
}
#[derive(Serialize, Clone)]
pub struct SingleBoatStat {
2023-07-24 20:56:46 +02:00
name: String,
2024-04-06 15:27:35 +02:00
location: String,
years: HashMap<String, i32>,
2023-07-24 20:56:46 +02:00
}
2024-04-06 15:27:35 +02:00
impl BoatStat {
pub async fn get(db: &SqlitePool) -> BoatStat {
let mut years = Vec::new();
let mut boat_stats_map: HashMap<String, SingleBoatStat> = HashMap::new();
let rows = sqlx::query(
2023-10-31 16:07:15 +01:00
"
2024-04-06 19:56:06 +02:00
SELECT
boat.id,
location.name AS location,
2024-04-06 21:17:23 +02:00
CAST(strftime('%Y', COALESCE(arrival, 'now')) AS INTEGER) AS year,
2024-04-06 19:56:06 +02:00
CAST(SUM(COALESCE(distance_in_km, 0)) AS INTEGER) AS rowed_km
FROM
boat
LEFT JOIN
logbook ON boat.id = logbook.boat_id AND logbook.arrival IS NOT NULL
LEFT JOIN
location ON boat.location_id = location.id
WHERE
boat.name != 'Externes Boot'
GROUP BY
boat.id, year
ORDER BY
boat.name, year DESC;
2024-04-06 15:27:35 +02:00
",
2023-10-31 16:07:15 +01:00
)
.fetch_all(db)
.await
2024-04-06 15:27:35 +02:00
.unwrap();
for row in rows {
2024-04-06 18:55:38 +02:00
let id: i32 = row.get("id");
let boat = Boat::find_by_id(db, id).await.unwrap();
let owner = if let Some(owner) = boat.owner(db).await {
owner.name
} else {
String::from("Verein")
};
let name = format!("{} ({})", boat.name, owner);
2024-04-06 15:27:35 +02:00
let location: String = row.get("location");
let year: i32 = row.get("year");
if year == 0 {
continue; // Boat still on water
}
2024-04-06 15:27:35 +02:00
if !years.contains(&year) {
years.push(year);
}
let year: String = format!("{year}");
let rowed_km: i32 = row.get("rowed_km");
let boat_stat = boat_stats_map
.entry(name.clone())
.or_insert(SingleBoatStat {
name,
location,
years: HashMap::new(),
});
boat_stat.years.insert(year, rowed_km);
}
BoatStat {
pot_years: years,
boats: boat_stats_map.into_values().collect(),
}
2023-10-31 16:07:15 +01:00
}
2024-04-06 15:27:35 +02:00
}
2023-10-31 16:07:15 +01:00
2024-04-06 15:27:35 +02:00
#[derive(FromRow, Serialize, Clone)]
pub struct Stat {
name: String,
rowed_km: i32,
}
impl Stat {
2023-12-23 15:26:49 +01:00
pub async fn guest(db: &SqlitePool, year: Option<i32>) -> Stat {
let year = match year {
Some(year) => year,
None => chrono::Local::now().year(),
2023-12-23 15:26:49 +01:00
};
//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()
2024-01-05 20:08:13 +01:00
.get::<i64, usize>(0) as i32;
let rowed_km_guests = sqlx::query(&format!(
"
SELECT CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km
2024-01-05 20:08:13 +01:00
FROM user u
INNER JOIN rower r ON u.id = r.rower_id
INNER JOIN logbook l ON r.logbook_id = l.id
WHERE u.id NOT IN (
SELECT ur.user_id
FROM user_role ur
INNER JOIN role ro ON ur.role_id = ro.id
WHERE ro.name = 'Donau Linz'
)
AND l.distance_in_km IS NOT NULL
AND l.arrival LIKE '{year}-%'
AND u.name != 'Externe Steuerperson';
2024-01-05 20:08:13 +01:00
"
))
.fetch_one(db)
.await
.unwrap()
.get::<i64, usize>(0) as i32;
2023-12-23 15:26:49 +01:00
Stat {
name: "Gäste".into(),
2024-01-05 20:08:13 +01:00
rowed_km: rowed_km + rowed_km_guests,
2023-12-23 15:26:49 +01:00
}
}
2024-03-20 13:34:21 +01:00
pub async fn sum_people(db: &SqlitePool, year: Option<i32>) -> i32 {
let stats = Self::people(db, year).await;
let mut sum = 0;
for stat in stats {
sum += stat.rowed_km;
}
sum
}
2023-11-18 12:21:37 +01:00
pub async fn people(db: &SqlitePool, year: Option<i32>) -> Vec<Stat> {
let year = match year {
Some(year) => year,
None => chrono::Local::now().year(),
2023-11-18 12:21:37 +01:00
};
2023-07-24 21:17:51 +02:00
//TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server)
2023-11-18 12:21:37 +01:00
sqlx::query(&format!(
2023-08-05 15:58:17 +02:00
"
2023-10-30 15:31:12 +01:00
SELECT u.name, CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km
2024-01-05 20:37:40 +01:00
FROM (
SELECT * FROM user
WHERE id IN (
2024-01-05 20:37:40 +01:00
SELECT user_id FROM user_role
JOIN role ON user_role.role_id = role.id
WHERE role.name = 'Donau Linz'
2024-01-05 20:37:40 +01:00
)
) u
2023-10-30 15:31:12 +01:00
INNER JOIN rower r ON u.id = r.rower_id
INNER JOIN logbook l ON r.logbook_id = l.id
2024-01-05 22:23:36 +01:00
WHERE l.distance_in_km IS NOT NULL AND l.arrival LIKE '{year}-%' AND u.name != 'Externe Steuerperson'
2023-08-05 15:58:17 +02:00
GROUP BY u.name
ORDER BY rowed_km DESC, u.name;
2023-11-27 12:49:36 +01:00
"
2023-11-18 12:21:37 +01:00
))
2023-07-24 20:56:46 +02:00
.fetch_all(db)
.await
.unwrap()
.into_iter()
.map(|row| Stat {
name: row.get("name"),
rowed_km: row.get("rowed_km"),
2023-07-24 20:56:46 +02:00
})
.collect()
}
}
2023-10-01 14:35:04 +02:00
#[derive(Debug, Serialize)]
pub struct PersonalStat {
date: String,
km: i32,
}
pub async fn get_personal(db: &SqlitePool, user: &User) -> Vec<PersonalStat> {
2023-10-01 18:14:05 +02:00
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()
2023-10-01 14:35:04 +02:00
}