moondb

API · generated

The interface

192 declarations across 6 packages — the contract and the three drivers that ratify it — read out of pkg.generated.mbti and described from the /// docs in the sources.

moonbitstack/moondb

moondb

Types 13

pub struct ArrayCursor {
  rows : Array[Row]
  mut pos : Int32
}

A [Cursor] over an already-materialised Array[Row]. The fallback the default [Driver::query_stream] hands back for any driver that has not overridden it: it preserves the streaming *interface* (callers pull rows one at a time) even though the rows were fetched up front. The mock driver and the reference query layer test against it.

pub struct AsyncArrayCursor {
  rows : Array[Row]
  mut pos : Int32
}

An [AsyncCursor] over already-materialised rows — the async twin of [ArrayCursor], and what the default [AsyncDriver::query_stream] hands back. It preserves the streaming *interface* (rows are pulled one at a time) even though they were all fetched up front.

It is a separate type from [ArrayCursor] rather than a second trait impl on it: one type implementing both Cursor and AsyncCursor makes every cursor.next() on the concrete type ambiguous between the two traits, which would break existing callers.

pub(open) trait AsyncCursor {
  async fn next(Self) -> Row? raise DbError
  async fn close(Self) -> Unit
}

The async counterpart of [Cursor] — a forward-only cursor whose next is awaited. A wire driver reads the next row off the socket when it is asked for, which is an I/O round trip and therefore async; the synchronous [Cursor] cannot express that, so a networked backend has no way to stream through it.

The resource discipline is [Cursor]'s: MoonBit has no finalizer, so a driver-backed cursor MUST be drained (next until None) or [closed], or the statement leaks and the connection is left mid-result. [AsyncArrayCursor] is the materialised fallback, for a driver with no incremental fetch.

close does not raise, mirroring [Cursor::close]: abandoning a cursor is best-effort. A driver whose close has to do I/O — draining an unread result off the wire — swallows the failure, because a connection whose drain failed is already unusable and the next statement on it will say so.

pub(open) so out-of-tree drivers implement it.

pub(open) trait AsyncDriver {
  async fn execute(Self, String, Array[Value]) -> ExecResult raise DbError
  async fn query(Self, String, Array[Value]) -> Array[Row] raise DbError
  async fn query_stream(Self, String, Array[Value]) -> &AsyncCursor raise DbError = _
  async fn begin(Self) -> Unit raise DbError
  async fn commit(Self) -> Unit raise DbError
  async fn rollback(Self) -> Unit raise DbError
  async fn close(Self) -> Unit
  async fn ping(Self) -> Bool = _
}

The contract a backend that talks over a network implements — [Driver] with every round trip awaited.

## Why there are two driver traits

[Driver] is synchronous, which fits a backend whose calls block in C: moonsqlite steps a prepared statement and returns. A backend reached over TCP cannot be written that way in MoonBit, because the only socket stack (moonbitlang/async) is async-only and an async fn cannot be called from a synchronous one. A wire driver forced to conform to [Driver] can therefore do nothing but raise — and, worse, it raises from ping too, so a [Pool] with pre_ping judges every one of its connections permanently unhealthy.

AsyncDriver is the seam for those backends. It is a peer of [Driver], not a replacement: a synchronous backend keeps implementing [Driver] and does not become async to satisfy anything here. The two traits are deliberately identical method for method, so a query layer can offer a sync and an async path that read the same.

Everything [Driver] documents about the calling convention holds unchanged: sql carries positional placeholders in the backend's own spelling, params supplies one [Value] per placeholder in order, and values are bound out-of-band rather than interpolated.

This trait declares async methods but pulls in no async runtime — moondb stays dependency-free and still compiles on every backend. Only a driver that implements it, and a caller that runs it inside an event loop, need the runtime.

pub(open) so out-of-tree drivers (moonpostgres, moonmysql, …) implement it.

pub(open) trait Cursor {
  fn next(Self) -> Row? raise DbError
  fn close(Self) -> Unit
}

A forward-only cursor over a query's rows — the streaming counterpart to [Driver::query]. Where query materialises the whole result, a cursor yields one [Row] at a time, Python DB-API's fetchone). next advances and returns the next row, or None once the result is exhausted; close releases the cursor early (a driver holding a server-side cursor or prepared statement frees it here). A driver with real incremental fetch — moonsqlite steps its prepared statement, an async driver reads rows off the wire on demand — returns a live cursor; the default [Driver::query_stream] falls back to an [ArrayCursor] over a materialised result, which honours the same interface without the memory bound. A live cursor holds a resource (a prepared statement, a busy connection). MoonBit has no finalizer to reclaim it, so a driver-backed cursor MUST be fully drained (next until None) or closed — abandoning it leaks the statement or leaves the connection mid-result. The materialised [ArrayCursor] holds nothing and is safe to drop. pub(open) so out-of-tree drivers implement it.

pub(all) suberror DbError {
  ConnectError(String)
  QueryError(String)
  TypeError(String)
  Closed
}

A database-layer failure. Every fallible operation on the interface raises this one error type, so a query layer catches a single kind. Kept deliberately few so drivers can classify without a taxonomy:

* ConnectError, opening, attaching, or handshaking a connection failed, or the connection dropped mid-flight. * QueryError — the backend rejected a statement: a prepare/step/bind error, a constraint violation, or a protocol error. Carries the backend's message. * TypeError — a [Row] typed accessor was asked to read a column as a type it does not hold (e.g. int on a Text), or a column index/name that does not exist in the row. * Closed — the connection or statement was used after close. Declared pub(all) so out-of-tree drivers (moonpostgres, moonmysql, …) that live in their own packages can *construct and raise* these cases — a plain pub suberror would let them catch a DbError but not build one.

pub(open) trait Driver {
  fn execute(Self, String, Array[Value]) -> ExecResult raise DbError
  fn query(Self, String, Array[Value]) -> Array[Row] raise DbError
  fn query_stream(Self, String, Array[Value]) -> &Cursor raise DbError = _
  fn begin(Self) -> Unit raise DbError
  fn commit(Self) -> Unit raise DbError
  fn rollback(Self) -> Unit raise DbError
  fn close(Self) -> Unit
  fn ping(Self) -> Bool = _
}

The contract every database backend implements and every query layer is written against — the seam moondb exists to define. Reduced to the smallest set of operations a relational backend must offer. ## The binding contract

