From 878d3fa59b35464fb8507f2b09a570bc25c2a17e Mon Sep 17 00:00:00 2001 From: Thomas Gideon Date: Sat, 7 Sep 2024 19:50:48 -0400 Subject: [PATCH] Build a view pane - Use techniques from refactor of user list, to work with suspense and error boundary from the start. - Add in necessary migration and query. - Extract out some common view factories for fallback. - Extract a field display function. --- sql/insert_series.sql | 2 +- sql/select_all_series.sql | 3 ++ sql/select_series.sql | 4 ++- src/app/series/add.rs | 14 +++++++- src/app/series/mod.rs | 24 +++++++++++-- src/app/series/view.rs | 73 ++++++++++++++++++++++++++++++++++++++- 6 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 sql/select_all_series.sql diff --git a/sql/insert_series.sql b/sql/insert_series.sql index 233d2d7..661d629 100644 --- a/sql/insert_series.sql +++ b/sql/insert_series.sql @@ -1 +1 @@ -insert into series (name) values ($1); +insert into series (name, source, imdb, wikipedia) values ($1, $2, $3, $4); diff --git a/sql/select_all_series.sql b/sql/select_all_series.sql new file mode 100644 index 0000000..9011149 --- /dev/null +++ b/sql/select_all_series.sql @@ -0,0 +1,3 @@ +select * +from series +order by updated desc; diff --git a/sql/select_series.sql b/sql/select_series.sql index cac4c73..eb3f109 100644 --- a/sql/select_series.sql +++ b/sql/select_series.sql @@ -1 +1,3 @@ -select * from series; +select * +from series +where id = $1; diff --git a/src/app/series/add.rs b/src/app/series/add.rs index f484d0e..99d84da 100644 --- a/src/app/series/add.rs +++ b/src/app/series/add.rs @@ -58,7 +58,12 @@ pub fn AddSeries() -> impl IntoView { } #[server(AddSeries)] -pub async fn add_series(name: String) -> Result<(), ServerFnError> { +pub async fn add_series( + name: String, + source: String, + imdb: String, + wikipedia: String, +) -> Result<(), ServerFnError> { use crate::db::load_statement; use sqlx::{Pool, Postgres}; let pool = expect_context::>(); @@ -67,6 +72,13 @@ pub async fn add_series(name: String) -> Result<(), ServerFnError> { sqlx::query(&s) .persistent(true) .bind(name) + .bind(source) + .bind(if imdb.is_empty() { None } else { Some(imdb) }) + .bind(if wikipedia.is_empty() { + None + } else { + Some(wikipedia) + }) .execute(&pool) .await?; diff --git a/src/app/series/mod.rs b/src/app/series/mod.rs index 2063110..b0cc1fe 100644 --- a/src/app/series/mod.rs +++ b/src/app/series/mod.rs @@ -18,7 +18,7 @@ pub fn SeriesList() -> impl IntoView { |_| async move { get_all().await }, ); view! { - "Loading..." }> + { move || all_series.get().map(format_all_series)}
@@ -85,11 +85,31 @@ fn format_series(series: Series) -> impl IntoView { } } +pub fn loading() -> impl IntoView { + view! {
Loading...
} +} + +pub fn format_errors(errors: RwSignal) -> impl IntoView { + view! { +
+ {errors.get() + .into_iter() + .map(|(_, e)| e.to_string()) + .collect::>() + .join(", ") + } +
+ } +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "ssr", derive(FromRow))] pub struct Series { id: Uuid, name: String, + source: String, + imdb: Option, + wikipedia: Option, } #[server] @@ -100,7 +120,7 @@ pub async fn get_all() -> Result, ServerFnError> { let pool: Pool = expect_context(); - let s = load_statement("select_series.sql"); + let s = load_statement("select_all_series.sql"); let mut r = sqlx::query_as::<_, Series>(&s).fetch(&pool); let mut found = Vec::new(); diff --git a/src/app/series/view.rs b/src/app/series/view.rs index 8120967..82d0f60 100644 --- a/src/app/series/view.rs +++ b/src/app/series/view.rs @@ -1,8 +1,27 @@ +use super::{format_errors, Series}; use leptos::*; use leptos_router::*; +use uuid::Uuid; + +#[derive(Params, PartialEq)] +pub struct ViewParams { + id: Uuid, +} #[component] pub fn ViewSeries() -> impl IntoView { + let ps = use_params::(); + let id = move || { + ps.with(|ps| { + ps.as_ref() + .map(|ps| ps.id.clone()) + .expect("Failed to parse Id value from query string!") + }) + }; + let details = create_resource( + move || id(), + |id| async move { get_series_details(id).await }, + ); view! {
@@ -15,8 +34,60 @@ pub fn ViewSeries() -> impl IntoView {

View Series

- View Series + + {details.get().map(format_series_details)} +
} } + +fn loading() -> impl IntoView { + view! { + {format_field("Name", view!())} + {format_field("Source", view!())} + {format_field("IMDB", view!())} + {format_field("Wikpedia", view!())} + } +} + +fn format_series_details( + details: Result, +) -> Result { + Ok(view! { + + {details.map(|details| view! { + {format_field("Name", details.name)} + {format_field("Source", details.source)} + {format_field("IMDB", details.imdb)} + {format_field("Wikipedia", details.wikipedia)} + }) + } + + }) +} + +fn format_field(label: &'static str, f: F) -> impl IntoView { + view! { +
+
{label}
+
{f}
+
+ } +} + +#[server(GetSeriesDetails)] +pub async fn get_series_details(id: Uuid) -> Result { + use crate::db::load_statement; + use sqlx::{Pool, Postgres}; + + let pool = expect_context::>(); + let s = load_statement("select_series.sql"); + let r = sqlx::query_as::<_, Series>(&s) + .persistent(true) + .bind(id) + .fetch_one(&pool) + .await?; + + Ok(r) +}