Json and Uuid support

cc #6
This commit is contained in:
Steven Fackler
2013-09-02 16:54:02 -04:00
parent 2cc7f0ff84
commit aa37fe31d4
2 changed files with 91 additions and 35 deletions

View File

@@ -1,5 +1,8 @@
extern mod extra;
extern mod postgres;
use extra::json;
use extra::uuid::Uuid;
use std::f32;
use std::f64;
@@ -92,7 +95,7 @@ fn test_lazy_query() {
}
}
fn test_param_type<T: Eq+ToSql+FromSql>(sql_type: &str, values: &[T]) {
fn test_type<T: Eq+ToSql+FromSql>(sql_type: &str, values: &[T]) {
do test_in_transaction |trans| {
trans.update("CREATE TABLE foo (
id SERIAL PRIMARY KEY,
@@ -113,54 +116,67 @@ fn test_param_type<T: Eq+ToSql+FromSql>(sql_type: &str, values: &[T]) {
#[test]
fn test_bool_params() {
test_param_type("BOOL", [Some(true), Some(false), None]);
test_type("BOOL", [Some(true), Some(false), None]);
}
#[test]
fn test_i16_params() {
test_param_type("SMALLINT", [Some(0x0011i16), Some(-0x0011i16), None]);
test_type("SMALLINT", [Some(0x0011i16), Some(-0x0011i16), None]);
}
#[test]
fn test_i32_params() {
test_param_type("INT", [Some(0x00112233i32), Some(-0x00112233i32), None]);
test_type("INT", [Some(0x00112233i32), Some(-0x00112233i32), None]);
}
#[test]
fn test_i64_params() {
test_param_type("BIGINT", [Some(0x0011223344556677i64),
Some(-0x0011223344556677i64), None]);
test_type("BIGINT", [Some(0x0011223344556677i64),
Some(-0x0011223344556677i64), None]);
}
#[test]
fn test_f32_params() {
test_param_type("REAL", [Some(f32::infinity), Some(f32::neg_infinity),
Some(1000.55), None]);
test_type("REAL", [Some(f32::infinity), Some(f32::neg_infinity),
Some(1000.55), None]);
}
#[test]
fn test_f64_params() {
test_param_type("DOUBLE PRECISION", [Some(f64::infinity),
Some(f64::neg_infinity),
Some(10000.55), None]);
test_type("DOUBLE PRECISION", [Some(f64::infinity),
Some(f64::neg_infinity),
Some(10000.55), None]);
}
#[test]
fn test_varchar_params() {
test_param_type("VARCHAR", [Some(~"hello world"),
Some(~"イロハニホヘト チリヌルヲ"), None]);
test_type("VARCHAR", [Some(~"hello world"),
Some(~"イロハニホヘト チリヌルヲ"), None]);
}
#[test]
fn test_text_params() {
test_param_type("TEXT", [Some(~"hello world"),
Some(~"イロハニホヘト チリヌルヲ"), None]);
test_type("TEXT", [Some(~"hello world"),
Some(~"イロハニホヘト チリヌルヲ"), None]);
}
#[test]
fn test_bytea_params() {
test_param_type("BYTEA", [Some(~[0u8, 1, 2, 3, 254, 255]), None]);
test_type("BYTEA", [Some(~[0u8, 1, 2, 3, 254, 255]), None]);
}
#[test]
fn test_json_params() {
test_type("JSON", [Some(json::from_str("[10, 11, 12]").unwrap()),
Some(json::from_str("{\"f\": \"asd\"}").unwrap()),
None])
}
#[test]
fn test_uuid_params() {
test_type("UUID", [Some(Uuid::parse_string("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11").unwrap()),
None])
}
fn test_nan_param<T: Float+ToSql+FromSql>(sql_type: &str) {

View File

@@ -1,3 +1,8 @@
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};
use std::rt::io::mem::{MemWriter, MemReader};
@@ -12,9 +17,11 @@ static INT8OID: Oid = 20;
static INT2OID: Oid = 21;
static INT4OID: Oid = 23;
static TEXTOID: Oid = 25;
static JSONOID: Oid = 114;
static FLOAT4OID: Oid = 700;
static FLOAT8OID: Oid = 701;
static VARCHAROID: Oid = 1043;
static UUIDOID: Oid = 2950;
pub enum Format {
Text = 0,
@@ -29,7 +36,8 @@ pub fn result_format(ty: Oid) -> Format {
INT2OID |
INT4OID |
FLOAT4OID |
FLOAT8OID => Binary,
FLOAT8OID |
UUIDOID => Binary,
_ => Text
}
}
@@ -98,8 +106,8 @@ from_option_impl!(f64)
impl FromSql for Option<~str> {
fn from_sql(ty:Oid, raw: &Option<~[u8]>) -> Option<~str> {
check_oid!(VARCHAROID | TEXTOID, ty)
do raw.chain_ref |buf| {
Some(str::from_bytes(buf.as_slice()))
do raw.map |buf| {
str::from_bytes(buf.as_slice())
}
}
}
@@ -113,6 +121,26 @@ impl FromSql for Option<~[u8]> {
}
from_option_impl!(~[u8])
impl FromSql for Option<Json> {
fn from_sql(ty: Oid, raw: &Option<~[u8]>) -> Option<Json> {
check_oid!(JSONOID, ty)
do raw.map |buf| {
json::from_str(str::from_bytes_slice(buf.as_slice())).unwrap()
}
}
}
from_option_impl!(Json)
impl FromSql for Option<Uuid> {
fn from_sql(ty: Oid, raw: &Option<~[u8]>) -> Option<Uuid> {
check_oid!(UUIDOID, ty)
do raw.map |buf| {
Uuid::from_bytes(buf.as_slice()).unwrap()
}
}
}
from_option_impl!(Uuid)
pub trait ToSql {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>);
}
@@ -129,6 +157,18 @@ 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]>) {
check_oid!($($oid)|+, ty)
match *self {
None => (Text, None),
Some(ref val) => val.to_sql(ty)
}
}
}
)
)
@@ -173,16 +213,7 @@ impl<'self> ToSql for &'self str {
}
to_option_impl!(VARCHAROID | TEXTOID, ~str)
impl<'self> ToSql for Option<&'self str> {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
check_oid!(VARCHAROID | TEXTOID, ty)
match *self {
None => (Text, None),
Some(val) => val.to_sql(ty)
}
}
}
to_option_impl!(self, VARCHAROID | TEXTOID, &'self str)
impl<'self> ToSql for &'self [u8] {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
@@ -192,13 +223,22 @@ impl<'self> ToSql for &'self [u8] {
}
to_option_impl!(BYTEAOID, ~[u8])
to_option_impl!(self, BYTEAOID, &'self [u8])
impl<'self> ToSql for Option<&'self [u8]> {
impl ToSql for Json {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
check_oid!(BYTEAOID, ty)
match *self {
None => (Text, None),
Some(val) => val.to_sql(ty)
}
check_oid!(JSONOID, ty)
(Text, Some(self.to_str().into_bytes()))
}
}
to_option_impl!(JSONOID, Json)
impl ToSql for Uuid {
fn to_sql(&self, ty: Oid) -> (Format, Option<~[u8]>) {
check_oid!(UUIDOID, ty)
(Binary, Some(self.to_bytes().to_owned()))
}
}
to_option_impl!(UUIDOID, Uuid)