Make nice types for parameter and result descs

This commit is contained in:
Steven Fackler 2013-09-04 21:26:43 -07:00
parent 06a9a7c399
commit 749aa735f6
2 changed files with 137 additions and 73 deletions

View File

@ -17,7 +17,7 @@ use std::rt::io::net::ip::SocketAddr;
use std::rt::io::net::tcp::TcpStream;
use message::*;
use types::{Oid, ToSql, FromSql};
use types::{PostgresType, ToSql, FromSql};
mod message;
mod types;
@ -295,11 +295,20 @@ impl PostgresConnection {
})
let param_types = match_read_message_or_fail!(self, {
ParameterDescription { types } => types
ParameterDescription { types } =>
types.iter().map(|ty| { PostgresType::from_oid(*ty) })
.collect()
});
let result_desc = match_read_message_or_fail!(self, {
RowDescription { descriptions } => descriptions,
RowDescription { descriptions } => {
let mut res: ~[ResultDescription] = descriptions
.move_rev_iter().map(|desc| {
ResultDescription::from_row_description_entry(desc)
}).collect();
res.reverse();
res
},
NoData => ~[]
});
@ -424,11 +433,28 @@ pub trait PostgresStatement {
pub struct NormalPostgresStatement<'self> {
priv conn: &'self PostgresConnection,
priv name: ~str,
priv param_types: ~[Oid],
priv result_desc: ~[RowDescriptionEntry],
priv param_types: ~[PostgresType],
priv result_desc: ~[ResultDescription],
priv next_portal_id: Cell<uint>
}
pub struct ResultDescription {
name: ~str,
ty: PostgresType
}
impl ResultDescription {
fn from_row_description_entry(row: RowDescriptionEntry)
-> ResultDescription {
let RowDescriptionEntry { name, type_oid, _ } = row;
ResultDescription {
name: name,
ty: PostgresType::from_oid(type_oid)
}
}
}
#[unsafe_destructor]
impl<'self> Drop for NormalPostgresStatement<'self> {
fn drop(&self) {
@ -461,7 +487,7 @@ impl<'self> NormalPostgresStatement<'self> {
};
let result_formats: ~[i16] = self.result_desc.iter().map(|desc| {
types::result_format(desc.type_oid) as i16
desc.ty.result_format() as i16
}).collect();
self.conn.write_messages([
@ -717,7 +743,7 @@ impl<'self> Container for PostgresRow<'self> {
impl<'self, I: RowIndex, T: FromSql> Index<I, T> for PostgresRow<'self> {
fn index(&self, idx: &I) -> T {
let idx = idx.idx(self.stmt);
FromSql::from_sql(self.stmt.result_desc[idx].type_oid,
FromSql::from_sql(self.stmt.result_desc[idx].ty,
&self.data[idx])
}
}

View File

@ -25,25 +25,63 @@ static BPCHAROID: Oid = 1042;
static VARCHAROID: Oid = 1043;
static UUIDOID: Oid = 2950;
pub enum PostgresType {
PgBool,
PgByteA,
PgChar,
PgInt8,
PgInt2,
PgInt4,
PgText,
PgJson,
PgFloat4,
PgFloat8,
PgCharN,
PgVarchar,
PgUuid,
PgUnknownType(Oid)
}
impl PostgresType {
pub fn from_oid(oid: Oid) -> PostgresType {
match oid {
BOOLOID => PgBool,
BYTEAOID => PgByteA,
CHAROID => PgChar,
INT8OID => PgInt8,
INT2OID => PgInt2,
INT4OID => PgInt4,
TEXTOID => PgText,
JSONOID => PgJson,
FLOAT4OID => PgFloat4,
FLOAT8OID => PgFloat8,
BPCHAROID => PgCharN,
VARCHAROID => PgVarchar,
UUIDOID => PgUuid,
oid => PgUnknownType(oid)
}
}
pub fn result_format(&self) -> Format {
match *self {
PgBool
| PgByteA
| PgInt8
| PgInt2
| PgInt4
| PgFloat4
| PgFloat8
| PgUuid => Binary,
_ => Text
}
}
}
pub enum Format {
Text = 0,
Binary = 1
}
pub fn result_format(ty: Oid) -> Format {
match ty {
BOOLOID |
BYTEAOID |
INT8OID |
INT2OID |
INT4OID |
FLOAT4OID |
FLOAT8OID |
UUIDOID => Binary,
_ => Text
}
}
macro_rules! check_oid(
($($expected:ident)|+, $actual:ident) => (
match $actual {
@ -54,13 +92,13 @@ macro_rules! check_oid(
)
pub trait FromSql {
fn from_sql(ty: Oid, raw: &Option<~[u8]>) -> Self;
fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Self;
}
macro_rules! from_map_impl(
($($oid:ident)|+, $t:ty, $blk:expr) => (
impl FromSql for Option<$t> {
fn from_sql(ty: Oid, raw: &Option<~[u8]>) -> Option<$t> {
fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<$t> {
check_oid!($($oid)|+, ty)
raw.map($blk)
}
@ -80,7 +118,7 @@ macro_rules! from_conversions_impl(
macro_rules! from_option_impl(
($t:ty) => (
impl FromSql for $t {
fn from_sql(ty: Oid, raw: &Option<~[u8]>) -> $t {
fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> $t {
// FIXME when you can specify Self types properly
let ret: Option<$t> = FromSql::from_sql(ty, raw);
ret.unwrap()
@ -89,53 +127,53 @@ macro_rules! from_option_impl(
)
)
from_map_impl!(BOOLOID, bool, |buf| { buf[0] != 0 })
from_map_impl!(PgBool, bool, |buf| { buf[0] != 0 })
from_option_impl!(bool)
from_conversions_impl!(CHAROID, i8, read_i8_)
from_conversions_impl!(PgChar, i8, read_i8_)
from_option_impl!(i8)
from_conversions_impl!(INT2OID, i16, read_be_i16_)
from_conversions_impl!(PgInt2, i16, read_be_i16_)
from_option_impl!(i16)
from_conversions_impl!(INT4OID, i32, read_be_i32_)
from_conversions_impl!(PgInt4, i32, read_be_i32_)
from_option_impl!(i32)
from_conversions_impl!(INT8OID, i64, read_be_i64_)
from_conversions_impl!(PgInt8, i64, read_be_i64_)
from_option_impl!(i64)
from_conversions_impl!(FLOAT4OID, f32, read_be_f32_)
from_conversions_impl!(PgFloat4, f32, read_be_f32_)
from_option_impl!(f32)
from_conversions_impl!(FLOAT8OID, f64, read_be_f64_)
from_conversions_impl!(PgFloat8, f64, read_be_f64_)
from_option_impl!(f64)
from_map_impl!(VARCHAROID | TEXTOID | BPCHAROID, ~str, |buf| {
from_map_impl!(PgVarchar | PgText | PgCharN, ~str, |buf| {
str::from_bytes(buf.as_slice())
})
from_option_impl!(~str)
impl FromSql for Option<~[u8]> {
fn from_sql(ty: Oid, raw: &Option<~[u8]>) -> Option<~[u8]> {
check_oid!(BYTEAOID, ty)
fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<~[u8]> {
check_oid!(PgByteA, ty)
raw.clone()
}
}
from_option_impl!(~[u8])
from_map_impl!(JSONOID, Json, |buf| {
from_map_impl!(PgJson, Json, |buf| {
json::from_str(str::from_bytes_slice(buf.as_slice())).unwrap()
})
from_option_impl!(Json)
from_map_impl!(UUIDOID, Uuid, |buf| {
from_map_impl!(PgUuid, Uuid, |buf| {
Uuid::from_bytes(buf.as_slice()).unwrap()
})
from_option_impl!(Uuid)
pub trait ToSql {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>);
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>);
}
macro_rules! to_option_impl(
($($oid:ident)|+, $t:ty) => (
impl ToSql for Option<$t> {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
check_oid!($($oid)|+, ty)
match *self {
@ -147,7 +185,7 @@ macro_rules! to_option_impl(
);
(self, $($oid:ident)|+, $t:ty) => (
impl<'self> ToSql for Option<$t> {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
check_oid!($($oid)|+, ty)
match *self {
@ -162,7 +200,7 @@ macro_rules! to_option_impl(
macro_rules! to_conversions_impl(
($($oid:ident)|+, $t:ty, $f:ident) => (
impl ToSql for $t {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
check_oid!($($oid)|+, ty)
let mut writer = MemWriter::new();
@ -174,74 +212,74 @@ macro_rules! to_conversions_impl(
)
impl ToSql for bool {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
check_oid!(BOOLOID, ty)
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
check_oid!(PgBool, ty)
(Binary, Some(~[*self as u8]))
}
}
to_option_impl!(BOOLOID, bool)
to_option_impl!(PgBool, bool)
to_conversions_impl!(CHAROID, i8, write_i8_)
to_option_impl!(CHAROID, i8)
to_conversions_impl!(INT2OID, i16, write_be_i16_)
to_option_impl!(INT2OID, i16)
to_conversions_impl!(INT4OID, i32, write_be_i32_)
to_option_impl!(INT4OID, i32)
to_conversions_impl!(INT8OID, i64, write_be_i64_)
to_option_impl!(INT8OID, i64)
to_conversions_impl!(FLOAT4OID, f32, write_be_f32_)
to_option_impl!(FLOAT4OID, f32)
to_conversions_impl!(FLOAT8OID, f64, write_be_f64_)
to_option_impl!(FLOAT8OID, f64)
to_conversions_impl!(PgChar, i8, write_i8_)
to_option_impl!(PgChar, i8)
to_conversions_impl!(PgInt2, i16, write_be_i16_)
to_option_impl!(PgInt2, i16)
to_conversions_impl!(PgInt4, i32, write_be_i32_)
to_option_impl!(PgInt4, i32)
to_conversions_impl!(PgInt8, i64, write_be_i64_)
to_option_impl!(PgInt8, i64)
to_conversions_impl!(PgFloat4, f32, write_be_f32_)
to_option_impl!(PgFloat4, f32)
to_conversions_impl!(PgFloat8, f64, write_be_f64_)
to_option_impl!(PgFloat8, f64)
impl ToSql for ~str {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
check_oid!(VARCHAROID | TEXTOID | BPCHAROID, ty)
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
check_oid!(PgVarchar | PgText | PgCharN, ty)
(Text, Some(self.as_bytes().to_owned()))
}
}
impl<'self> ToSql for &'self str {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
check_oid!(VARCHAROID | TEXTOID | BPCHAROID, ty)
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
check_oid!(PgVarchar | PgText | PgCharN, ty)
(Text, Some(self.as_bytes().to_owned()))
}
}
to_option_impl!(VARCHAROID | TEXTOID | BPCHAROID, ~str)
to_option_impl!(self, VARCHAROID | TEXTOID | BPCHAROID, &'self str)
to_option_impl!(PgVarchar | PgText | PgCharN, ~str)
to_option_impl!(self, PgVarchar | PgText | PgCharN, &'self str)
impl ToSql for ~[u8] {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
check_oid!(BYTEAOID, ty)
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
check_oid!(PgByteA, ty)
(Binary, Some(self.to_owned()))
}
}
impl<'self> ToSql for &'self [u8] {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
check_oid!(BYTEAOID, ty)
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
check_oid!(PgByteA, ty)
(Binary, Some(self.to_owned()))
}
}
to_option_impl!(BYTEAOID, ~[u8])
to_option_impl!(self, BYTEAOID, &'self [u8])
to_option_impl!(PgByteA, ~[u8])
to_option_impl!(self, PgByteA, &'self [u8])
impl ToSql for Json {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
check_oid!(JSONOID, ty)
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
check_oid!(PgJson, ty)
(Text, Some(self.to_str().into_bytes()))
}
}
to_option_impl!(JSONOID, Json)
to_option_impl!(PgJson, Json)
impl ToSql for Uuid {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
check_oid!(UUIDOID, ty)
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
check_oid!(PgUuid, ty)
(Binary, Some(self.to_bytes().to_owned()))
}
}
to_option_impl!(UUIDOID, Uuid)
to_option_impl!(PgUuid, Uuid)