Expand description
§Vantage Vista
Vista is the type-erased Table<T, E>. It takes a typed table, the kind a model layer defines
(bakery_model3::Product::sqlite_table(), vantage_aws::models::ecs::clusters_table()), and seals
its types behind a TableShell, so generic code (a CLI, a desktop UI, a config-driven dashboard)
can drive any backend through one handle. Rows travel as CBOR (ciborium::Value) and ids as
String, whatever the backend stores natively.
The shape is the same as Table’s: Vista is Clone, owns its query state, narrows with
with_* and changes in place with add_*/set_*.
§Three kinds of object
Every public type in Vantage above Table is one of three kinds, and its API follows from the
kind. A value (Table, Vista, VistaQuery, Reference) is narrowed by
clone().with_*(), which returns a new value and leaves the original alone, and changes through
add_*/set_* only when you own it (&mut self). A shared handle (diorama’s Lens and
Dio) never changes after construction: with_* derives a new handle. View state (diorama’s
sceneries and Servo) is opened by a builder and changed with set_* by its single owner. This
crate holds only values; the other two kinds live in vantage-diorama.
§Examples
§Build a Vista
A driver factory turns a typed table into a Vista:
use vantage_sql::sqlite::vista::SqliteVistaFactory;
let products = SqliteVistaFactory::new(db.clone()).from_table(Product::sqlite_table(db))?;from_table consumes the typed table and gives a Vista that knows its columns, references, id
column and the backend’s capabilities. The schema is fixed from there; Vista has no
add_column.
With no Rust entity for the table, the same factory builds one from a YAML spec:
use vantage_vista::VistaFactory;
let products = factory.from_yaml(include_str!("products.yaml"))?;A driver author wraps a shell directly:
use vantage_vista::{TableShell, Vista};
let vista = Vista::new("product", MyShell::new(conn));VistaFactory and TableShell are imported from the crate root, not the prelude: only driver
code and spec loaders name them.
§Narrow
use vantage_vista::prelude::*;
let pastries = products
.clone()
.with_condition("category", FilterOp::Eq, "pastries")?
.with_order("price", SortDirection::Descending)?;
let mut cheap = products.clone();
cheap.add_condition("price", FilterOp::Lt, 5)?;
cheap.set_search(Some("tart"))?;products is untouched by both. Each clause is offered to the shell first and recorded only once
the shell accepts it, so pastries.query() is a VistaQuery holding exactly what was applied. A
clause the backend can’t take is refused with an Unsupported error naming the Capability it
lacks. An unknown column is a plain error, so a typo is never mistaken for a missing feature.
§A query as a value
VistaQuery is plain data: Conditions (column <op> value), a search text, an order
((column, SortDirection)) and the keys of any driver-native conditions. Build one and apply it:
let query = VistaQuery::new()
.with_condition(Condition::new("category", FilterOp::Eq, "pastries"))
.with_order("price", SortDirection::Ascending);
let (pastries, residual) = products.clone().with_query(&query)?;residual holds the clauses the shell refused. A caller that needs every clause applied checks
it is empty; a cache or a client-side refine evaluates it over the rows itself, with
residual.matches(&row, &metadata) and residual.sort_rows(&mut rows, &metadata) (the evaluator
documented in vantage_vista::eval).
query.key() is a stable string for cache identity.
§Read and write
Vista implements ValueSet, ReadableValueSet, WritableValueSet and InsertableValueSet,
the same trait family Table<T, E> does:
let rows = pastries.list_values().await?;
let total = pastries.count().await?;
let page = pastries.fetch_window(40, 20).await?; // page.rows, page.totalThe leading window (fetch_window(0, n)) works on every shell. Any other offset needs
Capability::Window; a forward-only backend offers fetch_cursor under Capability::Cursor.
A write through a narrowed Vista needs Capability::ConfineWrites, so it can’t land outside the
set.
§Capabilities
let caps = products.capabilities();
if caps.has(Capability::Insert) { /* show "+ New" */ }
if caps.has(Capability::Order) { /* render sortable headers */ }
if caps.has(Capability::Search) { /* render the quicksearch box */ }
if caps.has(Capability::Subscribe) { /* follow products.watch() */ }Each Capability names exactly one method family, and a shell that advertises one must answer it
without refusing; the contract feature checks that. A read-only AWS API and a writable SQLite
table look the same from outside; the set tells the UI which controls to draw.
§Catalog and resolvers
VistaResolver is the one way to turn a name into a Vista: a model in a catalog, a relation’s
target, a table a script names. Any Fn(&str) -> Result<Vista> is one. Catalog maps model names
to loaders, which may sit on different backends, and is itself a resolver:
use vantage_vista::Catalog;
let catalog = Catalog::new()
.with("client", |name: &str| clients_vista(name))
.with("order", |name: &str| orders_vista(name));
let orders = catalog.vista("order")?;A name the resolver doesn’t know is not_found; a loader that fails for another reason keeps its
own error kind, so a caller can tell a missing model from an unreachable one. Within one backend,
vista.get_ref("orders", Some(&row)) traverses a declared reference; across backends, narrow the
catalog’s target with reference.narrow(catalog.vista(&reference.target)?, &row).
§Scripting with Rhai
The rhai feature adds the rhai module and its DataVocab, the one data vocabulary every
Vantage script uses:
let due = table("order").where("status", "due");
due.ref("client").list()table(name) returns a handle that narrows (where, sort, search, limit, offset, ref) and then
reads (list, get, first, count, ids), writes (insert, upsert, patch, delete,
import_from) or opens a record draft. A host picks the tables behind table(name) and which
verbs exist. The full guide is Scripting with Rhai in the
Vantage book.
§Why not a stateless shell?
A shell that held no query, with every read taking a VistaQuery, would make Vista a thin
wrapper and drivers simpler. It was considered and rejected: Vista would stop matching
Table<T, E>, which owns its conditions, and code written against the dataset traits would need a
query threaded through every call. The cost of the path taken is that a driver’s shell is Clone
and carries its narrowing, and a clone must not share it.
§Prelude
use vantage_vista::prelude::*; brings in Vista, VistaQuery, Condition, FilterOp,
SortDirection, Capability, VistaResolver, CborValue, and the vantage-dataset traits that
Vista implements (ValueSet, ReadableValueSet, WritableValueSet, InsertableValueSet).
Everything else is reached from the crate root: VistaFactory and TableShell for driver
authors, Catalog, Column, Reference, Page, VistaMetadata. VistaCapabilities is what
vista.capabilities() returns.
§Features
mocks:vantage_vista::mocks::MockShell, an in-memoryTableShellfor tests and examples. Enable it from[dev-dependencies].rhai: therhaimodule (DataVocab, the table handle, script-slot evaluators,run_script). Backends add their vendor expression vocabulary throughTableShell::register_rhai_extensions.contract:vantage_vista::contract, the driver-facing checks every backend’s test suite runs against its own fixture. Enable it from[dev-dependencies].
A test Vista over MockShell:
use vantage_vista::mocks::MockShell;
let users = Vista::new("user", MockShell::new().with_record("u1", record));§Integration
- vantage-dataset: the
ValueSettraitsVistaimplements - vantage-types: the
Record<V>carrier - vantage-core:
Result/VantageError - vantage-rhai: the script host behind the
rhaifeature - vantage-diorama: the
Lens/Diocache and the sceneries that sit on aVista
Modules§
- eval
- Evaluating a
VistaQueryover rows held in memory. - prelude
- What nearly every user of vantage-vista writes.
Macros§
- forward_
table_ shell - Implement
TableShellfor$ty, whose$fieldholds the inner shell (anything that derefs to aTableShell, usually aBox<dyn TableShell>).$tymust beClone; its clone carries the inner shell’s clone, narrowing included.
Structs§
- Catalog
- A map from model name to the loader that builds it.
- Column
- Display-relevant column metadata held by a
Vista. - Column
Spec - Per-column metadata in a
VistaSpec. - Committed
- What a successful commit reports.
- Condition
column <op> value. Equality isFilterOp::Eq.- Contained
Yaml - YAML shape of a contained relation — embedded records stored in a column of
the parent row. Mirrors
ReferenceSpecbut carries the contained record’s own column schema (built via the driver’sbuild_column) instead of a foreign key. - JoinKey
- One condition a join contributes: read the parent row’s
fromcolumn and constrain the target’stocolumn to that value. - Native
Condition - A condition in a driver’s own type (a SurrealDB expression, a BSON
document), passed through vista unread, with a
keynaming it. - NoExtras
- Empty extras placeholder. Serializes as an absent key.
- Page
- One window of rows, in the set’s order, and the set’s total row count
when the fetch learned it.
Nonemeans the fetch didn’t say, never zero. - Preview
- The query a shell would send for its next read, rendered without sending it. A debugging surface: it must not show a clause the shell wouldn’t send.
- Reference
- A relation a Vista exposes: a join to another table, or records contained
in a column of this table’s rows. Traversed with
Vista::get_ref. - Reference
Spec - Top-level reference declaration in a
VistaSpec. - ShortId
- A short random id: a fixed length over a fixed alphabet.
- Transaction
- A unit of work shared by every backend it touches. Commit runs backend by backend, so it’s atomic per backend, not across them: if one fails part-way, the backends before it stay committed and the rest roll back.
- TxKey
- Identifies a participant within one transaction by the address of a token the caller keeps alive (typically the connection it belongs to).
- TxOpen
- The begun transaction’s handle, locked. A plain
MutexGuard, not a mapped one: tokio’sMappedMutexGuardisSendonly under a lifetime bound the compiler can’t prove inside the async fns that hold it. - TxSlot
- Vista
- Universal, schema-bearing data handle: the type-erased
Table<T, E>. - Vista
Capabilities - The set of capabilities a shell advertises.
- Vista
Metadata - Schema a
Vistais built around. - Vista
Query - Every clause applied through a
Vista: its conditions, search and order, plus the keys of its driver-native conditions (NativeCondition::key). A native condition itself is opaque, so only its key is recorded, and aVistaQuerythat holds native keys can’t be re-applied to another Vista. - Vista
Spec - The YAML schema a vista is built from.
- Weak
Transaction - A
Transactionhandle that doesn’t keep it alive.
Enums§
- Capability
- One method family of
TableShellthat a shell may or may not implement. - Column
Family - The family of a column’s declared type.
- Column
Flag - A flag on a
Column. - Filter
Op - A comparison operator. The scalar operators mirror the query-builder
vocabulary the SQL and SurrealDB expression layers already expose
(
eq/ne/gt/…);InSet/NotInSettest membership against a list and carry aciborium::Value::Arrayoperand rather than a scalar. - IdGenerator
- How a missing id is minted when a new record is inserted.
- Reference
Kind - What a relation points at, and how many records it yields.
- Reference
Sugar - Sugar form for inline column references.
- Sort
Direction - Vista
Change - A single change observed on the underlying set by a live subscription.
Traits§
- Clone
Table Shell - Boxed cloning for
TableShell, soBox<dyn TableShell>isClone. EveryTableShell + Clonehas it; a shell implementsCloneand gets this for free. The trait is sealed: a clone must come fromClone, so it carries the shell’s narrowing. - Spec
Resolver - Looks up a spec by vista name. Factories hold it as
Arc<dyn SpecResolver<S>>and hand clones into each reference, so a child table is rebuilt from the current spec at traversal time. AnyFn(&str) -> Option<S>closure is a resolver. - Table
Shell - The driver side of a
Vista: schema, reads, narrowing and writes over one table of one backend. - TxBackend
- What a
TxSlotneeds from a backend. Errors come back already worded (couldn't begin the transaction,transaction commit failed, …). - TxParticipant
- One backend’s share of a transaction, finished together with the others.
- Vista
Factory - Factory that produces
Vistainstances from configuration sources. - Vista
Resolver - Builds the
Vistaa name stands for: a model in aCatalog, a relation’s bare target, a table a script names.
Functions§
- build_
contained_ vista - Build a sub-
Vistaover the recordsreferenceembeds inhost_value. - cant_
take_ part - The refusal of a table whose shell can’t rebind to a transaction. Marked
Unsupported:Transaction::wraprenames anyUnsupportedrebind refusal to the wrapped Vista’s name. - condition_
column_ error - The error for a condition on
column, which the shell doesn’t take as one of its own columns. - direct
shell, taking part in a transaction by writing outside it: a write through the wrapped Vista lands at once, stays after a rollback, and is reported inCommitted::unprotected.- operand_
text - A
FilterOp::Likeoperand as the text it matches against — the one spelling every side of the comparison uses, so a pattern pushed into a query and the same pattern evaluated locally read the operand alike. - resolve_
base_ spec - Resolve the spec a
base:vista derives from. Errors when no resolver is attached or the base isn’t known to it. - unknown_
relation - The error for a relation a shell doesn’t declare, marked
not_foundso a caller can tell a missing relation from one that fails to traverse. - unsupported
- The refusal of a method whose capability the shell doesn’t have: an
Unsupportederror naming the capability. Default trait methods answer with it; a caller probing a capability reads it as “no”, not as a fault.
Type Aliases§
- Cbor
Value - Convenience alias for the carrier type used at the
TableShellboundary. - Contained
Writeback - Persists a contained relation’s collection back into the parent row.
- Vista
Change Stream - A stream of
VistaChanges from a live subscription.'staticandSendso it can be handed to a background task.