Skip to main content

Crate improv_storage_sql

Crate improv_storage_sql 

Source
Expand description

SQL connectivity (Phase 7): import external SQL query results into an Improv Model, and export a measure’s cells back to a SQL table.

Design invariants (see .agent/steering/AGENT_DATABASE_CONNECTIVITY.md §7):

  • Storage separation. External SQL is a data source/sink; the canonical model lives in Mentat. Import produces ordinary categories/items/measures/ input cells — the engine gains no SQL-specific paths and stays deterministic.
  • Security. An import/refresh query must be a single SELECT/WITH statement (check_read_only_sql), and every backend runs it read-only (Postgres and DuckDB in a READ ONLY transaction, DuckDB with external access off; SQLite only if the statement is read-only). Data values are bound as parameters, never interpolated. Postgres has no TLS in this build, so connect_postgres refuses a non-loopback host unless the connection string says sslmode=disable.

Testing Postgres: the live tests skip unless IMPROV_TEST_PG holds a libpq DSN to a scratch database they may create/drop tables in, e.g. IMPROV_TEST_PG="host=127.0.0.1 user=improv password=improv dbname=improv_test" cargo test -p improv_storage_sql.

Backends sit behind a common Backend enum (backend module): SQLite (the reference driver, and what the embedded Mentat store already uses) and Postgres. Both produce a common typed backend::Table, so the column→model mapping below is backend-agnostic. Connections are described out of band by conn::Connection (no plaintext secrets) and opened via conn::open.

Re-exports§

pub use backend::Backend;
pub use backend::Cell;
pub use backend::SqlConn;
pub use backend::Table;
pub use conn::ConnKind;
pub use conn::Connection;
pub use duck::connect_duckdb;
pub use pg::connect_postgres;

Modules§

backend
Backend abstraction over SQL drivers.
conn
Connection descriptors with credentials handled out of band.
duck
DuckDB backend (embedded, via the duckdb crate with the bundled feature so no system libduckdb is required).
pg
Postgres backend (synchronous postgres crate).

Structs§

DimensionMapping
ImportSpec
How to map a query’s result columns onto model elements.

Enums§

SqlError

Functions§

add_sql_measure
Register an SQL-backed input measure (records its SqlSource on the model) and populate it by running the query once. The measure’s categories must already exist or be creatable from the import; this is a convenience over import_query that also marks the measure as SQL-backed so it can be refreshed later.
check_read_only_sql
Reject anything that is not a single read statement.
export_measure
Write a measure’s input cells to a SQL table: one column per dimension category (item name), plus a value column. Creates the table if missing and inserts one row per cell. Values are bound as parameters (no interpolation).
import_query
Import the result of spec.query into model as a new input measure over the mapped dimension categories. Distinct dimension-column values become items (interned by their string form). Returns the number of cells imported.
refresh_sql_measure
Refresh an SQL-backed measure: re-run its stored query and replace its input cells with the fresh result. New dimension values become new items. The measure must have a SqlSource (added via add_sql_measure).

Type Aliases§

Result