Add a Row struct
This commit is contained in:
parent
361c7bf395
commit
8b1034ad4e
@ -6,8 +6,11 @@ extern crate phf;
|
|||||||
extern crate postgres_protocol;
|
extern crate postgres_protocol;
|
||||||
|
|
||||||
use fallible_iterator::{FallibleIterator, FromFallibleIterator};
|
use fallible_iterator::{FallibleIterator, FromFallibleIterator};
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use types::Type;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod params;
|
pub mod params;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
@ -54,3 +57,67 @@ impl RowData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Column {
|
||||||
|
name: String,
|
||||||
|
type_: Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Column {
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn new(name: String, type_: Type) -> Column {
|
||||||
|
Column {
|
||||||
|
name: name,
|
||||||
|
type_: type_,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_(&self) -> &Type {
|
||||||
|
&self.type_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait implemented by types that can index into columns of a row.
|
||||||
|
pub trait RowIndex {
|
||||||
|
/// Returns the index of the appropriate column, or `None` if no such
|
||||||
|
/// column exists.
|
||||||
|
fn idx(&self, stmt: &[Column]) -> Option<usize>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RowIndex for usize {
|
||||||
|
#[inline]
|
||||||
|
fn idx(&self, stmt: &[Column]) -> Option<usize> {
|
||||||
|
if *self >= stmt.len() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RowIndex for str {
|
||||||
|
#[inline]
|
||||||
|
fn idx(&self, stmt: &[Column]) -> Option<usize> {
|
||||||
|
if let Some(idx) = stmt.iter().position(|d| d.name() == self) {
|
||||||
|
return Some(idx);
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME ASCII-only case insensitivity isn't really the right thing to
|
||||||
|
// do. Postgres itself uses a dubious wrapper around tolower and JDBC
|
||||||
|
// uses the US locale.
|
||||||
|
stmt.iter().position(|d| d.name().eq_ignore_ascii_case(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> RowIndex for &'a T
|
||||||
|
where T: RowIndex
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn idx(&self, columns: &[Column]) -> Option<usize> {
|
||||||
|
T::idx(*self, columns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,19 +14,21 @@ use postgres_protocol::message::{backend, frontend};
|
|||||||
use postgres_protocol::message::backend::{ErrorResponseBody, ErrorFields};
|
use postgres_protocol::message::backend::{ErrorResponseBody, ErrorFields};
|
||||||
use postgres_shared::RowData;
|
use postgres_shared::RowData;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::error::Error as StdError;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::sync::mpsc::{self, Sender, Receiver};
|
use std::sync::mpsc::{self, Sender, Receiver};
|
||||||
use tokio_core::reactor::Handle;
|
use tokio_core::reactor::Handle;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use postgres_shared::{params, types};
|
pub use postgres_shared::{params, types, Column, RowIndex};
|
||||||
|
|
||||||
use error::{ConnectError, Error, DbError};
|
use error::{ConnectError, Error, DbError};
|
||||||
use params::{ConnectParams, IntoConnectParams};
|
use params::{ConnectParams, IntoConnectParams};
|
||||||
use stream::PostgresStream;
|
use stream::PostgresStream;
|
||||||
use types::{Oid, Type, ToSql, SessionInfo, IsNull};
|
use types::{Oid, Type, ToSql, SessionInfo, IsNull, FromSql, WrongType};
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod stream;
|
mod stream;
|
||||||
@ -293,30 +295,6 @@ impl Connection {
|
|||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn read_rows(self, mut rows: Vec<RowData>) -> BoxFuture<(Vec<RowData>, Connection), Error> {
|
|
||||||
self.0.read()
|
|
||||||
.map_err(Error::Io)
|
|
||||||
.and_then(|(m, s)| {
|
|
||||||
match m {
|
|
||||||
backend::Message::EmptyQueryResponse |
|
|
||||||
backend::Message::CommandComplete(_) => Connection(s).ready(rows).boxed(),
|
|
||||||
backend::Message::DataRow(body) => {
|
|
||||||
match body.values().collect() {
|
|
||||||
Ok(row) => {
|
|
||||||
rows.push(row);
|
|
||||||
Connection(s).read_rows(rows)
|
|
||||||
}
|
|
||||||
Err(e) => Err(Error::Io(e)).into_future().boxed(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
backend::Message::ErrorResponse(body) => Connection(s).ready_err(body),
|
|
||||||
_ => Err(bad_message()).into_future().boxed(),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.boxed()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ready<T>(self, t: T) -> BoxFuture<(T, Connection), Error>
|
fn ready<T>(self, t: T) -> BoxFuture<(T, Connection), Error>
|
||||||
where T: 'static + Send
|
where T: 'static + Send
|
||||||
{
|
{
|
||||||
@ -452,7 +430,7 @@ impl Connection {
|
|||||||
s.get_types(r.into_iter(),
|
s.get_types(r.into_iter(),
|
||||||
vec![],
|
vec![],
|
||||||
|f| f.1,
|
|f| f.1,
|
||||||
|f, t| Column { name: f.0, type_: t })
|
|f, t| Column::new(f.0, t))
|
||||||
.map(|(r, s)| (p, r, s))
|
.map(|(r, s)| (p, r, s))
|
||||||
})
|
})
|
||||||
.boxed()
|
.boxed()
|
||||||
@ -594,7 +572,7 @@ impl Connection {
|
|||||||
close_sender: conn.0.close_sender.clone(),
|
close_sender: conn.0.close_sender.clone(),
|
||||||
name: name,
|
name: name,
|
||||||
params: params,
|
params: params,
|
||||||
columns: columns,
|
columns: Arc::new(columns),
|
||||||
};
|
};
|
||||||
(stmt, conn)
|
(stmt, conn)
|
||||||
})
|
})
|
||||||
@ -615,26 +593,11 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Column {
|
|
||||||
name: String,
|
|
||||||
type_: Type,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Column {
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_(&self) -> &Type {
|
|
||||||
&self.type_
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Statement {
|
pub struct Statement {
|
||||||
close_sender: Sender<(u8, String)>,
|
close_sender: Sender<(u8, String)>,
|
||||||
name: String,
|
name: String,
|
||||||
params: Vec<Type>,
|
params: Vec<Type>,
|
||||||
columns: Vec<Column>,
|
columns: Arc<Vec<Column>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Statement {
|
impl Drop for Statement {
|
||||||
@ -664,6 +627,42 @@ impl Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Row {
|
||||||
|
columns: Arc<Vec<Column>>,
|
||||||
|
data: RowData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Row {
|
||||||
|
pub fn get<T, I>(&self, idx: I) -> T
|
||||||
|
where T: FromSql,
|
||||||
|
I: RowIndex + fmt::Debug
|
||||||
|
{
|
||||||
|
match self.try_get(&idx) {
|
||||||
|
Ok(Some(v)) => v,
|
||||||
|
Ok(None) => panic!("no such column {:?}", idx),
|
||||||
|
Err(e) => panic!("error retrieving row {:?}: {}", idx, e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_get<T, I>(&self, idx: I) -> Result<Option<T>, Box<StdError + Sync + Send>>
|
||||||
|
where T: FromSql,
|
||||||
|
I: RowIndex
|
||||||
|
{
|
||||||
|
let idx = match idx.idx(&self.columns) {
|
||||||
|
Some(idx) => idx,
|
||||||
|
None => return Ok(None),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ty = self.columns[idx].type_();
|
||||||
|
if !T::accepts(ty) {
|
||||||
|
return Err(Box::new(WrongType::new(ty.clone())));
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
T::from_sql_nullable(ty, self.data.get(idx), &SessionInfo::new(&HashMap::new())).map(Some)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn connect_err(fields: &mut ErrorFields) -> ConnectError {
|
fn connect_err(fields: &mut ErrorFields) -> ConnectError {
|
||||||
match DbError::new(fields) {
|
match DbError::new(fields) {
|
||||||
Ok(err) => ConnectError::Db(Box::new(err)),
|
Ok(err) => ConnectError::Db(Box::new(err)),
|
||||||
|
Loading…
Reference in New Issue
Block a user