use crate::connection::ConnectionImpl;
use crate::error::{ConversionError, DataError, DriverError, RequestError, Result};
use crate::response::{Column, QueryResultDe, ResultSetDe};
use crate::response::{ParameterData, PreparedStatementDe};
use crate::row::{to_col_major, Row};
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::{json, Value};
use std::cell::RefCell;
use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;
use std::rc::Rc;
use std::vec::IntoIter;
pub enum QueryResult {
ResultSet(ResultSet),
RowCount(u32),
}
impl Debug for QueryResult {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::ResultSet(r) => write!(f, "{:?}", r),
Self::RowCount(c) => write!(f, "Row count: {}", c),
}
}
}
impl TryFrom<QueryResult> for ResultSet {
type Error = ConversionError;
#[inline]
fn try_from(value: QueryResult) -> std::result::Result<Self, Self::Error> {
match value {
QueryResult::ResultSet(r) => Ok(r),
_ => Err(ConversionError::ResultSetError),
}
}
}
impl TryFrom<QueryResult> for u32 {
type Error = ConversionError;
#[inline]
fn try_from(value: QueryResult) -> std::result::Result<Self, Self::Error> {
match value {
QueryResult::RowCount(r) => Ok(r),
_ => Err(ConversionError::RowCountError),
}
}
}
impl QueryResult {
#[inline]
pub(crate) fn from_de(
query_result: QueryResultDe,
con_rc: &Rc<RefCell<ConnectionImpl>>,
) -> Self {
match query_result {
QueryResultDe::ResultSet { result_set } => {
QueryResult::ResultSet(ResultSet::from_de(result_set, con_rc))
}
QueryResultDe::RowCount { row_count } => QueryResult::RowCount(row_count),
}
}
}
#[allow(unused)]
pub struct ResultSet<T: DeserializeOwned = Vec<Value>> {
num_columns: u8,
total_rows_num: u32,
total_rows_pos: u32,
chunk_rows_num: usize,
chunk_rows_pos: usize,
result_set_handle: Option<u16>,
columns: Vec<Column>,
data_iter: IntoIter<Vec<Value>>,
connection: Rc<RefCell<ConnectionImpl>>,
is_closed: bool,
row_type: PhantomData<*const T>,
}
impl<T> Debug for ResultSet<T>
where
T: DeserializeOwned,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Closed: {}\n\
Handle: {:?}\n\
Columns: {:?}\n\
Rows: {}",
self.is_closed, self.result_set_handle, self.columns, self.total_rows_num
)
}
}
impl<T> ResultSet<T>
where
T: DeserializeOwned,
{
#[inline]
pub fn columns(&self) -> &Vec<Column> {
&self.columns
}
#[inline]
pub fn num_columns(&self) -> &u8 {
&self.num_columns
}
#[inline]
pub fn num_rows(&self) -> &u32 {
&self.total_rows_num
}
pub fn with_row_type<R>(mut self) -> ResultSet<R>
where
R: DeserializeOwned,
{
ResultSet {
num_columns: self.num_columns,
total_rows_num: self.total_rows_num,
total_rows_pos: self.total_rows_pos,
chunk_rows_num: self.chunk_rows_num,
chunk_rows_pos: self.chunk_rows_pos,
result_set_handle: self.result_set_handle,
columns: std::mem::take(&mut self.columns),
data_iter: std::mem::replace(&mut self.data_iter, vec![].into_iter()),
connection: Rc::clone(&self.connection),
is_closed: self.is_closed,
row_type: PhantomData,
}
}
pub(crate) fn from_de(result_set: ResultSetDe, con_rc: &Rc<RefCell<ConnectionImpl>>) -> Self {
Self {
num_columns: result_set.num_columns,
total_rows_num: result_set.total_rows_num,
total_rows_pos: 0,
chunk_rows_num: result_set.chunk_rows_num,
chunk_rows_pos: 0,
result_set_handle: result_set.result_set_handle,
columns: result_set.columns,
data_iter: result_set.data.into_iter(),
connection: Rc::clone(con_rc),
is_closed: false,
row_type: PhantomData,
}
}
#[inline]
fn next_row(&mut self) -> Option<Result<T>> {
self.data_iter.next().map(|r| {
Ok(T::deserialize(Row::new(r, &self.columns))
.map_err(DataError::TypeParseError)
.map_err(DriverError::DataError)?)
})
}
#[inline]
fn close(&mut self) -> Result<()> {
self.result_set_handle.map_or(Ok(()), |h| {
if !self.is_closed {
self.is_closed = true;
(*self.connection).borrow_mut().close_result_set(h)
} else {
Ok(())
}
})
}
fn fetch_chunk(&mut self) -> Result<()> {
self.result_set_handle
.ok_or_else(|| DriverError::RequestError(RequestError::MissingHandleError).into())
.and_then(|h| {
let mut con = (*self.connection).borrow_mut();
let fetch_size = con.get_attr("fetch_size").unwrap();
let payload = json!({
"command": "fetch",
"resultSetHandle": h,
"startPosition": self.total_rows_pos,
"numBytes": fetch_size,
});
con.get_resp_data(payload)?.try_to_fetched_data().map(|f| {
self.chunk_rows_num = f.chunk_rows_num;
self.chunk_rows_pos = 0;
self.data_iter = f.data.into_iter();
})
})
}
}
impl<T> Iterator for ResultSet<T>
where
T: DeserializeOwned,
{
type Item = Result<T>;
fn next(&mut self) -> Option<Self::Item> {
let row = self.next_row().or_else(|| {
if self.total_rows_pos >= self.total_rows_num {
None
} else if self.chunk_rows_pos >= self.chunk_rows_num {
self.fetch_chunk()
.map_or_else(|e| Some(Err(e)), |_| self.next_row())
} else {
None
}
});
self.total_rows_pos += 1;
self.chunk_rows_pos += 1;
row.or_else(|| self.close().map_or_else(|e| Some(Err(e)), |_| None))
}
}
impl<T> Drop for ResultSet<T>
where
T: DeserializeOwned,
{
fn drop(&mut self) {
self.close().ok();
}
}
#[derive(Debug)]
pub struct PreparedStatement {
statement_handle: usize,
parameter_data: Option<ParameterData>,
connection: Rc<RefCell<ConnectionImpl>>,
}
impl PreparedStatement {
pub(crate) fn from_de(
prep_stmt: PreparedStatementDe,
con_rc: &Rc<RefCell<ConnectionImpl>>,
) -> Self {
Self {
statement_handle: prep_stmt.statement_handle,
parameter_data: prep_stmt.parameter_data,
connection: Rc::clone(con_rc),
}
}
pub fn execute<T, S>(&self, data: T) -> Result<QueryResult>
where
S: Serialize,
T: IntoIterator<Item = S>,
{
let (num_columns, columns) = match self.parameter_data.as_ref() {
Some(p) => (&p.num_columns, p.columns.as_slice()),
None => (&0, [].as_slice()),
};
let col_names = columns
.iter()
.map(|c| c.name.as_str())
.collect::<Vec<&str>>();
let col_major_data = to_col_major(&col_names, data).map_err(DriverError::DataError)?;
let payload = json!({
"command": "executePreparedStatement",
"statementHandle": &self.statement_handle,
"numColumns": num_columns,
"numRows": col_major_data.len(),
"columns": columns,
"data": col_major_data
});
self.connection
.borrow_mut()
.exec_and_get_first(&self.connection, payload)
}
#[inline]
pub fn close(&mut self) -> Result<()> {
(*self.connection)
.borrow_mut()
.close_prepared_stmt(self.statement_handle)
}
}
impl Drop for PreparedStatement {
fn drop(&mut self) {
self.close().ok();
}
}