diff --git a/sqlx-core/src/postgres/types/json.rs b/sqlx-core/src/postgres/types/json.rs index caf9bafd..27a322d5 100644 --- a/sqlx-core/src/postgres/types/json.rs +++ b/sqlx-core/src/postgres/types/json.rs @@ -1,8 +1,10 @@ use crate::decode::Decode; use crate::encode::Encode; -use crate::postgres::types::{PgJsonb, PgTypeInfo}; -use crate::postgres::{PgValue, Postgres}; +use crate::io::{Buf, BufMut}; +use crate::postgres::protocol::TypeId; +use crate::postgres::{PgData, PgTypeInfo, PgValue, Postgres}; use crate::types::{Json, Type}; +use crate::value::RawValue; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue as JsonRawValue; use serde_json::Value as JsonValue; @@ -15,43 +17,43 @@ use serde_json::Value as JsonValue; impl Type for JsonValue { fn type_info() -> PgTypeInfo { - as Type>::type_info() + as Type>::type_info() } } impl Encode for JsonValue { fn encode(&self, buf: &mut Vec) { - PgJsonb(self).encode(buf) + Json(self).encode(buf) } } impl<'de> Decode<'de, Postgres> for JsonValue { fn decode(value: PgValue<'de>) -> crate::Result { - as Decode>::decode(value).map(|item| item.0) + as Decode>::decode(value).map(|item| item.0) } } impl Type for &'_ JsonRawValue { fn type_info() -> PgTypeInfo { - as Type>::type_info() + as Type>::type_info() } } impl Encode for &'_ JsonRawValue { fn encode(&self, buf: &mut Vec) { - PgJsonb(self).encode(buf) + Json(self).encode(buf) } } impl<'de> Decode<'de, Postgres> for &'de JsonRawValue { fn decode(value: PgValue<'de>) -> crate::Result { - as Decode>::decode(value).map(|item| item.0) + as Decode>::decode(value).map(|item| item.0) } } impl Type for Json { fn type_info() -> PgTypeInfo { - as Type>::type_info() + PgTypeInfo::new(TypeId::JSONB, "JSONB") } } @@ -60,7 +62,11 @@ where T: Serialize, { fn encode(&self, buf: &mut Vec) { - PgJsonb(&self.0).encode(buf) + // JSONB version (as of 2020-03-20) + buf.put_u8(1); + + serde_json::to_writer(buf, &self.0) + .expect("failed to serialize json for encoding to database"); } } @@ -70,6 +76,23 @@ where T: Deserialize<'de>, { fn decode(value: PgValue<'de>) -> crate::Result { - as Decode>::decode(value).map(|item| Self(item.0)) + (match value.try_get()? { + PgData::Text(s) => serde_json::from_str(s), + PgData::Binary(mut buf) => { + if value.type_info().id == TypeId::JSONB { + let version = buf.get_u8()?; + + assert_eq!( + version, 1, + "unsupported JSONB format version {}; please open an issue", + version + ); + } + + serde_json::from_slice(buf) + } + }) + .map(Json) + .map_err(crate::Error::decode) } } diff --git a/sqlx-core/src/postgres/types/mod.rs b/sqlx-core/src/postgres/types/mod.rs index 179d63fa..cfe348ae 100644 --- a/sqlx-core/src/postgres/types/mod.rs +++ b/sqlx-core/src/postgres/types/mod.rs @@ -58,26 +58,16 @@ //! //! | Rust type | Postgres type(s) | //! |---------------------------------------|------------------------------------------------------| -//! | [`Json`] | JSONB | -//! | [`PgJson`] | JSON | -//! | [`PgJsonb`] | JSONB | -//! | `serde_json::Value` | JSONB | -//! | `PgJson` | JSON | -//! | `&serde_json::value::RawValue` | JSONB | -//! | `PgJson<&serde_json::value::RawValue>`| JSON | -//! -//! By default, Rust types are mapped to `JSONB`. They can be wrapped in [`PgJson`] to use `JSON` -//! instead. +//! | [`Json`] | JSON, JSONB | +//! | `serde_json::Value` | JSON, JSONB | +//! | `&serde_json::value::RawValue` | JSON, JSONB | //! //! `Value` and `RawValue` from `serde_json` can be used for unstructured JSON data with //! Postgres. //! -//! [`Json`] can be used for structured JSON data with Postgres. [`Json`] is an alias -//! for [`PgJsonb`]. +//! [`Json`] can be used for structured JSON data with Postgres. //! //! [`Json`]: crate::types::Json -//! [`PgJson`]: crate::postgres::types::PgJson -//! [`PgJsonb`]: crate::postgres::types::PgJsonb //! //! # [Composite types](https://www.postgresql.org/docs/current/rowtypes.html) //! @@ -177,9 +167,6 @@ mod json; #[cfg(feature = "ipnetwork")] mod ipnetwork; -#[cfg(feature = "json")] -pub use raw::{PgJson, PgJsonb}; - /// Type information for a Postgres SQL type. #[derive(Debug, Clone)] pub struct PgTypeInfo { @@ -289,6 +276,16 @@ impl TypeInfo for PgTypeInfo { true } + // JSON <=> JSONB + (TypeId::JSON, other) | (TypeId::JSONB, other) + if match other { + TypeId::JSON | TypeId::JSONB => true, + _ => false, + } => + { + true + } + _ => self.id.0 == other.id.0, } } diff --git a/sqlx-core/src/postgres/types/raw/json.rs b/sqlx-core/src/postgres/types/raw/json.rs deleted file mode 100644 index 705a7579..00000000 --- a/sqlx-core/src/postgres/types/raw/json.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::decode::Decode; -use crate::encode::Encode; -use crate::io::{Buf, BufMut}; -use crate::postgres::protocol::TypeId; -use crate::postgres::types::PgTypeInfo; -use crate::postgres::{PgData, PgValue, Postgres}; -use crate::types::Type; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, PartialEq)] -pub struct PgJson(pub T); - -impl Type for PgJson { - fn type_info() -> PgTypeInfo { - PgTypeInfo::new(TypeId::JSON, "JSON") - } -} - -impl Encode for PgJson -where - T: Serialize, -{ - fn encode(&self, buf: &mut Vec) { - serde_json::to_writer(buf, &self.0) - .expect("failed to serialize json for encoding to database"); - } -} - -impl<'de, T> Decode<'de, Postgres> for PgJson -where - T: 'de, - T: Deserialize<'de>, -{ - fn decode(value: PgValue<'de>) -> crate::Result { - (match value.try_get()? { - PgData::Text(s) => serde_json::from_str(s), - PgData::Binary(buf) => serde_json::from_slice(buf), - }) - .map(PgJson) - .map_err(crate::Error::decode) - } -} - -// This type has the Pg prefix as it is a postgres-only extension -// unlike the normal Json wrapper -#[derive(Debug, PartialEq)] -pub struct PgJsonb(pub T); - -impl Type for PgJsonb { - fn type_info() -> PgTypeInfo { - PgTypeInfo::new(TypeId::JSONB, "JSONB") - } -} - -impl Encode for PgJsonb -where - T: Serialize, -{ - fn encode(&self, buf: &mut Vec) { - // JSONB version (as of 2020-03-20) - buf.put_u8(1); - - serde_json::to_writer(buf, &self.0) - .expect("failed to serialize json for encoding to database"); - } -} - -impl<'de, T> Decode<'de, Postgres> for PgJsonb -where - T: 'de, - T: Deserialize<'de>, -{ - fn decode(value: PgValue<'de>) -> crate::Result { - (match value.try_get()? { - PgData::Text(s) => serde_json::from_str(s), - PgData::Binary(mut buf) => { - let version = buf.get_u8()?; - - assert_eq!( - version, 1, - "unsupported JSONB format version {}; please open an issue", - version - ); - - serde_json::from_slice(buf) - } - }) - .map(PgJsonb) - .map_err(crate::Error::decode) - } -} diff --git a/sqlx-core/src/postgres/types/raw/mod.rs b/sqlx-core/src/postgres/types/raw/mod.rs index dbd92ed9..80a3b1db 100644 --- a/sqlx-core/src/postgres/types/raw/mod.rs +++ b/sqlx-core/src/postgres/types/raw/mod.rs @@ -3,12 +3,6 @@ mod numeric; mod record; mod sequence; -#[cfg(feature = "json")] -mod json; - -#[cfg(feature = "json")] -pub use json::{PgJson, PgJsonb}; - pub(crate) use array::{PgArrayDecoder, PgArrayEncoder}; // Used in integration tests diff --git a/tests/postgres-types.rs b/tests/postgres-types.rs index 1a464810..e9c2052d 100644 --- a/tests/postgres-types.rs +++ b/tests/postgres-types.rs @@ -534,7 +534,6 @@ mod json { use super::*; use serde_json::value::RawValue; use serde_json::{json, Value as JsonValue}; - use sqlx::postgres::types::PgJson; use sqlx::postgres::PgRow; use sqlx::types::Json; use sqlx::Row; @@ -544,12 +543,12 @@ mod json { test_type!(json( Postgres, - PgJson, + JsonValue, "SELECT {0}::jsonb is not distinct from $1::jsonb, $2::text as _1, {0} as _2, $3 as _3", - "'\"Hello, World\"'::json" == PgJson(json!("Hello, World")), - "'\"😎\"'::json" == PgJson(json!("😎")), - "'\"🙋‍♀️\"'::json" == PgJson(json!("🙋‍♀️")), - "'[\"Hello\", \"World!\"]'::json" == PgJson(json!(["Hello", "World!"])) + "'\"Hello, World\"'::json" == json!("Hello, World"), + "'\"😎\"'::json" == json!("😎"), + "'\"🙋‍♀️\"'::json" == json!("🙋‍♀️"), + "'[\"Hello\", \"World!\"]'::json" == json!(["Hello", "World!"]) )); test_type!(jsonb( @@ -567,20 +566,15 @@ mod json { age: u32, } - // The default JSON type that SQLx chooses is JSONB - // sqlx::types::Json -> JSONB - // sqlx::postgres::types::PgJson -> JSON - // sqlx::postgres::types::PgJsonB -> JSONB - test_type!(jsonb_struct(Postgres, Json, "'{\"name\":\"Joe\",\"age\":33}'::jsonb" == Json(Friend { name: "Joe".to_string(), age: 33 }) )); test_type!(json_struct( Postgres, - PgJson, + Json, "SELECT {0}::jsonb is not distinct from $1::jsonb, $2::text as _1, {0} as _2, $3 as _3", - "'{\"name\":\"Joe\",\"age\":33}'::json" == PgJson(Friend { name: "Joe".to_string(), age: 33 }) + "'{\"name\":\"Joe\",\"age\":33}'::json" == Json(Friend { name: "Joe".to_string(), age: 33 }) )); #[cfg_attr(feature = "runtime-async-std", async_std::test)]