feat(server): pagination

repo-db
Jef Roosens 2023-07-31 23:11:02 +02:00
parent 25627e166e
commit e63d0b5565
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
5 changed files with 74 additions and 20 deletions

View File

@ -4,3 +4,9 @@ members = [
'libarchive',
'libarchive3-sys'
]
[profile.release]
lto = "fat"
codegen-units = 1
panic = "abort"
strip = true

View File

@ -22,9 +22,3 @@ tower-http = { version = "0.4.1", features = ["fs", "trace"] }
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
uuid = { version = "1.4.0", features = ["v4"] }
[profile.release]
lto = "fat"
codegen-units = 1
panic = "abort"
strip = true

View File

@ -1,33 +1,44 @@
use axum::extract::{Query, State};
mod pagination;
use axum::extract::{Path, Query, State};
use axum::routing::get;
use axum::Json;
use axum::Router;
use sea_orm::entity::EntityTrait;
use sea_orm::query::QueryOrder;
use sea_orm::PaginatorTrait;
use serde::Deserialize;
use pagination::PaginatedResponse;
use crate::db::entities::repo;
#[derive(Deserialize)]
pub struct Pagination {
page: Option<u64>,
per_page: Option<u64>,
}
pub fn router() -> Router<crate::Global> {
Router::new().route("/repos", get(get_repos))
Router::new()
.route("/repos", get(get_repos))
.route("/repos/:id", get(get_single_repo))
}
async fn get_repos(
State(global): State<crate::Global>,
Query(params): Query<Pagination>,
) -> crate::Result<Json<Vec<repo::Model>>> {
Query(pagination): Query<pagination::Query>,
) -> crate::Result<Json<PaginatedResponse<repo::Model>>> {
let repos = repo::Entity::find()
.order_by_asc(repo::Column::Id)
.paginate(&global.db, params.per_page.unwrap_or(25))
.fetch_page(params.page.unwrap_or(0))
.paginate(&global.db, pagination.per_page.unwrap_or(25))
.fetch_page(pagination.page.unwrap_or(1) - 1)
.await?;
Ok(Json(repos))
Ok(Json(pagination.res(repos)))
}
async fn get_single_repo(
State(global): State<crate::Global>,
Path(id): Path<i32>,
) -> crate::Result<Json<repo::Model>> {
let repo = repo::Entity::find_by_id(id)
.one(&global.db)
.await?
.ok_or(axum::http::StatusCode::NOT_FOUND)?;
Ok(Json(repo))
}

View File

@ -0,0 +1,34 @@
use axum::response::{IntoResponse, Response};
use axum::Json;
use serde::{Deserialize, Serialize};
pub const DEFAULT_PAGE: u64 = 0;
pub const DEFAULT_PER_PAGE: u64 = 25;
#[derive(Deserialize)]
pub struct Query {
pub page: Option<u64>,
pub per_page: Option<u64>,
}
#[derive(Serialize)]
pub struct PaginatedResponse<T>
where
T: for<'de> Serialize,
{
pub page: u64,
pub per_page: u64,
pub count: usize,
pub items: Vec<T>,
}
impl Query {
pub fn res<T: for<'de> Serialize>(self, items: Vec<T>) -> PaginatedResponse<T> {
PaginatedResponse {
page: self.page.unwrap_or(DEFAULT_PAGE),
per_page: self.page.unwrap_or(DEFAULT_PER_PAGE),
count: items.len(),
items,
}
}
}

View File

@ -12,6 +12,7 @@ pub enum ServerError {
Axum(axum::Error),
Status(StatusCode),
Db(sea_orm::DbErr),
Status(StatusCode),
}
impl fmt::Display for ServerError {
@ -21,6 +22,7 @@ impl fmt::Display for ServerError {
ServerError::Axum(err) => write!(fmt, "{}", err),
ServerError::Status(status) => write!(fmt, "{}", status),
ServerError::Db(err) => write!(fmt, "{}", err),
ServerError::Status(status) => write!(fmt, "{}", status),
}
}
}
@ -39,6 +41,7 @@ impl IntoResponse for ServerError {
StatusCode::NOT_FOUND.into_response()
}
ServerError::Db(_) => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
ServerError::Status(status) => status.into_response(),
}
}
}
@ -72,3 +75,9 @@ impl From<sea_orm::DbErr> for ServerError {
ServerError::Db(err)
}
}
impl From<StatusCode> for ServerError {
fn from(status: StatusCode) -> Self {
ServerError::Status(status)
}
}