Add filter on book index
This commit is contained in:
parent
e0ef3229ab
commit
673fd2c58a
@ -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
|
||||
|
||||
@ -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(¤t_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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ pub async fn index(
|
||||
.context(UserSnafu)?;
|
||||
|
||||
let books = BookOperator::new(state.clone())
|
||||
.list()
|
||||
.list(None)
|
||||
.await
|
||||
.context(BookSnafu)?;
|
||||
|
||||
|
||||
@ -6,6 +6,82 @@
|
||||
{% block main %}
|
||||
{{ typography::heading("All books") }}
|
||||
|
||||
|
||||
{% call cards::card() %}
|
||||
<form method="get">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<label for="title" class="form-label">Name</label>
|
||||
{% match query.title %}
|
||||
{% when Some with (value) %}
|
||||
<input type="text" name="title" value="{{ value }}" class="form-control" placeholder="Ex: La liberte ou rien">
|
||||
{% when None %}
|
||||
<input type="text" name="title" class="form-control" placeholder="Ex: La liberte ou rien">
|
||||
{% endmatch %}
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<label for="authors" class="form-label">Authors</label>
|
||||
|
||||
{% match query.authors %}
|
||||
{% when Some with (value) %}
|
||||
<input type="text" name="authors" value="{{ value }}" class="form-control" placeholder="Ex: Emma Goldmann">
|
||||
{% when None %}
|
||||
<input type="text" name="authors" class="form-control" placeholder="Ex: Emma Goldmann">
|
||||
{% endmatch %}
|
||||
</div>
|
||||
|
||||
<div class="col-md-2">
|
||||
<label for="owner_id" class="form-label">Owner</label>
|
||||
|
||||
<select name="owner_id" class="form-control">
|
||||
<option></option>
|
||||
{% match query.owner_id %}
|
||||
{% when Some with (owner_id) %}
|
||||
{% for user in users %}
|
||||
{% if *owner_id == user.id %}
|
||||
<option value="{{ user.id }}" selected>{{ user.name }}</option>
|
||||
{% else %}
|
||||
<option value="{{ user.id }}">{{ user.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% when None %}
|
||||
{% for user in users %}
|
||||
<option value="{{ user.id }}">{{ user.name }}</option>
|
||||
{% endfor %}
|
||||
{% endmatch %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-2">
|
||||
<label for="current_holder_id" class="form-label">Current Holder</label>
|
||||
|
||||
<select name="current_holder_id" class="form-control">
|
||||
<option></option>
|
||||
{% match query.current_holder_id %}
|
||||
{% when Some with (current_holder_id) %}
|
||||
{% for user in users %}
|
||||
{% if *current_holder_id == user.id %}
|
||||
<option value="{{ user.id }}" selected>{{ user.name }}</option>
|
||||
{% else %}
|
||||
<option value="{{ user.id }}">{{ user.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% when None %}
|
||||
{% for user in users %}
|
||||
<option value="{{ user.id }}">{{ user.name }}</option>
|
||||
{% endfor %}
|
||||
{% endmatch %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-1 d-flex align-items-end">
|
||||
<input type="submit" value="Search" class="btn btn-info btn">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endcall %}
|
||||
|
||||
{% call cards::card() %}
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
@ -19,14 +95,14 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for book_with_user in books_with_user %}
|
||||
{% for book_user in books_with_user %}
|
||||
<tr>
|
||||
<th scope="row">{{ book_with_user.book.id }}</th>
|
||||
<td>{{ book_with_user.book.title }}</td>
|
||||
<td>{{ book_with_user.book.authors }}</td>
|
||||
<td>{{ book_with_user.owner.name }}</td>
|
||||
<th scope="row">{{ book_user.book.id }}</th>
|
||||
<td>{{ book_user.book.title }}</td>
|
||||
<td>{{ book_user.book.authors }}</td>
|
||||
<td>{{ book_user.owner.name }}</td>
|
||||
<td>
|
||||
{% match book_with_user.current_holder %}
|
||||
{% match book_user.current_holder %}
|
||||
{% when Some with (current_holder) %}
|
||||
{{ current_holder.name }}
|
||||
{% when None %}
|
||||
@ -34,7 +110,7 @@
|
||||
{% endmatch %}
|
||||
</td>
|
||||
<td>
|
||||
{{ dropdown::book_dropdown_button(book_with_user.book) }}
|
||||
{{ dropdown::book_dropdown_button(book_user.book) }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user