use fnv::FnvHasher;
use mysql_common::row::new_row;
use std::collections::hash_map::HashMap;
use std::hash::BuildHasherDefault as BldHshrDflt;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use crate::{Column, Conn, Result as MyResult, Row, Stmt};
#[derive(Debug)]
pub enum ResultConnRef<'a> {
ViaConnRef(&'a mut Conn),
ViaStmt(Stmt<'a>),
}
impl<'a> Deref for ResultConnRef<'a> {
type Target = Conn;
fn deref(&self) -> &Conn {
match *self {
ResultConnRef::ViaConnRef(ref conn_ref) => conn_ref,
ResultConnRef::ViaStmt(ref stmt) => stmt.conn.deref(),
}
}
}
impl<'a> DerefMut for ResultConnRef<'a> {
fn deref_mut(&mut self) -> &mut Conn {
match *self {
ResultConnRef::ViaConnRef(ref mut conn_ref) => conn_ref,
ResultConnRef::ViaStmt(ref mut stmt) => stmt.conn.deref_mut(),
}
}
}
#[derive(Debug)]
pub struct QueryResult<'a> {
conn: ResultConnRef<'a>,
columns: Arc<Vec<Column>>,
is_bin: bool,
}
impl<'a> QueryResult<'a> {
pub(crate) fn new(
conn: ResultConnRef<'a>,
columns: Vec<Column>,
is_bin: bool,
) -> QueryResult<'a> {
QueryResult {
conn,
columns: Arc::new(columns),
is_bin,
}
}
fn handle_if_more_results(&mut self) -> Option<MyResult<Row>> {
if self.conn.more_results_exists() {
match self.conn.handle_result_set() {
Ok(cols) => {
self.columns = Arc::new(cols);
None
}
Err(e) => Some(Err(e)),
}
} else {
None
}
}
pub fn affected_rows(&self) -> u64 {
self.conn.affected_rows
}
pub fn last_insert_id(&self) -> u64 {
self.conn.last_insert_id
}
pub fn warnings(&self) -> u16 {
self.conn.warnings
}
pub fn info(&self) -> Vec<u8> {
self.conn
.info
.as_ref()
.map(Clone::clone)
.unwrap_or_else(Vec::new)
}
pub fn column_index<T: AsRef<str>>(&self, name: T) -> Option<usize> {
let name = name.as_ref().as_bytes();
for (i, c) in self.columns.iter().enumerate() {
if c.name_ref() == name {
return Some(i);
}
}
None
}
pub fn column_indexes(&self) -> HashMap<String, usize, BldHshrDflt<FnvHasher>> {
let mut indexes = HashMap::default();
for (i, column) in self.columns.iter().enumerate() {
indexes.insert(column.name_str().into_owned(), i);
}
indexes
}
pub fn columns_ref(&self) -> &[Column] {
self.columns.as_ref()
}
pub fn more_results_exists(&self) -> bool {
self.conn.more_results_exists() || !self.consumed()
}
pub fn consumed(&self) -> bool {
!self.conn.has_results
}
}
impl<'a> Iterator for QueryResult<'a> {
type Item = MyResult<Row>;
fn next(&mut self) -> Option<MyResult<Row>> {
let values = if self.columns.len() > 0 {
if self.is_bin {
self.conn.next_bin(&self.columns)
} else {
self.conn.next_text(self.columns.len())
}
} else {
Ok(None)
};
match values {
Ok(values) => match values {
Some(values) => Some(Ok(new_row(values, self.columns.clone()))),
None => self.handle_if_more_results(),
},
Err(e) => Some(Err(e)),
}
}
}
impl<'a> Drop for QueryResult<'a> {
fn drop(&mut self) {
while self.more_results_exists() {
while let Some(_) = self.next() {}
}
}
}