use self::query_result::QueryResult;
use self::stmt::Stmt;
use self::transaction::{Transaction, TransactionOptions};
use connection_like::ConnectionLike;
use consts::Command;
use errors::*;
use lib_futures::future::Future;
use myc::packets::{parse_ok_packet, RawPacket};
use myc::row::new_row;
use myc::value::{read_bin_values, read_text_values};
use prelude::FromRow;
use std::sync::Arc;
use BoxFuture;
use Column;
use Conn;
use Params;
use Row;
pub mod query_result;
pub mod stmt;
pub mod transaction;
pub trait Protocol: Send + 'static {
fn read_result_set_row(packet: &RawPacket, columns: Arc<Vec<Column>>) -> Result<Row>;
fn is_last_result_set_packet<T>(conn_like: &T, packet: &RawPacket) -> bool
where
T: ConnectionLike,
{
parse_ok_packet(&*packet.0, conn_like.get_capabilities()).is_ok()
}
}
pub struct TextProtocol;
pub struct BinaryProtocol;
impl Protocol for TextProtocol {
fn read_result_set_row(packet: &RawPacket, columns: Arc<Vec<Column>>) -> Result<Row> {
read_text_values(&*packet.0, columns.len())
.map(|values| new_row(values, columns))
.map_err(Into::into)
}
}
impl Protocol for BinaryProtocol {
fn read_result_set_row(packet: &RawPacket, columns: Arc<Vec<Column>>) -> Result<Row> {
read_bin_values(&*packet.0, &*columns)
.map(|values| new_row(values, columns))
.map_err(Into::into)
}
fn is_last_result_set_packet<T>(conn_like: &T, packet: &RawPacket) -> bool
where
T: ConnectionLike,
{
(parse_ok_packet(&*packet.0, conn_like.get_capabilities()).is_ok() && packet.0[0] == 0xFE)
}
}
pub trait Queryable: ConnectionLike
where
Self: Sized + 'static,
{
fn ping(self) -> BoxFuture<Self> {
let fut = self
.write_command_data(Command::COM_PING, &[])
.and_then(|this| this.read_packet())
.map(|(this, _)| this);
Box::new(fut)
}
fn disconnect(mut self) -> BoxFuture<()> {
self.on_disconnect();
let fut = self.write_command_data(Command::COM_QUIT, &[]).map(|_| ());
Box::new(fut)
}
fn query<Q: AsRef<str>>(self, query: Q) -> BoxFuture<QueryResult<Self, TextProtocol>> {
let fut = self
.write_command_data(Command::COM_QUERY, query.as_ref().as_bytes())
.and_then(|conn_like| conn_like.read_result_set(None));
Box::new(fut)
}
fn first<Q, R>(self, query: Q) -> BoxFuture<(Self, Option<R>)>
where
Q: AsRef<str>,
R: FromRow,
{
let fut = self
.query(query)
.and_then(|result| result.collect_and_drop::<Row>())
.map(|(this, mut rows)| {
if rows.len() > 1 {
(this, Some(FromRow::from_row(rows.swap_remove(0))))
} else {
(this, rows.pop().map(FromRow::from_row))
}
});
Box::new(fut)
}
fn drop_query<Q: AsRef<str>>(self, query: Q) -> BoxFuture<Self> {
let fut = self.query(query).and_then(|result| result.drop_result());
Box::new(fut)
}
fn prepare<Q: AsRef<str>>(self, query: Q) -> BoxFuture<Stmt<Self>> {
let fut = self
.prepare_stmt(query)
.map(|(this, inner_stmt, stmt_cache_result)| {
stmt::new(this, inner_stmt, stmt_cache_result)
});
Box::new(fut)
}
fn prep_exec<Q, P>(self, query: Q, params: P) -> BoxFuture<QueryResult<Self, BinaryProtocol>>
where
Q: AsRef<str>,
P: Into<Params>,
{
let params: Params = params.into();
let fut = self
.prepare(query)
.and_then(|stmt| stmt.execute(params))
.map(|result| {
let (stmt, columns, _) = query_result::disassemble(result);
let (conn_like, cached) = stmt.unwrap();
query_result::assemble(conn_like, columns, cached)
});
Box::new(fut)
}
fn first_exec<Q, P, R>(self, query: Q, params: P) -> BoxFuture<(Self, Option<R>)>
where
Q: AsRef<str>,
P: Into<Params>,
R: FromRow,
{
let fut = self
.prep_exec(query, params)
.and_then(|result| result.collect_and_drop::<Row>())
.map(|(this, mut rows)| {
if rows.len() > 1 {
(this, Some(FromRow::from_row(rows.swap_remove(0))))
} else {
(this, rows.pop().map(FromRow::from_row))
}
});
Box::new(fut)
}
fn drop_exec<Q, P>(self, query: Q, params: P) -> BoxFuture<Self>
where
Q: AsRef<str>,
P: Into<Params>,
{
let fut = self
.prep_exec(query, params)
.and_then(|result| result.drop_result());
Box::new(fut)
}
fn batch_exec<Q, I, P>(self, query: Q, params_iter: I) -> BoxFuture<Self>
where
Q: AsRef<str>,
I: IntoIterator<Item = P> + Send + 'static,
I::IntoIter: Send + 'static,
Params: From<P>,
P: Send + 'static,
{
let fut = self
.prepare(query)
.and_then(|stmt| stmt.batch(params_iter))
.and_then(|stmt| stmt.close());
Box::new(fut)
}
fn start_transaction(self, options: TransactionOptions) -> BoxFuture<Transaction<Self>> {
Box::new(transaction::new(self, options))
}
}
impl Queryable for Conn {}
impl<T: Queryable + ConnectionLike> Queryable for Transaction<T> {}