sqlx_postgres/types/
json.rs

1use crate::decode::Decode;
2use crate::encode::{Encode, IsNull};
3use crate::error::BoxDynError;
4use crate::types::array_compatible;
5use crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
6use serde::{Deserialize, Serialize};
7use serde_json::value::RawValue as JsonRawValue;
8use serde_json::Value as JsonValue;
9pub(crate) use sqlx_core::types::{Json, Type};
10
11// <https://www.postgresql.org/docs/12/datatype-json.html>
12
13// In general, most applications should prefer to store JSON data as jsonb,
14// unless there are quite specialized needs, such as legacy assumptions
15// about ordering of object keys.
16
17impl<T> Type<Postgres> for Json<T> {
18    fn type_info() -> PgTypeInfo {
19        PgTypeInfo::JSONB
20    }
21
22    fn compatible(ty: &PgTypeInfo) -> bool {
23        *ty == PgTypeInfo::JSON || *ty == PgTypeInfo::JSONB
24    }
25}
26
27impl<T> PgHasArrayType for Json<T> {
28    fn array_type_info() -> PgTypeInfo {
29        PgTypeInfo::JSONB_ARRAY
30    }
31
32    fn array_compatible(ty: &PgTypeInfo) -> bool {
33        array_compatible::<Json<T>>(ty)
34    }
35}
36
37impl PgHasArrayType for JsonValue {
38    fn array_type_info() -> PgTypeInfo {
39        PgTypeInfo::JSONB_ARRAY
40    }
41
42    fn array_compatible(ty: &PgTypeInfo) -> bool {
43        array_compatible::<JsonValue>(ty)
44    }
45}
46
47impl PgHasArrayType for JsonRawValue {
48    fn array_type_info() -> PgTypeInfo {
49        PgTypeInfo::JSONB_ARRAY
50    }
51
52    fn array_compatible(ty: &PgTypeInfo) -> bool {
53        array_compatible::<JsonRawValue>(ty)
54    }
55}
56
57impl<'q, T> Encode<'q, Postgres> for Json<T>
58where
59    T: Serialize,
60{
61    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
62        // we have a tiny amount of dynamic behavior depending if we are resolved to be JSON
63        // instead of JSONB
64        buf.patch(|buf, ty: &PgTypeInfo| {
65            if *ty == PgTypeInfo::JSON || *ty == PgTypeInfo::JSON_ARRAY {
66                buf[0] = b' ';
67            }
68        });
69
70        // JSONB version (as of 2020-03-20)
71        buf.push(1);
72
73        // the JSON data written to the buffer is the same regardless of parameter type
74        serde_json::to_writer(&mut **buf, &self.0)?;
75
76        Ok(IsNull::No)
77    }
78}
79
80impl<'r, T: 'r> Decode<'r, Postgres> for Json<T>
81where
82    T: Deserialize<'r>,
83{
84    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
85        let mut buf = value.as_bytes()?;
86
87        if value.format() == PgValueFormat::Binary && value.type_info == PgTypeInfo::JSONB {
88            assert_eq!(
89                buf[0], 1,
90                "unsupported JSONB format version {}; please open an issue",
91                buf[0]
92            );
93
94            buf = &buf[1..];
95        }
96
97        serde_json::from_slice(buf).map(Json).map_err(Into::into)
98    }
99}