execute and query both take (sql, params). sql carries **positional placeholders** and params supplies one [Value] per placeholder, in order. A driver is expected to bind values out-of-band rather than interpolate them into the SQL text. A driver that cannot — the MySQL text protocol has no out-of-band binding until prepared statements land — has to escape for the server's actual sql_mode, and must say so in its own documentation. The placeholder token itself is dialect-specific and chosen by the driver (SQLite/MySQL use ?, PostgreSQL uses $1, $2, …); a query layer that emits SQL for a given backend uses that backend's token. moondb fixes the *calling convention* (ordered params array), not the spelling. * execute runs a statement that returns no rows (INSERT/UPDATE/DELETE/DDL) and reports an [ExecResult]. * query runs a statement that returns rows and materialises every [Row]. * begin / commit / rollback bracket an explicit transaction. Nesting (savepoints), isolation levels, and read-only hints are driver concerns layered on top; the base contract is the three flat operations. * close releases the connection. It does not raise: closing is best-effort and idempotent. This trait is pub(open) so out-of-tree drivers (moonsqlite, moonpostgres, moonmysql, …) can implement it. A future prepared-Stmt handle and a streaming Rows cursor are noted in the README roadmap; v0.1 fixes exactly the operations below so the contract everything pins to stays small and stable.

pub(all) struct ExecResult {
  rows_affected : Int64
  last_insert_id : Int64
} derive(Eq)

The outcome of a non-query statement (INSERT/UPDATE/DELETE/DDL): how many rows it changed and the id of the last inserted row. rows_affected is 64-bit to hold bulk DML counts; last_insert_id is the backend's auto-increment / rowid value and is backend-defined (0 when the statement produced none).

pub(open) trait FromValue {
  fn from_value(Value) -> Self raise DbError
}

The conversions are the ones [Row]'s typed accessors make. A refusal is a TypeError whose message reads after "column N is", such as "Text, not Int".

pub struct MockDriver {
  mut rows : Array[Row]
  mut next_id : Int64
  savepoints : Array[Int32]
  mut closed : Bool
}

A dependency-free, in-memory reference [Driver]. It exists for two reasons: to *prove the interface is implementable* end to end, and to give query layers built on moondb (moonorm and friends) a real test double they can run against with no database and no native backend — it compiles on every target.

It is a deliberately naive echo store, **not** a SQL engine: it does not parse sql. Each execute appends one [Row] built from the bound params (columns named c0, c1, …) and hands back an [ExecResult] with a monotonically increasing last_insert_id; each query returns every stored row. What it *does* model faithfully is the transaction bracket: begin snapshots the store, rollback restores it, commit keeps the changes — so a test can assert real rollback semantics against it.

pub(all) struct Row {
  columns : Array[String]
  values : Array[Value]
} derive(Eq, @debug.Debug)

One row of a result set: the column names in projection order alongside the decoded [Value] for each. columns and values are the same length and are index-aligned — columns[i] names values[i].

This is the shape drivers hand back from [Driver::query] and the shape a query layer decodes. Read cells either positionally ([get]/[int]/…) or by column name ([by_name]/[int_by]/…). The typed accessors *raise* on a type or lookup mismatch rather than returning a sentinel, so a decode bug surfaces as a DbError at the call site instead of silently reading a zero value.

pub(open) trait ToValue {
  fn to_value(Self) -> Value
}

Implemented for the type behind each [Value] case and for T?, where None binds NULL. A type of the program's own implements it to be stored as one of those cases.

pub(all) enum Value {
  Null
  Bool(Bool)
  Int(Int32)
  Int64(Int64)
  Double(Double)
  Text(String)
  Blob(Bytes)
} derive(Eq, @debug.Debug)

A single dialect-neutral database value — the unit of everything that crosses the driver boundary in either direction. Bound parameters travel *in* as Values (never spliced into the SQL string, so binding is injection-safe by construction) and result columns come *back* as Values. Closed sum every backend can map onto its own wire types. Drivers are expected to normalise their column types down to these seven cases; a query layer built on moondb reads them back through [Row]'s typed accessors. * Null — SQL NULL / a missing value. * Bool — a boolean; backends without a native boolean map 0/1. * Int — a 32-bit signed integer. * Int64 — a 64-bit signed integer (rowids, BIGINT, counters). * Double — an IEEE-754 double (REAL / FLOAT8). * Text — a UTF-8 string (TEXT / VARCHAR); dates and times ride here as ISO-8601 text until a dedicated temporal case lands (see the README roadmap). * Blob — an opaque byte string (BLOB / BYTEA).

Functions & methods 42

pub fn ArrayCursor::close(Self) -> Unit

Cursor's close, callable on the value directly.

pub fn ArrayCursor::new(Array[Row]) -> Self

A cursor positioned before the first of rows.

pub fn ArrayCursor::next(Self) -> Row? raise DbError

Cursor's next, callable on the value directly.

pub fn AsyncArrayCursor::new(Array[Row]) -> Self

A cursor positioned before the first of rows.

pub fn DbError::to_string(Self) -> String

A one-line rendering of the error, e.g. QueryError: no such table: hero.

pub fn drain(&Cursor) -> Array[Row] raise DbError

Drain a cursor into an array — the inverse of streaming, for callers that do want every row (and for asserting a cursor yields exactly what query would).

pub fn MockDriver::begin(Self) -> Unit raise DbError

Driver's begin, callable on the value directly.

pub fn MockDriver::close(Self) -> Unit

Driver's close, callable on the value directly.

pub fn MockDriver::commit(Self) -> Unit raise DbError

Driver's commit, callable on the value directly.

pub fn MockDriver::execute(Self, String, Array[Value]) -> ExecResult raise DbError

Driver's execute, callable on the value directly.

pub fn MockDriver::in_transaction(Self) -> Bool

Whether a transaction is currently open (at least one un-committed begin).

pub fn MockDriver::is_closed(Self) -> Bool

Whether the connection has been closed.

pub fn MockDriver::new() -> Self

A fresh, empty mock connection.

pub fn MockDriver::ping(Self) -> Bool

Driver's ping, callable on the value directly.

pub fn MockDriver::query(Self, String, Array[Value]) -> Array[Row] raise DbError

Driver's query, callable on the value directly.

pub fn MockDriver::query_stream(Self, String, Array[Value]) -> &Cursor raise DbError

Driver's query_stream, callable on the value directly.

pub fn MockDriver::rollback(Self) -> Unit raise DbError

Driver's rollback, callable on the value directly.

pub fn MockDriver::row_count(Self) -> Int32

