Support hstore
This commit is contained in:
parent
deeba1bace
commit
6e9e9ebe3e
@ -265,6 +265,10 @@ types. The driver currently supports the following conversions:
|
||||
<td>types::array::ArrayBase<Option<i64>></td>
|
||||
<td>INT8[], INT8[][], ...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>std::hashmap::HashMap<~str, Option<~str>></td>
|
||||
<td>HSTORE</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
19
test.rs
19
test.rs
@ -12,6 +12,7 @@ use extra::uuid::Uuid;
|
||||
use ssl::{SslContext, Sslv3};
|
||||
use std::f32;
|
||||
use std::f64;
|
||||
use std::hashmap::HashMap;
|
||||
use std::io::timer;
|
||||
|
||||
use lib::{PostgresNoticeHandler,
|
||||
@ -447,6 +448,24 @@ fn test_int8array_params() {
|
||||
[(Some(a), "'[-1:0][0:1]={{0,1},{NULL,3}}'")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hstore_params() {
|
||||
macro_rules! make_map(
|
||||
($($k:expr => $v:expr),+) => ({
|
||||
let mut map = HashMap::new();
|
||||
$(map.insert($k, $v);)+
|
||||
map
|
||||
})
|
||||
)
|
||||
test_type("hstore",
|
||||
[(Some(make_map!(~"a" => Some(~"1"))), "'a=>1'"),
|
||||
(Some(make_map!(~"hello" => Some(~"world!"),
|
||||
~"hola" => Some(~"mundo!"),
|
||||
~"what" => None)),
|
||||
"'hello=>world!,hola=>mundo!,what=>NULL'"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
fn test_nan_param<T: Float+ToSql+FromSql>(sql_type: &str) {
|
||||
let conn = PostgresConnection::connect("postgres://postgres@localhost", &NoSsl);
|
||||
let stmt = conn.prepare("SELECT 'NaN'::" + sql_type);
|
||||
|
66
types/mod.rs
66
types/mod.rs
@ -6,6 +6,7 @@ use extra::time::Timespec;
|
||||
use extra::json;
|
||||
use extra::json::Json;
|
||||
use extra::uuid::Uuid;
|
||||
use std::hashmap::HashMap;
|
||||
use std::io::Decorator;
|
||||
use std::io::mem::{MemWriter, BufReader};
|
||||
use std::mem;
|
||||
@ -143,6 +144,7 @@ impl PostgresType {
|
||||
/// Returns the wire format needed for the value of `self`.
|
||||
pub fn result_format(&self) -> Format {
|
||||
match *self {
|
||||
PgUnknownType { name: ~"hstore", .. } => Binary,
|
||||
PgUnknownType { .. } => Text,
|
||||
_ => Binary
|
||||
}
|
||||
@ -379,6 +381,31 @@ from_option_impl!(ArrayBase<Option<i32>>)
|
||||
from_array_impl!(PgInt8Array, i64)
|
||||
from_option_impl!(ArrayBase<Option<i64>>)
|
||||
|
||||
from_map_impl!(PgUnknownType { name: ~"hstore", .. },
|
||||
HashMap<~str, Option<~str>>, |buf| {
|
||||
let mut rdr = BufReader::new(buf.as_slice());
|
||||
let mut map = HashMap::new();
|
||||
|
||||
let count = rdr.read_be_i32();
|
||||
|
||||
for _ in range(0, count) {
|
||||
let key_len = rdr.read_be_i32();
|
||||
let key = str::from_utf8_owned(rdr.read_bytes(key_len as uint));
|
||||
|
||||
let val_len = rdr.read_be_i32();
|
||||
let val = if val_len < 0 {
|
||||
None
|
||||
} else {
|
||||
Some(str::from_utf8_owned(rdr.read_bytes(val_len as uint)))
|
||||
};
|
||||
|
||||
map.insert(key, val);
|
||||
}
|
||||
|
||||
map
|
||||
})
|
||||
from_option_impl!(HashMap<~str, Option<~str>>)
|
||||
|
||||
/// A trait for types that can be converted into Postgres values
|
||||
pub trait ToSql {
|
||||
/// Converts the value of `self` into a format appropriate for the Postgres
|
||||
@ -427,7 +454,7 @@ impl RawToSql for Timespec {
|
||||
}
|
||||
|
||||
macro_rules! to_option_impl(
|
||||
($($oid:ident)|+, $t:ty) => (
|
||||
($($oid:pat)|+, $t:ty) => (
|
||||
impl ToSql for Option<$t> {
|
||||
fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) {
|
||||
check_types!($($oid)|+, ty)
|
||||
@ -438,8 +465,11 @@ macro_rules! to_option_impl(
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
(self, $($oid:ident)|+, $t:ty) => (
|
||||
)
|
||||
)
|
||||
|
||||
macro_rules! to_option_impl_self(
|
||||
($($oid:pat)|+, $t:ty) => (
|
||||
impl<'self> ToSql for Option<$t> {
|
||||
fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) {
|
||||
check_types!($($oid)|+, ty)
|
||||
@ -518,7 +548,7 @@ impl<'self> ToSql for &'self str {
|
||||
}
|
||||
|
||||
to_option_impl!(PgVarchar | PgText | PgCharN, ~str)
|
||||
to_option_impl!(self, PgVarchar | PgText | PgCharN, &'self str)
|
||||
to_option_impl_self!(PgVarchar | PgText | PgCharN, &'self str)
|
||||
|
||||
impl ToSql for ~[u8] {
|
||||
fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) {
|
||||
@ -535,7 +565,7 @@ impl<'self> ToSql for &'self [u8] {
|
||||
}
|
||||
|
||||
to_option_impl!(PgByteA, ~[u8])
|
||||
to_option_impl!(self, PgByteA, &'self [u8])
|
||||
to_option_impl_self!(PgByteA, &'self [u8])
|
||||
|
||||
impl ToSql for Json {
|
||||
fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) {
|
||||
@ -652,3 +682,29 @@ to_option_impl!(PgInt4Array, ArrayBase<Option<i32>>)
|
||||
|
||||
to_array_impl!(PgInt8Array, INT8OID, i64)
|
||||
to_option_impl!(PgInt8Array, ArrayBase<Option<i64>>)
|
||||
|
||||
impl<'self> ToSql for HashMap<~str, Option<~str>> {
|
||||
fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) {
|
||||
check_types!(PgUnknownType { name: ~"hstore", .. }, ty)
|
||||
let mut buf = MemWriter::new();
|
||||
|
||||
buf.write_be_i32(self.len() as i32);
|
||||
|
||||
for (key, val) in self.iter() {
|
||||
buf.write_be_i32(key.len() as i32);
|
||||
buf.write(key.as_bytes());
|
||||
|
||||
match *val {
|
||||
Some(ref val) => {
|
||||
buf.write_be_i32(val.len() as i32);
|
||||
buf.write(val.as_bytes());
|
||||
}
|
||||
None => buf.write_be_i32(-1)
|
||||
}
|
||||
}
|
||||
|
||||
(Binary, Some(buf.inner()))
|
||||
}
|
||||
}
|
||||
to_option_impl!(PgUnknownType { name: ~"hstore", .. },
|
||||
HashMap<~str, Option<~str>>)
|
||||
|
Loading…
Reference in New Issue
Block a user