Skip to content

Commit

Permalink
Merge pull request #3 from wyhaya/main
Browse files Browse the repository at this point in the history
Add more apis
  • Loading branch information
wyhaya authored Oct 12, 2024
2 parents e94482f + 416039d commit f761334
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 34 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ fn main() {
println!("Column {i}: {} {}", rst.column_name(i), rst.column_type(i));
}

while let Some(row) = (&mut rst).next() {
while let Some(row) = rst.fetch_row() {
dbg!(row);
}
}
```

## TODO
* NULL value
* Add more apis
* Windows support
* Dynamic link crossdb
Expand Down
2 changes: 1 addition & 1 deletion examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn main() {
println!("Column {i}: {} {}", rst.column_name(i), rst.column_type(i));
}

while let Some(row) = (&mut rst).next() {
while let Some(row) = rst.fetch_row() {
dbg!(row);
}
}
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ pub enum Error {
Utf8(#[from] std::str::Utf8Error),
#[error("Query error: {0}, {1}")]
Query(u16, String),
#[error("Clear bindings error")]
ClearBindings,
#[error("Bind params error")]
BindParams,
}
110 changes: 78 additions & 32 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ pub use error::{Error, Result};
pub use value::Value;

use crossdb_sys::*;
use params::{IntoParams, Value as ParamValue};
use std::ffi::{CStr, CString};
use std::fmt::Display;
mod params;

#[derive(Debug)]
pub struct Connection {
Expand Down Expand Up @@ -54,26 +56,70 @@ impl Connection {
let msg = CStr::from_ptr(xdb_errmsg(ptr)).to_str()?.to_string();
return Err(Error::Query(res.errcode, msg));
}
Ok(ExecResult {
ptr,
col_meta: res.col_meta,
column_count: res.col_count as usize,
row_count: res.row_count as usize,
column_types: ColumnType::all(&res),
row_index: 0,
})
let types = ColumnType::all(&res);
Ok(ExecResult { res, ptr, types })
}
}

pub fn begin(&self) -> bool {
unsafe { xdb_begin(self.ptr) == 0 }
}

pub fn commit(&self) -> bool {
unsafe { xdb_commit(self.ptr) == 0 }
}

pub fn rollback(&self) -> bool {
unsafe { xdb_rollback(self.ptr) == 0 }
}

// TODO: LRU cache
pub fn prepare<S: AsRef<str>>(&mut self, sql: S) -> Result<Stmt> {
unsafe {
let sql = CString::new(sql.as_ref())?;
let ptr = xdb_stmt_prepare(self.ptr, sql.as_ptr());
Ok(Stmt { ptr })
}
}
}

pub struct Stmt {
ptr: *mut xdb_stmt_t,
}

impl Drop for Stmt {
fn drop(&mut self) {
unsafe {
xdb_stmt_close(self.ptr);
}
}
}

impl Stmt {
pub fn exec(&self, params: impl IntoParams) -> Result<ExecResult> {
unsafe {
let ret = xdb_clear_bindings(self.ptr);
if ret != 0 {
return Err(Error::ClearBindings);
}
params.into_params()?.bind(self.ptr)?;
let ptr = xdb_stmt_exec(self.ptr);
let res = *ptr;
if res.errcode as u32 != xdb_errno_e_XDB_OK {
let msg = CStr::from_ptr(xdb_errmsg(ptr)).to_str()?.to_string();
return Err(Error::Query(res.errcode, msg));
}
let types = ColumnType::all(&res);
Ok(ExecResult { res, ptr, types })
}
}
}

#[derive(Debug)]
pub struct ExecResult {
res: xdb_res_t,
ptr: *mut xdb_res_t,
col_meta: u64,
column_count: usize,
row_count: usize,
column_types: Vec<ColumnType>,
row_index: usize,
types: Vec<ColumnType>,
}

impl Drop for ExecResult {
Expand All @@ -86,41 +132,41 @@ impl Drop for ExecResult {

impl ExecResult {
pub fn column_count(&self) -> usize {
self.column_count
self.res.col_count as usize
}

pub fn row_count(&self) -> usize {
self.row_count
self.res.row_count as usize
}

pub fn affected_rows(&self) -> u64 {
self.res.affected_rows
}

pub fn column_name<'a>(&'a self, i: usize) -> &'a str {
pub fn column_name(&self, i: usize) -> &str {
unsafe {
let name = xdb_column_name(self.col_meta, i as u16);
let name = xdb_column_name(self.res.col_meta, i as u16);
CStr::from_ptr(name).to_str().unwrap()
}
}

pub fn column_type(&self, i: usize) -> ColumnType {
self.column_types[i]
self.types[i]
}
}

impl<'a> Iterator for &'a mut ExecResult {
type Item = Vec<Value<'a>>;

fn next(&mut self) -> Option<Self::Item> {
if self.row_count <= self.row_index {
return None;
}
let mut values = Vec::with_capacity(self.column_count);
pub fn fetch_row(&mut self) -> Option<Vec<Value<'_>>> {
unsafe {
let y = xdb_fetch_row(self.ptr);
for x in 0..self.column_count {
let value = Value::from_result(self.col_meta, y, x as u16, self.column_type(x));
let row = xdb_fetch_row(self.ptr);
if row.is_null() {
return None;
}
let mut values = Vec::with_capacity(self.column_count());
for col in 0..self.column_count() {
let value =
Value::from_result(self.res.col_meta, row, col as u16, self.column_type(col));
values.push(value);
}
Some(values)
}
self.row_index += 1;
Some(values)
}
}
138 changes: 138 additions & 0 deletions src/params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
use crate::*;

pub enum Value {
Int(i32),
Int64(i64),
Float(f32),
Double(f64),
String(String),
}

trait IntoValue {
fn into_value(self) -> Result<Value>;
}

macro_rules! impl_value {
($t: ty, $v: ident) => {
impl IntoValue for $t {
fn into_value(self) -> Result<Value> {
Ok(Value::$v(self as _))
}
}
};
}
impl_value!(i8, Int);
impl_value!(u8, Int);
impl_value!(i16, Int);
impl_value!(u16, Int);
impl_value!(i32, Int);
impl_value!(u32, Int);
impl_value!(u64, Int64);
impl_value!(i64, Int64);
impl_value!(f32, Float);
impl_value!(f64, Double);
impl_value!(String, String);

impl IntoValue for &str {
fn into_value(self) -> Result<Value> {
Ok(Value::String(self.into()))
}
}

impl IntoValue for Value {
fn into_value(self) -> Result<Value> {
Ok(self)
}
}

pub enum Params {
None,
Positional(Vec<Value>),
}

impl Params {
pub(crate) unsafe fn bind(self, ptr: *mut xdb_stmt_t) -> Result<()> {
if let Params::Positional(params) = self {
for (i, p) in params.into_iter().enumerate() {
let i = i as u16 + 1;
let ret = match p {
ParamValue::Int(v) => xdb_bind_int(ptr, i, v),
ParamValue::Int64(v) => xdb_bind_int64(ptr, i, v),
ParamValue::Float(v) => xdb_bind_float(ptr, i, v),
ParamValue::Double(v) => xdb_bind_double(ptr, i, v),
ParamValue::String(v) => xdb_bind_str(ptr, i, CString::new(v)?.as_ptr()),
};
if ret != 0 {
return Err(Error::BindParams);
}
}
}
Ok(())
}
}

pub trait IntoParams {
fn into_params(self) -> Result<Params>;
}

impl IntoParams for () {
fn into_params(self) -> Result<Params> {
Ok(Params::None)
}
}

impl IntoParams for Params {
fn into_params(self) -> Result<Params> {
Ok(self)
}
}

impl<T: IntoValue> IntoParams for Vec<T> {
fn into_params(self) -> Result<Params> {
let mut params = Vec::with_capacity(self.len());
for param in self {
params.push(param.into_value()?);
}
Ok(Params::Positional(params))
}
}

impl<T: IntoValue + Clone> IntoParams for &[T] {
fn into_params(self) -> Result<Params> {
self.to_vec().into_params()
}
}

impl<T: IntoValue + Clone, const N: usize> IntoParams for &[T; N] {
fn into_params(self) -> Result<Params> {
self.to_vec().into_params()
}
}

// Copy from:https://github.com/tursodatabase/libsql/blob/main/libsql/src/params.rs#L206-L207
macro_rules! tuple_into_params {
($count:literal : $(($field:tt $ftype:ident)),* $(,)?) => {
impl<$($ftype,)*> IntoParams for ($($ftype,)*) where $($ftype: IntoValue,)* {
fn into_params(self) -> Result<Params> {
let params = Params::Positional(vec![$(self.$field.into_value()?),*]);
Ok(params)
}
}
}
}
tuple_into_params!(1: (0 A));
tuple_into_params!(2: (0 A), (1 B));
tuple_into_params!(3: (0 A), (1 B), (2 C));
tuple_into_params!(4: (0 A), (1 B), (2 C), (3 D));
tuple_into_params!(5: (0 A), (1 B), (2 C), (3 D), (4 E));
tuple_into_params!(6: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F));
tuple_into_params!(7: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G));
tuple_into_params!(8: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H));
tuple_into_params!(9: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I));
tuple_into_params!(10: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J));
tuple_into_params!(11: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K));
tuple_into_params!(12: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L));
tuple_into_params!(13: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L), (12 M));
tuple_into_params!(14: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L), (12 M), (13 N));
tuple_into_params!(15: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L), (12 M), (13 N), (14 O));
tuple_into_params!(16: (0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L), (12 M), (13 N), (14 O), (15 P));

0 comments on commit f761334

Please sign in to comment.