How many rows the store currently holds. A test-facing helper, not part of the [Driver] contract.

pub fn Row::blob(Self, Int32) -> Bytes raise DbError

Read column idx as an opaque blob. Raises TypeError unless the cell is Blob.

pub fn Row::blob_by(Self, String) -> Bytes raise DbError

Read the column named name as an opaque blob.

pub fn Row::bool(Self, Int32) -> Bool raise DbError

Read column idx as a Bool. Raises TypeError unless the cell is Bool.

pub fn Row::bool_by(Self, String) -> Bool raise DbError

Read the column named name as a Bool.

pub fn Row::by_name(Self, String) -> Value?

The [Value] of the column named name, or None if the row has no such column. Names match exactly as the driver reported them (case-sensitive).

pub fn Row::double(Self, Int32) -> Double raise DbError

Read column idx as a Double, widening an integer. Raises TypeError unless the cell is Double, Int, or Int64.

pub fn Row::double_by(Self, String) -> Double raise DbError

Read the column named name as a Double.

pub fn Row::get(Self, Int32) -> Value raise DbError

The raw [Value] at column idx (0-based, projection order). Raises QueryError if idx is out of range.

pub fn Row::index_of(Self, String) -> Int32 raise DbError

Resolve a column name to its index, raising QueryError if absent. The positional accessors are the primitives; the _by-name accessors resolve through this.

pub fn Row::int(Self, Int32) -> Int32 raise DbError

Read column idx as an Int, narrowing an Int64 to its low 32 bits. Raises TypeError unless the cell is Int or Int64.

pub fn Row::int64(Self, Int32) -> Int64 raise DbError

Read column idx as an Int64, widening an Int. Raises TypeError unless the cell is Int or Int64.

pub fn Row::int64_by(Self, String) -> Int64 raise DbError

Read the column named name as an Int64.

pub fn Row::int_by(Self, String) -> Int32 raise DbError

Read the column named name as an Int.

pub fn Row::is_null(Self, Int32) -> Bool raise DbError

Whether column idx is SQL NULL. Raises QueryError if idx is out of range. Call this before a typed accessor when a column is nullable, since the typed accessors treat NULL as a type mismatch.

pub fn Row::is_null_by(Self, String) -> Bool raise DbError

Whether the column named name is SQL NULL. Raises QueryError if the column is absent.

pub fn[T : FromValue] Row::read(Self, Int32) -> T raise DbError

Read column idx as any [FromValue] type, the typed accessors' common form: let age : Int? = row.read(3). A refusal names the column.

pub fn[T : FromValue] Row::read_by(Self, String) -> T raise DbError

Read the column named name as any [FromValue] type.

pub fn Row::text(Self, Int32) -> String raise DbError

Read column idx as text. Raises TypeError unless the cell is Text.

pub fn Row::text_by(Self, String) -> String raise DbError

Read the column named name as text.

pub fn Row::width(Self) -> Int32

The number of columns in the row.

pub fn Value::from_value(Self) -> Self raise DbError

FromValue's from_value, callable on the value directly.

pub fn Value::is_null(Self) -> Bool

Whether this value is SQL NULL.

pub fn Value::kind(Self) -> String

The name of a value's variant ("Null", "Int", "Blob", …). Used to build legible [DbError::TypeError] messages when a typed accessor is asked for the wrong shape.

pub fn Value::to_value(Self) -> Self

ToValue's to_value, callable on the value directly.

moonbitstack/moondb/pool

pool

Types 1

pub struct Pool[D] {
  // private fields
}

A fixed-ceiling connection pool over any [Driver]. Opening a database connection is expensive — a TCP handshake and auth round trip for a networked backend — so a server hands out a small set of connections and reuses them instead of opening one per request. The pool is generic in the concrete driver D rather than holding &Driver trait objects, so acquire gives back the real driver type and a caller keeps access to backend-specific methods (SQLite's exec_script, a driver's prepared-statement handle). new takes a make factory that opens one fresh connection; the pool calls it only when no idle connection is available and the open count is still below max_size. Beyond plain reuse, the pool keeps a connection healthy over its lifetime, before an idle connection is handed back it is probed with [Driver::ping]; a connection that fails the probe is closed and skipped, so a caller never receives a connection the backend has already dropped. * **max lifetime** (max_lifetime_ms) — a connection older than this is retired on acquire and replaced with a fresh one, so long-lived pools recycle connections a load balancer or the server may have aged out. Age is measured with an injected clock, exactly as database/sql swaps nowFunc in tests; the default clock disables the check. * **acquire timeout** (acquire_timeout_ms) — the wait budget an exhausted acquire is allowed. See the note on synchrony below. It is synchronous and single-threaded by design — moondb's base contract is sync, and MoonBit's pure backends have no shared-memory threads — so acquire never truly blocks: nothing else can return a connection while one call waits. A request that finds the pool exhausted therefore fails immediately rather than sleeping; acquire_timeout_ms is carried into that failure's message and is the budget a driver running on an async runtime honours when it layers real waiting on top. Use [try_acquire] for the non-raising "give me one only if free" path. The reuse, ceiling, health, and lifecycle bookkeeping all live here. The counting is moonpool's Pool: live, idle and lent, each lent connection's birth recognised on its way back so max_lifetime counts from creation. So is the optional ward in front of the database: backoff after failed connects, a token bucket spacing reconnections, a breaker, a shedder. This type adds only what needs a driver — opening, closing, probing.

Functions & methods 14

pub fn[D : @moondb.Driver] Pool::acquire(Self[D]) -> D raise @moondb.DbError

Take a connection: reuse an idle one if the pool has a healthy, unexpired one (the common path, avoiding a fresh handshake), otherwise open a new one through make as long as the open count is below max_size.

An idle connection past max_lifetime_ms, or one that fails the [Driver::ping] probe when pre_ping is on, is closed and dropped rather than handed back; the pool then tries the next idle connection or opens a fresh one. Raises QueryError if the pool is exhausted (all max_size connections are checked out), ConnectError if the ward holds back or refuses a new connection, or [Closed] if it has been closed. The caller must return the connection with [release] — or use [with_conn], which does so even on error.

pub fn[D] Pool::acquire_timeout_ms(Self[D]) -> Int64

The configured acquire wait budget in milliseconds (0 = fail immediately).

pub fn[D : @moondb.Driver] Pool::close_all(Self[D]) -> Unit

