diesel/pg/types/
json.rs

1//! Support for JSON and `jsonb` values under PostgreSQL.
2
3extern crate serde_json;
4
5use std::io::prelude::*;
6
7use crate::deserialize::{self, FromSql};
8use crate::pg::{Pg, PgValue};
9use crate::serialize::{self, IsNull, Output, ToSql};
10use crate::sql_types;
11
12#[cfg(all(feature = "postgres_backend", feature = "serde_json"))]
13impl FromSql<sql_types::Json, Pg> for serde_json::Value {
14    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
15        serde_json::from_slice(value.as_bytes()).map_err(|_| "Invalid Json".into())
16    }
17}
18
19#[cfg(all(feature = "postgres_backend", feature = "serde_json"))]
20impl ToSql<sql_types::Json, Pg> for serde_json::Value {
21    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
22        serde_json::to_writer(out, self)
23            .map(|_| IsNull::No)
24            .map_err(Into::into)
25    }
26}
27
28#[cfg(all(feature = "postgres_backend", feature = "serde_json"))]
29impl FromSql<sql_types::Jsonb, Pg> for serde_json::Value {
30    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
31        let bytes = value.as_bytes();
32        if bytes[0] != 1 {
33            return Err("Unsupported JSONB encoding version".into());
34        }
35        serde_json::from_slice(&bytes[1..]).map_err(|_| "Invalid Json".into())
36    }
37}
38
39#[cfg(all(feature = "postgres_backend", feature = "serde_json"))]
40impl ToSql<sql_types::Jsonb, Pg> for serde_json::Value {
41    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
42        out.write_all(&[1])?;
43        serde_json::to_writer(out, self)
44            .map(|_| IsNull::No)
45            .map_err(Into::into)
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use crate::deserialize::FromSql;
52    use crate::pg::{Pg, PgValue};
53    use crate::query_builder::bind_collector::ByteWrapper;
54    use crate::serialize::{Output, ToSql};
55    use crate::sql_types;
56
57    #[diesel_test_helper::test]
58    fn json_to_sql() {
59        let mut buffer = Vec::new();
60        let mut bytes = Output::test(ByteWrapper(&mut buffer));
61        let test_json = serde_json::Value::Bool(true);
62        ToSql::<sql_types::Json, Pg>::to_sql(&test_json, &mut bytes).unwrap();
63        assert_eq!(buffer, b"true");
64    }
65
66    #[diesel_test_helper::test]
67    fn some_json_from_sql() {
68        let input_json = b"true";
69        let output_json: serde_json::Value =
70            FromSql::<sql_types::Json, Pg>::from_sql(PgValue::for_test(input_json)).unwrap();
71        assert_eq!(output_json, serde_json::Value::Bool(true));
72    }
73
74    #[diesel_test_helper::test]
75    fn bad_json_from_sql() {
76        let uuid: Result<serde_json::Value, _> =
77            FromSql::<sql_types::Json, Pg>::from_sql(PgValue::for_test(b"boom"));
78        assert_eq!(uuid.unwrap_err().to_string(), "Invalid Json");
79    }
80
81    #[diesel_test_helper::test]
82    fn no_json_from_sql() {
83        let uuid: Result<serde_json::Value, _> =
84            FromSql::<sql_types::Json, Pg>::from_nullable_sql(None);
85        assert_eq!(
86            uuid.unwrap_err().to_string(),
87            "Unexpected null for non-null column"
88        );
89    }
90
91    #[diesel_test_helper::test]
92    fn jsonb_to_sql() {
93        let mut buffer = Vec::new();
94        let mut bytes = Output::test(ByteWrapper(&mut buffer));
95        let test_json = serde_json::Value::Bool(true);
96        ToSql::<sql_types::Jsonb, Pg>::to_sql(&test_json, &mut bytes).unwrap();
97        assert_eq!(buffer, b"\x01true");
98    }
99
100    #[diesel_test_helper::test]
101    fn some_jsonb_from_sql() {
102        let input_json = b"\x01true";
103        let output_json: serde_json::Value =
104            FromSql::<sql_types::Jsonb, Pg>::from_sql(PgValue::for_test(input_json)).unwrap();
105        assert_eq!(output_json, serde_json::Value::Bool(true));
106    }
107
108    #[diesel_test_helper::test]
109    fn bad_jsonb_from_sql() {
110        let uuid: Result<serde_json::Value, _> =
111            FromSql::<sql_types::Jsonb, Pg>::from_sql(PgValue::for_test(b"\x01boom"));
112        assert_eq!(uuid.unwrap_err().to_string(), "Invalid Json");
113    }
114
115    #[diesel_test_helper::test]
116    fn bad_jsonb_version_from_sql() {
117        let uuid: Result<serde_json::Value, _> =
118            FromSql::<sql_types::Jsonb, Pg>::from_sql(PgValue::for_test(b"\x02true"));
119        assert_eq!(
120            uuid.unwrap_err().to_string(),
121            "Unsupported JSONB encoding version"
122        );
123    }
124
125    #[diesel_test_helper::test]
126    fn no_jsonb_from_sql() {
127        let uuid: Result<serde_json::Value, _> =
128            FromSql::<sql_types::Jsonb, Pg>::from_nullable_sql(None);
129        assert_eq!(
130            uuid.unwrap_err().to_string(),
131            "Unexpected null for non-null column"
132        );
133    }
134}