diff --git a/vingo/Cargo.lock b/vingo/Cargo.lock index 47de09f..9248aa8 100644 --- a/vingo/Cargo.lock +++ b/vingo/Cargo.lock @@ -2955,10 +2955,12 @@ version = "1.1.0" dependencies = [ "axum", "chrono", + "dotenvy", "migration", "rand", "reqwest", "sea-orm", + "sea-query", "serde", "tokio", "tower-http", diff --git a/vingo/Cargo.toml b/vingo/Cargo.toml index 585906e..c7e9fd6 100644 --- a/vingo/Cargo.toml +++ b/vingo/Cargo.toml @@ -46,3 +46,5 @@ tracing = "=0.1" tracing-subscriber = "=0.3" migration = { path = "migration" } +dotenvy = "0.15.7" +sea-query = { version = "0.32.0", default-features = false} diff --git a/vingo/migration/src/m20240903_194156_create_scan.rs b/vingo/migration/src/m20240903_194156_create_scan.rs index fd49f10..05411e2 100644 --- a/vingo/migration/src/m20240903_194156_create_scan.rs +++ b/vingo/migration/src/m20240903_194156_create_scan.rs @@ -8,7 +8,8 @@ pub struct Migration; enum Scan { Table, Id, - Time, + #[allow(clippy::enum_variant_names)] //TODO: rename ScanTime -> Time + ScanTime, CardSerial, } @@ -22,7 +23,9 @@ impl MigrationTrait for Migration { .table(Scan::Table) .col(pk_auto(Scan::Id)) .col(text(Scan::CardSerial)) - .col(timestamp_with_time_zone(Scan::Time).default(Expr::current_timestamp())) + .col( + timestamp_with_time_zone(Scan::ScanTime).default(Expr::current_timestamp()), + ) .foreign_key( ForeignKey::create() .from(Scan::Table, Scan::CardSerial) diff --git a/vingo/src/main.rs b/vingo/src/main.rs index 61ae6a7..93a3591 100644 --- a/vingo/src/main.rs +++ b/vingo/src/main.rs @@ -45,6 +45,8 @@ struct RegisterState { #[tokio::main] async fn main() { + let _ = dotenvy::dotenv(); + tracing_subscriber::fmt() .with_max_level(tracing::Level::DEBUG) .init(); diff --git a/vingo/src/routes/scans.rs b/vingo/src/routes/scans.rs index da2af6b..94a98dc 100644 --- a/vingo/src/routes/scans.rs +++ b/vingo/src/routes/scans.rs @@ -6,14 +6,16 @@ use crate::{ }; use axum::{extract::State, Json}; -use chrono::{Local, Duration}; +use chrono::{Duration, Local}; +use migration::Expr; use reqwest::StatusCode; -use serde::{Serialize}; use sea_orm::{ - ActiveModelTrait, ColumnTrait, EntityTrait, JoinType::InnerJoin, QueryFilter, QuerySelect, - RelationTrait, Set, FromQueryResult, entity::prelude::DateTimeWithTimeZone, Statement, DbBackend, - Value + entity::prelude::DateTimeWithTimeZone, + ActiveModelTrait, ColumnTrait, EntityTrait, FromQueryResult, IdenStatic, + JoinType::{self, InnerJoin}, + QueryFilter, QueryOrder, QuerySelect, RelationTrait, Set, }; +use serde::Serialize; use tower_sessions::Session; use super::util::{ @@ -113,19 +115,31 @@ pub struct RecentScanItem { pub async fn recent(state: State) -> ResponseResult>> { let fourteen_days_ago = (Local::now() - Duration::days(14)).naive_local(); - let scans = RecentScanItem::find_by_statement(Statement::from_sql_and_values(DbBackend::Postgres, " - SELECT DISTINCT ON (s.user_id, DATE(s.scan_time)) s.id, s.scan_time - FROM ( - SELECT scan.id, scan.scan_time, \"user\".id as user_id - FROM scan - INNER JOIN card ON card.serial = scan.card_serial - INNER JOIN \"user\" ON \"user\".id = card.user_id - WHERE scan.scan_time > $1 - ) s - ORDER BY s.user_id, DATE(s.scan_time), s.id;", [Value::ChronoDateTime(Some(Box::new(fourteen_days_ago)))])) - .all(&state.db) - .await - .or_log((StatusCode::INTERNAL_SERVER_ERROR, "could not get all recent scans"))?; + let scans = Scan::find() + .select_only() + .expr(Expr::cust(format!( + "DISTINCT ON ({}, DATE({})) scan.{}, scan.{}", //NOTE: this is a pain + card::Column::UserId.as_str(), + scan::Column::ScanTime.as_str(), + scan::Column::Id.as_str(), + scan::Column::ScanTime.as_str(), + ))) + .join(JoinType::InnerJoin, scan::Relation::Card.def()) + .join(JoinType::InnerJoin, card::Relation::User.def()) + .filter(scan::Column::ScanTime.gt(fourteen_days_ago)) + .order_by_asc(card::Column::UserId) + .order_by_asc(Expr::cust(format!( + "DATE({})", + scan::Column::ScanTime.as_str() + ))) + .order_by_asc(scan::Column::Id) + .into_model::() + .all(&state.db) + .await + .or_log(( + StatusCode::INTERNAL_SERVER_ERROR, + "could not get all recent scans", + ))?; Ok(Json(scans)) }