Close every idle connection and mark the pool closed. Connections still checked out are not touched — each is closed as it is [release]d back. After this, acquire raises Closed. Idempotent.

This is the graceful half of a shutdown: nothing in flight is cut off. To wait for the rest, poll [in_use_count] until it reaches zero — this pool is synchronous, so the waiting belongs to whatever async layer owns it.

pub fn[D] Pool::idle_count(Self[D]) -> Int32

How many connections are currently idle (checked in and reusable).

pub fn[D] Pool::in_use_count(Self[D]) -> Int32

How many connections are checked out right now. A shutdown that wants to wait for borrowed connections to come home polls this after close_all: the close empties the idle set, so what is left is exactly what is still in use.

pub fn[D] Pool::is_closed(Self[D]) -> Bool

Whether [close_all] has been called.

pub fn[D] Pool::max_lifetime_ms(Self[D]) -> Int64

The configured maximum connection lifetime in milliseconds (0 = unlimited).

pub fn[D] Pool::max_size(Self[D]) -> Int32

The pool's ceiling on simultaneously open connections.

pub fn[D] Pool::new(() -> D raise @moondb.DbError, max_size? : Int32, max_lifetime_ms? : Int64, pre_ping? : Bool, acquire_timeout_ms? : Int64, clock? : () -> Int64, ward? : @moonpool.Ward, rand? : () -> Double, cpu? : () -> Int32) -> Self[D] raise @moondb.DbError

Build a pool whose connections come from make. * max_size caps how many connections may be open at once (in use plus idle); it defaults to 10, and must be positive. * max_lifetime_ms retires a connection older than this many milliseconds on acquire (0, the default, means no age limit). Enforcing it requires a real clock; with the default clock every connection reads as age 0. * pre_ping turns on the [Driver::ping] health probe before an idle connection is reused (off by default). * acquire_timeout_ms records the wait budget for an exhausted acquire; 0 (the default) means "fail immediately". In this synchronous pool the wait is always degenerate (see the type doc), so the value serves the error message and an async layer above. * clock returns a monotonically non-decreasing millisecond reading and exists so max_lifetime is testable and portable; it defaults to a constant 0, which disables age-based retirement. * ward is moonpool's, none by default. A ward that times anything needs a real clock. * rand draws from [0, 1) for the ward's breaker and backoff jitter; without it the pool draws from a system-seeded generator. * cpu reads the processor load in thousandths for the ward's shedder; without it the load reads as zero and the shedder never sheds.

pub fn[D] Pool::open_count(Self[D]) -> Int32

How many connections the pool has open in total: those checked out plus those sitting idle. Never exceeds max_size.

pub fn[D] Pool::pre_ping(Self[D]) -> Bool

Whether the pre-ping health probe is enabled.

pub fn[D : @moondb.Driver] Pool::release(Self[D], D) -> Unit

Return a connection to the idle set so a later [acquire] can reuse it, preserving the birth time it was opened with so max_lifetime keeps counting from creation rather than resetting on every checkout. A connection released back into a closed pool is closed immediately rather than pooled, so no handle outlives close_all.

pub fn[D : @moondb.Driver] Pool::try_acquire(Self[D]) -> D? raise @moondb.DbError

Take a connection only if one is immediately available — an idle one or fresh headroom under max_size — returning None instead of raising when the pool is exhausted or its ward says no. This is the non-blocking counterpart of [acquire], so a caller can choose to shed load or retry. Health and lifetime eviction apply exactly as in acquire; a genuine failure while opening a fresh connection (the make factory raising) still propagates.

pub fn[D : @moondb.Driver, R] Pool::with_conn(Self[D], (D) -> R raise @moondb.DbError) -> R raise @moondb.DbError

Run f with a pooled connection, returning it afterwards whether f returns or raises. This is the leak-proof way to use the pool: the release happens on every path, so a raising query never strands a connection checked out.

moonbitstack/moonsqlite

moonsqlite

Types 1

pub struct SqliteDriver {
  handle : Int64
  mut closed : Bool
}

A live connection to a SQLite database. Open it with SqliteDriver::open; it implements @moondb.Driver, so a moondb query layer can drive it directly. The opaque sqlite3* is carried as its pointer bits in handle.

Functions & methods 13

pub fn SqliteCursor::close(Self) -> Unit

@moondb.Cursor's close, callable on the value directly.

pub fn SqliteCursor::next(Self) -> @moondb.Row? raise @moondb.DbError

@moondb.Cursor's next, callable on the value directly.

pub fn SqliteDriver::begin(Self) -> Unit raise @moondb.DbError

@moondb.Driver's begin, callable on the value directly.

pub fn SqliteDriver::close(Self) -> Unit

@moondb.Driver's close, callable on the value directly.

pub fn SqliteDriver::commit(Self) -> Unit raise @moondb.DbError

@moondb.Driver's commit, callable on the value directly.

pub fn SqliteDriver::exec_script(Self, String) -> Unit raise @moondb.DbError

Run a semicolon-separated script (e.g. a schema DDL block) in one call. Unlike execute, this uses SQLite's multi-statement exec path and binds no parameters. Raises @moondb.QueryError with SQLite's message on failure.

pub fn SqliteDriver::execute(Self, String, Array[@moondb.Value]) -> @moondb.ExecResult raise @moondb.DbError

@moondb.Driver's execute, callable on the value directly.

pub fn SqliteDriver::is_closed(Self) -> Bool

Whether close has been called. Once closed, every statement raises @moondb.Closed rather than touching the freed sqlite3*.

pub fn SqliteDriver::open(String) -> Self raise @moondb.DbError

Open (or create) the database at path. Use ":memory:" for a private in-memory database. Raises @moondb.ConnectError if the file cannot be opened.

pub fn SqliteDriver::ping(Self) -> Bool

@moondb.Driver's ping, callable on the value directly.

pub fn SqliteDriver::query(Self, String, Array[@moondb.Value]) -> Array[@moondb.Row] raise @moondb.DbError

@moondb.Driver's query, callable on the value directly.

pub fn SqliteDriver::query_stream(Self, String, Array[@moondb.Value]) -> &@moondb.Cursor raise @moondb.DbError

@moondb.Driver's query_stream, callable on the value directly.

pub fn SqliteDriver::rollback(Self) -> Unit raise @moondb.DbError

@moondb.Driver's rollback, callable on the value directly.

moonbitstack/moonpostgres

moonpostgres

Types 3

pub struct PgConn {
  tcp : @socket.Tcp
  mut closed : Bool
  mut streaming : Bool
}

