mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-12-29 21:00:54 +00:00
postgres: simplify JSON support to just Json<T>
This commit is contained in:
parent
8454fa4e96
commit
7ab772ea80
@ -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<Postgres> for JsonValue {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
<PgJsonb<Self> as Type<Postgres>>::type_info()
|
||||
<Json<Self> as Type<Postgres>>::type_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode<Postgres> for JsonValue {
|
||||
fn encode(&self, buf: &mut Vec<u8>) {
|
||||
PgJsonb(self).encode(buf)
|
||||
Json(self).encode(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Decode<'de, Postgres> for JsonValue {
|
||||
fn decode(value: PgValue<'de>) -> crate::Result<Postgres, Self> {
|
||||
<PgJsonb<Self> as Decode<Postgres>>::decode(value).map(|item| item.0)
|
||||
<Json<Self> as Decode<Postgres>>::decode(value).map(|item| item.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Type<Postgres> for &'_ JsonRawValue {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
<PgJsonb<Self> as Type<Postgres>>::type_info()
|
||||
<Json<Self> as Type<Postgres>>::type_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode<Postgres> for &'_ JsonRawValue {
|
||||
fn encode(&self, buf: &mut Vec<u8>) {
|
||||
PgJsonb(self).encode(buf)
|
||||
Json(self).encode(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Decode<'de, Postgres> for &'de JsonRawValue {
|
||||
fn decode(value: PgValue<'de>) -> crate::Result<Postgres, Self> {
|
||||
<PgJsonb<Self> as Decode<Postgres>>::decode(value).map(|item| item.0)
|
||||
<Json<Self> as Decode<Postgres>>::decode(value).map(|item| item.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Type<Postgres> for Json<T> {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
<PgJsonb<T> as Type<Postgres>>::type_info()
|
||||
PgTypeInfo::new(TypeId::JSONB, "JSONB")
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +62,11 @@ where
|
||||
T: Serialize,
|
||||
{
|
||||
fn encode(&self, buf: &mut Vec<u8>) {
|
||||
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<Postgres, Self> {
|
||||
<PgJsonb<T> as Decode<Postgres>>::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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,26 +58,16 @@
|
||||
//!
|
||||
//! | Rust type | Postgres type(s) |
|
||||
//! |---------------------------------------|------------------------------------------------------|
|
||||
//! | [`Json<T>`] | JSONB |
|
||||
//! | [`PgJson<T>`] | JSON |
|
||||
//! | [`PgJsonb<T>`] | JSONB |
|
||||
//! | `serde_json::Value` | JSONB |
|
||||
//! | `PgJson<serde_json::Value>` | 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<T>`] to use `JSON`
|
||||
//! instead.
|
||||
//! | [`Json<T>`] | 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<T>`] can be used for structured JSON data with Postgres. [`Json<T>`] is an alias
|
||||
//! for [`PgJsonb<T>`].
|
||||
//! [`Json<T>`] can be used for structured JSON data with Postgres.
|
||||
//!
|
||||
//! [`Json<T>`]: crate::types::Json
|
||||
//! [`PgJson<T>`]: crate::postgres::types::PgJson
|
||||
//! [`PgJsonb<T>`]: 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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<T>(pub T);
|
||||
|
||||
impl<T> Type<Postgres> for PgJson<T> {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
PgTypeInfo::new(TypeId::JSON, "JSON")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Encode<Postgres> for PgJson<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn encode(&self, buf: &mut Vec<u8>) {
|
||||
serde_json::to_writer(buf, &self.0)
|
||||
.expect("failed to serialize json for encoding to database");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Decode<'de, Postgres> for PgJson<T>
|
||||
where
|
||||
T: 'de,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn decode(value: PgValue<'de>) -> crate::Result<Postgres, Self> {
|
||||
(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<T> wrapper
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct PgJsonb<T>(pub T);
|
||||
|
||||
impl<T> Type<Postgres> for PgJsonb<T> {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
PgTypeInfo::new(TypeId::JSONB, "JSONB")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Encode<Postgres> for PgJsonb<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn encode(&self, buf: &mut Vec<u8>) {
|
||||
// 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<T>
|
||||
where
|
||||
T: 'de,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn decode(value: PgValue<'de>) -> crate::Result<Postgres, Self> {
|
||||
(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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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>,
|
||||
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<Friend>,
|
||||
"'{\"name\":\"Joe\",\"age\":33}'::jsonb" == Json(Friend { name: "Joe".to_string(), age: 33 })
|
||||
));
|
||||
|
||||
test_type!(json_struct(
|
||||
Postgres,
|
||||
PgJson<Friend>,
|
||||
Json<Friend>,
|
||||
"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)]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user