diff options
| author | Santo Cariotti <santo@dcariotti.me> | 2022-09-10 09:11:35 +0000 |
|---|---|---|
| committer | Santo Cariotti <santo@dcariotti.me> | 2022-09-10 09:11:35 +0000 |
| commit | 5a43e5e38bea77d63074a8db9a319e3ff77fd75a (patch) | |
| tree | 2906b8c3292f126ddef9e7801f054b7294f97820 /src | |
| parent | e8c799cb65f58c1e9a4b2809489ef3b5760638d8 (diff) | |
Add pagination
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.rs | 1 | ||||
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/models/model.rs | 20 | ||||
| -rw-r--r-- | src/models/user.rs | 19 | ||||
| -rw-r--r-- | src/pagination.rs | 7 | ||||
| -rw-r--r-- | src/routes/model.rs | 18 | ||||
| -rw-r--r-- | src/routes/user.rs | 25 |
7 files changed, 80 insertions, 12 deletions
diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..6449a3f --- /dev/null +++ b/src/config.rs @@ -0,0 +1 @@ +pub static PAGE_LIMIT: i64 = 20; diff --git a/src/main.rs b/src/main.rs index 1c9d63a..59ffb24 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ +mod config; mod db; mod errors; mod logger; mod models; +mod pagination; mod routes; use axum::{ diff --git a/src/models/model.rs b/src/models/model.rs index e3fc7ac..a87cddb 100644 --- a/src/models/model.rs +++ b/src/models/model.rs @@ -1,4 +1,6 @@ +use crate::config::PAGE_LIMIT; use crate::db::get_client; + use crate::errors::AppError; use sqlx::types::JsonValue; @@ -111,18 +113,32 @@ impl Model { } /// List all models - pub async fn list() -> Result<Vec<ModelUser>, AppError> { + pub async fn list(page: i64) -> Result<Vec<ModelUser>, AppError> { let pool = unsafe { get_client() }; let rows = sqlx::query_as!( ModelUser, r#"SELECT models.*, json_build_object('id', users.id, 'email', users.email, 'username', users.username, 'is_staff', users.is_staff) as author - FROM models JOIN users ON users.id = models.author_id"# + FROM models JOIN users ON users.id = models.author_id + LIMIT $1 OFFSET $2 + "#, + PAGE_LIMIT, + PAGE_LIMIT * page ) .fetch_all(pool) .await?; Ok(rows) } + + /// Return the number of models. + pub async fn count() -> Result<i64, AppError> { + let pool = unsafe { get_client() }; + let row = sqlx::query!(r#"SELECT COUNT(id) as count FROM models"#) + .fetch_one(pool) + .await?; + + Ok(row.count.unwrap()) + } } diff --git a/src/models/user.rs b/src/models/user.rs index 71b35b6..22bd130 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -1,3 +1,4 @@ +use crate::config::PAGE_LIMIT; use crate::db::get_client; use crate::errors::AppError; @@ -113,15 +114,29 @@ impl User { } /// List all users - pub async fn list() -> Result<Vec<UserList>, AppError> { + pub async fn list(page: i64) -> Result<Vec<UserList>, AppError> { let pool = unsafe { get_client() }; let rows = sqlx::query_as!( UserList, - r#"SELECT id, email, username, is_staff FROM users"# + r#"SELECT id, email, username, is_staff FROM users + LIMIT $1 OFFSET $2 + "#, + PAGE_LIMIT, + PAGE_LIMIT * page ) .fetch_all(pool) .await?; Ok(rows) } + + /// Return the number of users. + pub async fn count() -> Result<i64, AppError> { + let pool = unsafe { get_client() }; + let row = sqlx::query!(r#"SELECT COUNT(id) as count FROM users"#) + .fetch_one(pool) + .await?; + + Ok(row.count.unwrap()) + } } diff --git a/src/pagination.rs b/src/pagination.rs new file mode 100644 index 0000000..1f902b4 --- /dev/null +++ b/src/pagination.rs @@ -0,0 +1,7 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug)] +pub struct Pagination { + #[serde(skip_serializing_if = "Option::is_none")] + pub page: Option<i64>, +} diff --git a/src/routes/model.rs b/src/routes/model.rs index a5cd2b3..4ac2688 100644 --- a/src/routes/model.rs +++ b/src/routes/model.rs @@ -3,18 +3,28 @@ use crate::models::{ auth::Claims, model::{Model, ModelCreate, ModelUser}, }; -use axum::{routing::get, Json, Router}; +use crate::pagination::Pagination; +use axum::{extract::Query, routing::get, Json, Router}; +use serde::Serialize; /// Create routes for `/v1/models/` namespace pub fn create_route() -> Router { Router::new().route("/", get(list_models).post(create_model)) } +#[derive(Serialize)] +struct ModelPagination { + count: i64, + results: Vec<ModelUser>, +} + /// List models. -async fn list_models() -> Result<Json<Vec<ModelUser>>, AppError> { - let models = Model::list().await?; +async fn list_models(pagination: Query<Pagination>) -> Result<Json<ModelPagination>, AppError> { + let page = pagination.0.page.unwrap_or_default(); + let results = Model::list(page).await?; + let count = Model::count().await?; - Ok(Json(models)) + Ok(Json(ModelPagination { count, results })) } /// Create a model. Checks Authorization token diff --git a/src/routes/user.rs b/src/routes/user.rs index 3dfb73a..4ac994c 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -3,7 +3,13 @@ use crate::models::{ auth::Claims, user::{User, UserCreate, UserList}, }; -use axum::{extract::Path, routing::get, Json, Router}; +use crate::pagination::Pagination; +use axum::{ + extract::{Path, Query}, + routing::get, + Json, Router, +}; +use serde::Serialize; /// Create routes for `/v1/users/` namespace pub fn create_route() -> Router { @@ -12,11 +18,22 @@ pub fn create_route() -> Router { .route("/:id", get(get_user)) } +#[derive(Serialize)] +struct UserPagination { + count: i64, + results: Vec<UserList>, +} + /// List users. Checks Authorization token -async fn list_users(_: Claims) -> Result<Json<Vec<UserList>>, AppError> { - let users = User::list().await?; +async fn list_users( + _: Claims, + pagination: Query<Pagination>, +) -> Result<Json<UserPagination>, AppError> { + let page = pagination.0.page.unwrap_or_default(); + let results = User::list(page).await?; + let count = User::count().await?; - Ok(Json(users)) + Ok(Json(UserPagination { count, results })) } /// Create an user. Checks Authorization token |
