Skip to main content

rullst_orm/
types.rs

1use std::ops::{Deref, DerefMut};
2
3/// A wrapper for JSON columns in the database.
4/// This type allows users to easily cast a column to a struct that implements Serialize and Deserialize.
5#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
6#[serde(transparent)]
7pub struct Json<T>(pub T);
8
9impl<T> Deref for Json<T> {
10    type Target = T;
11
12    fn deref(&self) -> &Self::Target {
13        &self.0
14    }
15}
16
17impl<T> DerefMut for Json<T> {
18    fn deref_mut(&mut self) -> &mut Self::Target {
19        &mut self.0
20    }
21}
22
23#[cfg(not(any(feature = "strict-postgres", feature = "strict-mysql", feature = "strict-sqlite")))]
24impl<'r, T: serde::de::DeserializeOwned> sqlx::Decode<'r, sqlx::Any> for Json<T> {
25    fn decode(value: sqlx::any::AnyValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {
26        let text = <String as sqlx::Decode<sqlx::Any>>::decode(value)?;
27        let parsed: T = serde_json::from_str(&text)?;
28        Ok(Json(parsed))
29    }
30}
31
32#[cfg(not(any(feature = "strict-postgres", feature = "strict-mysql", feature = "strict-sqlite")))]
33impl<'q, T: serde::Serialize> sqlx::Encode<'q, sqlx::Any> for Json<T> {
34    fn encode_by_ref(&self, buf: &mut <sqlx::Any as sqlx::database::Database>::ArgumentBuffer) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync>> {
35        let stringified = serde_json::to_string(&self.0)?;
36        <String as sqlx::Encode<sqlx::Any>>::encode(stringified, buf)
37    }
38}
39
40#[cfg(not(any(feature = "strict-postgres", feature = "strict-mysql", feature = "strict-sqlite")))]
41impl<T> sqlx::Type<sqlx::Any> for Json<T> {
42    fn type_info() -> sqlx::any::AnyTypeInfo {
43        <String as sqlx::Type<sqlx::Any>>::type_info()
44    }
45}
46
47#[cfg(any(feature = "strict-postgres", feature = "strict-mysql", feature = "strict-sqlite"))]
48impl<'r, T: serde::de::DeserializeOwned> sqlx::Decode<'r, crate::database::EloquentDatabase> for Json<T> {
49    fn decode(value: <crate::database::EloquentDatabase as sqlx::database::Database>::ValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {
50        let text = <String as sqlx::Decode<crate::database::EloquentDatabase>>::decode(value)?;
51        let parsed: T = serde_json::from_str(&text)?;
52        Ok(Json(parsed))
53    }
54}
55
56#[cfg(any(feature = "strict-postgres", feature = "strict-mysql", feature = "strict-sqlite"))]
57impl<'q, T: serde::Serialize> sqlx::Encode<'q, crate::database::EloquentDatabase> for Json<T> {
58    fn encode_by_ref(&self, buf: &mut <crate::database::EloquentDatabase as sqlx::database::Database>::ArgumentBuffer) -> Result<sqlx::encode::IsNull, Box<dyn std::error::Error + Send + Sync>> {
59        let stringified = serde_json::to_string(&self.0)?;
60        <String as sqlx::Encode<crate::database::EloquentDatabase>>::encode(stringified, buf)
61    }
62}
63
64#[cfg(any(feature = "strict-postgres", feature = "strict-mysql", feature = "strict-sqlite"))]
65impl<T> sqlx::Type<crate::database::EloquentDatabase> for Json<T> {
66    fn type_info() -> <crate::database::EloquentDatabase as sqlx::database::Database>::TypeInfo {
67        <String as sqlx::Type<crate::database::EloquentDatabase>>::type_info()
68    }
69}