Extending the Schema
Reading and writing tables and RPCs a deployment adds on top of Scout's
Extending the schema
Scout models its own tables as Rust structs, but the transport underneath is generic. A
deployment that adds tables or PostgREST functions defines plain serde structs and reaches them
through ScoutDbClient, which ScoutClient::get_db_client exposes.
Remote tables
query, query_one, insert, insert_bulk, upsert_bulk, update and delete are generic
over any Serialize/Deserialize type, so an added table needs no changes to the crate.
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct FieldNote {
id: Option<i64>,
herd_id: i64,
body: String,
}
let db = client.get_db_client()?;
let notes: Vec<FieldNote> = db
.query(|rest| {
rest.from("field_notes")
.select("*")
.eq("herd_id", herd_id.to_string())
})
.await?;Remote RPCs
rpc calls any function the deployment exposes and deserializes the result; rpc_execute
discards it, which is what a function returning void needs. Both name the function in their
error and report the message from a PostgREST error body where there is one.
let notes: Vec<FieldNote> = db
.rpc(
"field_notes_for_herd",
&serde_json::json!({ "herd_id_caller": herd_id }),
)
.await?;
db.rpc_execute("archive_field_notes", &serde_json::json!({ "herd_id": herd_id }))
.await?;What is not extensible
The sync engine's embedded database holds Scout's own models only. Its model set is fixed at the
versions Scout ships so that a database written by an older build still opens, and flush pushes
a fixed tree to the remote database: sessions, then their connectivity, events, operators and
artifacts, then tags and sensor poses.
A deployment that needs its own local persistence keeps it outside the sync engine and pushes it
through ScoutDbClient.