diff --git a/Cargo.toml b/Cargo.toml index 4787b0bf..a96f52fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ rustc-serialize = "0.3" net2 = { version = "0.2", features = ["nightly"] } chrono = { version = "0.2.14", optional = true } openssl = { version = "0.6.4", optional = true } +serde = { version = "0.3", optional = true } # Delete for 0.11 serde_json = { version = "0.6", optional = true } time = { version = "0.1.14", optional = true } unix_socket = { version = ">= 0.3, < 0.5", optional = true, features = ["socket_timeout"] } diff --git a/src/types/mod.rs b/src/types/mod.rs index febddb5c..9d8ed8a3 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -51,6 +51,8 @@ mod slice; mod rustc_serialize; #[cfg(feature = "serde_json")] mod serde_json; +#[cfg(feature = "serde")] +mod serde; #[cfg(feature = "chrono")] mod chrono; diff --git a/src/types/serde.rs b/src/types/serde.rs new file mode 100644 index 00000000..b5db60fc --- /dev/null +++ b/src/types/serde.rs @@ -0,0 +1,41 @@ +extern crate serde; + +use std::error; +use std::io::prelude::*; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use self::serde::json::{self, Value}; + +use Result; +use error::Error; +use types::{FromSql, ToSql, IsNull, Type, SessionInfo}; + +impl FromSql for Value { + fn from_sql(ty: &Type, raw: &mut R, _: &SessionInfo) -> Result { + if let Type::Jsonb = *ty { + // We only support version 1 of the jsonb binary format + if try!(raw.read_u8()) != 1 { + let err: Box = "unsupported JSONB encoding version".into(); + return Err(Error::Conversion(err)); + } + } + json::de::from_reader(raw).map_err(|err| Error::Conversion(Box::new(err))) + } + + accepts!(Type::Json, Type::Jsonb); +} + +impl ToSql for Value { + fn to_sql(&self, ty: &Type, mut out: &mut W, _: &SessionInfo) + -> Result { + if let Type::Jsonb = *ty { + try!(out.write_u8(1)); + } + + try!(write!(out, "{:?}", self)); + + Ok(IsNull::No) + } + + accepts!(Type::Json, Type::Jsonb); + to_sql_checked!(); +}