alibi_sqlx/
json_metadata.rs1use crate::pool::Engine;
11use crate::value::{ColumnKind, SqlValue, SqlxValue, ValueTypeError};
12use alibi_core::error::AuthResult;
13use sqlx::encode::IsNull;
14use sqlx::error::BoxDynError;
15#[cfg(feature = "postgres")]
16use sqlx::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueRef, Postgres};
17#[cfg(feature = "sqlite")]
18use sqlx::sqlite::{Sqlite, SqliteArgumentsBuffer, SqliteTypeInfo, SqliteValueRef};
19use sqlx::{Decode, Encode, Type};
20
21#[derive(Clone, Debug, serde::Serialize)]
34#[serde(transparent)]
35pub struct JsonMetadata(serde_json::Value, #[serde(skip)] Option<String>);
36
37impl JsonMetadata {
38 pub(crate) fn for_backend(
39 value: serde_json::Value,
40 backend: Engine,
41 ) -> Result<Self, serde_json::Error> {
42 let text = if backend == Engine::Sqlite {
43 Some(alibi_core::utils::json::to_string(&value)?)
44 } else {
45 None
46 };
47 Ok(Self(value, text))
48 }
49
50 #[cfg(feature = "sqlite")]
51 fn sqlite_text(&self) -> Result<String, serde_json::Error> {
52 match &self.1 {
53 Some(text) => Ok(text.clone()),
54 None => serde_json::to_string(&self.0),
55 }
56 }
57}
58
59impl PartialEq for JsonMetadata {
60 fn eq(&self, other: &Self) -> bool {
61 self.0 == other.0
62 }
63}
64
65impl<'de> serde::Deserialize<'de> for JsonMetadata {
66 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
67 alibi_core::utils::json::deserialize_value(deserializer).map(Self::from)
68 }
69}
70
71impl From<serde_json::Value> for JsonMetadata {
72 fn from(value: serde_json::Value) -> Self {
73 Self(value, None)
74 }
75}
76
77impl From<JsonMetadata> for serde_json::Value {
78 fn from(value: JsonMetadata) -> Self {
79 value.0
80 }
81}
82
83impl std::ops::Deref for JsonMetadata {
84 type Target = serde_json::Value;
85 fn deref(&self) -> &Self::Target {
86 &self.0
87 }
88}
89
90impl SqlxValue for JsonMetadata {
91 const KIND: ColumnKind = ColumnKind::Json;
92 fn null() -> SqlValue {
93 SqlValue::Json(None)
94 }
95 fn into_sql_value(self) -> SqlValue {
96 match self.1 {
97 Some(text) => SqlValue::Text(Some(text)),
98 None => SqlValue::Json(Some(Box::new(self.0))),
99 }
100 }
101 fn from_sql_value(value: SqlValue) -> Result<Self, ValueTypeError> {
102 match value {
103 SqlValue::Json(Some(value)) => Ok(Self::from(*value)),
104 SqlValue::Text(Some(text)) => {
105 alibi_core::utils::json::from_slice::<serde_json::Value>(text.as_bytes())
106 .map(Self::from)
107 .map_err(|_error| ValueTypeError)
108 }
109 _ => Err(ValueTypeError),
110 }
111 }
112 fn prepare(self, engine: Engine) -> AuthResult<Self> {
113 let value = alibi_core::utils::json::to_value(&self.0)?;
114 Ok(Self::for_backend(value, engine)?)
115 }
116}
117
118#[cfg(feature = "sqlite")]
119impl Type<Sqlite> for JsonMetadata {
120 fn type_info() -> SqliteTypeInfo {
121 <sqlx::types::Json<Self> as Type<Sqlite>>::type_info()
122 }
123 fn compatible(ty: &SqliteTypeInfo) -> bool {
124 <sqlx::types::Json<Self> as Type<Sqlite>>::compatible(ty)
125 }
126}
127
128#[cfg(feature = "sqlite")]
129impl<'r> Decode<'r, Sqlite> for JsonMetadata {
130 fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
131 <sqlx::types::Json<Self> as Decode<'r, Sqlite>>::decode(value).map(|json| json.0)
132 }
133}
134
135#[cfg(feature = "sqlite")]
136impl Encode<'_, Sqlite> for JsonMetadata {
137 fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {
138 <String as Encode<'_, Sqlite>>::encode(self.sqlite_text()?, buf)
139 }
140}
141
142#[cfg(feature = "postgres")]
143impl Type<Postgres> for JsonMetadata {
144 fn type_info() -> PgTypeInfo {
145 <sqlx::types::Json<Self> as Type<Postgres>>::type_info()
146 }
147 fn compatible(ty: &PgTypeInfo) -> bool {
148 <sqlx::types::Json<Self> as Type<Postgres>>::compatible(ty)
149 }
150}
151
152#[cfg(feature = "postgres")]
153impl<'r> Decode<'r, Postgres> for JsonMetadata {
154 fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
155 <sqlx::types::Json<Self> as Decode<'r, Postgres>>::decode(value).map(|json| json.0)
156 }
157}
158
159#[cfg(feature = "postgres")]
160impl Encode<'_, Postgres> for JsonMetadata {
161 fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
162 <serde_json::Value as Encode<'_, Postgres>>::encode_by_ref(&self.0, buf)
163 }
164}