Add paginate
This commit is contained in:
parent
e0ef3229ab
commit
46c9b89ccc
@ -51,6 +51,13 @@ pub struct BookOperator {
|
|||||||
pub state: AppState,
|
pub state: AppState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct BooksPaginate {
|
||||||
|
pub books: Vec<Model>,
|
||||||
|
pub current_page: u64,
|
||||||
|
pub total_page: u64,
|
||||||
|
}
|
||||||
|
|
||||||
impl BookOperator {
|
impl BookOperator {
|
||||||
pub fn new(state: AppState) -> Self {
|
pub fn new(state: AppState) -> Self {
|
||||||
Self { state }
|
Self { state }
|
||||||
@ -64,6 +71,24 @@ impl BookOperator {
|
|||||||
.context(DBSnafu)
|
.context(DBSnafu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn list_paginate(&self, page: u64) -> Result<BooksPaginate, BookError> {
|
||||||
|
let page = if page > 0 { page - 1 } else { 0 };
|
||||||
|
|
||||||
|
let book_pages = Entity::find()
|
||||||
|
.order_by_desc(Column::Id)
|
||||||
|
.paginate(&self.state.db, 1);
|
||||||
|
|
||||||
|
let books = book_pages.fetch_page(page).await.context(DBSnafu)?;
|
||||||
|
let current_page = book_pages.cur_page();
|
||||||
|
let total_page = book_pages.num_pages().await.context(DBSnafu)?;
|
||||||
|
|
||||||
|
Ok(BooksPaginate {
|
||||||
|
books,
|
||||||
|
current_page,
|
||||||
|
total_page,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn find_by_id(&self, id: i32) -> Result<Model, BookError> {
|
pub async fn find_by_id(&self, id: i32) -> Result<Model, BookError> {
|
||||||
let book_by_id = Entity::find_by_id(id)
|
let book_by_id = Entity::find_by_id(id)
|
||||||
.one(&self.state.db)
|
.one(&self.state.db)
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use askama::Template;
|
|||||||
use askama_web::WebTemplate;
|
use askama_web::WebTemplate;
|
||||||
use axum::{
|
use axum::{
|
||||||
Form,
|
Form,
|
||||||
extract::{Path, State},
|
extract::{Path, Query, State},
|
||||||
response::{IntoResponse, Redirect},
|
response::{IntoResponse, Redirect},
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -26,6 +26,8 @@ use crate::{
|
|||||||
#[template(path = "index.html")]
|
#[template(path = "index.html")]
|
||||||
struct BookIndexTemplate {
|
struct BookIndexTemplate {
|
||||||
books_with_user: Vec<BookWithUser>,
|
books_with_user: Vec<BookWithUser>,
|
||||||
|
current_page: u64,
|
||||||
|
total_page: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Book list with the owner and the current holder inside
|
// Book list with the owner and the current holder inside
|
||||||
@ -35,21 +37,36 @@ struct BookWithUser {
|
|||||||
pub current_holder: Option<UserModel>,
|
pub current_holder: Option<UserModel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Pagination {
|
||||||
|
pub page: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn index(
|
pub async fn index(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
|
Query(pagination): Query<Pagination>,
|
||||||
) -> Result<impl axum::response::IntoResponse, AppStateError> {
|
) -> Result<impl axum::response::IntoResponse, AppStateError> {
|
||||||
|
let page: u64 = if let Some(page) = pagination.page {
|
||||||
|
page.try_into().unwrap()
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
let users = UserOperator::new(state.clone())
|
let users = UserOperator::new(state.clone())
|
||||||
.list()
|
.list()
|
||||||
.await
|
.await
|
||||||
.context(UserSnafu)?;
|
.context(UserSnafu)?;
|
||||||
let books = BookOperator::new(state).list().await.context(BookSnafu)?;
|
let books_paginate = BookOperator::new(state)
|
||||||
|
.list_paginate(page)
|
||||||
|
.await
|
||||||
|
.context(BookSnafu)?;
|
||||||
|
|
||||||
let user_by_id: HashMap<i32, UserModel> =
|
let user_by_id: HashMap<i32, UserModel> =
|
||||||
users.into_iter().map(|user| (user.id, user)).collect();
|
users.into_iter().map(|user| (user.id, user)).collect();
|
||||||
|
|
||||||
let mut result: Vec<BookWithUser> = Vec::with_capacity(books.len());
|
let mut result: Vec<BookWithUser> = Vec::with_capacity(books_paginate.books.len());
|
||||||
|
|
||||||
for book in books {
|
for book in books_paginate.books {
|
||||||
let owner = user_by_id.get(&book.owner_id).cloned().unwrap();
|
let owner = user_by_id.get(&book.owner_id).cloned().unwrap();
|
||||||
let current_holder = if let Some(current_holder_id) = book.current_holder_id {
|
let current_holder = if let Some(current_holder_id) = book.current_holder_id {
|
||||||
user_by_id.get(¤t_holder_id).cloned()
|
user_by_id.get(¤t_holder_id).cloned()
|
||||||
@ -66,6 +83,8 @@ pub async fn index(
|
|||||||
|
|
||||||
Ok(BookIndexTemplate {
|
Ok(BookIndexTemplate {
|
||||||
books_with_user: result,
|
books_with_user: result,
|
||||||
|
current_page: books_paginate.current_page,
|
||||||
|
total_page: books_paginate.total_page,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,5 +40,25 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<nav aria-label="Page navigation">
|
||||||
|
<ul class="pagination">
|
||||||
|
<li class="page-item {% if current_page == 1 %}disabled{% endif %}">
|
||||||
|
<a class="page-link" href="/?page={{ current_page - 1 }}">Prev</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{% for page in (current_page - 1)..(current_page + 1) %}
|
||||||
|
{% if page >= 1 && page <= total_page %}
|
||||||
|
<li class="page-item {% if page == current_page %}active{% endif %}">
|
||||||
|
<a class="page-link" href="/?page={{ page }}">{{ page }}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<li class="page-item {% if current_page == total_page %}disabled{% endif %}">
|
||||||
|
<a class="page-link" href="/?page={{ current_page + 1 }}">Next</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user