Rust Live Queries
Use KalamLinkClient::live() to receive materialized row snapshots. The SDK merges inserts, updates, and deletes; your async loop handles rows, server errors, transport failures, and shutdown.
Prepare the live-query example
Create app.live_messages with the shared inbox schema. Use the same authenticated identity for the subscriber and the test writes because this is a USER table.
Run the Rust inbox
Save this as src/main.rs, then run cargo run. It loads a fresh snapshot, prints each current row list, and waits for changes until Ctrl+C. Credentials come from the local terminal; use your application’s authentication strategy for deployment.
Handle each outcome deliberately
Result of live.next() | Meaning | Example behavior |
|---|---|---|
Some(Ok(LiveRowsEvent::Rows { .. })) | Current rows, including an empty snapshot | Replace/print the list |
Some(Ok(LiveRowsEvent::Error { .. })) | Server subscription error with a code | Report it and exit cleanly |
Some(Err(error)) | SDK/transport failure | Return the error after closing |
None | Stream ended | Report unexpected termination |
event? alone does not handle LiveRowsEvent::Error: that variant is inside Ok. Keep both error paths. The first-row deadline applies only to startup; a quiet inbox after loading is normal. live.close() runs after success or loop failure, and disconnect() runs even if subscription setup fails.
This CLI deliberately exits on reported errors. A long-running service can reopen after correcting the cause, using bounded backoff for retryable failures. Do not spin on invalid SQL or denied access, and do not start a second subscription while the first is still owned by another loop.
Verify changes and cleanup
Run the test insert, update, and delete one at a time using the same identity. On a fresh table, expect empty → one message → edited message → empty. The whole current list prints after each change; this is not an append-only event stream.
Press Ctrl+C and confirm the process exits. Temporarily use a missing table to exercise server errors. Stop the server to exercise transport recovery or failure handling. After restarting the example, it obtains a new snapshot with the current rows.
Options and recovery
Use live_with_config(config, LiveRowsConfig { limit: Some(100), ..Default::default() }) to cap the direct materializer’s retained rows. SubscriptionOptions::with_last_rows(100) restricts the starting history; it is separate from retention and snapshot batch_size. The complete inbox above leaves these unset so it can show every matching row.
Keep the SQL in SELECT ... FROM ... WHERE ... form; no joins, aggregates, ORDER BY, or LIMIT. Include the primary key. Sort for presentation if needed. For raw events, use live_events().
The shared connection manages reconnects. Durable resume requires cached state and a checkpoint belonging to the same query and identity. Do not save only the cursor and later expect a full list from an empty materializer. Replay is bounded; follow the WebSocket recovery contract for gaps and expired cursors.
More examples
The repository also includes a self-contained live-inbox smoke example that creates a temporary table, inserts a row, and cleans it up. Its table setup differs from the long-running inbox above.