Make JSON support an optional feature

Even though we currently depend on rustc-serialize, this may not always
be the case. Forcing opt-in for all integration with external crates is
a safer course of action.
This commit is contained in:
Steven Fackler 2015-02-07 19:20:18 -08:00
parent 5ed898949e
commit b352b12c48
6 changed files with 66 additions and 46 deletions

View File

@ -5,7 +5,7 @@ before_script:
- "./.travis/setup.sh"
script:
- cargo test
- cargo test --features "uuid"
- cargo test --features "uuid rustc-serialize"
- cargo doc --no-deps
after_success:
- test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && ./.travis/update_docs.sh

View File

@ -204,7 +204,10 @@ types. The driver currently supports the following conversions:
<td>BYTEA</td>
</tr>
<tr>
<td>serialize::json::Json</td>
<td>
<a href="https://github.com/rust-lang/rustc-serialize">serialize::json::Json</a>
(<a href="#optional-features">optional</a>)
</td>
<td>JSON/JSONB</td>
</tr>
<tr>
@ -245,6 +248,11 @@ Support for Postgres ranges is located in the
[UUID](http://www.postgresql.org/docs/9.4/static/datatype-uuid.html) support is
provided optionally by the `uuid` feature.
### JSON/JSONB types
[JSON and JSONB](http://www.postgresql.org/docs/9.4/static/datatype-json.html)
support is provided optionally by the `rustc-serialize` feature.
## Development
Like Rust itself, Rust-Postgres is still in the early stages of development, so
don't be surprised if APIs change and things break. If something's not working

30
src/types/json.rs Normal file
View File

@ -0,0 +1,30 @@
use serialize::json;
use {Result, Error};
use types::{RawFromSql, RawToSql, Type};
impl RawFromSql for json::Json {
fn raw_from_sql<R: Reader>(ty: &Type, raw: &mut R) -> Result<json::Json> {
if let Type::Jsonb = *ty {
// We only support version 1 of the jsonb binary format
if try!(raw.read_u8()) != 1 {
return Err(Error::BadData);
}
}
json::Json::from_reader(raw).map_err(|_| Error::BadData)
}
}
from_raw_from_impl!(Type::Json, Type::Jsonb; json::Json);
impl RawToSql for json::Json {
fn raw_to_sql<W: Writer>(&self, ty: &Type, raw: &mut W) -> Result<()> {
if let Type::Jsonb = *ty {
try!(raw.write_u8(1));
}
Ok(try!(write!(raw, "{}", self)))
}
}
to_raw_to_impl!(Type::Json, Type::Jsonb; json::Json);

View File

@ -1,7 +1,6 @@
//! Traits dealing with Postgres data types
pub use self::slice::Slice;
use serialize::json;
use std::collections::HashMap;
use std::old_io::net::ip::IpAddr;
use std::fmt;
@ -135,6 +134,8 @@ macro_rules! to_raw_to_impl {
mod uuid;
mod time;
mod slice;
#[cfg(feature = "rustc-serialize")]
mod json;
/// A Postgres OID
pub type Oid = u32;
@ -378,18 +379,6 @@ raw_from_impl!(i64, read_be_i64);
raw_from_impl!(f32, read_be_f32);
raw_from_impl!(f64, read_be_f64);
impl RawFromSql for json::Json {
fn raw_from_sql<R: Reader>(ty: &Type, raw: &mut R) -> Result<json::Json> {
if let Type::Jsonb = *ty {
// We only support version 1 of the jsonb binary format
if try!(raw.read_u8()) != 1 {
return Err(Error::BadData);
}
}
json::Json::from_reader(raw).map_err(|_| Error::BadData)
}
}
impl RawFromSql for IpAddr {
fn raw_from_sql<R: Reader>(_: &Type, raw: &mut R) -> Result<IpAddr> {
let family = try!(raw.read_u8());
@ -427,7 +416,6 @@ from_raw_from_impl!(Type::Oid; u32);
from_raw_from_impl!(Type::Int8; i64);
from_raw_from_impl!(Type::Float4; f32);
from_raw_from_impl!(Type::Float8; f64);
from_raw_from_impl!(Type::Json, Type::Jsonb; json::Json);
from_raw_from_impl!(Type::Inet, Type::Cidr; IpAddr);
impl FromSql for Option<String> {
@ -537,16 +525,6 @@ raw_to_impl!(i64, write_be_i64);
raw_to_impl!(f32, write_be_f32);
raw_to_impl!(f64, write_be_f64);
impl RawToSql for json::Json {
fn raw_to_sql<W: Writer>(&self, ty: &Type, raw: &mut W) -> Result<()> {
if let Type::Jsonb = *ty {
try!(raw.write_u8(1));
}
Ok(try!(write!(raw, "{}", self)))
}
}
impl RawToSql for IpAddr {
fn raw_to_sql<W: Writer>(&self, _: &Type, raw: &mut W) -> Result<()> {
match *self {
@ -580,7 +558,6 @@ impl RawToSql for IpAddr {
to_raw_to_impl!(Type::Bool; bool);
to_raw_to_impl!(Type::ByteA; Vec<u8>);
to_raw_to_impl!(Type::Json, Type::Jsonb; json::Json);
to_raw_to_impl!(Type::Inet, Type::Cidr; IpAddr);
to_raw_to_impl!(Type::Char; i8);
to_raw_to_impl!(Type::Int2; i16);

22
tests/types/json.rs Normal file
View File

@ -0,0 +1,22 @@
use serialize::json::Json;
use types::test_type;
#[test]
fn test_json_params() {
test_type("JSON", &[(Some(Json::from_str("[10, 11, 12]").unwrap()),
"'[10, 11, 12]'"),
(Some(Json::from_str("{\"f\": \"asd\"}").unwrap()),
"'{\"f\": \"asd\"}'"),
(None, "NULL")])
}
#[test]
fn test_jsonb_params() {
if option_env!("TRAVIS").is_some() { return } // Travis doesn't have Postgres 9.4 yet
test_type("JSONB", &[(Some(Json::from_str("[10, 11, 12]").unwrap()),
"'[10, 11, 12]'"),
(Some(Json::from_str("{\"f\": \"asd\"}").unwrap()),
"'{\"f\": \"asd\"}'"),
(None, "NULL")])
}

View File

@ -1,4 +1,3 @@
use serialize::json::Json;
use std::collections::HashMap;
use std::f32;
use std::f64;
@ -12,6 +11,8 @@ use postgres::types::{ToSql, FromSql};
#[cfg(feature = "uuid")]
mod uuid;
mod time;
#[cfg(feature = "rustc-serialize")]
mod json;
fn test_type<T: PartialEq+FromSql+ToSql, S: fmt::Display>(sql_type: &str, checks: &[(T, S)]) {
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
@ -135,24 +136,6 @@ fn test_bytea_params() {
(None, "NULL")]);
}
#[test]
fn test_json_params() {
test_type("JSON", &[(Some(Json::from_str("[10, 11, 12]").unwrap()),
"'[10, 11, 12]'"),
(Some(Json::from_str("{\"f\": \"asd\"}").unwrap()),
"'{\"f\": \"asd\"}'"),
(None, "NULL")])
}
#[test]
fn test_jsonb_params() {
test_type("JSONB", &[(Some(Json::from_str("[10, 11, 12]").unwrap()),
"'[10, 11, 12]'"),
(Some(Json::from_str("{\"f\": \"asd\"}").unwrap()),
"'{\"f\": \"asd\"}'"),
(None, "NULL")])
}
#[test]
fn test_inet_params() {
test_type("INET", &[(Some("127.0.0.1".parse::<IpAddr>().unwrap()),