vantage-vista 2.2.2

Universal, schema-bearing data handle for the Vantage data framework
Documentation
# 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:

```rust
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:

```rust
use vantage_vista::VistaFactory;

let products = factory.from_yaml(include_str!("products.yaml"))?;
```

A driver author wraps a shell directly:

```rust
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

```rust
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: `Condition`s (`column <op> value`), a search text, an order
(`(column, SortDirection)`) and the keys of any driver-native conditions. Build one and apply it:

```rust
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:

```rust
let rows = pastries.list_values().await?;
let total = pastries.count().await?;
let page = pastries.fetch_window(40, 20).await?;   // page.rows, page.total
```

The 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

```rust
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:

```rust
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:

```rhai
let due = table("order").where("status", "due");
due.ref("client").list()
```

`table(name)` returns a handle that narrows (`where`, `sort`, `search`, `limit`, `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](https://vantage-ui.com/book/rhai.html) 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-memory `TableShell` for tests and examples.
  Enable it from `[dev-dependencies]`.
- `rhai`: the `rhai` module (`DataVocab`, the table handle, script-slot evaluators,
  `run_script`). Backends add their vendor expression vocabulary through
  `TableShell::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`:

```rust
use vantage_vista::mocks::MockShell;

let users = Vista::new("user", MockShell::new().with_record("u1", record));
```

## Integration

- vantage-dataset: the `ValueSet` traits `Vista` implements
- vantage-types: the `Record<V>` carrier
- vantage-core: `Result` / `VantageError`
- vantage-rhai: the script host behind the `rhai` feature
- vantage-diorama: the `Lens`/`Dio` cache and the sceneries that sit on a `Vista`