Rust API Reference
Complete reference for the Stoolap Rust API (stoolap crate).
[dependencies]
stoolap = "0.4"
Database
The Database struct is the main entry point. It is thread-safe and can be shared across threads via cloning.
Opening a Database
use stoolap::Database;
// In-memory (unique instance per call)
let db = Database::open_in_memory()?;
// In-memory (shared instance, same DSN returns same engine)
let db = Database::open("memory://")?;
// File-based (persistent)
let db = Database::open("file:///path/to/database")?;
// File-based with configuration
let db = Database::open("file:///path/to/db?sync=full&checkpoint_interval=60")?;
open_in_memory() creates a unique, isolated instance each time. open("memory://") returns the same shared engine for the same DSN. Each open returns a new session on that engine, with its own transaction state, like clone(). The engine closes when the last handle on it drops, or on close(). An open Transaction counts as a handle: it keeps the engine open until it commits, rolls back or drops.
Connection String Options
| Parameter | Default | Description |
|---|---|---|
sync / sync_mode |
normal |
Sync mode: none, normal, full (or 0, 1, 2) |
checkpoint_interval |
60 |
Seconds between automatic checkpoint cycles |
compact_threshold |
4 |
Sub-target volumes per table before merging |
keep_snapshots |
3 |
Backup snapshots to retain per table |
wal_flush_trigger |
32768 |
WAL flush trigger size in bytes |
wal_buffer_size |
65536 |
WAL buffer size in bytes |
wal_max_size |
67108864 |
Max WAL file size before rotation (64 MB) |
commit_batch_size |
100 |
Commits to batch before syncing (normal mode) |
sync_interval_ms |
1000 |
Minimum ms between syncs (normal mode) |
wal_compression |
on |
LZ4 compression for WAL entries |
compression |
– | Alias that sets both wal_compression and volume_compression |
compression_threshold |
64 |
Minimum bytes before compressing an entry |
volume_compression |
on |
LZ4 compression for cold volume files |
checkpoint_on_close |
on |
Seal all hot rows to volumes on clean shutdown |
target_volume_rows |
1048576 |
Target rows per cold volume. Controls compaction split boundary. |
execute()
Execute DDL or DML statements. Returns the number of rows affected.
use stoolap::params;
// DDL, no parameters
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)", ())?;
// DML with tuple parameters
db.execute("INSERT INTO users VALUES ($1, $2, $3)", (1, "Alice", 30))?;
// DML with params! macro
db.execute("INSERT INTO users VALUES ($1, $2, $3)", params![2, "Bob", 25])?;
// Returns rows affected
let affected = db.execute("UPDATE users SET name = $1 WHERE id = $2", ("Charlie", 1))?;
For an UPDATE, the rows affected are the rows the WHERE clause matched, whether or not the SET changed them.
execute_counts()
Execute a statement and return two counts: matched, the rows affected as execute() reports them, and changed, the matched rows whose SET gave a column a value different from the one it held. For any statement other than UPDATE, changed equals matched. A statement with RETURNING answers with its rows instead, and both counts are 0, as execute() returns 0 for it. Statement and Transaction have the same method.
db.execute("INSERT INTO users VALUES ($1, $2, $3)", (3, "Dana", 41))?;
// Alice already has age 30, Dana changes from 41 to 30
let counts = db.execute_counts("UPDATE users SET age = 30 WHERE id IN (1, 3)", ())?;
assert_eq!(counts.matched, 2);
assert_eq!(counts.changed, 1);
query()
Execute a SELECT query and iterate over results.
// Iterate rows
for row in db.query("SELECT * FROM users", ())? {
let row = row?;
let id: i64 = row.get(0)?;
let name: String = row.get_by_name("name")?;
}
// With parameters
for row in db.query("SELECT * FROM users WHERE age > $1", (18,))? {
let row = row?;
// ...
}
// Collect into Vec
let users: Vec<_> = db.query("SELECT * FROM users", ())?
.collect::<Result<Vec<_>, _>>()?;
query_one()
Return a single value. Errors if no rows are returned.
let count: i64 = db.query_one("SELECT COUNT(*) FROM users", ())?;
let name: String = db.query_one("SELECT name FROM users WHERE id = $1", (1,))?;
query_opt()
Return an optional single value. Returns None if no rows match.
let name: Option<String> = db.query_opt("SELECT name FROM users WHERE id = $1", (999,))?;
match name {
Some(n) => println!("Found: {}", n),
None => println!("Not found"),
}
Named Parameters
Use :name syntax with named_params! macro or the NamedParams builder. A name the statement reads and the call does not give is an error, as a missing positional parameter is; see Parameter Binding.
use stoolap::named_params;
// Execute with named params
db.execute_named(
"INSERT INTO users VALUES (:id, :name, :age)",
named_params!{ id: 1, name: "Alice", age: 30 }
)?;
// Query with named params
for row in db.query_named(
"SELECT * FROM users WHERE age > :min_age",
named_params!{ min_age: 25 }
)? {
// ...
}
// Query single value with named params
let count: i64 = db.query_one_named(
"SELECT COUNT(*) FROM users WHERE age > :min_age",
named_params!{ min_age: 18 }
)?;
// Builder API (alternative to macro)
use stoolap::NamedParams;
let params = NamedParams::new()
.add("id", 1)
.add("name", "Alice")
.add("age", 30);
db.execute_named("INSERT INTO users VALUES (:id, :name, :age)", params)?;
Timeout Methods
Cancel queries that exceed a time limit. Timeout is in milliseconds; use 0 for no timeout.
A connection can also carry a timeout for every statement whose call sets none, with PRAGMA query_timeout = ms or the connection string’s query_timeout. The timeout a call passes is used instead; a call that passes 0 gets the connection’s.
- A call has one deadline, fixed when the call starts. Its subqueries and views, and a query run again because a
TRUNCATEorDROPovertook it, share that deadline. - The rows a query returns keep the deadline while you read them, and the time between two reads counts toward it.
- An
INSERT,UPDATE,DELETEorCOPYthat the deadline stops changes no row, the rows its foreign key actions reach included. Inside a transaction the statement is undone and the transaction stays open. - Cancellation is cooperative. A query stops at its next check, which its loops make every few thousand rows they read, and returns
Error::QueryCancelled. A wait for a lock, file I/O and a user function are not interrupted, and a table-valued function such asgenerate_seriesmakes all its rows before they are checked. A sort that has started runs to its end; the deadline is checked before and after it.
// Execute with 5 second timeout
db.execute_with_timeout("DELETE FROM large_table WHERE old = true", (), 5000)?;
// Query with 10 second timeout
for row in db.query_with_timeout("SELECT * FROM large_table", (), 10000)? {
let row = row?;
// ...
}
Struct Mapping with FromRow
Map query results directly to structs.
use stoolap::{Database, FromRow, ResultRow, Result};
struct User {
id: i64,
name: String,
email: Option<String>,
}
impl FromRow for User {
fn from_row(row: &ResultRow) -> Result<Self> {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
email: row.get(2)?,
})
}
}
// Query and map to structs
let users: Vec<User> = db.query_as("SELECT id, name, email FROM users", ())?;
// With named params
let users: Vec<User> = db.query_as_named(
"SELECT id, name, email FROM users WHERE id = :id",
named_params!{ id: 1 }
)?;
Cached Plans
Parse SQL once and execute many times with zero cache-lookup overhead.
// Create a cached plan (parse once)
let insert_plan = db.cached_plan("INSERT INTO users VALUES ($1, $2, $3)")?;
// Execute many times (no parsing, no cache lookup)
db.execute_plan(&insert_plan, (1, "Alice", 30))?;
db.execute_plan(&insert_plan, (2, "Bob", 25))?;
// Query with cached plan
let query_plan = db.cached_plan("SELECT * FROM users WHERE id = $1")?;
let rows = db.query_plan(&query_plan, (1,))?;
// Named params with cached plan
let plan = db.cached_plan("INSERT INTO users VALUES (:id, :name, :age)")?;
db.execute_named_plan(&plan, named_params!{ id: 3, name: "Charlie", age: 35 })?;
let rows = db.query_named_plan(
&db.cached_plan("SELECT * FROM users WHERE id = :id")?,
named_params!{ id: 3 }
)?;
Utility Methods
// Close the database (releases file lock immediately)
db.close()?;
// Check if a table exists
if db.table_exists("users")? {
// ...
}
// Get the DSN this database was opened with
let dsn = db.dsn(); // "memory://" or "file:///path"
// Set this handle's isolation level (same as SET isolation_level):
// begin(), BEGIN and autocommit statements on this handle use it
use stoolap::IsolationLevel;
db.set_default_isolation_level(IsolationLevel::SnapshotIsolation)?;
// Create a point-in-time snapshot (for file-based databases)
db.create_snapshot()?;
// Semantic cache stats
let stats = db.semantic_cache_stats()?;
println!("Hits: {}, Subsumption: {}", stats.hits, stats.subsumption_hits);
// Clear the semantic cache
db.clear_semantic_cache()?;
Prepared Statements
Prepare a statement for repeated execution with different parameters. The SQL is validated at prepare time.
// Prepare once
let stmt = db.prepare("SELECT * FROM users WHERE id = $1")?;
// Execute multiple times
for id in 1..=10 {
for row in stmt.query((id,))? {
let row = row?;
// ...
}
}
// Single value
let name: String = stmt.query_one((1,))?;
// Optional value
let name: Option<String> = stmt.query_opt((999,))?;
// DML prepared statement
let insert = db.prepare("INSERT INTO users VALUES ($1, $2, $3)")?;
insert.execute((1, "Alice", 30))?;
insert.execute((2, "Bob", 25))?;
// Get the SQL text
assert_eq!(insert.sql(), "INSERT INTO users VALUES ($1, $2, $3)");
Statement holds a weak reference to the Database. It becomes invalid after the Database is dropped.
Transactions
Programmatic API
// Begin at this handle's isolation level (ReadCommitted unless set)
let mut tx = db.begin()?;
// Begin with specific isolation level
use stoolap::IsolationLevel;
let mut tx = db.begin_with_isolation(IsolationLevel::SnapshotIsolation)?;
// Execute within transaction
tx.execute("INSERT INTO users VALUES ($1, $2, $3)", (1, "Alice", 30))?;
tx.execute("UPDATE accounts SET balance = balance - $1 WHERE id = $2", (100, 1))?;
// Query within transaction (sees uncommitted changes)
for row in tx.query("SELECT * FROM users", ())? {
let row = row?;
// ...
}
// Single value query
let count: i64 = tx.query_one("SELECT COUNT(*) FROM users", ())?;
// Optional value query
let name: Option<String> = tx.query_opt("SELECT name FROM users WHERE id = $1", (999,))?;
// Named parameters
tx.execute_named(
"INSERT INTO users VALUES (:id, :name, :age)",
named_params!{ id: 3, name: "Charlie", age: 35 }
)?;
for row in tx.query_named(
"SELECT * FROM users WHERE age > :min_age",
named_params!{ min_age: 25 }
)? {
let row = row?;
// ...
}
// Commit or rollback
tx.commit()?;
// Or: tx.rollback()?;
Transactions auto-rollback on drop if not committed. A transaction keeps its database open, so it can still commit after the last Database handle drops. After an explicit close(), its commit() returns Error::EngineNotOpen and nothing is written.
Prepared Statements in Transactions
A statement prepared on the database runs inside a transaction with execute_in and query_in. It keeps its parsed plan and the compiled fast paths (primary key lookups, INSERT) that it has outside a transaction.
// Prepare once (via Database)
let insert = db.prepare("INSERT INTO users VALUES ($1, $2, $3)")?;
let mut tx = db.begin()?;
for (id, name, age) in data {
insert.execute_in(&mut tx, (id, name, age))?;
}
tx.commit()?;
Query with a prepared statement inside a transaction:
let lookup = db.prepare("SELECT * FROM users WHERE id = $1")?;
let mut tx = db.begin()?;
// Reads within the transaction see uncommitted changes
let rows = lookup.query_in(&mut tx, (42,))?;
tx.commit()?;
Named parameters use execute_named_in and query_named_in:
let insert = db.prepare("INSERT INTO users VALUES (:id, :name, :age)")?;
let mut tx = db.begin()?;
insert.execute_named_in(&mut tx, named_params!{ id: 1, name: "Alice", age: 30 })?;
insert.execute_named_in(&mut tx, named_params!{ id: 2, name: "Bob", age: 25 })?;
tx.commit()?;
// Query variant
let lookup = db.prepare("SELECT * FROM users WHERE id = :id")?;
let mut tx = db.begin()?;
let rows = lookup.query_named_in(&mut tx, named_params!{ id: 1 })?;
tx.commit()?;
SQL text passed to tx.execute and tx.query is parsed once and kept in the same plan cache as the database’s own statements, so repeating it inside a transaction does not parse it again. A transaction runs SELECT, INSERT, UPDATE, DELETE and savepoint statements; other statements return Error::NotSupported.
tx.execute_prepared and tx.query_prepared take a parsed parser::ast::Statement rather than a prepared Statement, and run without a cached plan. They take positional values only and check them against the count the parser wrote on the statement before it runs; for named values, prepare the SQL and use execute_named_in / query_named_in.
SQL-based Transactions
db.execute("BEGIN", ())?;
db.execute("INSERT INTO users VALUES ($1, $2)", (1, "Alice"))?;
db.execute("COMMIT", ())?;
// Or: db.execute("ROLLBACK", ())?;
Savepoints
db.execute("BEGIN", ())?;
db.execute("INSERT INTO users VALUES ($1, $2)", (1, "Alice"))?;
db.execute("SAVEPOINT sp1", ())?;
db.execute("INSERT INTO users VALUES ($1, $2)", (2, "Bob"))?;
db.execute("ROLLBACK TO SAVEPOINT sp1", ())?; // Undo Bob
db.execute("RELEASE SAVEPOINT sp1", ())?; // Release savepoint
db.execute("COMMIT", ())?; // Only Alice is inserted
The same statements work on a Transaction:
let mut tx = db.begin()?;
tx.execute("SAVEPOINT sp1", ())?;
tx.execute("INSERT INTO users VALUES ($1, $2)", (2, "Bob"))?;
tx.execute("ROLLBACK TO SAVEPOINT sp1", ())?;
tx.execute("RELEASE SAVEPOINT sp1", ())?;
tx.commit()?;
RELEASE also drops every savepoint opened after the named one; ROLLBACK TO drops the later ones and keeps its own. See Savepoints for the full rules.
Isolation Levels
// Programmatic
let mut tx = db.begin_with_isolation(IsolationLevel::SnapshotIsolation)?;
// SQL-based
db.execute("BEGIN TRANSACTION ISOLATION LEVEL SNAPSHOT", ())?;
// Set the default for this handle's new transactions and autocommit statements
db.set_default_isolation_level(IsolationLevel::SnapshotIsolation)?;
The default belongs to the handle: a clone, or the same DSN opened again, keeps its own.
The Rust API has two enum variants: ReadCommitted (default) and SnapshotIsolation. At the SQL level, SNAPSHOT, SERIALIZABLE, REPEATABLE READ all map to SnapshotIsolation, and READ UNCOMMITTED maps to ReadCommitted.
Working with Rows
Rows Iterator
query() returns a Rows struct that implements Iterator<Item = Result<ResultRow>>.
let mut rows = db.query("SELECT * FROM users", ())?;
// Column metadata
let columns: &[String] = rows.columns();
let count: usize = rows.column_count();
// Iterate
for row in rows {
let row = row?;
// ...
}
// Or collect
let all: Vec<ResultRow> = db.query("SELECT * FROM users", ())?.collect_vec()?;
Zero-Clone Cursor
For bulk serialization, advance() / current_row() avoids per-row cloning.
let mut rows = db.query("SELECT * FROM users", ())?;
while rows.advance() {
let row: &Row = rows.current_row();
// Access row by reference, no clone
if let Some(value) = row.get(0) {
// ...
}
}
ResultRow Accessors
let row = db.query("SELECT id, name, active FROM users", ())?
.next().unwrap()?;
// By index (0-based)
let id: i64 = row.get(0)?;
// By column name (case-insensitive)
let name: String = row.get_by_name("name")?;
// Optional values (for nullable columns)
let active: Option<bool> = row.get_by_name("active")?;
// Raw Value access
let value: Option<&Value> = row.get_value(0);
// NULL check
if row.is_null(2) {
println!("active is NULL");
}
// Metadata
let columns: &[String] = row.columns();
let len: usize = row.len();
let empty: bool = row.is_empty();
// Get underlying Row
let inner: &Row = row.as_row();
let owned: Row = row.into_inner();
Type Conversions (FromValue, reading)
Types you can use with row.get::<T>():
| SQL Type | Rust Type |
|---|---|
| INTEGER | i64, i32, f64, bool, String, Value |
| FLOAT | f64, i64, i32, String, Value |
| TEXT | String, Value |
| BOOLEAN | bool, Value |
| TIMESTAMP | String (ISO format), Value |
| JSON | String, Value |
| NULL | Option<T> for any supported T |
Parameter Types (ToParam, writing)
Types you can pass as SQL parameters:
| Rust Type | SQL Value |
|---|---|
i8, i16, i32, i64 |
INTEGER |
u8, u16, u32, usize |
INTEGER |
f32, f64 |
FLOAT |
bool |
BOOLEAN |
&str, String, Arc<str> |
TEXT |
DateTime<Utc> |
TIMESTAMP |
Value |
as-is |
Option<T> |
T or NULL |
Tuple parameters support up to 12 elements. For more, use params![] macro or Vec<Value>.
Error Handling
use stoolap::{Database, Error};
match db.execute("INSERT INTO users VALUES (1, 'Alice')", ()) {
Ok(affected) => println!("Inserted {} rows", affected),
Err(e) => {
let msg = e.to_string();
if msg.contains("UNIQUE constraint") {
println!("Duplicate key");
} else if msg.contains("write-write conflict") {
println!("Transaction conflict, retry");
} else {
return Err(e.into());
}
}
}
Thread Safety
Database is Send + Sync. Clone to share across threads. Each clone has its own executor with independent transaction state but shares the same storage engine.
Threads may also share one handle. Its statements run at the same time while the handle has no open transaction. BEGIN, COMMIT, ROLLBACK, SET, PRAGMA and EXPLAIN wait for the running statements and run alone, as does every statement while a transaction is open, since those statements run inside that transaction. A multi-statement string runs as a whole. Its statements are separated by ;: a token after a whole statement that is not ; is a parse error, so SELECT id FROM t WHERE s ~ 'a' fails at ~ instead of running ~ 'a' as a second statement.
use std::sync::Arc;
use std::thread;
let db = Arc::new(Database::open("memory://")?);
db.execute("CREATE TABLE counter (id INTEGER PRIMARY KEY, value INTEGER)", ())?;
db.execute("INSERT INTO counter VALUES (1, 0)", ())?;
let handles: Vec<_> = (0..4).map(|_| {
let db = Arc::clone(&db);
thread::spawn(move || {
for _ in 0..100 {
db.execute("UPDATE counter SET value = value + 1 WHERE id = 1", ()).unwrap();
}
})
}).collect();
for h in handles {
h.join().unwrap();
}
let count: i64 = db.query_one("SELECT value FROM counter WHERE id = 1", ())?;
Complete Example
use stoolap::{Database, FromRow, ResultRow, Result, named_params, params};
struct User {
id: i64,
name: String,
email: Option<String>,
}
impl FromRow for User {
fn from_row(row: &ResultRow) -> Result<Self> {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
email: row.get(2)?,
})
}
}
fn main() -> Result<()> {
let db = Database::open("file:///tmp/myapp.db")?;
// Schema
db.execute("
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name TEXT NOT NULL,
email TEXT,
created_at TIMESTAMP DEFAULT NOW()
)
", ())?;
db.execute("CREATE INDEX IF NOT EXISTS idx_email ON users(email)", ())?;
// Batch insert with cached plan
let plan = db.cached_plan("INSERT INTO users (name, email) VALUES ($1, $2)")?;
db.execute_plan(&plan, ("Alice", "alice@example.com"))?;
db.execute_plan(&plan, ("Bob", "bob@example.com"))?;
// Query with struct mapping
let users: Vec<User> = db.query_as("SELECT id, name, email FROM users", ())?;
for user in &users {
println!("{}: {} ({:?})", user.id, user.name, user.email);
}
// Aggregation
let count: i64 = db.query_one("SELECT COUNT(*) FROM users", ())?;
println!("Total users: {}", count);
// Window function
for row in db.query("
SELECT name, ROW_NUMBER() OVER (ORDER BY created_at) as row_num
FROM users
", ())? {
let row = row?;
let name: String = row.get_by_name("name")?;
let num: i64 = row.get_by_name("row_num")?;
println!("{}: {}", num, name);
}
db.close()?;
Ok(())
}
Method Reference
Database
| Method | Returns | Description |
|---|---|---|
open(dsn) |
Result<Database> |
Open or reuse a database by DSN |
open_in_memory() |
Result<Database> |
Open a unique in-memory database |
execute(sql, params) |
Result<i64> |
Execute DDL/DML, return rows affected |
query(sql, params) |
Result<Rows> |
Execute SELECT, return row iterator |
query_one(sql, params) |
Result<T> |
Query single value |
query_opt(sql, params) |
Result<Option<T>> |
Query optional value |
execute_named(sql, params) |
Result<i64> |
Execute with named params |
query_named(sql, params) |
Result<Rows> |
Query with named params |
query_one_named(sql, params) |
Result<T> |
Single value with named params |
query_as(sql, params) |
Result<Vec<T>> |
Query and map to structs |
query_as_named(sql, params) |
Result<Vec<T>> |
Map to structs with named params |
execute_with_timeout(sql, params, ms) |
Result<i64> |
Execute with timeout |
query_with_timeout(sql, params, ms) |
Result<Rows> |
Query with timeout |
cached_plan(sql) |
Result<CachedPlanRef> |
Create a cached execution plan |
execute_plan(plan, params) |
Result<i64> |
Execute cached plan |
query_plan(plan, params) |
Result<Rows> |
Query with cached plan |
execute_named_plan(plan, params) |
Result<i64> |
Execute cached plan with named params |
query_named_plan(plan, params) |
Result<Rows> |
Query cached plan with named params |
prepare(sql) |
Result<Statement> |
Create a prepared statement |
begin() |
Result<Transaction> |
Begin transaction at this handle’s isolation level |
begin_with_isolation(level) |
Result<Transaction> |
Begin with isolation level |
close() |
Result<()> |
Close database, release file lock |
table_exists(name) |
Result<bool> |
Check if table exists |
dsn() |
&str |
Get the DSN |
set_default_isolation_level(level) |
Result<()> |
Set this handle’s isolation level (same as SET isolation_level) |
create_snapshot() |
Result<()> |
Create point-in-time snapshot |
semantic_cache_stats() |
Result<Stats> |
Get cache statistics |
clear_semantic_cache() |
Result<()> |
Clear query cache |
Statement
| Method | Returns | Description |
|---|---|---|
execute(params) |
Result<i64> |
Execute DML |
query(params) |
Result<Rows> |
Query rows |
query_one(params) |
Result<T> |
Single value |
query_opt(params) |
Result<Option<T>> |
Optional value |
execute_named(params) |
Result<i64> |
Execute with named params |
query_named(params) |
Result<Rows> |
Query with named params |
execute_in(tx, params) |
Result<i64> |
Execute DML inside a transaction |
query_in(tx, params) |
Result<Rows> |
Query rows inside a transaction |
execute_named_in(tx, params) |
Result<i64> |
Execute inside a transaction with named params |
query_named_in(tx, params) |
Result<Rows> |
Query inside a transaction with named params |
sql() |
&str |
Get the SQL text |
Transaction
| Method | Returns | Description |
|---|---|---|
execute(sql, params) |
Result<i64> |
Execute DML |
query(sql, params) |
Result<Rows> |
Query rows |
query_one(sql, params) |
Result<T> |
Single value |
query_opt(sql, params) |
Result<Option<T>> |
Optional value |
execute_named(sql, params) |
Result<i64> |
Execute with named params |
query_named(sql, params) |
Result<Rows> |
Query with named params |
execute_prepared(ast, params) |
Result<i64> |
Execute a parsed AST statement |
query_prepared(ast, params) |
Result<Rows> |
Query with a parsed AST statement |
commit() |
Result<()> |
Commit |
rollback() |
Result<()> |
Rollback |
id() |
i64 |
Transaction ID |
Rows
| Method | Returns | Description |
|---|---|---|
next() |
Option<Result<ResultRow>> |
Iterator next |
advance() |
bool |
Zero-clone cursor advance |
current_row() |
&Row |
Current row reference |
columns() |
&[String] |
Column names |
column_count() |
usize |
Number of columns |
rows_affected() |
i64 |
DML rows affected |
collect_vec() |
Result<Vec<ResultRow>> |
Collect all rows |
close() |
() |
Close result set |
ResultRow
| Method | Returns | Description |
|---|---|---|
get(index) |
Result<T> |
Value by column index |
get_by_name(name) |
Result<T> |
Value by column name |
get_value(index) |
Option<&Value> |
Raw Value reference |
is_null(index) |
bool |
Check if NULL |
columns() |
&[String] |
Column names |
len() |
usize |
Number of columns |
is_empty() |
bool |
Empty check |
as_row() |
&Row |
Reference to inner Row |
into_inner() |
Row |
Consume into Row |