break search out into own module

This commit is contained in:
Joe Ardent 2024-02-09 16:56:05 -08:00
parent 61ad0a17e8
commit 8ee362b991
6 changed files with 84 additions and 62 deletions

View file

@ -29,6 +29,7 @@ mod auth;
mod db;
mod generic_handlers;
mod login;
mod search;
mod signup;
mod stars;
mod templates;
@ -47,11 +48,12 @@ pub async fn app(db_pool: sqlx::SqlitePool) -> IntoMakeService<axum::Router> {
use auth::*;
use generic_handlers::{handle_slash, handle_slash_redir};
use login::{get_login, get_logout, post_login, post_logout};
use search::get_search_watch;
use signup::handlers::{get_create_user, get_signup_success, post_create_user};
use tower_http::services::ServeDir;
use watches::handlers::{
get_add_new_watch, get_search_watch, get_watch, get_watch_status, get_watches,
post_add_new_watch, post_add_watch_quest,
get_add_new_watch, get_watch, get_watch_status, get_watches, post_add_new_watch,
post_add_watch_quest,
};
let auth_layer = {

70
src/search.rs Normal file
View file

@ -0,0 +1,70 @@
use askama::Template;
use axum::{
extract::{Query, State},
response::IntoResponse,
};
use serde::{Deserialize, Serialize};
use sqlx::{query_as, SqlitePool};
use crate::{
misc_util::empty_string_as_none, AuthSession, OptionalOptionalUser, Star, User, Watch,
};
#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser)]
#[template(path = "search_watches_page.html")]
pub struct SearchPage {
pub results: Vec<Watch>,
pub user: Option<User>,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub enum SearchResult {
Star(Star),
Watch(Watch),
}
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)]
pub struct SearchQuery {
#[serde(default, deserialize_with = "empty_string_as_none")]
pub search: Option<String>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub title: Option<String>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub kind: Option<String>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub year: Option<i64>,
}
pub async fn get_search_watch(
auth: AuthSession,
State(pool): State<SqlitePool>,
search: Query<SearchQuery>,
) -> impl IntoResponse {
const DEFAULT_WATCHES_QUERY: &str =
"select * from (select * from watches order by random() limit 50) order by release_date asc";
let user = auth.user;
let search_query = search.0;
let query = if search_query == SearchQuery::default() {
query_as(DEFAULT_WATCHES_QUERY)
} else if let Some(title) = search_query.title {
query_as(
"select * from watches where id in (select id from watch_search where title match ? order by rank)",
)
.bind(title)
} else if let Some(ref search) = search_query.search {
query_as("select * from watches where id in (select id from watch_search where title match ?) outer join (select * from stars where id in (select id from star_search where name match ?)) s")
.bind(search).bind(search)
} else {
query_as(DEFAULT_WATCHES_QUERY)
};
// until tantivy search
let watches: Vec<Watch> = query.fetch_all(&pool).await.unwrap();
SearchPage {
results: watches,
user,
}
}

View file

@ -1,5 +1,5 @@
use axum::{
extract::{Form, Path, Query, State},
extract::{Form, Path, State},
http::StatusCode,
response::{IntoResponse, Redirect, Response},
};
@ -8,7 +8,7 @@ use julid::Julid;
use serde::Deserialize;
use sqlx::{query, query_as, query_scalar, SqlitePool};
use super::templates::{AddNewWatchPage, AddWatchButton, GetWatchPage, SearchWatchesPage};
use super::templates::{AddNewWatchPage, AddWatchButton, GetWatchPage};
use crate::{
misc_util::{empty_string_as_none, year_to_epoch},
AuthSession, MyWatchesPage, ShowKind, Watch, WatchQuest,
@ -23,9 +23,6 @@ const GET_QUEST_QUERY: &str = "select * from watch_quests where user = ? and wat
const GET_WATCH_QUERY: &str = "select * from watches where id = $1";
const DEFAULT_WATCHES_QUERY: &str =
"select * from (select * from watches order by random() limit 50) order by release_date asc";
const ADD_WATCH_QUERY: &str = "insert into watches (title, kind, release_date, metadata_url, added_by, length) values ($1, $2, $3, $4, $5, $6) returning id";
const ADD_WATCH_QUEST_QUERY: &str =
"insert into watch_quests (user, watch, public, watched) values ($1, $2, $3, $4)";
@ -65,18 +62,6 @@ impl IntoResponse for AddError {
// Types for receiving arguments from forms
//-************************************************************************
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)]
pub struct SearchQuery {
#[serde(default, deserialize_with = "empty_string_as_none")]
pub search: Option<String>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub title: Option<String>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub kind: Option<String>,
#[serde(default, deserialize_with = "empty_string_as_none")]
pub year: Option<i64>,
}
// kinda the main form?
#[derive(Debug, Default, Deserialize, PartialEq, Eq)]
pub struct PostAddNewWatch {
@ -239,34 +224,6 @@ pub async fn get_watches(auth: AuthSession, State(pool): State<SqlitePool>) -> i
MyWatchesPage { watches, user }
}
pub async fn get_search_watch(
auth: AuthSession,
State(pool): State<SqlitePool>,
search: Query<SearchQuery>,
) -> impl IntoResponse {
let user = auth.user;
let search_query = search.0;
let query = if search_query == SearchQuery::default() {
query_as(DEFAULT_WATCHES_QUERY)
} else if let Some(title) = search_query.title {
query_as(
"select * from watches where id in (select id from watch_search where title match ? order by rank)",
)
.bind(title)
} else if let Some(ref search) = search_query.search {
query_as("select * from watches where id in (select id from watch_search where title match ?) outer join (select * from stars where id in (select id from star_search where name match ?)) s")
.bind(search).bind(search)
} else {
query_as(DEFAULT_WATCHES_QUERY)
};
// until tantivy search
let watches: Vec<Watch> = query.fetch_all(&pool).await.unwrap();
SearchWatchesPage { watches, user }
}
pub async fn get_watch_status(
auth: AuthSession,
State(pool): State<SqlitePool>,

View file

@ -11,13 +11,6 @@ pub struct MyWatchesPage {
pub user: Option<User>,
}
#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser)]
#[template(path = "search_watches_page.html")]
pub struct SearchWatchesPage {
pub watches: Vec<Watch>,
pub user: Option<User>,
}
#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq, OptionalOptionalUser)]
#[template(path = "get_watch_page.html")]
pub struct GetWatchPage {

View file

@ -18,7 +18,7 @@
</tr>
</thead>
<tbody>
{% for watch in watches %}
{% for res in results %}
{% include "watch-search-result.html" %}
{% endfor %}
</tbody>

View file

@ -1,18 +1,18 @@
<tr id="watchlist-item-{{watch.id}}">
<td><span class="watchtitle"><a href="/watch/{{watch.id}}">{{watch.title}}</a></span></td>
<tr id="watchlist-item-{{res.id}}">
<td><span class="watchtitle"><a href="/watch/{{res.id}}">{{res.title}}</a></span></td>
<td><span>
{% match watch.metadata_url %}
{% match res.metadata_url %}
{% when Some with (mdurl) %}
<a href="{{ mdurl }}">{{ mdurl }}</a>
{% when None %}
{% endmatch %}
</span>
</td>
<td>{{watch.kind}}</td>
<td> {% call m::get_or_default(watch.year(), "when??") -%}</td>
<td>{{res.kind}}</td>
<td> {% call m::get_or_default(res.year(), "when??") -%}</td>
<td>
<span id="add-watch-{{watch.id}}">
<span hx-get="/watch/status/{{watch.id}}" hx-target="this" hx-trigger="load, reveal"
<span id="add-watch-{{res.id}}">
<span hx-get="/watch/status/{{res.id}}" hx-target="this" hx-trigger="load, reveal"
hx-swap="outerHTML">???</span>
</span>
</td>