A live connection to a PostgreSQL backend, already past the startup handshake and sitting at ReadyForQuery. Runs the v3 frontend/backend protocol over a single @socket.Tcp. Not safe for concurrent use by multiple tasks: one statement must complete (drain to ReadyForQuery) before the next begins, as the wire protocol is a strict request/response pipeline per connection.

pub struct PgDriver {
  host : String
  port : Int32
  user : String
  password : String
  database : String
}

The parameters needed to reach a PostgreSQL backend — a connection descriptor, not a connection. [connect](PgDriver::connect) opens the live [PgConn], which is the thing that implements the driver seam.

It exists so a caller can carry connection settings around (a config value, a pool factory) and open a connection from them on demand, the way a DSN string works elsewhere.

pub struct PgRowStream {
  conn : PgConn
  mut col_names : Array[String]
  mut col_oids : Array[Int32]
  mut done : Bool
}

A forward-only cursor that reads a query's rows off the wire on demand instead of buffering them, the streaming counterpart to [query], for results too large to materialise (asyncpg's cursor. It is bound to its PgConn, which is a single-statement pipeline: the stream must be drained (next returns None) or [closed](PgRowStream::close) before another statement runs on that connection.

Functions & methods 33

pub fn build_bind(Array[@moondb.Value]) -> Bytes

Bind ('B'): bind params (all text format) to the unnamed statement, producing the unnamed portal, and request all result columns in text format.

pub fn build_describe_portal() -> Bytes

Describe ('D') the unnamed portal, so the server sends a RowDescription before the DataRows (giving column names + type OIDs for decoding).

pub fn build_execute() -> Bytes

Execute ('E') the unnamed portal with no row limit (0 = all rows).

pub fn build_parse(String) -> Bytes

Parse ('P'): prepare the unnamed statement from sql (with $n placeholders). Zero declared parameter types — the server infers them.

pub fn build_password(String) -> Bytes

PasswordMessage ('p'): the auth response token (cleartext, or the md5… digest), as a C string.

pub fn build_query(String) -> Bytes

Simple Query ('Q'): one SQL string, no bound parameters.

pub fn build_sasl_initial(String, String) -> Bytes

SASLInitialResponse ('p'): the chosen mechanism name, then the length-prefixed client-first SCRAM message (PG protocol §55.2.1).

pub fn build_sasl_response(String) -> Bytes

SASLResponse ('p'): the raw client-final SCRAM message, no length prefix.

pub fn build_startup(String, String) -> Bytes

StartupMessage: protocol version 3.0 (196608) plus the user / database parameters and a client_encoding=UTF8 request, terminated by an empty key.

pub fn build_sync() -> Bytes

Sync ('S'): close the extended-query batch; the server replies ReadyForQuery.

pub fn build_terminate() -> Bytes

Terminate ('X'): ask the backend to close the connection.

pub fn concat_bytes(Bytes, Bytes) -> Bytes

Concatenate two byte strings. A small helper the MD5 auth path and message framing lean on; MoonBit's Bytes is immutable so this allocates once.

pub fn count_placeholders(String) -> Int32

The number of ? placeholders [translate_placeholders] would consume — the count of parameters a statement expects. Shares the same scanner discipline so ?? escapes and quoted/comment spans do not count.

pub fn decode_bytea(String) -> Bytes

Decode PostgreSQL bytea hex text (\xDEADBEEF) back to raw bytes. A value not in hex form (legacy escape format) rides back as its UTF-8 bytes.

pub fn decode_value(Int32, Bool, String) -> @moondb.Value

Decode a text-format result cell (raw, already UTF-8) tagged with its column oid into a [Value]. is_null marks a wire NULL (length -1), which decodes to Null regardless of type. Numeric and boolean OIDs decode to their typed cases; everything else — including numeric, dates, and unknown OIDs — rides back as Text, exactly the dialect-neutral contract moondb documents (temporal/numeric typing is a roadmap item).

pub fn encode_param(@moondb.Value) -> Bytes?

Encode a bound parameter to its text-format bytes, or None for SQL NULL (which the Bind message sends as a length of -1). Binding is out-of-band — the value never touches the SQL string — so this is the injection-safe path.

* integers / doubles / bools render to their canonical PostgreSQL text literals (t/f for booleans); * Text passes through UTF-8; * Blob uses the bytea hex format (\x + lowercase hex), which the server accepts for a text-format bytea parameter.

pub const OID_BOOL : Int32 = 16

The pg_type OID of bool, as a column description reports it.

pub const OID_BYTEA : Int32 = 17

The pg_type OID of bytea, as a column description reports it.

pub const OID_FLOAT4 : Int32 = 700

The pg_type OID of float4, as a column description reports it.

pub const OID_FLOAT8 : Int32 = 701

The pg_type OID of float8, as a column description reports it.

pub const OID_INT2 : Int32 = 21

The pg_type OID of int2, as a column description reports it.

pub const OID_INT4 : Int32 = 23

The pg_type OID of int4, as a column description reports it.

pub const OID_INT8 : Int32 = 20

The pg_type OID of int8, as a column description reports it.

pub fn parse_double(String) -> Double?

Parse a floating-point literal from PostgreSQL text (123.45, -1e10, Infinity, NaN), or None if malformed. Handles sign, fraction, and a base-10 exponent; the special IEEE tokens PostgreSQL emits are recognised.

pub fn parse_int(String) -> Int32?

Parse a base-10 Int, or None if s is not a well-formed integer. Used to decode int2/int4 result text; a parse failure falls back to Text so a surprising server rendering never silently becomes a wrong number.

pub fn parse_int64(String) -> Int64?

Parse a base-10 Int64, or None on any non-digit (after an optional sign).

pub fn pg_md5_password(String, String, Bytes) -> String

"md5" + hex(md5(hex(md5(password + user)) + salt)).

It is what the server asks for and nothing else uses it, which is why the shape is stated rather than assembled from parts a caller might reorder.

pub fn PgDriver::new(host~ : String, port? : Int32, user~ : String, password? : String, database~ : String) -> Self

Build a connection descriptor. Does not connect: PostgreSQL I/O is async, so the connection is opened by [connect](PgDriver::connect) inside an event loop.

pub fn scram_client_final(Bytes, String, String) -> (String, Bytes) raise @moondb.DbError

