use core::ops::{Deref, DerefMut};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::error::DrizzleError;
use crate::expr::{AggregateKind, ColumnBinOp, ColumnNeg, Excluded, Nullability, SQLExpr};
use crate::placeholder::{Placeholder, TypedPlaceholder};
use crate::prelude::{String, Vec};
use crate::traits::SQLParam;
use crate::types::DataType;
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Json<T>(pub T);
impl<T> Json<T> {
#[inline]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> From<T> for Json<T> {
#[inline]
fn from(value: T) -> Self {
Self(value)
}
}
impl<T> Deref for Json<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for Json<T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T: Serialize> Serialize for Json<T> {
#[inline]
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize(serializer)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Json<T> {
#[inline]
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
T::deserialize(deserializer).map(Self)
}
}
impl<T: Serialize> Json<T> {
pub fn to_json_string(&self) -> Result<String, DrizzleError> {
serde_json::to_string(&self.0).map_err(DrizzleError::from)
}
pub fn to_json_vec(&self) -> Result<Vec<u8>, DrizzleError> {
serde_json::to_vec(&self.0).map_err(DrizzleError::from)
}
pub fn to_json_value(&self) -> Result<serde_json::Value, DrizzleError> {
serde_json::to_value(&self.0).map_err(DrizzleError::from)
}
#[doc(hidden)]
#[track_caller]
pub fn encode_json_text(&self) -> String {
self.to_json_string()
.unwrap_or_else(|error| serialization_failed(&error))
}
#[doc(hidden)]
#[track_caller]
pub fn encode_json_bytes(&self) -> Vec<u8> {
self.to_json_vec()
.unwrap_or_else(|error| serialization_failed(&error))
}
#[doc(hidden)]
#[track_caller]
pub fn encode_json_value(&self) -> serde_json::Value {
self.to_json_value()
.unwrap_or_else(|error| serialization_failed(&error))
}
}
#[cold]
#[track_caller]
fn serialization_failed(error: &DrizzleError) -> ! {
panic!("drizzle: failed to serialize JSON value for a JSON column: {error}")
}
impl<T: DeserializeOwned> Json<T> {
pub fn from_json_str(json: &str) -> Result<Self, DrizzleError> {
serde_json::from_str(json)
.map(Self)
.map_err(DrizzleError::from)
}
pub fn from_json_slice(json: &[u8]) -> Result<Self, DrizzleError> {
serde_json::from_slice(json)
.map(Self)
.map_err(DrizzleError::from)
}
pub fn from_json_value(value: serde_json::Value) -> Result<Self, DrizzleError> {
serde_json::from_value(value)
.map(Self)
.map_err(DrizzleError::from)
}
}
pub trait JsonColumnValue<T>: Sized {
fn from_json(value: Json<T>) -> Self;
}
pub trait JsonColumnOperand {}
pub mod arg {
#[derive(Debug)]
pub enum Payload {}
#[derive(Debug)]
pub enum Wrapped {}
#[derive(Debug)]
pub enum Operand {}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` cannot be assigned to this JSON column",
note = "pass the column's payload type, `drizzle::core::Json(value)`, a placeholder, or an SQL expression"
)]
pub trait JsonColumnArg<Out, Marker>: Sized {
fn into_json_column(self) -> Out;
}
impl<T, Out: JsonColumnValue<T>> JsonColumnArg<Out, arg::Payload> for T {
#[inline]
fn into_json_column(self) -> Out {
Out::from_json(Json(self))
}
}
impl<T, Out: JsonColumnValue<T>> JsonColumnArg<Out, arg::Wrapped> for Json<T> {
#[inline]
fn into_json_column(self) -> Out {
Out::from_json(self)
}
}
impl<V, Out> JsonColumnArg<Out, arg::Operand> for V
where
V: JsonColumnOperand + Into<Out>,
{
#[inline]
fn into_json_column(self) -> Out {
self.into()
}
}
impl JsonColumnOperand for Placeholder {}
impl<T: DataType, N: Nullability> JsonColumnOperand for TypedPlaceholder<T, N> {}
impl<C> JsonColumnOperand for Excluded<C> {}
impl<V, T, N, A> JsonColumnOperand for SQLExpr<'_, V, T, N, A>
where
V: SQLParam,
T: DataType,
N: Nullability,
A: AggregateKind,
{
}
impl<L, R, Op, D, T, N> JsonColumnOperand for ColumnBinOp<L, R, Op, D, T, N> {}
impl<E, D, T, N> JsonColumnOperand for ColumnNeg<E, D, T, N> {}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
use crate::prelude::ToString;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
struct Payload {
name: String,
count: i64,
}
#[test]
fn serializes_and_deserializes_transparently() {
let value = Json(Payload {
name: "a".into(),
count: 2,
});
let text = value.to_json_string().unwrap();
assert_eq!(text, r#"{"name":"a","count":2}"#);
assert_eq!(value.to_json_vec().unwrap(), text.as_bytes());
assert_eq!(Json::<Payload>::from_json_str(&text).unwrap(), value);
assert_eq!(
Json::<Payload>::from_json_slice(text.as_bytes()).unwrap(),
value
);
assert_eq!(
Json::<Payload>::from_json_value(value.to_json_value().unwrap()).unwrap(),
value
);
assert_eq!(
serde_json::to_string(&value).unwrap(),
serde_json::to_string(&value.0).unwrap()
);
}
#[test]
fn wrapper_conversions_reach_the_payload() {
let mut value = Json::from(Payload::default());
value.count += 5;
assert_eq!(value.count, 5);
assert_eq!(value.into_inner().count, 5);
}
#[test]
fn serialization_failures_are_errors() {
let mut map = std::collections::BTreeMap::new();
map.insert((1, 2), "tuple keys are not JSON object keys");
let error = Json(map).to_json_string().unwrap_err();
assert!(matches!(error, DrizzleError::JsonError(_)));
assert!(error.to_string().contains("key must be a string"));
}
#[test]
#[should_panic(expected = "drizzle: failed to serialize JSON value")]
fn infallible_encoders_panic_with_a_drizzle_message() {
let mut map = std::collections::BTreeMap::new();
map.insert((1, 2), 3);
let _ = Json(map).encode_json_text();
}
#[test]
fn decoding_failures_are_errors() {
assert!(matches!(
Json::<Payload>::from_json_str("{\"name\":1}"),
Err(DrizzleError::JsonError(_))
));
assert!(Json::<Payload>::from_json_slice(b"not json").is_err());
}
}