1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! Support for JSON and `jsonb` values under PostgreSQL.

extern crate serde_json;

use std::io::prelude::*;

use crate::deserialize::{self, FromSql};
use crate::pg::{Pg, PgValue};
use crate::serialize::{self, IsNull, Output, ToSql};
use crate::sql_types;

impl FromSql<sql_types::Json, Pg> for serde_json::Value {
    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
        serde_json::from_slice(value.as_bytes()).map_err(|_| "Invalid Json".into())
    }
}

impl ToSql<sql_types::Json, Pg> for serde_json::Value {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        serde_json::to_writer(out, self)
            .map(|_| IsNull::No)
            .map_err(Into::into)
    }
}

impl FromSql<sql_types::Jsonb, Pg> for serde_json::Value {
    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
        let bytes = value.as_bytes();
        if bytes[0] != 1 {
            return Err("Unsupported JSONB encoding version".into());
        }
        serde_json::from_slice(&bytes[1..]).map_err(|_| "Invalid Json".into())
    }
}

impl ToSql<sql_types::Jsonb, Pg> for serde_json::Value {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        out.write_all(&[1])?;
        serde_json::to_writer(out, self)
            .map(|_| IsNull::No)
            .map_err(Into::into)
    }
}

#[test]
fn json_to_sql() {
    let mut bytes = Output::test();
    let test_json = serde_json::Value::Bool(true);
    ToSql::<sql_types::Json, Pg>::to_sql(&test_json, &mut bytes).unwrap();
    assert_eq!(bytes, b"true");
}

#[test]
fn some_json_from_sql() {
    let input_json = b"true";
    let output_json: serde_json::Value =
        FromSql::<sql_types::Json, Pg>::from_sql(PgValue::for_test(input_json)).unwrap();
    assert_eq!(output_json, serde_json::Value::Bool(true));
}

#[test]
fn bad_json_from_sql() {
    let uuid: Result<serde_json::Value, _> =
        FromSql::<sql_types::Json, Pg>::from_sql(PgValue::for_test(b"boom"));
    assert_eq!(uuid.unwrap_err().to_string(), "Invalid Json");
}

#[test]
fn no_json_from_sql() {
    let uuid: Result<serde_json::Value, _> =
        FromSql::<sql_types::Json, Pg>::from_nullable_sql(None);
    assert_eq!(
        uuid.unwrap_err().to_string(),
        "Unexpected null for non-null column"
    );
}

#[test]
fn jsonb_to_sql() {
    let mut bytes = Output::test();
    let test_json = serde_json::Value::Bool(true);
    ToSql::<sql_types::Jsonb, Pg>::to_sql(&test_json, &mut bytes).unwrap();
    assert_eq!(bytes, b"\x01true");
}

#[test]
fn some_jsonb_from_sql() {
    let input_json = b"\x01true";
    let output_json: serde_json::Value =
        FromSql::<sql_types::Jsonb, Pg>::from_sql(PgValue::for_test(input_json)).unwrap();
    assert_eq!(output_json, serde_json::Value::Bool(true));
}

#[test]
fn bad_jsonb_from_sql() {
    let uuid: Result<serde_json::Value, _> =
        FromSql::<sql_types::Jsonb, Pg>::from_sql(PgValue::for_test(b"\x01boom"));
    assert_eq!(uuid.unwrap_err().to_string(), "Invalid Json");
}

#[test]
fn bad_jsonb_version_from_sql() {
    let uuid: Result<serde_json::Value, _> =
        FromSql::<sql_types::Jsonb, Pg>::from_sql(PgValue::for_test(b"\x02true"));
    assert_eq!(
        uuid.unwrap_err().to_string(),
        "Unsupported JSONB encoding version"
    );
}

#[test]
fn no_jsonb_from_sql() {
    let uuid: Result<serde_json::Value, _> =
        FromSql::<sql_types::Jsonb, Pg>::from_nullable_sql(None);
    assert_eq!(
        uuid.unwrap_err().to_string(),
        "Unexpected null for non-null column"
    );
}