Build the SCRAM client-final message and the expected server signature from the server's first message (RFC 5802). client_first_bare is n=…,r=clientnonce; server_first is r=nonce,s=salt,i=iters. Returns (client_final_message, server_signature) — the client sends the first and verifies the server's v= against the base64 of the second.

pub fn scram_client_proof(Bytes, Bytes) -> Bytes

The SCRAM ClientProof for the AuthMessage: ClientKey XOR HMAC(StoredKey, AuthMessage), where ClientKey = HMAC(SaltedPassword, "Client Key") and StoredKey = SHA256(ClientKey) (RFC 5802 §3).

pub fn scram_server_signature(Bytes, Bytes) -> Bytes

The SCRAM ServerSignature: HMAC(ServerKey, AuthMessage), ServerKey = HMAC(SaltedPassword, "Server Key"). The client verifies the server's v= against this to authenticate the server (RFC 5802 §3).

pub fn translate_placeholders(String) -> String

Rewrite moondb's dialect-neutral ? positional placeholders into PostgreSQL's numbered $1, $2, … form. moondb fixes the *calling convention* (an ordered params array) but leaves the placeholder spelling to the driver; PostgreSQL's extended-query protocol requires $n, so a query layer that emits ? for portability is translated here before Parse.

A ? is only a placeholder in SQL text — never inside a single-quoted string literal, a dollar-quoted string, a "-quoted identifier, or a -- / /* */ comment. Those spans are scanned through verbatim so a literal ? in data or a comment is left untouched and does not shift the parameter numbering. A literal ? an application genuinely needs in output can be written ??, which collapses to a single ? (mirroring JDBC-style escaping).

pub fn utf8_decode(Bytes) -> String

Decode UTF-8 bytes to a String. PostgreSQL text values, column names, and error fields all arrive UTF-8 (the startup message negotiates client_encoding). Decodes the ASCII fast path directly and multi-byte sequences by code point; malformed input yields U+FFFD rather than raising, matching a lenient text codec.

moonbitstack/moonmysql

moonmysql

Types 7

pub(all) struct ColumnDef {
  name : String
  column_type : Int32
  charset : Int32
  flags : Int32
} derive(Eq)

One result-set column's definition, reduced to what text decoding needs: the projected name, the MySQL type code, the collation (to tell text from binary), and the column flags.

pub struct Handshake {
  server_version : String
  server_kind : ServerKind
  connection_id : Int32
  salt : Bytes
  capability : Int32
  mariadb_capability : Int32
  charset : Int32
  status : Int32
  auth_plugin : String
}

The server's initial Handshake packet (protocol version 10), decoded down to the fields the client needs: the 20-byte auth salt, the negotiated capabilities, and the auth-plugin name that selects the scramble.

pub(all) suberror MysqlError {
  ProtocolError(String)
  ServerError(Int32, String, String)
  UnsupportedError(String)
} derive(Eq)

A failure raised while speaking the MySQL wire protocol. It is deliberately distinct from @moondb.DbError: the pure codec and the socket transport raise MysqlError (which carries wire-level specifics — a server error code, an unsupported auth plugin, a malformed packet), and the @moondb.Driver adapter maps it onto the coarse DbError cases at the public boundary.

* ProtocolError — a packet did not parse: short read, bad prefix byte, an out-of-place packet in the result-set state machine. * ServerError — the server sent an ERR packet. Carries the numeric error code, the 5-char SQLSTATE, and the human message verbatim. * UnsupportedError — a code path this round does not implement (e.g. the caching_sha2_password full-auth exchange, a LOCAL INFILE request).

pub(all) struct OkPacket {
  affected_rows : Int64
  last_insert_id : Int64
  status : Int32
  warnings : Int32
} derive(Eq)

An OK packet: a statement that returned no result set (INSERT/UPDATE/DELETE/DDL) or the terminator of a successful command.

pub struct PacketReader {
  data : Bytes
  mut pos : Int32
}

A cursor over one decoded MySQL packet payload. Every field type the protocol uses — fixed-width little-endian integers, length-encoded integers and strings, NUL-terminated strings, and raw byte runs — is read through this, advancing a position and raising [MysqlError::ProtocolError] on any short read. It holds no socket: the transport reads a full payload into Bytes first, then parses it here, which is what lets the whole codec be tested off any backend.

pub(all) enum QuoteMode {
  Backslash
  DoubleQuote
} derive(Eq)

How the server reads a string literal, which decides how a value has to be escaped. NO_BACKSLASH_ESCAPES is part of ANSI and of several stock sql_mode combinations: there, a backslash is an ordinary character and the only escape is a doubled quote — so a backslash-escaping writer leaves the value's own quote live and the statement is injectable.

pub(all) enum ServerKind {
  MySQL
  MariaDB
} derive(Eq, @debug.Debug)

Which server dialect answered the handshake. Both speak the MySQL wire protocol; they diverge in the version string and the extended capabilities.

Functions & methods 51

pub fn bind_params(String, Array[@moondb.Value], mode? : QuoteMode) -> Bytes raise MysqlError

Substitute the ordered params for the ? placeholders in sql, producing the UTF-8 query bytes a COM_QUERY carries.

The text protocol has no out-of-band parameter binding — that arrives with prepared statements (COM_STMT_PREPARE, binary protocol) in a later round — so values are rendered as escaped literals here. The scanner tracks single-, double-, and backtick-quoted spans (honouring backslash escapes) so a literal ? inside a string or identifier is never mistaken for a placeholder, and it raises when the placeholder and parameter counts disagree.

pub fn build_handshake_response(Handshake, String, Bytes, String) -> Bytes raise MysqlError

Build the client's HandshakeResponse41 payload for user/password/database.

