Compare commits

..

No commits in common. "57af399ace52873b2137caa7729d97fe0d6f6b63" and "374d318deae52e68c6667b1450375ad4e1ba9d0a" have entirely different histories.

4 changed files with 14 additions and 99 deletions

View File

@ -7,7 +7,7 @@ use snafu::ResultExt;
use snafu::prelude::*;
use crate::routes::book::BookForm;
use crate::routes::book::IndexQuery;
use crate::routes::book::BookQuery;
use crate::state::AppState;
use crate::state::error::BookSnafu;
@ -54,13 +54,6 @@ pub struct BookOperator {
pub state: AppState,
}
#[derive(Debug, Clone)]
pub struct BooksPaginate {
pub books: Vec<Model>,
pub current_page: u64,
pub total_page: u64,
}
impl BookOperator {
/// Creates a new `BookOperator` with the given application state.
pub fn new(state: AppState) -> Self {
@ -70,22 +63,7 @@ impl BookOperator {
/// Lists all books matching the optional query filters.
///
/// Results are ordered by ID in descending order (newest first).
pub async fn list(&self) -> Result<Vec<Model>, BookError> {
Entity::find()
.order_by_desc(Column::Id)
.all(&self.state.db)
.await
.context(DBSnafu)
}
pub async fn list_paginate(
&self,
page: u64,
query: Option<IndexQuery>,
) -> Result<BooksPaginate, BookError> {
let page = if page > 0 { page } else { 1 }; // keep 1-indexed
let page_0indexed = page - 1; // convert for SeaORM (0-based index)
pub async fn list(&self, query: Option<BookQuery>) -> Result<Vec<Model>, BookError> {
let mut conditions = Condition::all();
if let Some(book_query) = query {
if let Some(title) = book_query.title {
@ -105,22 +83,12 @@ impl BookOperator {
}
}
let book_pages = Entity::find()
Entity::find()
.filter(conditions)
.order_by_desc(Column::Id)
.paginate(&self.state.db, 1);
let books = book_pages
.fetch_page(page_0indexed)
.all(&self.state.db)
.await
.context(DBSnafu)?;
let total_page = book_pages.num_pages().await.context(DBSnafu)?;
Ok(BooksPaginate {
books,
current_page: page,
total_page,
})
.context(DBSnafu)
}
/// Finds a book by its ID.

View File

@ -31,15 +31,12 @@ struct BookWithUser {
/// Query for filter search query
#[serde_as]
#[derive(Deserialize, Clone, Debug)]
pub struct IndexQuery {
#[derive(Deserialize, Clone)]
pub struct BookQuery {
pub title: Option<String>,
pub page: Option<usize>,
pub authors: Option<String>,
#[serde(default)]
#[serde_as(as = "NoneAsEmptyString")]
pub owner_id: Option<i32>,
#[serde(default)]
#[serde_as(as = "NoneAsEmptyString")]
pub current_holder_id: Option<i32>,
}
@ -48,31 +45,22 @@ pub struct IndexQuery {
#[template(path = "index.html")]
struct BookIndexTemplate {
books_with_user: Vec<BookWithUser>,
query: IndexQuery,
query: BookQuery,
users: Vec<UserModel>,
current_page: u64,
total_page: u64,
base_query: String,
}
pub async fn index(
State(state): State<AppState>,
Query(query): Query<IndexQuery>,
Query(query): Query<BookQuery>,
) -> Result<impl axum::response::IntoResponse, AppStateError> {
let page: u64 = query
.page
.map(|p| p.max(1) as u64) // Minimum 1
.unwrap_or(1);
// Get all Users
let users = UserOperator::new(state.clone())
.list()
.await
.context(UserSnafu)?;
// Get all Book filtered with query
let books_paginate = BookOperator::new(state)
.list_paginate(page, Some(query.clone()))
let books = BookOperator::new(state)
.list(Some(query.clone()))
.await
.context(BookSnafu)?;
@ -85,8 +73,7 @@ pub async fn index(
.collect();
// Build object of Book with his relation Owner (User) and current_holder (User)
let result: Vec<BookWithUser> = books_paginate
.books
let result: Vec<BookWithUser> = books
.into_iter()
.filter_map(|book| {
let owner = user_by_id.get(&book.owner_id).cloned()?;
@ -102,29 +89,10 @@ pub async fn index(
})
.collect();
// build original search to be sure to keep
// search when we change page
let mut base_query = String::new();
if let Some(title) = &query.title {
base_query.push_str(&format!("title={}&", title));
}
if let Some(authors) = &query.authors {
base_query.push_str(&format!("authors={}&", authors));
}
if let Some(owner_id) = &query.owner_id {
base_query.push_str(&format!("owner_id={}&", owner_id));
}
if let Some(current_holder_id) = &query.current_holder_id {
base_query.push_str(&format!("current_holder_id={}&", current_holder_id));
}
Ok(BookIndexTemplate {
books_with_user: result,
query,
users,
current_page: books_paginate.current_page,
total_page: books_paginate.total_page,
base_query,
})
}

View File

@ -36,7 +36,7 @@ pub async fn index(
.context(UserSnafu)?;
let books = BookOperator::new(state.clone())
.list()
.list(None)
.await
.context(BookSnafu)?;

View File

@ -6,6 +6,7 @@
{% block main %}
{{ typography::heading("All books") }}
{% call cards::card() %}
<form method="get">
<div class="row">
@ -115,27 +116,5 @@
{% endfor %}
</tbody>
</table>
{% if total_page > 1 %}
<nav aria-label="Page navigation">
<ul class="pagination">
<li class="page-item {% if current_page <= 1 %}disabled{% endif %}">
<a class="page-link" href="/?{{ base_query }}page={% if current_page > 1 %}{{ current_page - 1 }}{% else %}1{% endif %}">Prev</a>
</li>
{% for page in 1..(total_page + 1) %}
{% if page >= current_page - 1 && page <= current_page + 1 %}
<li class="page-item {% if page == current_page %}active{% endif %}">
<a class="page-link" href="/?{{ base_query }}page={{ page }}">{{ page }}</a>
</li>
{% endif %}
{% endfor %}
<li class="page-item {% if current_page == total_page %}disabled{% endif %}">
<a class="page-link" href="/?{{ base_query }}page={{ current_page + 1 }}">Next</a>
</li>
</ul>
</nav>
{% endif %}
{% endcall %}
{% endblock %}