rust-postgres/src/types.rs

287 lines
7.2 KiB
Rust
Raw Normal View History

2013-09-02 20:54:02 +00:00
extern mod extra;
use extra::json;
use extra::json::Json;
use extra::uuid::Uuid;
use std::rt::io::Decorator;
use std::rt::io::extensions::{WriterByteConversions, ReaderByteConversions};
2013-09-04 02:35:28 +00:00
use std::rt::io::mem::{MemWriter, BufReader};
use std::str;
pub type Oid = i32;
// Values from pg_type.h
static BOOLOID: Oid = 16;
static BYTEAOID: Oid = 17;
2013-09-02 22:14:22 +00:00
static CHAROID: Oid = 18;
static INT8OID: Oid = 20;
static INT2OID: Oid = 21;
static INT4OID: Oid = 23;
2013-09-02 20:07:57 +00:00
static TEXTOID: Oid = 25;
2013-09-02 20:54:02 +00:00
static JSONOID: Oid = 114;
static FLOAT4OID: Oid = 700;
static FLOAT8OID: Oid = 701;
2013-09-02 21:52:23 +00:00
static BPCHAROID: Oid = 1042;
2013-09-02 17:27:09 +00:00
static VARCHAROID: Oid = 1043;
2013-09-02 20:54:02 +00:00
static UUIDOID: Oid = 2950;
#[deriving(Eq)]
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
}
2013-09-05 04:30:20 +00:00
macro_rules! check_types(
($($expected:pat)|+, $actual:ident) => (
2013-09-02 20:07:57 +00:00
match $actual {
$($expected)|+ => (),
2013-09-05 04:30:20 +00:00
actual => fail2!("Invalid Postgres type {:?}", actual)
}
)
)
pub trait FromSql {
fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Self;
}
2013-09-02 21:06:22 +00:00
macro_rules! from_map_impl(
2013-09-05 04:30:20 +00:00
($($expected:pat)|+, $t:ty, $blk:expr) => (
impl FromSql for Option<$t> {
fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<$t> {
2013-09-05 04:30:20 +00:00
check_types!($($expected)|+, ty)
2013-09-02 21:06:22 +00:00
raw.map($blk)
}
}
)
)
2013-09-02 21:06:22 +00:00
macro_rules! from_conversions_impl(
2013-09-05 04:30:20 +00:00
($expected:pat, $t:ty, $f:ident) => (
from_map_impl!($expected, $t, |buf| {
2013-09-04 02:35:28 +00:00
let mut reader = BufReader::new(buf.as_slice());
2013-09-02 21:06:22 +00:00
reader.$f()
})
)
)
macro_rules! from_option_impl(
($t:ty) => (
impl FromSql for $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()
}
}
)
)
from_map_impl!(PgBool, bool, |buf| { buf[0] != 0 })
from_option_impl!(bool)
from_conversions_impl!(PgChar, i8, read_i8_)
2013-09-02 22:14:22 +00:00
from_option_impl!(i8)
from_conversions_impl!(PgInt2, i16, read_be_i16_)
from_option_impl!(i16)
from_conversions_impl!(PgInt4, i32, read_be_i32_)
from_option_impl!(i32)
from_conversions_impl!(PgInt8, i64, read_be_i64_)
from_option_impl!(i64)
from_conversions_impl!(PgFloat4, f32, read_be_f32_)
from_option_impl!(f32)
from_conversions_impl!(PgFloat8, f64, read_be_f64_)
from_option_impl!(f64)
from_map_impl!(PgVarchar | PgText | PgCharN, ~str, |buf| {
str::from_utf8(buf.as_slice())
2013-09-02 21:06:22 +00:00
})
from_option_impl!(~str)
impl FromSql for Option<~[u8]> {
fn from_sql(ty: PostgresType, raw: &Option<~[u8]>) -> Option<~[u8]> {
2013-09-05 04:30:20 +00:00
check_types!(PgByteA, ty)
raw.clone()
}
}
from_option_impl!(~[u8])
from_map_impl!(PgJson, Json, |buf| {
json::from_str(str::from_utf8_slice(buf.as_slice())).unwrap()
2013-09-02 21:06:22 +00:00
})
2013-09-02 20:54:02 +00:00
from_option_impl!(Json)
from_map_impl!(PgUuid, Uuid, |buf| {
Uuid::from_utf8(buf.as_slice()).unwrap()
2013-09-02 21:06:22 +00:00
})
2013-09-02 20:54:02 +00:00
from_option_impl!(Uuid)
pub trait ToSql {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>);
}
macro_rules! to_option_impl(
2013-09-02 20:07:57 +00:00
($($oid:ident)|+, $t:ty) => (
impl ToSql for Option<$t> {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
2013-09-05 04:30:20 +00:00
check_types!($($oid)|+, ty)
2013-09-02 17:27:09 +00:00
match *self {
None => (Text, None),
2013-09-02 17:27:09 +00:00
Some(ref val) => val.to_sql(ty)
}
}
}
2013-09-02 20:54:02 +00:00
);
(self, $($oid:ident)|+, $t:ty) => (
impl<'self> ToSql for Option<$t> {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
2013-09-05 04:30:20 +00:00
check_types!($($oid)|+, ty)
2013-09-02 20:54:02 +00:00
match *self {
None => (Text, None),
Some(ref val) => val.to_sql(ty)
}
}
}
)
)
macro_rules! to_conversions_impl(
2013-09-02 20:07:57 +00:00
($($oid:ident)|+, $t:ty, $f:ident) => (
impl ToSql for $t {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
2013-09-05 04:30:20 +00:00
check_types!($($oid)|+, ty)
2013-09-02 17:27:09 +00:00
let mut writer = MemWriter::new();
writer.$f(*self);
(Binary, Some(writer.inner()))
}
}
)
)
impl ToSql for bool {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
2013-09-05 04:30:20 +00:00
check_types!(PgBool, ty)
2013-09-02 17:27:09 +00:00
(Binary, Some(~[*self as u8]))
}
}
to_option_impl!(PgBool, bool)
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)
2013-09-03 06:19:03 +00:00
impl ToSql for ~str {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
2013-09-05 04:30:20 +00:00
check_types!(PgVarchar | PgText | PgCharN, ty)
2013-09-03 06:19:03 +00:00
(Text, Some(self.as_bytes().to_owned()))
}
}
impl<'self> ToSql for &'self str {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
2013-09-05 04:30:20 +00:00
check_types!(PgVarchar | PgText | PgCharN, ty)
(Text, Some(self.as_bytes().to_owned()))
}
}
to_option_impl!(PgVarchar | PgText | PgCharN, ~str)
to_option_impl!(self, PgVarchar | PgText | PgCharN, &'self str)
2013-09-03 06:19:03 +00:00
impl ToSql for ~[u8] {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
2013-09-05 04:30:20 +00:00
check_types!(PgByteA, ty)
2013-09-03 06:19:03 +00:00
(Binary, Some(self.to_owned()))
}
}
impl<'self> ToSql for &'self [u8] {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
2013-09-05 04:30:20 +00:00
check_types!(PgByteA, ty)
(Binary, Some(self.to_owned()))
}
}
to_option_impl!(PgByteA, ~[u8])
to_option_impl!(self, PgByteA, &'self [u8])
2013-09-02 20:54:02 +00:00
impl ToSql for Json {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
2013-09-05 04:30:20 +00:00
check_types!(PgJson, ty)
2013-09-02 20:54:02 +00:00
(Text, Some(self.to_str().into_bytes()))
}
}
to_option_impl!(PgJson, Json)
2013-09-02 20:54:02 +00:00
impl ToSql for Uuid {
fn to_sql(&self, ty: PostgresType) -> (Format, Option<~[u8]>) {
2013-09-05 04:30:20 +00:00
check_types!(PgUuid, ty)
2013-09-02 20:54:02 +00:00
(Binary, Some(self.to_bytes().to_owned()))
}
}
2013-09-02 20:54:02 +00:00
to_option_impl!(PgUuid, Uuid)