- Add `publish_key()` default method to `Query` trait (returns `None`) - Add `mutation_exec!` macro for SQLite INSERT/UPDATE/DELETE ops; overrides `publish_key()` so the mutation carries its own invalidation key - Add `Store::exec()` which runs a mutation and auto-publishes its key — action handlers no longer need a separate `store.publish()` call - Add `PgQuery` trait + `pg_query_one!` / `pg_query_all!` macros (feature-gated on `pg_replication`) mirroring the SQLite Query API - Add `cx.run_pg(pool, query)` to `RenderContext` which executes a PgQuery and auto-subscribes its cache key — no more manual `cx.subscribe()` calls - Update todo example: replace plain mutation fns with `mutation_exec!` structs and `store.exec()` calls; remove `action_then_publish` helper - Update pg_replication example: add `ListMessages` via `pg_query_all!` and replace manual subscribe + raw query with `cx.run_pg()` https://claude.ai/code/session_01HXe8rAZPweU9j2piBo9MdG
82 lines
2.4 KiB
Rust
82 lines
2.4 KiB
Rust
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 (mutation structs via mutation_exec!)
|
|
// ---------------------------------------------------------------------------
|
|
//
|
|
// Each mutation struct implements Query with publish_key() set to the cache
|
|
// key it invalidates. Use Store::exec() in action handlers — it executes the
|
|
// mutation and publishes the key automatically.
|
|
|
|
/// Insert a new todo.
|
|
pub struct CreateTodo {
|
|
pub title: String,
|
|
}
|
|
|
|
livevue_rs::mutation_exec!(CreateTodo {
|
|
sql: "INSERT INTO todos (title, completed) VALUES (?, false)",
|
|
params: [|s: &CreateTodo| s.title.clone()],
|
|
publish: |_| CacheKey::Table { table: "todos" },
|
|
});
|
|
|
|
/// Toggle a todo's completed status.
|
|
pub struct ToggleTodo {
|
|
pub id: i64,
|
|
}
|
|
|
|
livevue_rs::mutation_exec!(ToggleTodo {
|
|
sql: "UPDATE todos SET completed = NOT completed WHERE id = ?",
|
|
params: [|s: &ToggleTodo| s.id],
|
|
publish: |_| CacheKey::Table { table: "todos" },
|
|
});
|
|
|
|
/// Delete a todo by id.
|
|
pub struct DeleteTodo {
|
|
pub id: i64,
|
|
}
|
|
|
|
livevue_rs::mutation_exec!(DeleteTodo {
|
|
sql: "DELETE FROM todos WHERE id = ?",
|
|
params: [|s: &DeleteTodo| s.id],
|
|
publish: |_| CacheKey::Table { table: "todos" },
|
|
});
|