1extern 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 let first_byte = bytes
33 .first()
34 .ok_or("Received an empty response from the server")?;
35
36 if *first_byte != 1 {
37 return Err("Unsupported JSONB encoding version".into());
38 }
39 serde_json::from_slice(&bytes[1..]).map_err(|_| "Invalid Json".into())
42 }
43}
44
45#[cfg(all(feature = "postgres_backend", feature = "serde_json"))]
46impl ToSql<sql_types::Jsonb, Pg> for serde_json::Value {
47 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
48 out.write_all(&[1])?;
49 serde_json::to_writer(out, self)
50 .map(|_| IsNull::No)
51 .map_err(Into::into)
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use crate::deserialize::FromSql;
58 use crate::pg::{Pg, PgValue};
59 use crate::query_builder::bind_collector::ByteWrapper;
60 use crate::serialize::{Output, ToSql};
61 use crate::sql_types;
62 use crate::test_helpers::format_error;
63
64 #[diesel_test_helper::test]
65 fn regression_json_float_survives_a_round_trip() {
66 crate::test_helpers::assert_floats_survive_a_json_round_trip::<sql_types::Json, Pg>(
67 |bytes| FromSql::<sql_types::Json, Pg>::from_sql(PgValue::for_test(bytes)),
68 );
69 crate::test_helpers::assert_floats_survive_a_json_round_trip::<sql_types::Jsonb, Pg>(
70 |bytes| FromSql::<sql_types::Jsonb, Pg>::from_sql(PgValue::for_test(bytes)),
71 );
72 }
73
74 #[diesel_test_helper::test]
75 fn json_to_sql() {
76 let mut buffer = Vec::new();
77 let mut bytes = Output::test(ByteWrapper(&mut buffer));
78 let test_json = serde_json::Value::Bool(true);
79 ToSql::<sql_types::Json, Pg>::to_sql(&test_json, &mut bytes).unwrap();
80 assert_eq!(buffer, b"true");
81 }
82
83 #[diesel_test_helper::test]
84 fn some_json_from_sql() {
85 let input_json = b"true";
86 let output_json: serde_json::Value =
87 FromSql::<sql_types::Json, Pg>::from_sql(PgValue::for_test(input_json)).unwrap();
88 assert_eq!(output_json, serde_json::Value::Bool(true));
89 }
90
91 #[diesel_test_helper::test]
92 fn bad_json_from_sql() {
93 let uuid: Result<serde_json::Value, _> =
94 FromSql::<sql_types::Json, Pg>::from_sql(PgValue::for_test(b"boom"));
95 assert_eq!(format_error(&*uuid.unwrap_err()), "Invalid Json");
96 }
97
98 #[diesel_test_helper::test]
99 fn no_json_from_sql() {
100 let uuid: Result<serde_json::Value, _> =
101 FromSql::<sql_types::Json, Pg>::from_nullable_sql(None);
102 assert_eq!(
103 format_error(&*uuid.unwrap_err()),
104 "Unexpected null for non-null column"
105 );
106 }
107
108 #[diesel_test_helper::test]
109 fn jsonb_to_sql() {
110 let mut buffer = Vec::new();
111 let mut bytes = Output::test(ByteWrapper(&mut buffer));
112 let test_json = serde_json::Value::Bool(true);
113 ToSql::<sql_types::Jsonb, Pg>::to_sql(&test_json, &mut bytes).unwrap();
114 assert_eq!(buffer, b"\x01true");
115 }
116
117 #[diesel_test_helper::test]
118 fn some_jsonb_from_sql() {
119 let input_json = b"\x01true";
120 let output_json: serde_json::Value =
121 FromSql::<sql_types::Jsonb, Pg>::from_sql(PgValue::for_test(input_json)).unwrap();
122 assert_eq!(output_json, serde_json::Value::Bool(true));
123 }
124
125 #[diesel_test_helper::test]
126 fn bad_jsonb_from_sql() {
127 let uuid: Result<serde_json::Value, _> =
128 FromSql::<sql_types::Jsonb, Pg>::from_sql(PgValue::for_test(b"\x01boom"));
129 assert_eq!(format_error(&*uuid.unwrap_err()), "Invalid Json");
130 }
131
132 #[diesel_test_helper::test]
133 fn bad_jsonb_version_from_sql() {
134 let uuid: Result<serde_json::Value, _> =
135 FromSql::<sql_types::Jsonb, Pg>::from_sql(PgValue::for_test(b"\x02true"));
136 assert_eq!(
137 format_error(&*uuid.unwrap_err()),
138 "Unsupported JSONB encoding version"
139 );
140 }
141
142 #[diesel_test_helper::test]
143 fn no_jsonb_from_sql() {
144 let uuid: Result<serde_json::Value, _> =
145 FromSql::<sql_types::Jsonb, Pg>::from_nullable_sql(None);
146 assert_eq!(
147 format_error(&*uuid.unwrap_err()),
148 "Unexpected null for non-null column"
149 );
150 }
151}