The codebase is now split into two clear layers: Framework library (src/): - lib.rs — public API surface, re-exports all framework types - signal.rs — SignalOpts, Signal, SignalStore, mangle/global/client_only helpers - query.rs — Query trait, CacheKey, query_one!/query_all! macros (macro paths updated from $crate::framework::* to $crate::*) - context.rs — RenderContext, ComponentTree, ComponentNode - connection.rs — ConnectionManager, SubscriptionRegistry, ConnectionState - sse.rs — format_patch_elements, format_patch_signals - server.rs — AppState, SharedState, sse_handler (pure framework plumbing) Todo example (examples/todo/): - main.rs — SQLite setup, seeding, server bootstrap - app.rs — router, document_shell, resolve_and_render, render_page, action_then_render, and all HTTP handlers - queries.rs — Todo model, ListTodos/GetTodo queries, mutation helpers - todo_list.rs — TodoList page component - about.rs — About page component Run the example independently with: cargo run --example todo https://claude.ai/code/session_01JThiQbp3Bn9J1VhBpRuz4u
65 lines
2.0 KiB
Rust
65 lines
2.0 KiB
Rust
mod app;
|
|
mod queries;
|
|
mod todo_list;
|
|
mod about;
|
|
|
|
use livevue_rs::{AppState, ConnectionManager, SubscriptionRegistry};
|
|
use std::sync::Arc;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> anyhow::Result<()> {
|
|
// -----------------------------------------------------------------------
|
|
// Database setup
|
|
// -----------------------------------------------------------------------
|
|
|
|
// SQLite with create-if-missing. In-memory `:memory:` also works for dev.
|
|
let db = sqlx::SqlitePool::connect("sqlite:todo.db?mode=rwc").await?;
|
|
|
|
// Run migrations inline (no migration files needed for v0).
|
|
sqlx::query(
|
|
"CREATE TABLE IF NOT EXISTS todos (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
title TEXT NOT NULL,
|
|
completed BOOLEAN NOT NULL DEFAULT FALSE
|
|
)",
|
|
)
|
|
.execute(&db)
|
|
.await?;
|
|
|
|
// Seed a few todos if the table is empty (nice for first run)
|
|
let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM todos")
|
|
.fetch_one(&db)
|
|
.await?;
|
|
if count.0 == 0 {
|
|
for title in &["Learn Rust", "Build LiveVue.rs", "Ship v0"] {
|
|
sqlx::query("INSERT INTO todos (title, completed) VALUES (?, false)")
|
|
.bind(title)
|
|
.execute(&db)
|
|
.await?;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Application state
|
|
// -----------------------------------------------------------------------
|
|
|
|
let state = Arc::new(AppState {
|
|
db,
|
|
connections: ConnectionManager::new(),
|
|
subscriptions: SubscriptionRegistry::new(),
|
|
});
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Server
|
|
// -----------------------------------------------------------------------
|
|
|
|
let app = app::router(state);
|
|
|
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
|
println!("Todo example listening on http://localhost:3000");
|
|
|
|
axum::serve(listener, app).await?;
|
|
|
|
Ok(())
|
|
}
|