Now races and teamraces are paginated.
This commit is contained in:
parent
71ed4d8b70
commit
504c580dfd
|
@ -1,24 +1,34 @@
|
||||||
use rocket::{serde::json::Json, Route, State};
|
use rocket::{serde::json::Json, Route, State};
|
||||||
|
|
||||||
use crate::database::{models::race::Race, DatabaseHandler};
|
use crate::database::{
|
||||||
|
models::{
|
||||||
|
race::Race,
|
||||||
|
search_result::{get_page_number_as_i32_from_str, SearchResult},
|
||||||
|
},
|
||||||
|
DatabaseHandler,
|
||||||
|
};
|
||||||
|
|
||||||
#[get("/player/<player>")]
|
#[get("/player/<player>?<page>")]
|
||||||
async fn get_races_by_player(
|
async fn get_races_by_player(
|
||||||
db: &State<DatabaseHandler>,
|
db: &State<DatabaseHandler>,
|
||||||
player: &str,
|
player: &str,
|
||||||
) -> Result<Json<Vec<Race>>, String> {
|
page: Option<&str>,
|
||||||
match Race::get_races_by_player(db, player).await {
|
) -> Result<Json<SearchResult<Race>>, String> {
|
||||||
|
let page_num = get_page_number_as_i32_from_str(page);
|
||||||
|
match Race::get_races_by_player(db, player, page_num).await {
|
||||||
Ok(maps) => Ok(Json(maps)),
|
Ok(maps) => Ok(Json(maps)),
|
||||||
Err(err) => Err(format!("Error: {}", err)),
|
Err(err) => Err(format!("Error: {}", err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/map/<map>")]
|
#[get("/map/<map>?<page>")]
|
||||||
async fn get_races_by_map(
|
async fn get_races_by_map(
|
||||||
db: &State<DatabaseHandler>,
|
db: &State<DatabaseHandler>,
|
||||||
map: &str,
|
map: &str,
|
||||||
) -> Result<Json<Vec<Race>>, String> {
|
page: Option<&str>,
|
||||||
match Race::get_races_by_map(db, map).await {
|
) -> Result<Json<SearchResult<Race>>, String> {
|
||||||
|
let page_num = get_page_number_as_i32_from_str(page);
|
||||||
|
match Race::get_races_by_map(db, map, page_num).await {
|
||||||
Ok(maps) => Ok(Json(maps)),
|
Ok(maps) => Ok(Json(maps)),
|
||||||
Err(err) => Err(format!("Error: {}", err)),
|
Err(err) => Err(format!("Error: {}", err)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,34 @@
|
||||||
use rocket::{serde::json::Json, Route, State};
|
use rocket::{serde::json::Json, Route, State};
|
||||||
|
|
||||||
use crate::database::{models::teamrace::Teamrace, DatabaseHandler};
|
use crate::database::{
|
||||||
|
models::{
|
||||||
|
search_result::{get_page_number_as_i32_from_str, SearchResult},
|
||||||
|
teamrace::Teamrace,
|
||||||
|
},
|
||||||
|
DatabaseHandler,
|
||||||
|
};
|
||||||
|
|
||||||
#[get("/player/<player>")]
|
#[get("/player/<player>?<page>")]
|
||||||
async fn get_teamrace_by_player(
|
async fn get_teamrace_by_player(
|
||||||
db: &State<DatabaseHandler>,
|
db: &State<DatabaseHandler>,
|
||||||
player: &str,
|
player: &str,
|
||||||
) -> Result<Json<Vec<Teamrace>>, String> {
|
page: Option<&str>,
|
||||||
match Teamrace::get_teamrace_by_player(db, player).await {
|
) -> Result<Json<SearchResult<Teamrace>>, String> {
|
||||||
|
let page_num = get_page_number_as_i32_from_str(page);
|
||||||
|
match Teamrace::get_teamrace_by_player(db, player, page_num).await {
|
||||||
Ok(maps) => Ok(Json(maps)),
|
Ok(maps) => Ok(Json(maps)),
|
||||||
Err(err) => Err(format!("Error: {}", err)),
|
Err(err) => Err(format!("Error: {}", err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/map/<map>")]
|
#[get("/map/<map>?<page>")]
|
||||||
async fn get_teamrace_by_map(
|
async fn get_teamrace_by_map(
|
||||||
db: &State<DatabaseHandler>,
|
db: &State<DatabaseHandler>,
|
||||||
map: &str,
|
map: &str,
|
||||||
) -> Result<Json<Vec<Teamrace>>, String> {
|
page: Option<&str>,
|
||||||
match Teamrace::get_teamrace_by_map(db, map).await {
|
) -> Result<Json<SearchResult<Teamrace>>, String> {
|
||||||
|
let page_num = get_page_number_as_i32_from_str(page);
|
||||||
|
match Teamrace::get_teamrace_by_map(db, map, page_num).await {
|
||||||
Ok(maps) => Ok(Json(maps)),
|
Ok(maps) => Ok(Json(maps)),
|
||||||
Err(err) => Err(format!("Error: {}", err)),
|
Err(err) => Err(format!("Error: {}", err)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod race;
|
pub mod race;
|
||||||
|
pub mod search_result;
|
||||||
pub mod teamrace;
|
pub mod teamrace;
|
||||||
|
|
|
@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::database::DatabaseHandler;
|
use crate::database::DatabaseHandler;
|
||||||
|
|
||||||
|
use super::search_result::{SearchResult, ROWS_PER_PAGE};
|
||||||
|
|
||||||
#[derive(Debug, Clone, sqlx::FromRow, Serialize, Deserialize)]
|
#[derive(Debug, Clone, sqlx::FromRow, Serialize, Deserialize)]
|
||||||
pub struct Race {
|
pub struct Race {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -19,8 +21,9 @@ impl Race {
|
||||||
pub async fn get_races_by_player(
|
pub async fn get_races_by_player(
|
||||||
db: &DatabaseHandler,
|
db: &DatabaseHandler,
|
||||||
player: &str,
|
player: &str,
|
||||||
) -> Result<Vec<Race>, sqlx::Error> {
|
page: i32,
|
||||||
sqlx::query_as!(
|
) -> Result<SearchResult<Race>, sqlx::Error> {
|
||||||
|
let results = sqlx::query_as!(
|
||||||
Race,
|
Race,
|
||||||
"
|
"
|
||||||
SELECT name,
|
SELECT name,
|
||||||
|
@ -42,35 +45,73 @@ impl Race {
|
||||||
player
|
player
|
||||||
)
|
)
|
||||||
.fetch_all(&db.pool)
|
.fetch_all(&db.pool)
|
||||||
.await
|
.await?;
|
||||||
|
|
||||||
|
let total_pages = sqlx::query!(
|
||||||
|
"SELECT ceil(count(*) / $2) + 1 as total_pages FROM record_race WHERE name = $1",
|
||||||
|
player,
|
||||||
|
ROWS_PER_PAGE as i64
|
||||||
|
)
|
||||||
|
.fetch_one(&db.pool)
|
||||||
|
.await?
|
||||||
|
.total_pages
|
||||||
|
.map_or_else(|| 0, |as_i64| as_i64 as i32);
|
||||||
|
|
||||||
|
Ok(SearchResult {
|
||||||
|
results,
|
||||||
|
total_pages,
|
||||||
|
current_page: page,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_races_by_map(
|
pub async fn get_races_by_map(
|
||||||
db: &DatabaseHandler,
|
db: &DatabaseHandler,
|
||||||
map: &str,
|
map: &str,
|
||||||
) -> Result<Vec<Race>, sqlx::Error> {
|
page: i32,
|
||||||
sqlx::query_as!(
|
) -> Result<SearchResult<Race>, sqlx::Error> {
|
||||||
|
let results = sqlx::query_as!(
|
||||||
Race,
|
Race,
|
||||||
"
|
"
|
||||||
SELECT name,
|
SELECT
|
||||||
|
name,
|
||||||
map,
|
map,
|
||||||
time,
|
time,
|
||||||
timestamp,
|
timestamp,
|
||||||
server,
|
server,
|
||||||
ARRAY[cp1, cp2, cp3, cp4, cp5,
|
ARRAY[cp1, cp2, cp3, cp4, cp5,
|
||||||
cp6, cp7, cp8, cp9, cp10,
|
cp6, cp7, cp8, cp9, cp10,
|
||||||
cp11, cp12, cp13, cp14, cp15,
|
cp11, cp12, cp13, cp14, cp15,
|
||||||
cp16, cp17, cp18, cp19, cp20,
|
cp16, cp17, cp18, cp19, cp20,
|
||||||
cp21, cp22, cp23, cp24, cp25
|
cp21, cp22, cp23, cp24, cp25
|
||||||
] AS checkpoints,
|
] AS checkpoints,
|
||||||
gameid,
|
gameid,
|
||||||
ddnet7
|
ddnet7
|
||||||
FROM record_race WHERE map = $1
|
FROM record_race WHERE map = $1
|
||||||
ORDER BY map, time
|
ORDER BY map, time
|
||||||
|
OFFSET (($2 - 1) * $3)
|
||||||
|
FETCH NEXT $3 ROWS ONLY
|
||||||
",
|
",
|
||||||
map
|
map,
|
||||||
|
page,
|
||||||
|
ROWS_PER_PAGE
|
||||||
)
|
)
|
||||||
.fetch_all(&db.pool)
|
.fetch_all(&db.pool)
|
||||||
.await
|
.await?;
|
||||||
|
|
||||||
|
let total_pages = sqlx::query!(
|
||||||
|
"SELECT ceil(count(*) / $2) + 1 as total_pages FROM record_race WHERE map = $1",
|
||||||
|
map,
|
||||||
|
ROWS_PER_PAGE as i64
|
||||||
|
)
|
||||||
|
.fetch_one(&db.pool)
|
||||||
|
.await?
|
||||||
|
.total_pages
|
||||||
|
.map_or_else(|| 0, |as_i64| as_i64 as i32);
|
||||||
|
|
||||||
|
Ok(SearchResult {
|
||||||
|
results,
|
||||||
|
total_pages,
|
||||||
|
current_page: page,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/database/models/search_result.rs
Normal file
16
src/database/models/search_result.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct SearchResult<T> {
|
||||||
|
pub results: Vec<T>,
|
||||||
|
pub current_page: i32,
|
||||||
|
pub total_pages: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This constant should be used everywhere so that it can easily changed.
|
||||||
|
pub const ROWS_PER_PAGE: i32 = 200;
|
||||||
|
|
||||||
|
/// This gets an i32 from an Option<&str>. It is very fail safe of any bad value, where it will return 1 instead of an error.
|
||||||
|
pub fn get_page_number_as_i32_from_str(page_as_str: Option<&str>) -> i32 {
|
||||||
|
str::parse(page_as_str.unwrap_or("1")).unwrap_or(1)
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::database::DatabaseHandler;
|
use crate::database::{models::search_result::ROWS_PER_PAGE, DatabaseHandler};
|
||||||
|
|
||||||
|
use super::search_result::SearchResult;
|
||||||
|
|
||||||
#[derive(Debug, Clone, sqlx::FromRow, Serialize, Deserialize)]
|
#[derive(Debug, Clone, sqlx::FromRow, Serialize, Deserialize)]
|
||||||
pub struct Teamrace {
|
pub struct Teamrace {
|
||||||
|
@ -15,25 +17,76 @@ impl Teamrace {
|
||||||
pub async fn get_teamrace_by_player(
|
pub async fn get_teamrace_by_player(
|
||||||
db: &DatabaseHandler,
|
db: &DatabaseHandler,
|
||||||
player: &str,
|
player: &str,
|
||||||
) -> Result<Vec<Teamrace>, sqlx::Error> {
|
page: i32,
|
||||||
sqlx::query_as!(
|
) -> Result<SearchResult<Teamrace>, sqlx::Error> {
|
||||||
|
let results = sqlx::query_as!(
|
||||||
Teamrace,
|
Teamrace,
|
||||||
"SELECT players, map, time, timestamp FROM record_teamrace_array WHERE $1 = ANY(players)",
|
"
|
||||||
player
|
SELECT players, map, time, timestamp
|
||||||
).fetch_all(&db.pool)
|
FROM record_teamrace_array
|
||||||
.await
|
WHERE $1 = ANY(players)
|
||||||
|
OFFSET (($2 - 1) * $3)
|
||||||
|
FETCH NEXT $3 ROWS ONLY
|
||||||
|
",
|
||||||
|
player,
|
||||||
|
page,
|
||||||
|
ROWS_PER_PAGE
|
||||||
|
)
|
||||||
|
.fetch_all(&db.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let total_pages = sqlx::query!(
|
||||||
|
"SELECT ceil(count(*) / $2) + 1 as total_pages FROM record_teamrace_array WHERE $1 = ANY(players)",
|
||||||
|
player,
|
||||||
|
ROWS_PER_PAGE as i64
|
||||||
|
)
|
||||||
|
.fetch_one(&db.pool)
|
||||||
|
.await?
|
||||||
|
.total_pages
|
||||||
|
.map_or_else(|| 0, |as_i64| as_i64 as i32);
|
||||||
|
|
||||||
|
Ok(SearchResult {
|
||||||
|
results,
|
||||||
|
total_pages,
|
||||||
|
current_page: page,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_teamrace_by_map(
|
pub async fn get_teamrace_by_map(
|
||||||
db: &DatabaseHandler,
|
db: &DatabaseHandler,
|
||||||
map: &str,
|
map: &str,
|
||||||
) -> Result<Vec<Teamrace>, sqlx::Error> {
|
page: i32,
|
||||||
sqlx::query_as!(
|
) -> Result<SearchResult<Teamrace>, sqlx::Error> {
|
||||||
|
let results = sqlx::query_as!(
|
||||||
Teamrace,
|
Teamrace,
|
||||||
"SELECT players, map, time, timestamp FROM record_teamrace_array WHERE map = $1",
|
"
|
||||||
map
|
SELECT players, map, time, timestamp
|
||||||
|
FROM record_teamrace_array
|
||||||
|
WHERE map = $1
|
||||||
|
OFFSET (($2 - 1) * $3)
|
||||||
|
FETCH NEXT $3 ROWS ONLY
|
||||||
|
",
|
||||||
|
map,
|
||||||
|
page,
|
||||||
|
ROWS_PER_PAGE
|
||||||
)
|
)
|
||||||
.fetch_all(&db.pool)
|
.fetch_all(&db.pool)
|
||||||
.await
|
.await?;
|
||||||
|
|
||||||
|
let total_pages = sqlx::query!(
|
||||||
|
"SELECT ceil(count(*) / $2) + 1 as total_pages FROM record_teamrace_array WHERE map = $1",
|
||||||
|
map,
|
||||||
|
ROWS_PER_PAGE as i64
|
||||||
|
)
|
||||||
|
.fetch_one(&db.pool)
|
||||||
|
.await?
|
||||||
|
.total_pages
|
||||||
|
.map_or_else(|| 0, |as_i64| as_i64 as i32);
|
||||||
|
|
||||||
|
Ok(SearchResult {
|
||||||
|
results,
|
||||||
|
total_pages,
|
||||||
|
current_page: page,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user