A bit of transaction support
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
extern mod sql;
|
||||
|
||||
use std::libc::c_int;
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
@@ -62,6 +60,24 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! ret_err(
|
||||
($mat:expr { $($p:pat => $blk:expr),+ }) => (
|
||||
match $mat {
|
||||
Err(err) => return Err(err),
|
||||
$(
|
||||
$p => $blk,
|
||||
)+
|
||||
}
|
||||
);
|
||||
|
||||
($mat:expr) => (
|
||||
match $mat {
|
||||
Err(err) => return Err(err),
|
||||
_ => ()
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
impl Connection {
|
||||
pub fn prepare<'a>(&'a self, query: &str)
|
||||
-> Result<~PreparedStatement<'a>, ~str> {
|
||||
@@ -85,18 +101,25 @@ impl Connection {
|
||||
|
||||
pub fn query<T>(&self, query: &str, blk: &fn (&mut ResultIterator) -> T)
|
||||
-> Result<T, ~str> {
|
||||
let stmt = match self.prepare(query) {
|
||||
Ok(stmt) => stmt,
|
||||
Err(err) => return Err(err)
|
||||
};
|
||||
|
||||
let mut it = match stmt.query() {
|
||||
Ok(it) => it,
|
||||
Err(err) => return Err(err)
|
||||
};
|
||||
|
||||
let stmt = ret_err!(self.prepare(query) { Ok(stmt) => stmt });
|
||||
let mut it = ret_err!(stmt.query() { Ok(it) => it });
|
||||
Ok(blk(&mut it))
|
||||
}
|
||||
|
||||
pub fn in_transaction<T>(&self, blk: &fn(&Connection) -> Result<T, ~str>)
|
||||
-> Result<T, ~str> {
|
||||
ret_err!(self.update("BEGIN"));
|
||||
|
||||
let ret = blk(self);
|
||||
|
||||
// TODO: What to do with errors here?
|
||||
match ret {
|
||||
Ok(_) => self.update("COMMIT"),
|
||||
Err(_) => self.update("ROLLBACK")
|
||||
};
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PreparedStatement<'self> {
|
||||
@@ -124,7 +147,7 @@ impl<'self> PreparedStatement<'self> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn query<'a>(&'a self) -> Result<ResultIterator<'a>, ~str> {
|
||||
pub fn query(&'self self) -> Result<ResultIterator<'self>, ~str> {
|
||||
unsafe { ffi::sqlite3_reset(self.stmt); }
|
||||
Ok(ResultIterator {stmt: self})
|
||||
}
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
extern mod sqlite3;
|
||||
|
||||
macro_rules! chk (
|
||||
($result:expr) => (
|
||||
match $result {
|
||||
Err(err) => fail!(err),
|
||||
Ok(val) => val
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let conn = sqlite3::open("db").unwrap();
|
||||
conn.update("DROP TABLE IF EXISTS foo");
|
||||
conn.update("CREATE TABLE foo (
|
||||
fn test_basic() {
|
||||
let conn = chk!(sqlite3::open("db1"));
|
||||
chk!(conn.update("DROP TABLE IF EXISTS foo"));
|
||||
chk!(conn.update("CREATE TABLE foo (
|
||||
id BIGINT PRIMARY KEY
|
||||
)");
|
||||
conn.update("INSERT INTO foo (id) VALUES (101), (102)");
|
||||
)"));
|
||||
chk!(conn.update("INSERT INTO foo (id) VALUES (101), (102)"));
|
||||
|
||||
do conn.query("SELECT id FROM foo") |it| {
|
||||
for it.advance |row| {
|
||||
@@ -15,3 +24,28 @@ fn test() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trans() {
|
||||
let conn = chk!(sqlite3::open("db2"));
|
||||
chk!(conn.update("DROP TABLE IF EXISTS bar"));
|
||||
chk!(conn.update("CREATE TABLE bar (
|
||||
id BIGINT PRIMARY KEY
|
||||
)"));
|
||||
do conn.in_transaction |conn| {
|
||||
chk!(conn.update("INSERT INTO bar (id) VALUES (100)"));
|
||||
Err::<(), ~str>(~"")
|
||||
};
|
||||
assert_eq!(0, chk!(conn.query("SELECT COUNT(*) FROM bar", |it| {
|
||||
it.next().get().get(0).get()
|
||||
})));
|
||||
|
||||
do conn.in_transaction |conn| {
|
||||
chk!(conn.update("INSERT INTO bar (id) VALUES (100)"));
|
||||
Ok(())
|
||||
};
|
||||
|
||||
assert_eq!(1, chk!(conn.query("SELECT COUNT(*) FROM bar", |it| {
|
||||
it.next().get().get(0).get()
|
||||
})));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user