use livevue_rs::CacheKey; use serde::{Deserialize, Serialize}; // --------------------------------------------------------------------------- // Models // --------------------------------------------------------------------------- /// A single todo item. Maps to the `todos` SQLite table. #[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)] pub struct Todo { pub id: i64, pub title: String, pub completed: bool, } // --------------------------------------------------------------------------- // Read queries (go through cx.run / Query trait) // --------------------------------------------------------------------------- /// Fetch all todos, ordered by id. pub struct ListTodos; livevue_rs::query_all!(ListTodos { sql: "SELECT id, title, completed FROM todos ORDER BY id", params: [], output: Todo, cache: |_s: &ListTodos| CacheKey::Table { table: "todos" }, }); /// Fetch a single todo by id. pub struct GetTodo { pub id: i64, } livevue_rs::query_one!(GetTodo { sql: "SELECT id, title, completed FROM todos WHERE id = ?", params: [|s: &GetTodo| s.id], output: Todo, cache: |s: &GetTodo| CacheKey::PrimaryKey { table: "todos", id: s.id }, }); // --------------------------------------------------------------------------- // Write operations (plain sqlx, not through Query trait) // --------------------------------------------------------------------------- // // Mutations don't go through cx.run() because they're not reads and don't // produce subscription keys. They're called directly by action handlers, // which then trigger a full rerender. /// Insert a new todo. Returns the new row's id. pub async fn create_todo(db: &sqlx::SqlitePool, title: &str) -> anyhow::Result { let result = sqlx::query("INSERT INTO todos (title, completed) VALUES (?, false)") .bind(title) .execute(db) .await?; Ok(result.last_insert_rowid()) } /// Toggle a todo's completed status. pub async fn toggle_todo(db: &sqlx::SqlitePool, id: i64) -> anyhow::Result<()> { sqlx::query("UPDATE todos SET completed = NOT completed WHERE id = ?") .bind(id) .execute(db) .await?; Ok(()) } /// Delete a todo by id. pub async fn delete_todo(db: &sqlx::SqlitePool, id: i64) -> anyhow::Result<()> { sqlx::query("DELETE FROM todos WHERE id = ?") .bind(id) .execute(db) .await?; Ok(()) }