Wire in a database

This commit is contained in:
Thomas Gideon 2024-09-02 17:43:49 -04:00
parent 232a9877e6
commit c7e4983e46
7 changed files with 252 additions and 28 deletions

View file

@ -2,6 +2,10 @@ use crate::error_template::{AppError, ErrorTemplate};
use leptos::*;
use leptos_meta::*;
use leptos_router::*;
use serde::{Deserialize, Serialize};
#[cfg(feature = "ssr")]
use sqlx::FromRow;
use uuid::Uuid;
#[component]
pub fn App() -> impl IntoView {
@ -21,7 +25,7 @@ pub fn App() -> impl IntoView {
/>
// sets the document title
<Title text="Welcome to Leptos"/>
<Title text="Watch"/>
// content for this welcome page
<Router fallback=|| {
@ -41,38 +45,55 @@ pub fn App() -> impl IntoView {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "ssr", derive(FromRow))]
struct Series {
id: Uuid,
name: String,
}
#[server]
pub async fn get_all() -> Result<Vec<String>, ServerFnError> {
use std::time::Duration;
use sqlx::{Pool, Postgres};
use tokio_stream::StreamExt;
std::thread::sleep(Duration::from_millis(250));
println!("Loading");
Ok(vec!["data1".to_string(), "data2".to_string()])
let pool: Pool<Postgres> = expect_context();
let mut r = sqlx::query_as::<_, Series>("select * from series;").fetch(&pool);
let mut found = Vec::new();
while let Some(series) = r.try_next().await? {
found.push(series.name);
}
Ok(found)
}
/// Renders the home page of your application.
#[component]
fn HomePage() -> impl IntoView {
// Creates a reactive value to update the button
let load = create_local_resource(|| (), |_| async move { get_all().await });
let load = create_resource(|| (), |_| async move { get_all().await });
view! {
<h1>"Welcome to Leptos!"</h1>
{
move || match load() {
None => view!{ <div>"Loading..."</div> },
Some(data) => {
view! {
<div><ul>
{
data.unwrap_or_default().into_iter().map(|d| view!{
<li>{d}</li>
}).collect::<Vec<_>>()
}
</ul></div>
}
}
}
}
<h1>"What We're Watching"</h1>
<div class="card">
<Suspense fallback=|| view!{ <div>"Loading..."</div> }>
<ul>
{load().map(format_series)}
</ul>
</Suspense>
</div>
}
}
fn format_series(data: Result<Vec<String>, ServerFnError>) -> Vec<impl IntoView> {
data.unwrap_or_default()
.into_iter()
.map(|d| {
view! {
<li>{d}</li>
}
})
.collect::<Vec<_>>()
}

View file

@ -1,9 +1,13 @@
#[cfg(feature = "ssr")]
#[tokio::main]
async fn main() {
use std::env;
use axum::Router;
use leptos::*;
use leptos_axum::{generate_route_list, LeptosRoutes};
use log::info;
use sqlx::postgres::PgPoolOptions;
use watch::app::*;
use watch::fileserv::file_and_error_handler;
@ -17,14 +21,35 @@ async fn main() {
let addr = leptos_options.site_addr;
let routes = generate_route_list(App);
let pool = PgPoolOptions::new()
.test_before_acquire(true)
.max_lifetime(None)
.connect_lazy(&env::var("DATABASE_URL").expect("DATABASE_URL was not set!"))
.expect("Failed to create database connection pool");
// build our application with a route
let app = Router::new()
.leptos_routes(&leptos_options, routes, App)
.leptos_routes_with_context(
&leptos_options,
routes,
{
let pool = pool.clone();
move || provide_context(pool.clone())
},
App,
)
.fallback(file_and_error_handler)
.with_state(leptos_options);
.with_state(leptos_options)
.with_state(pool);
if env::var("RUST_LOG").is_err() {
env::set_var("RUST_LOG", format!("{}=debug", module_path!()));
}
env_logger::init();
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
logging::log!("listening on http://{}", &addr);
info!("listening on http://{}", &addr);
axum::serve(listener, app.into_make_service())
.await
.unwrap();