dbson/
lib.rs

1use serde::{Deserialize, Serialize};
2
3/// A wrapper type for BSON data.
4///
5/// Any type that implements serde::Deserialize && serde::Serialize can be wrapped by this type.
6/// and used inside of a database as a blob.
7///
8/// This type is useful for storing data that is not easily represented in a relational database.
9/// For example, a HashMap or a Vec of structs.
10/// Currently only supports rusqlite and sqlx
11///
12/// It's basically a newtype wrapper over T
13/// So it implements many of the same traits as T
14#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
15#[serde(transparent)]
16#[repr(transparent)]
17pub struct DBson<T>(T);
18
19// impl<'de> Deserialize<'de> for DBson<bson::Document> {
20//     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
21//     where
22//         D: serde::Deserializer<'de>,
23//     {
24//         bson::Document::deserialize(deserializer).map(Self)
25//     }
26// }
27
28// impl Serialize for DBson<bson::Document> {
29//     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
30//     where
31//         S: serde::Serializer,
32//     {
33//         self.0.serialize(serializer)
34//     }
35// }
36
37impl<T> From<T> for DBson<T> {
38    fn from(inner: T) -> Self {
39        Self(inner)
40    }
41}
42
43impl<T> DBson<T> {
44    pub fn new(inner: T) -> Self {
45        Self(inner)
46    }
47
48    pub fn into_inner(self) -> T {
49        self.0
50    }
51}
52
53#[cfg(feature = "rusqlite")]
54#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
55mod impl_rusqlite {
56    use rusqlite::{types::FromSql, ToSql};
57    impl<T: serde::Serialize> ToSql for super::DBson<T> {
58        fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
59            let bytes = bson::to_vec(&self.0)
60                .map_err(|e| rusqlite::Error::ToSqlConversionFailure(e.into()))?;
61            Ok(rusqlite::types::ToSqlOutput::Owned(
62                rusqlite::types::Value::Blob(bytes),
63            ))
64        }
65    }
66
67    impl<T: for<'de> serde::de::Deserialize<'de>> FromSql for super::DBson<T> {
68        fn column_result(
69            value: rusqlite::types::ValueRef<'_>,
70        ) -> rusqlite::types::FromSqlResult<Self> {
71            let bytes = value.as_blob()?;
72            let inner = bson::from_slice(bytes)
73                .map_err(|e| rusqlite::types::FromSqlError::Other(Box::new(e)))?;
74            Ok(Self::new(inner))
75        }
76    }
77}
78
79#[cfg(feature = "sqlx")]
80#[cfg_attr(docsrs, doc(cfg(feature = "sqlx")))]
81mod impl_sqlx {
82    use sqlx::{
83        database::{HasArguments, HasValueRef},
84        decode::Decode,
85        encode::Encode,
86        types::Type,
87    };
88
89    impl<'a, T: Serialize + serde::de::DeserializeOwned, DB: sqlx::database::Database> Type<DB>
90        for DBson<T>
91    where
92        &'a [u8]: Type<DB>,
93    {
94        fn type_info() -> DB::TypeInfo {
95            <&[u8] as ::sqlx::types::Type<DB>>::type_info()
96        }
97    }
98
99    impl<'a, T: Serialize + serde::de::DeserializeOwned, DB: sqlx::database::Database>
100        Encode<'a, DB> for DBson<T>
101    where
102        Vec<u8>: Type<DB>,
103        Vec<u8>: Encode<'a, DB>,
104    {
105        fn encode_by_ref(
106            &self,
107            buf: &mut <DB as HasArguments<'a>>::ArgumentBuffer,
108        ) -> sqlx::encode::IsNull {
109            let Ok(bytes) = bson::to_vec(&self.inner) else {
110                return sqlx::encode::IsNull::Yes;
111            };
112            <Vec<u8> as Encode<'a, DB>>::encode_by_ref(&bytes, buf)
113        }
114        fn encode(
115            self,
116            buf: &mut <DB as HasArguments<'a>>::ArgumentBuffer,
117        ) -> sqlx::encode::IsNull {
118            let Ok(bytes) = bson::to_vec(&self.inner) else {
119                return sqlx::encode::IsNull::Yes;
120            };
121            <Vec<u8> as Encode<'a, DB>>::encode(bytes, buf)
122        }
123    }
124
125    impl<'r, T: Serialize + serde::de::DeserializeOwned, DB: sqlx::database::Database>
126        Decode<'r, DB> for DBson<T>
127    where
128        &'r [u8]: Type<DB>,
129        &'r [u8]: Decode<'r, DB>,
130    {
131        fn decode(
132            value: <DB as HasValueRef<'r>>::ValueRef,
133        ) -> Result<Self, Box<dyn std::error::Error + Send + Sync + 'static>> {
134            let bytes = <&[u8] as Decode<'r, DB>>::decode(value)?;
135            let inner = bson::from_slice(&bytes)?;
136            Ok(Self { inner })
137        }
138    }
139}