Wire in a database
This commit is contained in:
parent
232a9877e6
commit
c7e4983e46
7 changed files with 252 additions and 28 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -11,3 +11,5 @@ node_modules/
|
|||
test-results/
|
||||
end2end/playwright-report/
|
||||
playwright/.cache/
|
||||
|
||||
.envrc
|
||||
|
|
152
Cargo.lock
generated
152
Cargo.lock
generated
|
@ -44,6 +44,55 @@ version = "0.2.18"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.86"
|
||||
|
@ -328,6 +377,12 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
|
@ -563,6 +618,29 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"humantime",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
|
@ -937,6 +1015,12 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.4.1"
|
||||
|
@ -1018,6 +1102,12 @@ version = "0.3.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
|
@ -1898,6 +1988,40 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "8.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0"
|
||||
dependencies = [
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "8.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rust-embed-utils",
|
||||
"syn 2.0.77",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "8.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d"
|
||||
dependencies = [
|
||||
"sha2",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
|
@ -2198,6 +2322,15 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.2.0"
|
||||
|
@ -2327,6 +2460,7 @@ dependencies = [
|
|||
"tokio-stream",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
|
@ -2408,6 +2542,7 @@ dependencies = [
|
|||
"stringprep",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
|
@ -2446,6 +2581,7 @@ dependencies = [
|
|||
"stringprep",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
|
@ -2470,6 +2606,7 @@ dependencies = [
|
|||
"sqlx-core",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2600,6 +2737,7 @@ dependencies = [
|
|||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.52.0",
|
||||
|
@ -2625,6 +2763,7 @@ dependencies = [
|
|||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2864,6 +3003,12 @@ version = "0.1.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.10.0"
|
||||
|
@ -2871,6 +3016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2994,17 +3140,23 @@ dependencies = [
|
|||
"anyhow",
|
||||
"axum",
|
||||
"console_error_panic_hook",
|
||||
"env_logger",
|
||||
"http",
|
||||
"leptos",
|
||||
"leptos_axum",
|
||||
"leptos_meta",
|
||||
"leptos_router",
|
||||
"log",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"sqlx",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
|
|
18
Cargo.toml
18
Cargo.toml
|
@ -20,8 +20,14 @@ wasm-bindgen = "=0.2.93"
|
|||
thiserror = "1"
|
||||
tracing = { version = "0.1", optional = true }
|
||||
http = "1"
|
||||
sqlx = { version = "0.8.1", features = ["postgres", "runtime-tokio", "tls-rustls-ring"], optional = true }
|
||||
sqlx = { version = "0.8.1", features = ["postgres", "runtime-tokio", "tls-rustls-ring", "uuid"], optional = true }
|
||||
anyhow = "1.0.86"
|
||||
log = { version = "0.4.22", optional = true }
|
||||
env_logger = { version = "0.11.5", optional = true }
|
||||
rust-embed = { version = "8.5.0", optional = true }
|
||||
uuid = { version = "1.10.0", features = ["serde", "v4"] }
|
||||
serde = { version = "1.0.209", features = ["derive"] }
|
||||
tokio-stream = { version = "0.1.15", optional = true, features = ["full"] }
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
|
@ -35,8 +41,16 @@ ssr = [
|
|||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
"dep:tracing",
|
||||
"dep:sqlx"
|
||||
"dep:sqlx",
|
||||
"dep:log",
|
||||
"dep:env_logger",
|
||||
"dep:rust-embed",
|
||||
"dep:tokio-stream"
|
||||
]
|
||||
log = ["dep:log"]
|
||||
env_logger = ["dep:env_logger"]
|
||||
rust-embed = ["dep:rust-embed"]
|
||||
tokio-stream = ["dep:tokio-stream"]
|
||||
|
||||
# Defines a size-optimized profile for the WASM bundle in release mode
|
||||
[profile.wasm-release]
|
||||
|
|
|
@ -14,7 +14,11 @@ services:
|
|||
# size: 134217728 # 128*2^20 bytes = 128Mb
|
||||
volumes:
|
||||
- watch_data:/var/lib/postgres/data
|
||||
ports:
|
||||
- 5432:5432
|
||||
environment:
|
||||
POSTGRES_DB: watch
|
||||
POSTGRES_USER: watch
|
||||
POSTGRES_PASSWORD: watch
|
||||
|
||||
adminer:
|
||||
|
|
6
migrations/20240902212954_add-series.sql
Normal file
6
migrations/20240902212954_add-series.sql
Normal file
|
@ -0,0 +1,6 @@
|
|||
create table if not exists "public"."series" (
|
||||
"id" uuid default gen_random_uuid() not null primary key,
|
||||
"name" text not null,
|
||||
"created" timestamptz default now() not null,
|
||||
"updated" timestamptz default now() not null
|
||||
);
|
63
src/app.rs
63
src/app.rs
|
@ -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) => {
|
||||
<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! {
|
||||
<div><ul>
|
||||
{
|
||||
data.unwrap_or_default().into_iter().map(|d| view!{
|
||||
<li>{d}</li>
|
||||
}).collect::<Vec<_>>()
|
||||
}
|
||||
</ul></div>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
|
31
src/main.rs
31
src/main.rs
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue