mirror of
https://github.com/fluencelabs/sqlite-wasm-connector
synced 2025-03-15 06:20:50 +00:00
Eliminate Binding; introduce Parameter
This commit is contained in:
parent
56c36f7ddc
commit
7441967fbc
@ -90,10 +90,10 @@ mod statement;
|
||||
|
||||
pub use database::Database;
|
||||
pub use error::{Error, ErrorKind};
|
||||
pub use statement::{Statement, Binding, Value, State};
|
||||
pub use statement::{Statement, State, Parameter, Value};
|
||||
|
||||
/// A result.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// Open a connection to a new or existing database.
|
||||
#[inline]
|
||||
|
@ -10,17 +10,20 @@ pub struct Statement<'l> {
|
||||
phantom: PhantomData<(ffi::sqlite3_stmt, &'l ffi::sqlite3)>,
|
||||
}
|
||||
|
||||
/// A binding of a parameter of a prepared statement.
|
||||
pub enum Binding<'l> {
|
||||
Float(usize, f64),
|
||||
Integer(usize, i64),
|
||||
Text(usize, &'l str),
|
||||
/// A parameter of a prepared statement.
|
||||
pub trait Parameter {
|
||||
/// Bind the parameter at a specific location.
|
||||
///
|
||||
/// The leftmost location has the index 1.
|
||||
fn bind(&self, &Statement, usize) -> Result<()>;
|
||||
}
|
||||
|
||||
/// A value stored in a result row of a query.
|
||||
/// A value stored in a prepared statement.
|
||||
pub trait Value {
|
||||
/// Read the value stored in a specific column.
|
||||
fn read(statement: &Statement, i: usize) -> Result<Self>;
|
||||
///
|
||||
/// The leftmost column has the index 0.
|
||||
fn read(&Statement, usize) -> Result<Self>;
|
||||
}
|
||||
|
||||
/// A state of a prepared statement.
|
||||
@ -31,38 +34,20 @@ pub enum State {
|
||||
}
|
||||
|
||||
impl<'l> Statement<'l> {
|
||||
/// Bind values to the parameters.
|
||||
/// Bind the parameter at a specific location.
|
||||
///
|
||||
/// The leftmost parameter has the index 1.
|
||||
pub fn bind(&mut self, bindings: &[Binding]) -> Result<()> {
|
||||
for binding in bindings.iter() {
|
||||
match binding {
|
||||
&Binding::Float(i, value) => unsafe {
|
||||
debug_assert!(i > 0, "the indexing starts from 1");
|
||||
success!(self.raw.1, ffi::sqlite3_bind_double(self.raw.0, i as c_int,
|
||||
value as c_double));
|
||||
},
|
||||
&Binding::Integer(i, value) => unsafe {
|
||||
debug_assert!(i > 0, "the indexing starts from 1");
|
||||
success!(self.raw.1, ffi::sqlite3_bind_int64(self.raw.0, i as c_int,
|
||||
value as ffi::sqlite3_int64));
|
||||
},
|
||||
&Binding::Text(i, value) => unsafe {
|
||||
debug_assert!(i > 0, "the indexing starts from 1");
|
||||
success!(self.raw.1, ffi::sqlite3_bind_text(self.raw.0, i as c_int,
|
||||
str_to_c_str!(value), -1, None));
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
/// The leftmost location has the index 1.
|
||||
#[inline]
|
||||
pub fn bind<P: Parameter>(&mut self, i: usize, parameter: P) -> Result<()> {
|
||||
parameter.bind(self, i)
|
||||
}
|
||||
|
||||
/// Return the value stored in a specific column of the current result row.
|
||||
/// Read the value stored in a specific column.
|
||||
///
|
||||
/// The leftmost column has the index 0.
|
||||
#[inline]
|
||||
pub fn column<T: Value>(&self, i: usize) -> Result<T> {
|
||||
<T as Value>::read(self, i)
|
||||
pub fn read<V: Value>(&self, i: usize) -> Result<V> {
|
||||
Value::read(self, i)
|
||||
}
|
||||
|
||||
/// Evaluate the statement.
|
||||
@ -89,19 +74,59 @@ impl<'l> Drop for Statement<'l> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parameter for f64 {
|
||||
#[inline]
|
||||
fn bind(&self, statement: &Statement, i: usize) -> Result<()> {
|
||||
debug_assert!(i > 0, "the indexing starts from 1");
|
||||
unsafe {
|
||||
success!(statement.raw.1, ffi::sqlite3_bind_double(statement.raw.0, i as c_int,
|
||||
*self as c_double));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Parameter for i64 {
|
||||
#[inline]
|
||||
fn bind(&self, statement: &Statement, i: usize) -> Result<()> {
|
||||
debug_assert!(i > 0, "the indexing starts from 1");
|
||||
unsafe {
|
||||
success!(statement.raw.1, ffi::sqlite3_bind_int64(statement.raw.0, i as c_int,
|
||||
*self as ffi::sqlite3_int64));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l> Parameter for &'l str {
|
||||
#[inline]
|
||||
fn bind(&self, statement: &Statement, i: usize) -> Result<()> {
|
||||
debug_assert!(i > 0, "the indexing starts from 1");
|
||||
unsafe {
|
||||
success!(statement.raw.1, ffi::sqlite3_bind_text(statement.raw.0, i as c_int,
|
||||
str_to_c_str!(self.as_bytes()),
|
||||
-1, None));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for f64 {
|
||||
#[inline]
|
||||
fn read(statement: &Statement, i: usize) -> Result<f64> {
|
||||
Ok(unsafe { ffi::sqlite3_column_double(statement.raw.0, i as c_int) as f64 })
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for i64 {
|
||||
#[inline]
|
||||
fn read(statement: &Statement, i: usize) -> Result<i64> {
|
||||
Ok(unsafe { ffi::sqlite3_column_int64(statement.raw.0, i as c_int) as i64 })
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for String {
|
||||
#[inline]
|
||||
fn read(statement: &Statement, i: usize) -> Result<String> {
|
||||
unsafe {
|
||||
let pointer = ffi::sqlite3_column_text(statement.raw.0, i as c_int);
|
||||
|
16
tests/lib.rs
16
tests/lib.rs
@ -7,7 +7,6 @@ macro_rules! ok(
|
||||
|
||||
#[test]
|
||||
fn workflow() {
|
||||
use sqlite::Binding::*;
|
||||
use sqlite::State;
|
||||
|
||||
macro_rules! pair(
|
||||
@ -22,7 +21,9 @@ fn workflow() {
|
||||
{
|
||||
let sql = r#"INSERT INTO `users` (id, name, age) VALUES (?, ?, ?);"#;
|
||||
let mut statement = ok!(database.prepare(sql));
|
||||
ok!(statement.bind(&[Integer(1, 1), Text(2, "Alice"), Float(3, 20.99)]));
|
||||
ok!(statement.bind(1, 1));
|
||||
ok!(statement.bind(2, "Alice"));
|
||||
ok!(statement.bind(3, 20.99));
|
||||
assert!(ok!(statement.step()) == State::Done);
|
||||
}
|
||||
|
||||
@ -44,16 +45,15 @@ fn workflow() {
|
||||
let sql = r#"SELECT * FROM `users`;"#;
|
||||
let mut statement = ok!(database.prepare(sql));
|
||||
assert!(ok!(statement.step()) == State::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!(ok!(statement.read::<i64>(0)) == 1);
|
||||
assert!(ok!(statement.read::<String>(1)) == String::from("Alice"));
|
||||
assert!(ok!(statement.read::<f64>(2)) == 20.99);
|
||||
assert!(ok!(statement.step()) == State::Done);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress() {
|
||||
use sqlite::Binding::*;
|
||||
use sqlite::State;
|
||||
use std::path::PathBuf;
|
||||
use std::thread;
|
||||
@ -73,7 +73,9 @@ fn stress() {
|
||||
ok!(database.set_busy_handler(|_| true));
|
||||
let sql = r#"INSERT INTO `users` (id, name, age) VALUES (?, ?, ?);"#;
|
||||
let mut statement = ok!(database.prepare(sql));
|
||||
ok!(statement.bind(&[Integer(1, 1), Text(2, "Alice"), Float(3, 20.99)]));
|
||||
ok!(statement.bind(1, 1));
|
||||
ok!(statement.bind(2, "Alice"));
|
||||
ok!(statement.bind(3, 20.99));
|
||||
assert!(ok!(statement.step()) == State::Done);
|
||||
true
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user