Add filter on book index

This commit is contained in:
gabatxo1312 2026-01-29 00:36:23 +01:00
commit 673fd2c58a
No known key found for this signature in database
4 changed files with 155 additions and 36 deletions

View file

@ -1,4 +1,5 @@
use sea_orm::ActiveValue::Set;
use sea_orm::Condition;
use sea_orm::DeleteResult;
use sea_orm::QueryOrder;
use sea_orm::entity::prelude::*;
@ -6,6 +7,7 @@ use snafu::ResultExt;
use snafu::prelude::*;
use crate::routes::book::BookForm;
use crate::routes::book::BookQuery;
use crate::state::AppState;
use crate::state::error::BookSnafu;
@ -56,8 +58,28 @@ impl BookOperator {
Self { state }
}
pub async fn list(&self) -> Result<Vec<Model>, BookError> {
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 {
conditions = conditions.add(Column::Title.contains(&title));
}
if let Some(authors) = book_query.authors {
conditions = conditions.add(Column::Authors.contains(&authors));
}
if let Some(owner_id) = book_query.owner_id {
conditions = conditions.add(Column::OwnerId.eq(owner_id));
}
if let Some(current_holder_id) = book_query.current_holder_id {
conditions = conditions.add(Column::CurrentHolderId.eq(current_holder_id));
}
}
Entity::find()
.filter(conditions)
.order_by_desc(Column::Id)
.all(&self.state.db)
.await

View file

@ -4,7 +4,7 @@ use askama::Template;
use askama_web::WebTemplate;
use axum::{
Form,
extract::{Path, State},
extract::{Path, Query, State},
response::{IntoResponse, Redirect},
};
use serde::Deserialize;
@ -22,12 +22,6 @@ use crate::{
},
};
#[derive(Template, WebTemplate)]
#[template(path = "index.html")]
struct BookIndexTemplate {
books_with_user: Vec<BookWithUser>,
}
// Book list with the owner and the current holder inside
struct BookWithUser {
pub book: BookModel,
@ -35,37 +29,64 @@ struct BookWithUser {
pub current_holder: Option<UserModel>,
}
#[serde_as]
#[derive(Deserialize, Clone)]
pub struct BookQuery {
pub title: Option<String>,
pub authors: Option<String>,
#[serde_as(as = "NoneAsEmptyString")]
pub owner_id: Option<i32>,
#[serde_as(as = "NoneAsEmptyString")]
pub current_holder_id: Option<i32>,
}
#[derive(Template, WebTemplate)]
#[template(path = "index.html")]
struct BookIndexTemplate {
books_with_user: Vec<BookWithUser>,
query: BookQuery,
users: Vec<UserModel>,
}
pub async fn index(
State(state): State<AppState>,
Query(query): Query<BookQuery>,
) -> Result<impl axum::response::IntoResponse, AppStateError> {
let users = UserOperator::new(state.clone())
.list()
.await
.context(UserSnafu)?;
let books = BookOperator::new(state).list().await.context(BookSnafu)?;
let books = BookOperator::new(state)
.list(Some(query.clone()))
.await
.context(BookSnafu)?;
let user_by_id: HashMap<i32, UserModel> =
users.into_iter().map(|user| (user.id, user)).collect();
let user_by_id: HashMap<i32, UserModel> = users
.clone()
.into_iter()
.map(|user| (user.id, user))
.collect();
let mut result: Vec<BookWithUser> = Vec::with_capacity(books.len());
let result: Vec<BookWithUser> = books
.into_iter()
.filter_map(|book| {
let owner = user_by_id.get(&book.owner_id).cloned()?;
let current_holder = book
.current_holder_id
.and_then(|id| user_by_id.get(&id).cloned());
for book in books {
let owner = user_by_id.get(&book.owner_id).cloned().unwrap();
let current_holder = if let Some(current_holder_id) = book.current_holder_id {
user_by_id.get(&current_holder_id).cloned()
} else {
None
};
result.push(BookWithUser {
book,
owner,
current_holder,
});
}
Some(BookWithUser {
book,
owner,
current_holder,
})
})
.collect();
Ok(BookIndexTemplate {
books_with_user: result,
query,
users,
})
}

View file

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