This commit is contained in:
Aadi Desai 2023-12-18 16:26:21 +00:00
parent e4a1d23e67
commit e685669c32
Signed by: supleed2
SSH key fingerprint: SHA256:CkbNRs0yVzXEiUp2zd0PSxsfRUMFF9bLlKXtE1xEbKM
2 changed files with 170 additions and 1 deletions

167
src/cal/day18.rs Normal file
View file

@ -0,0 +1,167 @@
use axum::{
extract::{Path, State},
http::StatusCode,
response::IntoResponse,
routing::{get, post},
Json, Router,
};
#[derive(Clone)]
struct Day18State {
pool: sqlx::PgPool,
}
pub(crate) fn router(pool: sqlx::PgPool) -> Router {
Router::new()
.route("/18/reset", post(reset))
.route("/18/orders", post(orders))
.route("/18/regions", post(regions))
.route("/18/regions/total", get(total))
.route("/18/regions/top_list/:count", get(top_list))
.with_state(Day18State { pool })
}
async fn reset(State(state): State<Day18State>) -> Result<StatusCode, StatusCode> {
sqlx::query!("drop table if exists regions")
.execute(&state.pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
sqlx::query!("drop table if exists orders")
.execute(&state.pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
sqlx::query!(
"create table regions (
id INT PRIMARY KEY,
name VARCHAR(50)
)"
)
.execute(&state.pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
sqlx::query!(
"create table orders (
id INT PRIMARY KEY,
region_id INT,
gift_name VARCHAR(50),
quantity INT
)"
)
.execute(&state.pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(StatusCode::OK)
}
#[derive(serde::Deserialize)]
struct Order {
id: i32,
region_id: i32,
gift_name: String,
quantity: i32,
}
async fn orders(
State(state): State<Day18State>,
Json(orders): Json<Vec<Order>>,
) -> Result<StatusCode, (StatusCode, String)> {
for Order {
id,
region_id,
gift_name,
quantity,
} in orders
{
sqlx::query!(
"insert into orders values ($1, $2, $3, $4)",
id,
region_id,
gift_name,
quantity
)
.execute(&state.pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
}
Ok(StatusCode::OK)
}
#[derive(serde::Deserialize)]
struct Region {
id: i32,
name: String,
}
async fn regions(
State(state): State<Day18State>,
Json(regions): Json<Vec<Region>>,
) -> Result<StatusCode, (StatusCode, String)> {
for Region { id, name } in regions {
sqlx::query!("insert into regions values ($1, $2)", id, name)
.execute(&state.pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
}
Ok(StatusCode::OK)
}
#[derive(serde::Serialize)]
struct Total {
region: String,
total: i64,
}
async fn total(State(state): State<Day18State>) -> Result<impl IntoResponse, (StatusCode, String)> {
let totals = sqlx::query_as!(
Total,
"select name as \"region!\", sum(quantity) as \"total!\"
from orders join regions on orders.region_id = regions.id
group by name order by name"
)
.fetch_all(&state.pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(totals))
}
#[derive(serde::Serialize)]
struct TopGifts {
region: String,
top_gifts: Vec<String>,
}
async fn top_list(
Path(limit): Path<i64>,
State(state): State<Day18State>,
) -> Result<Json<Vec<TopGifts>>, (StatusCode, String)> {
let mut top_list = vec![];
let regions = sqlx::query_as!(
Region,
"select id, name as \"name!\" from regions order by name"
)
.fetch_all(&state.pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
for region in regions {
let top_gifts = sqlx::query!(
"select gift_name as \"gift_name!\" from orders where region_id = $1 group by gift_name order by sum(quantity) desc limit $2",
region.id,
limit
)
.fetch_all(&state.pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.into_iter()
.map(|r| r.gift_name)
.collect();
top_list.push(TopGifts {
region: region.name,
top_gifts,
});
}
Ok(Json(top_list))
}

View file

@ -9,6 +9,7 @@ mod day12;
mod day13;
mod day14;
mod day15;
mod day18;
pub(crate) fn router(pool: sqlx::PgPool) -> axum::Router {
axum::Router::new()
@ -20,7 +21,8 @@ pub(crate) fn router(pool: sqlx::PgPool) -> axum::Router {
.nest("/", day08::router())
.nest("/", day11::router())
.nest("/", day12::router())
.nest("/", day13::router(pool))
.nest("/", day13::router(pool.clone()))
.nest("/", day14::router())
.nest("/", day15::router())
.nest("/", day18::router(pool))
}