mysql_native_password and caching_sha2_password (MySQL 8's default, fast-path scramble here and full auth driven in [MysqlConn::connect]) are both handled directly. For any other plugin the client advertises mysql_native_password and sends a native token, so a native-capable account authenticates and otherwise the server drives an AuthSwitchRequest the connection layer answers (native or caching_sha2) or rejects. Only a server that requires a non-native plugin *and* does not offer pluggable auth is rejected here. client_ed25519 remains on the README roadmap.

pub fn build_text_rows(Array[ColumnDef], Array[Bytes]) -> Array[@moondb.Row] raise MysqlError

Build the materialised rows of a text-protocol result set from its column definitions and the raw row packets. This is the pure heart of query: the socket transport collects columns and row_payloads, and every cell decode happens here, off any backend.

pub fn bytes_to_string(Bytes) -> String

Bytes → String, lossily (server version, error text, text-protocol cells).

pub fn caching_sha2_full_auth_token(Bytes, Bytes, String, Bytes) -> Bytes raise MysqlError

The caching_sha2_password full-auth token: the NUL-terminated password XORed with the nonce (cycled), then RSA-OAEP encrypted under the server's public key.

seed is the 20 random octets OAEP masks with. MySQL's own client draws them from OpenSSL; here they are a parameter, because this package has no entropy source and a caller that reuses a seed should have to write that down.

pub fn caching_sha2_scramble(Bytes, Bytes) -> Bytes

The caching_sha2_password fast-auth scramble: SHA256(pw) XOR SHA256( SHA256(SHA256(pw)) ‖ nonce ), 32 bytes. An empty password sends an empty token.

pub let client_connect_with_db : Int32

The CLIENT_CONNECT_WITH_DB capability flag of the connection handshake.

pub let client_long_flag : Int32

The CLIENT_LONG_FLAG capability flag of the connection handshake.

pub let client_long_password : Int32

The CLIENT_LONG_PASSWORD capability flag of the connection handshake.

pub let client_plugin_auth : Int32

The CLIENT_PLUGIN_AUTH capability flag of the connection handshake.

pub let client_protocol_41 : Int32

The CLIENT_PROTOCOL_41 capability flag of the connection handshake.

pub let client_secure_connection : Int32

The CLIENT_SECURE_CONNECTION capability flag of the connection handshake.

pub let client_transactions : Int32

The CLIENT_TRANSACTIONS capability flag of the connection handshake.

pub fn concat_bytes(Bytes, Bytes) -> Bytes

Concatenate two byte strings. A small helper the MD5 auth path and message framing lean on; MoonBit's Bytes is immutable so this allocates once.

pub fn decode_text_value(Bytes?, ColumnDef) -> @moondb.Value raise MysqlError

Map one text-protocol cell (None = the 0xFB NULL sentinel) onto a [@moondb.Value] using the column's declared type. Integers narrow to Int except BIGINT, which keeps 64 bits; FLOAT/DOUBLE become Double; binary-collation strings become Blob; everything else (VARCHAR, TEXT, DECIMAL, temporal types as ISO text, JSON) becomes Text.

pub fn is_auth_switch_request(Bytes) -> Bool

Whether payload is an AuthSwitchRequest (0xFE lead byte with a body — the length is what tells it apart from a 5-byte EOF, exactly as [is_eof_packet] keys off < 9).

pub fn is_eof_packet(Bytes) -> Bool

Whether payload is an EOF packet (first byte 0xFE, fewer than 9 bytes — which is what tells it apart from a row whose first cell is an 8-byte length-encoded value).

pub fn is_err_packet(Bytes) -> Bool

Whether payload is an ERR packet (first byte 0xFF).

pub fn is_ok_packet(Bytes) -> Bool

Whether payload is an OK packet (first byte 0x00, at least 7 bytes).

pub let mariadb_client_cache_metadata : Int32

MariaDB's MARIADB_CLIENT_CACHE_METADATA capability flag of the connection handshake.

pub let mariadb_client_com_multi : Int32

MariaDB's MARIADB_CLIENT_COM_MULTI capability flag of the connection handshake.

pub let mariadb_client_extended_metadata : Int32

MariaDB's MARIADB_CLIENT_EXTENDED_METADATA capability flag of the connection handshake.

pub let mariadb_client_progress : Int32

MariaDB's MARIADB_CLIENT_PROGRESS capability flag of the connection handshake.

pub let mariadb_client_stmt_bulk_operations : Int32

MariaDB's MARIADB_CLIENT_STMT_BULK_OPERATIONS capability flag of the connection handshake.

pub fn mariadb_ed25519_response(Bytes, Bytes) -> Bytes

The MariaDB client_ed25519 response: the 64-byte Ed25519 signature of the server's 32-byte challenge, keyed by the password.

MariaDB keys the signature with the password itself, where RFC 8032 would expand a 32-byte seed — the derivation PrivateKey::of_secret exists for. The plugin signs unconditionally, so an empty password expands to SHA-512("") and still yields a valid signature.

pub fn MysqlError::to_string(Self) -> String

A one-line rendering, e.g. ServerError(1146, 42S02): Table 'test.t' doesn't exist.

pub fn native_password_scramble(Bytes, Bytes) -> Bytes

The mysql_native_password challenge response: SHA1(password) XOR SHA1(salt ++ SHA1(SHA1(password))), 20 bytes. An empty password produces an empty response (the server accepts a zero-length token).

pub fn PacketReader::at_end(Self) -> Bool

Whether the cursor has consumed the whole payload.

pub fn PacketReader::bytes(Self, Int32) -> Bytes raise MysqlError

Read n raw bytes.

pub fn PacketReader::lenenc_bytes(Self) -> Bytes? raise MysqlError

Read a length-encoded string (the string<lenenc> type), returning None for the 0xFB NULL sentinel that appears in text-protocol rows.

pub fn PacketReader::lenenc_uint(Self) -> Int64 raise MysqlError

Read a length-encoded unsigned integer (the int<lenenc> type). The 0xFB NULL sentinel and 0xFF are rejected here — NULL only has meaning inside a row, which [lenenc_bytes] handles.

pub fn PacketReader::new(Bytes) -> Self

Wrap a decoded packet payload for reading from the start.

pub fn PacketReader::peek(Self) -> Int32

Peek the next byte without advancing; -1 at end of payload.

pub fn PacketReader::remaining(Self) -> Int32

Bytes not yet consumed.

pub fn PacketReader::rest(Self) -> Bytes

Read everything left in the payload (an EOF-terminated string field).

pub fn PacketReader::skip(Self, Int32) -> Unit raise MysqlError

Skip n bytes.

pub fn PacketReader::string_nul(Self) -> Bytes raise MysqlError

Read a NUL-terminated string, consuming the terminator.

pub fn PacketReader::u8(Self) -> Int32 raise MysqlError

Read one byte as an Int in 0..=255.

pub fn PacketReader::uint_le(Self, Int32) -> Int64 raise MysqlError

Read an n-byte little-endian unsigned integer.

pub fn parse_auth_switch_request(Bytes) -> (String, Bytes) raise MysqlError

Decode an AuthSwitchRequest into the plugin name the server wants and the fresh 20-byte auth salt for it. The trailing NUL that follows the scramble is dropped so the salt feeds [native_password_scramble] directly.

pub fn parse_column_def(Bytes) -> ColumnDef raise MysqlError

Decode a column-definition packet (protocol 41). Only the fields that steer text decoding are kept; catalog/schema/table names and the length/decimals fields are read past.

pub fn parse_ed25519_challenge(Bytes) -> Bytes raise MysqlError

The 32-byte nonce from a client_ed25519 AuthSwitchRequest. MariaDB sends exactly NONCE_BYTES (= 32) with no NUL terminator and the client signs all of them, so — unlike the native scramble — the full 32 bytes are read raw rather than through the NUL-stripping [parse_auth_switch_request].

pub fn parse_err(Bytes) -> MysqlError raise MysqlError

Decode a full ERR packet (including its 0xFF marker) into the [MysqlError::ServerError] it represents.

pub fn parse_handshake(Bytes) -> Handshake raise MysqlError

Parse a protocol-10 initial Handshake payload. An ERR packet in its place (0xFF, e.g. "Host is blocked" / "Too many connections") is surfaced as a [MysqlError::ServerError].

pub fn parse_ok(Bytes) -> OkPacket raise MysqlError

Decode an OK packet (including its 0x00 marker).

pub fn parse_rsa_public_key(String) -> @rsa.PublicKey raise MysqlError

The RSA public key inside the PEM SubjectPublicKeyInfo the server sends.

pub fn parse_server_version(String) -> (ServerKind, String)

Classify a raw handshake version string and recover the real version.

MariaDB 10+ prefixes its version with the fake 5.5.5- sentinel (MySQL 5.5.5 was never released), so pre-10 clients that gate on the leading 5. still connect. Strip it to get the true version — e.g. 5.5.5-11.4.2-MariaDB-ubu2404 → 11.4.2-MariaDB-ubu2404 as [ServerKind::MariaDB]; a plain 8.0.35 is returned unchanged as [ServerKind::MySQL].

pub fn put_lenenc_bytes(@buffer.Buffer, Bytes) -> Unit

Append a length-encoded string (its lenenc length prefix, then the bytes).

pub fn put_lenenc_uint(@buffer.Buffer, Int64) -> Unit

Append a length-encoded unsigned integer.

pub fn put_string_nul(@buffer.Buffer, Bytes) -> Unit

Append raw bytes followed by a NUL terminator.

pub fn put_uint_le(@buffer.Buffer, Int64, Int32) -> Unit

Append an n-byte little-endian unsigned integer.

moonbitstack/moonmysql/client

client

Types 3

pub struct MysqlConn {
  tcp : @socket.Tcp
  mut seq : Int32
  mut closed : Bool
  mut server_kind : @moonmysql.ServerKind
  mut streaming : Bool
  mut quote_mode : @moonmysql.QuoteMode
}

A live MySQL connection over a raw TCP socket, speaking the wire protocol in pure MoonBit. This is the asynchronous, full-fidelity driver: it owns the socket for its whole lifetime, so begin/commit/rollback bracket a real server-side transaction. The synchronous @moondb.Driver adapter ([MysqlDriver]) is layered on top for the moondb contract.

Framing is the classic 3-byte little-endian length + 1-byte sequence id header; the transport transparently reassembles the 0xFFFFFF continuation frames a large payload is split into.

pub struct MysqlDriver {
  host : String
  port : Int32
  user : String
  password : String
  database : String
}

A synchronous @moondb.Driver over MySQL — the adapter that lets a moondb query layer (moonorm) talk to MySQL through the same contract as the SQLite and Postgres drivers.

## The async wall, and what it means here

moonbitlang/async sockets are asynchronous, but @moondb.Driver's methods are synchronous, and MoonBit forbids calling an async function from a non-async one. The bridge is @async.run_async_main, which spins an event loop, runs an async body to completion, and returns — the same hook the toolchain uses to enter async fn main.

A socket does **not** survive across two such event loops (each tears its file descriptors down; verified empirically), so every execute/query opens a fresh connection, authenticates, runs its one statement, and closes. That is correct and efficient enough for autocommit work — which is exactly what the moondb roundtrip is — but it means a transaction cannot be held open across separate Driver calls. begin/commit/rollback therefore raise a clear error directing callers to the asynchronous [MysqlConn] API, which owns its socket for its whole lifetime and brackets real transactions. This is a language constraint, not a shortcut, and it is documented in the README.

pub struct MysqlRowStream {
  conn : MysqlConn
  columns : Array[@moonmysql.ColumnDef]
  mut pending : Bytes?
  mut done : Bool
}

A forward-only cursor that reads a query's rows off the wire on demand instead of buffering them, the streaming counterpart to [query], for results too large to materialise at once (mysql_use_result. Bound to its MysqlConn, a single-command pipeline: the stream must be drained (next returns None) or [closed](MysqlRowStream::close) before another statement runs on that connection.

Functions & methods 11

pub fn MysqlConn::close(Self) -> Unit

Close the socket (best-effort, idempotent).

pub fn MysqlConn::server_kind(Self) -> @moonmysql.ServerKind

The dialect (MySQL or MariaDB) reported by the server's handshake.

pub fn MysqlDriver::begin(Self) -> Unit raise @moondb.DbError

@moondb.Driver's begin, callable on the value directly.

pub fn MysqlDriver::close(Self) -> Unit

@moondb.Driver's close, callable on the value directly.

pub fn MysqlDriver::commit(Self) -> Unit raise @moondb.DbError

@moondb.Driver's commit, callable on the value directly.

pub fn MysqlDriver::execute(Self, String, Array[@moondb.Value]) -> @moondb.ExecResult raise @moondb.DbError

@moondb.Driver's execute, callable on the value directly.

pub fn MysqlDriver::new(user~ : String, password? : String, database? : String, host? : String, port? : Int32) -> Self

Configure a driver. host defaults to loopback, port to 3306; password and database may be empty.

pub fn MysqlDriver::ping(Self) -> Bool

@moondb.Driver's ping, callable on the value directly.

pub fn MysqlDriver::query(Self, String, Array[@moondb.Value]) -> Array[@moondb.Row] raise @moondb.DbError

@moondb.Driver's query, callable on the value directly.

pub fn MysqlDriver::query_stream(Self, String, Array[@moondb.Value]) -> &@moondb.Cursor raise @moondb.DbError

@moondb.Driver's query_stream, callable on the value directly.

pub fn MysqlDriver::rollback(Self) -> Unit raise @moondb.DbError

@moondb.Driver's rollback, callable on the value directly.