pub struct Runtime { /* private fields */ }Expand description
A minimal runtime that executes CRUD operations against a SQLite database based on a manifest contract.
In WAL mode SQLite allows one writer and multiple concurrent readers. This struct exploits that by keeping a single write connection behind a mutex and a pool of read-only connections that can be acquired in parallel, so read operations never block on (or are blocked by) writes.
Implementations§
Source§impl Runtime
impl Runtime
Sourcepub fn open(db_path: &str, manifest: AppManifest) -> Result<Self, RuntimeError>
pub fn open(db_path: &str, manifest: AppManifest) -> Result<Self, RuntimeError>
Open a runtime against an existing SQLite database.
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. 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 runtime (useful for tests and benchmarks).
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.
Sourcepub fn read_pool_size(&self) -> usize
pub fn read_pool_size(&self) -> usize
Return the number of read connections in the pool (0 for in-memory DBs).
Sourcepub fn crdt_store(&self) -> &LoroStore
pub fn crdt_store(&self) -> &LoroStore
Borrow the CRDT store. Tests use this to inspect cache state and the WS handler will use it to fetch snapshots on subscribe.
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.
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);