mirror of
https://github.com/fluencelabs/sqlite-wasm-connector
synced 2025-03-15 06:20:50 +00:00
Implement column reading
This commit is contained in:
parent
f7f9af43ed
commit
ae0a12444b
@ -67,21 +67,12 @@ impl<'l> Drop for Database<'l> {
|
||||
extern fn execute_callback(callback: *mut c_void, count: c_int, values: *mut *mut c_char,
|
||||
columns: *mut *mut c_char) -> c_int {
|
||||
|
||||
macro_rules! c_str_to_string(
|
||||
($string:expr) => (
|
||||
match ::std::str::from_utf8(::std::ffi::CStr::from_ptr($string).to_bytes()) {
|
||||
Ok(string) => String::from(string),
|
||||
Err(_) => return 1,
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
unsafe {
|
||||
let mut pairs = Vec::with_capacity(count as usize);
|
||||
|
||||
for i in 0..(count as isize) {
|
||||
let column = c_str_to_string!(*columns.offset(i) as *const _);
|
||||
let value = c_str_to_string!(*values.offset(i) as *const _);
|
||||
let column = c_str_to_string!(*columns.offset(i));
|
||||
let value = c_str_to_string!(*values.offset(i));
|
||||
pairs.push((column, value));
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,13 @@ macro_rules! str_to_c_str(
|
||||
);
|
||||
);
|
||||
|
||||
macro_rules! c_str_to_string(
|
||||
($cstr:expr) => (
|
||||
String::from_utf8_lossy(::std::ffi::CStr::from_ptr($cstr as *const _).to_bytes())
|
||||
.into_owned()
|
||||
);
|
||||
);
|
||||
|
||||
mod database;
|
||||
mod statement;
|
||||
|
||||
|
@ -17,6 +17,12 @@ pub enum Binding<'l> {
|
||||
Text(usize, &'l str),
|
||||
}
|
||||
|
||||
/// A value stored in a column.
|
||||
pub trait Value {
|
||||
/// Read the value from a prepared statement at a specific position.
|
||||
fn read(statement: &mut Statement, i: usize) -> Result<Self>;
|
||||
}
|
||||
|
||||
impl<'l> Statement<'l> {
|
||||
/// Assign values to the placeholders.
|
||||
pub fn bind(&mut self, bindings: &[Binding]) -> Result<()> {
|
||||
@ -38,6 +44,12 @@ impl<'l> Statement<'l> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the value of a column.
|
||||
#[inline]
|
||||
pub fn column<T: Value>(&mut self, i: usize) -> Result<T> {
|
||||
<T as Value>::read(self, i)
|
||||
}
|
||||
|
||||
/// Take a step.
|
||||
#[inline]
|
||||
pub fn step(&mut self) -> ResultCode {
|
||||
@ -59,6 +71,30 @@ impl<'l> Drop for Statement<'l> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for f64 {
|
||||
fn read(statement: &mut Statement, i: usize) -> Result<f64> {
|
||||
Ok(unsafe { ::raw::sqlite3_column_double(statement.raw, i as c_int) as f64 })
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for i64 {
|
||||
fn read(statement: &mut Statement, i: usize) -> Result<i64> {
|
||||
Ok(unsafe { ::raw::sqlite3_column_int64(statement.raw, i as c_int) as i64 })
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for String {
|
||||
fn read(statement: &mut Statement, i: usize) -> Result<String> {
|
||||
unsafe {
|
||||
let pointer = ::raw::sqlite3_column_text(statement.raw, i as c_int);
|
||||
if pointer.is_null() {
|
||||
raise!("cannot read a TEXT column");
|
||||
}
|
||||
Ok(c_str_to_string!(pointer))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_raw<'l>(raw: *mut raw::sqlite3_stmt) -> Statement<'l> {
|
||||
Statement { raw: raw, _phantom: PhantomData }
|
||||
|
44
tests/lib.rs
44
tests/lib.rs
@ -23,22 +23,36 @@ fn workflow() {
|
||||
let sql = r#"CREATE TABLE `users` (id INTEGER, name VARCHAR(255), age REAL);"#;
|
||||
ok!(database.execute(sql, None));
|
||||
|
||||
let sql = r#"INSERT INTO `users` (id, name, age) VALUES (?, ?, ?);"#;
|
||||
let mut statement = ok!(database.statement(sql));
|
||||
ok!(statement.bind(&[Integer(1, 1), Text(2, "Alice"), Float(3, 20.99)]));
|
||||
assert!(statement.step() == ResultCode::Done);
|
||||
{
|
||||
let sql = r#"INSERT INTO `users` (id, name, age) VALUES (?, ?, ?);"#;
|
||||
let mut statement = ok!(database.statement(sql));
|
||||
ok!(statement.bind(&[Integer(1, 1), Text(2, "Alice"), Float(3, 20.99)]));
|
||||
assert!(statement.step() == ResultCode::Done);
|
||||
}
|
||||
|
||||
let mut done = false;
|
||||
let sql = r#"SELECT * FROM `users`;"#;
|
||||
ok!(database.execute(sql, Some(&mut |pairs: Vec<(String, String)>| -> bool {
|
||||
assert!(pairs.len() == 3);
|
||||
assert!(pairs[0] == pair!("id", "1"));
|
||||
assert!(pairs[1] == pair!("name", "Alice"));
|
||||
assert!(pairs[2] == pair!("age", "20.99"));
|
||||
done = true;
|
||||
true
|
||||
})));
|
||||
assert!(done);
|
||||
{
|
||||
let mut done = false;
|
||||
let sql = r#"SELECT * FROM `users`;"#;
|
||||
ok!(database.execute(sql, Some(&mut |pairs: Vec<(String, String)>| -> bool {
|
||||
assert!(pairs.len() == 3);
|
||||
assert!(pairs[0] == pair!("id", "1"));
|
||||
assert!(pairs[1] == pair!("name", "Alice"));
|
||||
assert!(pairs[2] == pair!("age", "20.99"));
|
||||
done = true;
|
||||
true
|
||||
})));
|
||||
assert!(done);
|
||||
}
|
||||
|
||||
{
|
||||
let sql = r#"SELECT * FROM `users`;"#;
|
||||
let mut statement = ok!(database.statement(sql));
|
||||
assert!(statement.step() == ResultCode::Row);
|
||||
assert!(ok!(statement.column::<i64>(0)) == 1);
|
||||
assert!(ok!(statement.column::<String>(1)) == String::from("Alice"));
|
||||
assert!(ok!(statement.column::<f64>(2)) == 20.99);
|
||||
assert!(statement.step() == ResultCode::Done);
|
||||
}
|
||||
}
|
||||
|
||||
fn setup() -> (PathBuf, Directory) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user