02 / DATA
sql
Statements, rows, single values and transactions over a database driver the caller supplies; a transaction commits when its body returns and rolls back when it raises.
WHERE IT SITS
INTERFACE
struct SqlstructA handle on a database: statements, rows and transactions, with the driver supplied by the caller so one service works over SQLite in a test and over Postgres in production without changing a line.
fn Sql::new(driver : &@moondb.AsyncDriver) -> SqlfnA handle over driver.
fn Sql::blocking(driver : &@moondb.Driver) -> SqlfnA handle over a synchronous driver. The calls still happen inside the async function, so a blocking driver occupies the task it runs on — which is what a service over an embedded database wants and what a test uses.
extend Blocking with @moondb.AsyncDriver::item
impl @moondb.AsyncDriver for Blocking with fn execute( self : Blocking, query : String, args : Array[@moondb.Value]) -> @moondb.ExecResult raise @moondb.DbErroritem
impl @moondb.AsyncDriver for Blocking with fn query( self : Blocking, query : String, args : Array[@moondb.Value]) -> Array[@moondb.Row] raise @moondb.DbErroritem
impl @moondb.AsyncDriver for Blocking with fn begin(self : Blocking) -> Unit raise @moondb.DbErroritem
impl @moondb.AsyncDriver for Blocking with fn commit(self : Blocking) -> Unit raise @moondb.DbErroritem
impl @moondb.AsyncDriver for Blocking with fn rollback(self : Blocking) -> Unit raise @moondb.DbErroritem
impl @moondb.AsyncDriver for Blocking with fn close(self : Blocking) -> Unititem
impl @moondb.AsyncDriver for Blocking with fn ping(self : Blocking) -> Boolitem
impl @moondb.AsyncDriver for Blocking with fn dialect(self : Blocking) -> @moondb.DialectitemThe wrapped driver's dialect: the default would report SQLite for every backend.
impl @moondb.AsyncDriver for Blocking with fn capabilities(self : Blocking) -> @moondb.Capabilitiesitem
async fn Sql::exec( self : Sql, query : String, args~ : Array[@moondb.Value] = []) -> @moondb.ExecResult raise @moondb.DbErroritemRun a statement and report how many rows it touched.
async fn Sql::query( self : Sql, query : String, args~ : Array[@moondb.Value] = []) -> Array[@moondb.Row] raise @moondb.DbErroritemRun a query and return every row.
async fn Sql::one( self : Sql, query : String, args~ : Array[@moondb.Value] = []) -> @moondb.Row? raise @moondb.DbErroritemRun a query and return its first row, or None when it matched nothing.
async fn[T : @moondb.FromValue] Sql::scalar( self : Sql, query : String, args~ : Array[@moondb.Value] = []) -> T? raise @moondb.DbErroritemRun a query and read one column of its first row as T, which is what most callers of one actually want.
async fn[T] Sql::transact(self : Sql, body : async (Sql) -> T) -> TitemRun body inside a transaction: it commits when the body returns and rolls back when it raises, so a failure halfway through leaves nothing behind. The body receives a Sql bound to the same driver — the driver is the transaction, in this contract — so a nested call cannot silently start a second one.
async fn Sql::ping(self : Sql) -> BoolitemWhether the database answers.
fn count_rows( rows : Array[@moondb.Row], predicate : (@moondb.Row) -> Bool) -> Int32fnHow many of rows match predicate — the counting pass a page of results is paired with.