Skip to content

Commit d5ae7a6

Browse files
committed
fix: ranking as Trait method
1 parent f0f5d5b commit d5ae7a6

File tree

1 file changed

+122
-113
lines changed
  • atcoder-problems-backend/src/server/ranking

1 file changed

+122
-113
lines changed
Lines changed: 122 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use crate::server::{AppData, CommonResponse};
2+
23
use actix_web::{error, web, HttpRequest, HttpResponse, Result};
34
use serde::{Deserialize, Serialize};
45
use sql_client::accepted_count::AcceptedCountClient;
56
use sql_client::language_count::LanguageCountClient;
67
use sql_client::rated_point_sum::RatedPointSumClient;
78
use sql_client::streak::StreakClient;
89
use std::ops::Range;
10+
use async_trait::async_trait;
911

1012
#[derive(Deserialize)]
1113
struct UserRankRequest {
@@ -32,87 +34,108 @@ pub(crate) struct RankingResponseEntry {
3234

3335
const MAX_RANKING_RANGE_LENGTH: usize = 1_000;
3436

35-
pub(crate) fn ranking<State, Fut, F, A>(
36-
f: F,
37-
) -> impl actix_web::Handler<(
38-
HttpRequest,
39-
web::Data<AppData<A>>,
40-
web::Query<RankingRequest>,
41-
)>
42-
where
43-
State: Send + Sync + 'static + Clone,
44-
F: Sync + Send + 'static + Copy + Fn(web::Data<AppData<A>>, Range<usize>) -> Fut,
45-
Fut: std::future::Future<Output = Result<Vec<RankingResponseEntry>>> + Send + 'static,
46-
{
47-
move |request: HttpRequest, data: web::Data<AppData<A>>, query: web::Query<RankingRequest>| async move {
37+
// HttpRequest が Sync + Send でないエラーはこれで解消する
38+
// 実行時に問題があるようであれば (?Send) は外し、ranking の引数から request を除けば良さそう
39+
#[async_trait(?Send)]
40+
pub(crate) trait RankingSelector<A: Sync + Send + Clone + 'static> {
41+
async fn fetch(data: web::Data<AppData<A>>, query: Range<usize>) -> Result<Vec<RankingResponseEntry>>;
42+
async fn get_ranking(request: HttpRequest, data: web::Data<AppData<A>>, query: web::Query<RankingRequest>) -> Result<HttpResponse> {
4843
let query = (query.from)..(query.to);
4944
if query.len() > MAX_RANKING_RANGE_LENGTH {
5045
return Ok(HttpResponse::Ok().finish());
5146
}
52-
let ranking = f(data, query).await?;
47+
let ranking = Self::fetch(data, query).await?;
5348
let response = HttpResponse::json(&ranking)?;
5449
<Result<HttpResponse>>::Ok(response)
5550
}
5651
}
5752

58-
pub(crate) fn user_rank<State, Fut, F, A>(
59-
f: F,
60-
) -> impl actix_web::Handler<(
61-
HttpRequest,
62-
web::Data<AppData<A>>,
63-
web::Query<UserRankRequest>,
64-
)>
65-
where
66-
State: Send + Sync + 'static + Clone,
67-
F: Sync + Send + 'static + Copy + Fn(web::Data<AppData<A>>, &str) -> Fut,
68-
Fut: std::future::Future<Output = Result<Option<UserRankResponse>>> + Send + 'static,
69-
{
70-
move |request: HttpRequest, data: web::Data<AppData<A>>, query: web::Query<UserRankRequest>| async move {
71-
{
72-
let user_rank = f(data, &query.user).await?;
73-
// map と ok_or に書き換えられる
74-
match user_rank {
75-
Some(rank) => {
76-
let response = HttpResponse::json(&rank)?;
77-
<Result<HttpResponse>>::Ok(response)
78-
}
79-
None => Ok(HttpResponse::NotFound().finish()),
53+
#[async_trait(?Send)]
54+
pub(crate) trait UserRankSelector<A: Sync + Send + Clone + 'static> {
55+
async fn fetch(data: web::Data<AppData<A>>, query: &str) -> Result<Option<UserRankResponse>>;
56+
async fn get_users_rank(request: HttpRequest, data: web::Data<AppData<A>>, query: web::Query<UserRankRequest>) -> Result<HttpResponse> {
57+
let user_rank = Self::fetch(data, &query.user).await?;
58+
// map と ok_or に書き換えられる
59+
match user_rank {
60+
Some(rank) => {
61+
let response = HttpResponse::json(&rank)?;
62+
<Result<HttpResponse>>::Ok(response)
8063
}
64+
None => Ok(HttpResponse::NotFound().finish()),
8165
}
8266
}
8367
}
8468

85-
pub(crate) async fn get_streak_ranking<A>(
86-
data: web::Data<AppData<A>>,
87-
query: Range<usize>,
88-
) -> Result<Vec<RankingResponseEntry>> {
89-
let conn = data.pg_pool.clone();
90-
let ranking = conn
91-
.load_streak_count_in_range(query)
92-
.await
93-
.map_err(error::ErrorInternalServerError)?;
94-
Ok(ranking
95-
.into_iter()
96-
.map(|entry| RankingResponseEntry {
97-
user_id: entry.user_id,
98-
count: entry.streak,
99-
})
100-
.collect())
69+
pub(crate) struct StreakRanking;
70+
71+
#[async_trait(?Send)]
72+
impl<A: Sync + Send + Clone + 'static> RankingSelector<A> for StreakRanking {
73+
async fn fetch(data: web::Data<AppData<A>>, query: Range<usize>) -> Result<Vec<RankingResponseEntry>> {
74+
let conn = data.pg_pool.clone();
75+
let ranking = conn
76+
.load_streak_count_in_range(query)
77+
.await
78+
.map_err(error::ErrorInternalServerError)?;
79+
Ok(ranking
80+
.into_iter()
81+
.map(|entry| RankingResponseEntry {
82+
user_id: entry.user_id,
83+
count: entry.streak,
84+
})
85+
.collect())
86+
}
10187
}
10288

103-
pub(crate) async fn get_ac_ranking<A>(
104-
data: web::Data<AppData<A>>,
105-
query: Range<usize>,
106-
) -> Result<Vec<RankingResponseEntry>> {
107-
let conn = data.pg_pool.clone();
108-
let ranking = conn.load_accepted_count_in_range(query).await.map_err(error::ErrorInternalServerError)?;
109-
Ok(ranking
110-
.into_iter()
111-
.map(|entry| RankingResponseEntry {
112-
user_id: entry.user_id,
113-
count: entry.problem_count as i64,
114-
})
115-
.collect())
89+
#[async_trait(?Send)]
90+
impl<A: Sync + Send + Clone + 'static> UserRankSelector<A> for StreakRanking {
91+
async fn fetch(data: web::Data<AppData<A>>, user_id: &str) -> Result<Option<UserRankResponse>> {
92+
let conn = data.pg_pool.clone();
93+
let count = match conn.get_users_streak_count(user_id).await {
94+
Some(number) => number,
95+
None => return Ok(None),
96+
};
97+
let rank = conn
98+
.get_streak_count_rank(count)
99+
.await
100+
.map_err(error::ErrorInternalServerError)?;
101+
Ok(Some(UserRankResponse { count, rank }))
102+
}
103+
}
104+
105+
pub(crate) struct AcRanking;
106+
107+
#[async_trait(?Send)]
108+
impl<A: Sync + Send + Clone + 'static> RankingSelector<A> for AcRanking {
109+
async fn fetch(data: web::Data<AppData<A>>, query: Range<usize>) -> Result<Vec<RankingResponseEntry>> {
110+
let conn = data.pg_pool.clone();
111+
let ranking = conn
112+
.load_accepted_count_in_range(query)
113+
.await
114+
.map_err(error::ErrorInternalServerError)?;
115+
Ok(ranking
116+
.into_iter()
117+
.map(|entry| RankingResponseEntry {
118+
user_id: entry.user_id,
119+
count: entry.problem_count as i64,
120+
})
121+
.collect())
122+
}
123+
}
124+
125+
#[async_trait(?Send)]
126+
impl<A: Sync + Send + Clone + 'static> UserRankSelector<A> for AcRanking {
127+
async fn fetch(data: web::Data<AppData<A>>, user_id: &str) -> Result<Option<UserRankResponse>> {
128+
let conn = data.pg_pool.clone();
129+
let count = match conn.get_users_accepted_count(user_id).await {
130+
Some(number) => number,
131+
None => return Ok(None),
132+
};
133+
let rank = conn
134+
.get_accepted_count_rank(count)
135+
.await
136+
.map_err(error::ErrorInternalServerError)?;
137+
Ok(Some(UserRankResponse { count, rank }))
138+
}
116139
}
117140

118141
#[derive(Deserialize)]
@@ -125,7 +148,7 @@ struct LanguageQuery {
125148
pub(crate) async fn get_language_ranking<A>(
126149
request: HttpRequest,
127150
data: web::Data<AppData<A>>,
128-
query: web::Query<LanguageQuery>
151+
query: web::Query<LanguageQuery>,
129152
) -> Result<HttpResponse> {
130153
let conn = data.pg_pool.clone();
131154
let range = (query.from)..(query.to);
@@ -135,7 +158,8 @@ pub(crate) async fn get_language_ranking<A>(
135158

136159
let ranking = conn
137160
.load_language_count_in_range(&query.language, range)
138-
.await.map_err(error::ErrorInternalServerError)?;
161+
.await
162+
.map_err(error::ErrorInternalServerError)?;
139163
let ranking = ranking
140164
.into_iter()
141165
.map(|entry| RankingResponseEntry {
@@ -147,32 +171,6 @@ pub(crate) async fn get_language_ranking<A>(
147171
Ok(response)
148172
}
149173

150-
pub(crate) async fn get_users_ac_rank<A>(
151-
data: web::Data<AppData<A>>,
152-
user_id: &str,
153-
) -> Result<Option<UserRankResponse>> {
154-
let conn = data.pg_pool.clone();
155-
let count = match conn.get_users_accepted_count(user_id).await {
156-
Some(number) => number,
157-
None => return Ok(None),
158-
};
159-
let rank = conn.get_accepted_count_rank(count).await.map_err(error::ErrorInternalServerError)?;
160-
Ok(Some(UserRankResponse { count, rank }))
161-
}
162-
163-
pub(crate) async fn get_users_streak_rank<A>(
164-
data: web::Data<AppData<A>>,
165-
user_id: &str,
166-
) -> Result<Option<UserRankResponse>> {
167-
let conn = data.pg_pool.clone();
168-
let count = match conn.get_users_streak_count(user_id).await {
169-
Some(number) => number,
170-
None => return Ok(None),
171-
};
172-
let rank = conn.get_streak_count_rank(count).await.map_err(error::ErrorInternalServerError)?;
173-
Ok(Some(UserRankResponse { count, rank }))
174-
}
175-
176174
#[derive(Debug, Deserialize)]
177175
struct UsersLanguageQuery {
178176
user: String,
@@ -181,7 +179,7 @@ struct UsersLanguageQuery {
181179
pub(crate) async fn get_users_language_rank<A>(
182180
request: HttpRequest,
183181
data: web::Data<AppData<A>>,
184-
query: web::Query<UsersLanguageQuery>
182+
query: web::Query<UsersLanguageQuery>,
185183
) -> Result<HttpResponse> {
186184
#[derive(Debug, Serialize)]
187185
struct UsersLanguageResponse {
@@ -190,8 +188,14 @@ pub(crate) async fn get_users_language_rank<A>(
190188
rank: i64,
191189
}
192190
let conn = data.pg_pool.clone();
193-
let counts = conn.load_users_language_count(&query.user).await.map_err(error::ErrorInternalServerError)?;
194-
let ranks = conn.load_users_language_count_rank(&query.user).await.map_err(error::ErrorInternalServerError)?;
191+
let counts = conn
192+
.load_users_language_count(&query.user)
193+
.await
194+
.map_err(error::ErrorInternalServerError)?;
195+
let ranks = conn
196+
.load_users_language_count_rank(&query.user)
197+
.await
198+
.map_err(error::ErrorInternalServerError)?;
195199
let info = counts
196200
.into_iter()
197201
.zip(ranks)
@@ -205,21 +209,26 @@ pub(crate) async fn get_users_language_rank<A>(
205209
Ok(response)
206210
}
207211

208-
pub(crate) async fn get_users_rated_point_sum_rank<A>(
209-
data: web::Data<AppData<A>>,
210-
user_id: &str,
211-
) -> Result<Option<UserRankResponse>> {
212-
let conn = data.pg_pool.clone();
213-
let point_sum = conn.get_users_rated_point_sum(user_id).await;
214-
let point_sum = match point_sum {
215-
Some(point_sum) => point_sum,
216-
None => return Ok(None),
217-
};
218-
219-
let rank = conn.get_rated_point_sum_rank(point_sum).await.map_err(error::ErrorInternalServerError)?;
220-
let response = UserRankResponse {
221-
count: point_sum,
222-
rank,
223-
};
224-
Ok(Some(response))
212+
pub(crate) struct RatedPointSumRanking;
213+
214+
#[async_trait(?Send)]
215+
impl<A: Sync + Send + Clone + 'static> UserRankSelector<A> for RatedPointSumRanking {
216+
async fn fetch(data: web::Data<AppData<A>>, user_id: &str) -> Result<Option<UserRankResponse>> {
217+
let conn = data.pg_pool.clone();
218+
let point_sum = conn.get_users_rated_point_sum(user_id).await;
219+
let point_sum = match point_sum {
220+
Some(point_sum) => point_sum,
221+
None => return Ok(None),
222+
};
223+
224+
let rank = conn
225+
.get_rated_point_sum_rank(point_sum)
226+
.await
227+
.map_err(error::ErrorInternalServerError)?;
228+
let response = UserRankResponse {
229+
count: point_sum,
230+
rank,
231+
};
232+
Ok(Some(response))
233+
}
225234
}

0 commit comments

Comments
 (0)