use super::{Column, Connection, FetchedData, QueryResultDe, ResultSetDe, Row};
use crate::error::{DataError, DriverError, RequestError, Result};
use serde::{de::DeserializeOwned, Deserialize};
use serde_json::{json, Value};
use std::fmt::Debug;
use std::marker::PhantomData;
#[derive(Debug, Deserialize)]
#[serde(from = "QueryResultDe")]
pub struct QueryResult {
row_count: usize,
result_set: Option<ResultSet>,
}
impl QueryResult {
fn new(row_count: usize, result_set: Option<ResultSet>) -> Self {
Self {
row_count,
result_set,
}
}
pub fn row_count(&self) -> usize {
self.row_count
}
pub fn result_set(&self) -> Option<&ResultSet> {
self.result_set.as_ref()
}
pub fn has_rows(&self) -> bool {
self.result_set().map(|rs| rs.is_closed()).unwrap_or(false)
}
pub(crate) fn result_set_mut(&mut self) -> Option<&mut ResultSet> {
self.result_set.as_mut()
}
pub(crate) fn lowercase_columns(&mut self, flag: bool) {
if let Some(rs) = self.result_set.as_mut() {
rs.lowercase_columns(flag);
}
}
}
impl From<QueryResultDe> for QueryResult {
fn from(qr: QueryResultDe) -> Self {
match qr {
QueryResultDe::RowCount { row_count: rc } => QueryResult::new(rc, None),
QueryResultDe::ResultSet { result_set: rs } => {
QueryResult::new(rs.num_rows(), Some(rs))
}
}
}
}
#[derive(Debug, Deserialize)]
#[serde(from = "ResultSetDe")]
pub struct ResultSet {
num_columns: usize,
total_rows_num: usize,
total_rows_pos: usize,
result_set_handle: Option<u16>,
columns: Vec<Column>,
is_closed: bool,
fetched_data: FetchedData,
}
impl From<ResultSetDe> for ResultSet {
fn from(rs: ResultSetDe) -> Self {
let fetched_data = FetchedData {
chunk_rows_num: rs.chunk_rows_num,
chunk_rows_pos: 0,
data: rs.data,
};
Self {
num_columns: rs.num_columns,
total_rows_num: rs.total_rows_num,
total_rows_pos: 0,
result_set_handle: rs.result_set_handle,
columns: rs.columns,
is_closed: false,
fetched_data,
}
}
}
impl ResultSet {
#[inline]
pub fn is_closed(&self) -> bool {
self.is_closed
}
#[inline]
pub fn columns(&self) -> &Vec<Column> {
&self.columns
}
#[inline]
pub fn num_columns(&self) -> usize {
self.num_columns
}
#[inline]
pub fn num_rows(&self) -> usize {
self.total_rows_num
}
#[inline]
pub fn position(&self) -> usize {
self.total_rows_pos
}
#[inline]
pub fn handle(&self) -> Option<u16> {
self.result_set_handle
}
pub(crate) fn lowercase_columns(&mut self, flag: bool) {
if flag {
self.columns.iter_mut().for_each(|c| c.use_lowercase_name());
}
}
}
pub struct ResultSetIter<'a, T: DeserializeOwned> {
rs: &'a mut ResultSet,
con: &'a mut Connection,
row_type: PhantomData<T>,
}
impl<'a, T> ResultSetIter<'a, T>
where
T: DeserializeOwned,
{
pub fn new(rs: &'a mut ResultSet, con: &'a mut Connection) -> Self {
Self {
rs,
con,
row_type: PhantomData,
}
}
fn parse_row(&self, row: Vec<Value>) -> Result<T> {
let row_len = row.len();
let res = match row_len == self.rs.num_columns {
true => self.deser_row(row),
false => Err(DataError::IncorrectLength(self.rs.num_columns, row_len)),
};
Ok(res.map_err(DriverError::DataError)?)
}
fn deser_row(&self, row: Vec<Value>) -> std::result::Result<T, DataError> {
T::deserialize(Row::new(row, &self.rs.columns)).map_err(DataError::TypeParseError)
}
fn next_row(&mut self) -> Result<T> {
let mut row = Vec::with_capacity(self.rs.num_columns);
let fd = &mut self.rs.fetched_data;
(0..self.rs.num_columns)
.into_iter()
.map(|i| fd.chunk_rows_pos + i * fd.chunk_rows_num)
.map(|i| fd.data.get_mut(i).map(|v| v.take()))
.for_each(|o| row.extend(o));
self.parse_row(row)
}
fn close(&mut self) -> Result<()> {
self.rs.is_closed = true;
self.rs
.result_set_handle
.map_or(Ok(()), |h| self.con.close_results_impl(&[h]))
}
fn fetch_chunk(&mut self) -> Result<()> {
self.rs
.result_set_handle
.ok_or_else(|| DriverError::RequestError(RequestError::MissingHandleError).into())
.and_then(|h| {
let payload = json!({
"command": "fetch",
"resultSetHandle": h,
"startPosition": self.rs.total_rows_pos,
"numBytes": self.con.fetch_size()
});
self.rs.fetched_data = self.con.get_resp_data(payload)?.try_into()?;
Ok(())
})
}
}
impl<'a, T> Iterator for ResultSetIter<'a, T>
where
T: DeserializeOwned,
{
type Item = Result<T>;
fn next(&mut self) -> Option<Self::Item> {
let row = if self.rs.fetched_data.chunk_rows_pos < self.rs.fetched_data.chunk_rows_num {
Some(self.next_row())
} else if self.rs.total_rows_pos >= self.rs.total_rows_num {
None
} else {
self.fetch_chunk()
.map_or_else(|e| Some(Err(e)), |_| Some(self.next_row()))
};
self.rs.total_rows_pos += 1;
self.rs.fetched_data.chunk_rows_pos += 1;
row.or_else(|| self.close().map_or_else(|e| Some(Err(e)), |_| None))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.rs.total_rows_num - self.rs.total_rows_pos;
(remaining, Some(remaining))
}
}