pub struct Runtime { /* private fields */ }Expand description
A manifest-driven runtime that executes CRUD operations against an underlying data store. Two backends are supported:
- SQLite (default): single-process, file-or-memory, with a write mutex + read pool, FTS5 search, and per-row LoroDoc CRDT snapshots.
- Postgres: live cluster, suitable for multi-replica deployments.
Routes entity CRUD through
pylon_storage::pg_datastore::PostgresDataStore. CRDT mode and FTS5-shaped search are SQLite-only at this layer; the Postgres backend returnsNOT_SUPPORTEDfor those paths and the router degrades to JSON change events (no binary CRDT broadcasts).
Pick a backend by passing a postgres:// URL to Runtime::open; any
other string is treated as a SQLite filesystem path.
Implementations§
Source§impl Runtime
impl Runtime
Sourcepub fn open(url: &str, manifest: AppManifest) -> Result<Self, RuntimeError>
pub fn open(url: &str, manifest: AppManifest) -> Result<Self, RuntimeError>
Open a runtime against either a SQLite file path or a Postgres URL.
Backend selection is by URL prefix:
postgres://...orpostgresql://...→ Postgres (requires thepostgres-livefeature onpylon-storage, enabled by default).- Anything else → SQLite, treating the string as a filesystem path
(
":memory:"works viaRuntime::in_memoryinstead).
Sourcepub fn open_postgres(
url: &str,
manifest: AppManifest,
) -> Result<Self, RuntimeError>
pub fn open_postgres( url: &str, manifest: AppManifest, ) -> Result<Self, RuntimeError>
Open a runtime backed by a live Postgres cluster.
Schema must be applied separately via pylon migrate / the
storage adapter’s plan apply path — Runtime does not auto-create
tables on Postgres (in contrast to SQLite, where from_connection
runs CREATE TABLE IF NOT EXISTS on every open). This matches how
production Postgres deployments are typically managed: schema is
migrated via a controlled, observable step, not as a side effect
of the server starting up.
Sourcepub fn is_in_memory(&self) -> bool
pub fn is_in_memory(&self) -> bool
Returns true if this runtime is backed by an in-memory SQLite DB.
Stored at open time rather than queried via conn.path() because
the path-based check conflates “no filename” with “in-memory”:
Connection::open("") yields a file-backed DB with empty path,
and would falsely pass as in-memory. Since we always know at
construction time which constructor was used, track the bit.
Gates the test-reset endpoint — a false positive here would let
/api/__test__/reset truncate real tables.
Sourcepub fn db_path(&self) -> Option<String>
pub fn db_path(&self) -> Option<String>
Filesystem path to the SQLite database, if this runtime is file-backed.
Returns None for in-memory runtimes AND Postgres runtimes (no local
file). Used by the server bootstrap to derive companion paths
(session store, change log persistence) without requiring the caller
to pass them in.
Sourcepub fn reset_for_tests(&self) -> Result<(), RuntimeError>
pub fn reset_for_tests(&self) -> Result<(), RuntimeError>
Drop every row from every entity table. Intended for test harnesses
that call /api/__test__/reset between cases; refuses to run on
anything but an in-memory database.
Does NOT drop the tables themselves — schema stays, indexes stay, triggers stay. Just truncates user data + the change log.
Sourcepub fn in_memory(manifest: AppManifest) -> Result<Self, RuntimeError>
pub fn in_memory(manifest: AppManifest) -> Result<Self, RuntimeError>
Create an in-memory SQLite-backed runtime (useful for tests and
benchmarks). For Postgres-backed equivalents, use open_postgres
with a test-cluster URL.
Sourcepub fn ensure_search_indexes(&self) -> Result<(), RuntimeError>
pub fn ensure_search_indexes(&self) -> Result<(), RuntimeError>
Create the search index tables (_facet_bitmap, per-entity
_fts_<Entity>, and a covering index for each declared
sortable field) for every searchable entity in the manifest.
Production deployments do this via the storage adapter’s
apply_schema / migration plan; that path also handles
adding/removing the tables when a search: block is added or
removed across deploys. This method is a quick path for tests
and benchmarks that build a Runtime::in_memory(...) directly
without going through the schema-plan pipeline.
Sourcepub fn manifest(&self) -> &AppManifest
pub fn manifest(&self) -> &AppManifest
Return a reference to the app manifest.
Sourcepub fn lock_conn_pub(&self) -> Result<MutexGuard<'_, Connection>, RuntimeError>
pub fn lock_conn_pub(&self) -> Result<MutexGuard<'_, Connection>, RuntimeError>
Expose the write connection mutex for transactional operations.
SQLite-only — Postgres mode returns NOT_SQLITE_BACKEND. Callers
that need a transaction on Postgres should use [Runtime::transact_ops]
(via the DataStore trait), which routes to a real Postgres
transaction inside PostgresDataStore.
Sourcepub fn read_pool_size(&self) -> usize
pub fn read_pool_size(&self) -> usize
Return the number of read connections in the pool. Always 0 for
in-memory SQLite (pool is empty by design) and for Postgres mode
(the pool concept doesn’t apply — PostgresDataStore manages its
own connection internally).
Sourcepub fn is_postgres(&self) -> bool
pub fn is_postgres(&self) -> bool
Return true if this runtime is backed by Postgres. Useful for SQLite-only fast-paths to early-exit cleanly.
Sourcepub fn crdt_store(&self) -> &LoroStore
pub fn crdt_store(&self) -> &LoroStore
Borrow the CRDT store. SQLite-only — Postgres mode does not yet support per-row CRDT snapshots at the runtime layer (CRDT broadcasts degrade to JSON change events).
§Panics
Panics on Postgres backend. Call sites that may run under either
backend should branch on is_postgres() first.
Sourcepub fn insert(&self, entity: &str, data: &Value) -> Result<String, RuntimeError>
pub fn insert(&self, entity: &str, data: &Value) -> Result<String, RuntimeError>
Insert a new row. Returns the generated ID.
For entities with crdt: true (the default) the LoroDoc snapshot
- the SQLite materialized row are committed together in a single
SQLite transaction so a crash between the two leaves neither.
crdt: falseentities skip the LoroDoc and use a direct write (legacy LWW path). Both produce the same on-disk row shape, so reads, indexes, FTS, and policies don’t change between modes.
Sourcepub fn get_by_id(
&self,
entity: &str,
id: &str,
) -> Result<Option<Value>, RuntimeError>
pub fn get_by_id( &self, entity: &str, id: &str, ) -> Result<Option<Value>, RuntimeError>
Get a single row by ID.
Sourcepub fn list(&self, entity: &str) -> Result<Vec<Value>, RuntimeError>
pub fn list(&self, entity: &str) -> Result<Vec<Value>, RuntimeError>
List all rows for an entity.
Sourcepub fn list_after(
&self,
entity: &str,
after: Option<&str>,
limit: usize,
) -> Result<Vec<Value>, RuntimeError>
pub fn list_after( &self, entity: &str, after: Option<&str>, limit: usize, ) -> Result<Vec<Value>, RuntimeError>
List rows after a cursor ID (for cursor-based pagination).
Sourcepub fn update(
&self,
entity: &str,
id: &str,
data: &Value,
) -> Result<bool, RuntimeError>
pub fn update( &self, entity: &str, id: &str, data: &Value, ) -> Result<bool, RuntimeError>
Update a row by ID. Returns true if a row was found and updated.
For entities with crdt: true (the default) the LoroDoc receives
the patch first; the SQLite UPDATE writes the same fields so the
materialized view stays in lockstep with the doc state.
Sourcepub fn delete(&self, entity: &str, id: &str) -> Result<bool, RuntimeError>
pub fn delete(&self, entity: &str, id: &str) -> Result<bool, RuntimeError>
Delete a row by ID. Returns true if a row was actually deleted.
Sourcepub fn lookup(
&self,
entity: &str,
field: &str,
value: &str,
) -> Result<Option<Value>, RuntimeError>
pub fn lookup( &self, entity: &str, field: &str, value: &str, ) -> Result<Option<Value>, RuntimeError>
Lookup a single row by a field value (e.g., email).
Sourcepub fn link(
&self,
entity: &str,
id: &str,
relation: &str,
target_id: &str,
) -> Result<bool, RuntimeError>
pub fn link( &self, entity: &str, id: &str, relation: &str, target_id: &str, ) -> Result<bool, RuntimeError>
Link two entities by setting a foreign-key field.
Sourcepub fn unlink(
&self,
entity: &str,
id: &str,
relation: &str,
) -> Result<bool, RuntimeError>
pub fn unlink( &self, entity: &str, id: &str, relation: &str, ) -> Result<bool, RuntimeError>
Unlink a relation by setting the foreign-key field to null.
Sourcepub fn query_filtered(
&self,
entity: &str,
filter: &Value,
) -> Result<Vec<Value>, RuntimeError>
pub fn query_filtered( &self, entity: &str, filter: &Value, ) -> Result<Vec<Value>, RuntimeError>
Execute a filtered query with operators ($not, $gt, $in, $like, $order, $limit).
Sourcepub fn query_graph(&self, query: &Value) -> Result<Value, RuntimeError>
pub fn query_graph(&self, query: &Value) -> Result<Value, RuntimeError>
Execute a graph-style query.
Input: { "User": { "where": { "email": "..." }, "include": { "posts": {} } } }
Returns nested results following relations.
Sourcepub fn insert_with_conn(
&self,
conn: &Connection,
entity: &str,
data: &Value,
) -> Result<String, RuntimeError>
pub fn insert_with_conn( &self, conn: &Connection, entity: &str, data: &Value, ) -> Result<String, RuntimeError>
Insert using an already-locked connection (for transactions).
Sourcepub fn update_with_conn(
&self,
conn: &Connection,
entity: &str,
id: &str,
data: &Value,
) -> Result<bool, RuntimeError>
pub fn update_with_conn( &self, conn: &Connection, entity: &str, id: &str, data: &Value, ) -> Result<bool, RuntimeError>
Update using an already-locked connection (for transactions).
Sourcepub fn delete_with_conn(
&self,
conn: &Connection,
entity: &str,
id: &str,
) -> Result<bool, RuntimeError>
pub fn delete_with_conn( &self, conn: &Connection, entity: &str, id: &str, ) -> Result<bool, RuntimeError>
Delete using an already-locked connection (for transactions).
Sourcepub fn get_by_id_with_conn(
&self,
conn: &Connection,
entity: &str,
id: &str,
) -> Result<Option<Value>, RuntimeError>
pub fn get_by_id_with_conn( &self, conn: &Connection, entity: &str, id: &str, ) -> Result<Option<Value>, RuntimeError>
Read a row by id using a pre-held connection (for transactions).
Sourcepub fn list_with_conn(
&self,
conn: &Connection,
entity: &str,
) -> Result<Vec<Value>, RuntimeError>
pub fn list_with_conn( &self, conn: &Connection, entity: &str, ) -> Result<Vec<Value>, RuntimeError>
List rows using a pre-held connection (for transactions).
Sourcepub fn list_after_with_conn(
&self,
conn: &Connection,
entity: &str,
after: Option<&str>,
limit: usize,
) -> Result<Vec<Value>, RuntimeError>
pub fn list_after_with_conn( &self, conn: &Connection, entity: &str, after: Option<&str>, limit: usize, ) -> Result<Vec<Value>, RuntimeError>
List after cursor using a pre-held connection (for transactions).
Sourcepub fn lookup_with_conn(
&self,
conn: &Connection,
entity: &str,
field: &str,
value: &str,
) -> Result<Option<Value>, RuntimeError>
pub fn lookup_with_conn( &self, conn: &Connection, entity: &str, field: &str, value: &str, ) -> Result<Option<Value>, RuntimeError>
Lookup by field using a pre-held connection (for transactions).
Sourcepub fn link_with_conn(
&self,
conn: &Connection,
entity: &str,
id: &str,
relation: &str,
target_id: &str,
) -> Result<bool, RuntimeError>
pub fn link_with_conn( &self, conn: &Connection, entity: &str, id: &str, relation: &str, target_id: &str, ) -> Result<bool, RuntimeError>
Link relation using a pre-held connection (for transactions).
Sourcepub fn unlink_with_conn(
&self,
conn: &Connection,
entity: &str,
id: &str,
relation: &str,
) -> Result<bool, RuntimeError>
pub fn unlink_with_conn( &self, conn: &Connection, entity: &str, id: &str, relation: &str, ) -> Result<bool, RuntimeError>
Unlink relation using a pre-held connection (for transactions).
Sourcepub fn query_filtered_with_conn(
&self,
conn: &Connection,
entity: &str,
filter: &Value,
) -> Result<Vec<Value>, RuntimeError>
pub fn query_filtered_with_conn( &self, conn: &Connection, entity: &str, filter: &Value, ) -> Result<Vec<Value>, RuntimeError>
Query with filters using a pre-held connection (for transactions).
Shares the filter-building logic with [query_filtered] by executing
against the provided connection rather than acquiring one.
Sourcepub fn query_graph_with_conn(
&self,
conn: &Connection,
query: &Value,
) -> Result<Value, RuntimeError>
pub fn query_graph_with_conn( &self, conn: &Connection, query: &Value, ) -> Result<Value, RuntimeError>
Graph query using a pre-held connection (for transactions).
Sourcepub fn aggregate(
&self,
entity: &str,
spec: &Value,
) -> Result<Value, RuntimeError>
pub fn aggregate( &self, entity: &str, spec: &Value, ) -> Result<Value, RuntimeError>
Run an aggregation query. See pylon_http::DataStore::aggregate
for the spec shape.
Sourcepub fn pg_data_store_pub(&self) -> Option<&PostgresDataStore>
pub fn pg_data_store_pub(&self) -> Option<&PostgresDataStore>
Borrow the underlying Postgres DataStore if this runtime is
Postgres-backed. Used by the DataStore adapter in datastore.rs
to delegate transact/search etc. without re-implementing them.
Accessor for the underlying PostgresDataStore. Used by
integration tests to exercise in-tx primitives directly
without going through a TS function handler. Also useful for
callers that need to drop down to raw PG (e.g. running an
EXPLAIN against the live cluster from an admin tool).
Returns None on SQLite-backed runtimes.
Trait Implementations§
Source§impl DataStore for Runtime
impl DataStore for Runtime
Source§fn search(&self, entity: &str, query: &Value) -> Result<Value, DataError>
fn search(&self, entity: &str, query: &Value) -> Result<Value, DataError>
Bridge the typed SearchQuery / SearchResult shapes to the
trait’s JSON-in / JSON-out contract. The router passes a JSON
body; we deserialize, look up the entity’s SearchConfig, run
the planner, and re-serialize. Serialization round-tripping
lets this method live on the DataStore trait without forcing
pylon-http to depend on pylon-storage.
Source§fn crdt_snapshot(
&self,
entity: &str,
row_id: &str,
) -> Result<Option<Vec<u8>>, DataError>
fn crdt_snapshot( &self, entity: &str, row_id: &str, ) -> Result<Option<Vec<u8>>, DataError>
Return the binary CRDT snapshot for a row. Ok(None) for any
entity with crdt: false (the LWW opt-out) — the router uses
that to decide whether to ship a binary update over WebSocket
after the write.
Source§fn crdt_apply_update(
&self,
entity: &str,
row_id: &str,
update: &[u8],
) -> Result<Vec<u8>, DataError>
fn crdt_apply_update( &self, entity: &str, row_id: &str, update: &[u8], ) -> Result<Vec<u8>, DataError>
Client-pushed Loro update. Imports into the row’s LoroDoc, re-projects the doc state into the materialized SQLite columns (so subsequent reads see the merged content), and returns the fresh full-row snapshot for the router to broadcast to other clients.
Wrapped in a single SQLite transaction — same crash-safety
shape as Runtime::insert/update. Either the LoroStore +
SQLite columns both update or neither does.
fn manifest(&self) -> &AppManifest
fn insert(&self, entity: &str, data: &Value) -> Result<String, DataError>
fn get_by_id(&self, entity: &str, id: &str) -> Result<Option<Value>, DataError>
fn list(&self, entity: &str) -> Result<Vec<Value>, DataError>
fn list_after( &self, entity: &str, after: Option<&str>, limit: usize, ) -> Result<Vec<Value>, DataError>
fn update( &self, entity: &str, id: &str, data: &Value, ) -> Result<bool, DataError>
fn delete(&self, entity: &str, id: &str) -> Result<bool, DataError>
fn lookup( &self, entity: &str, field: &str, value: &str, ) -> Result<Option<Value>, DataError>
fn link( &self, entity: &str, id: &str, relation: &str, target_id: &str, ) -> Result<bool, DataError>
fn unlink( &self, entity: &str, id: &str, relation: &str, ) -> Result<bool, DataError>
fn query_filtered( &self, entity: &str, filter: &Value, ) -> Result<Vec<Value>, DataError>
fn query_graph(&self, query: &Value) -> Result<Value, DataError>
Auto Trait Implementations§
impl !Freeze for Runtime
impl RefUnwindSafe for Runtime
impl Send for Runtime
impl Sync for Runtime
impl Unpin for Runtime
impl UnsafeUnpin for Runtime
impl UnwindSafe for Runtime
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);