-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
day13.rs
110 lines (102 loc) · 3.05 KB
/
day13.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use axum::{
extract::State,
http::StatusCode,
response::IntoResponse,
routing::{get, post},
Json, Router,
};
#[derive(Clone)]
struct Day13State {
pool: sqlx::PgPool,
}
pub(crate) fn router(pool: sqlx::PgPool) -> Router {
Router::new()
.route("/13/sql", get(sql))
.route("/13/reset", post(reset))
.route("/13/orders", post(orders))
.route("/13/orders/total", get(total))
.route("/13/orders/popular", get(popular))
.with_state(Day13State { pool })
}
async fn sql(State(state): State<Day13State>) -> Result<impl IntoResponse, (StatusCode, String)> {
Ok(sqlx::query!("select 20231213 as \"i32!\"")
.fetch_one(&state.pool)
.await
.map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?
.i32
.to_string())
}
async fn reset(State(state): State<Day13State>) -> Result<StatusCode, StatusCode> {
sqlx::query!("drop table if exists orders")
.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<Day13State>,
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)
}
async fn total(State(state): State<Day13State>) -> Result<impl IntoResponse, (StatusCode, String)> {
let total = sqlx::query!("select sum(quantity) as \"i64!\" from orders")
.fetch_one(&state.pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.i64;
Ok(format!("{{\"total\":{total}}}"))
}
async fn popular(
State(state): State<Day13State>,
) -> Result<impl IntoResponse, (StatusCode, String)> {
let gifts = sqlx::query!(
"select sum(quantity) as \"sq!\", gift_name as \"gift_name!\" \
from orders group by gift_name order by \"sq!\" desc"
)
.fetch_all(&state.pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
match gifts.len() {
0 => Ok("{\"popular\":null}".to_string()),
1 => Ok(format!("{{\"popular\":\"{}\"}}", gifts[0].gift_name)),
_ if gifts[0].sq == gifts[1].sq => Ok("{\"popular\":null}".to_string()),
_ => Ok(format!("{{\"popular\":\"{}\"}}", gifts[0].gift_name)),
}
}