miden_node_db/sqlite/
codec.rs1use std::rc::Rc;
13
14use rusqlite::ToSql;
15use rusqlite::types::{ToSqlOutput, Value, ValueRef};
16
17use crate::DatabaseError;
18
19#[derive(Debug, Clone)]
28pub enum DbValue {
29 Single(Value),
31 Array(Rc<Vec<Value>>),
33}
34
35impl DbValue {
36 pub fn integer(value: i64) -> Self {
38 Self::Single(Value::Integer(value))
39 }
40
41 pub fn real(value: f64) -> Self {
43 Self::Single(Value::Real(value))
44 }
45
46 pub fn text(value: String) -> Self {
48 Self::Single(Value::Text(value))
49 }
50
51 pub fn blob(value: Vec<u8>) -> Self {
53 Self::Single(Value::Blob(value))
54 }
55
56 pub fn null() -> Self {
58 Self::Single(Value::Null)
59 }
60
61 pub(crate) fn array(values: Vec<Value>) -> Self {
63 Self::Array(Rc::new(values))
64 }
65}
66
67impl ToSql for DbValue {
68 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
69 match self {
70 Self::Single(value) => value.to_sql(),
71 Self::Array(values) => values.to_sql(),
72 }
73 }
74}
75
76#[derive(Debug, Clone, Copy)]
80pub struct DbValueRef<'a>(ValueRef<'a>);
81
82impl<'a> DbValueRef<'a> {
83 pub(crate) fn new(value: ValueRef<'a>) -> Self {
84 Self(value)
85 }
86
87 pub fn as_i64(self) -> Result<i64, DatabaseError> {
89 self.0.as_i64().map_err(|err| DatabaseError::deserialization("i64", err))
90 }
91
92 pub fn as_blob(self) -> Result<&'a [u8], DatabaseError> {
94 self.0.as_blob().map_err(|err| DatabaseError::deserialization("blob", err))
95 }
96
97 pub fn as_str(self) -> Result<&'a str, DatabaseError> {
99 self.0.as_str().map_err(|err| DatabaseError::deserialization("str", err))
100 }
101
102 pub fn is_null(self) -> bool {
104 matches!(self.0, ValueRef::Null)
105 }
106}
107
108pub trait ToSqlValue {
113 fn to_sql_value(&self) -> DbValue;
115}
116
117pub trait FromSqlValue: Sized {
119 fn from_sql_value(value: DbValueRef<'_>) -> Result<Self, DatabaseError>;
121}
122
123impl<T: ToSqlValue + ?Sized> ToSqlValue for &T {
125 fn to_sql_value(&self) -> DbValue {
126 (**self).to_sql_value()
127 }
128}
129
130impl ToSqlValue for i64 {
134 fn to_sql_value(&self) -> DbValue {
135 DbValue::integer(*self)
136 }
137}
138
139impl FromSqlValue for i64 {
140 fn from_sql_value(value: DbValueRef<'_>) -> Result<Self, DatabaseError> {
141 value.as_i64()
142 }
143}
144
145impl ToSqlValue for bool {
146 fn to_sql_value(&self) -> DbValue {
147 DbValue::integer(i64::from(*self))
148 }
149}
150
151impl FromSqlValue for bool {
152 fn from_sql_value(value: DbValueRef<'_>) -> Result<Self, DatabaseError> {
153 Ok(value.as_i64()? != 0)
154 }
155}
156
157impl ToSqlValue for Vec<u8> {
158 fn to_sql_value(&self) -> DbValue {
159 DbValue::blob(self.clone())
160 }
161}
162
163impl FromSqlValue for Vec<u8> {
164 fn from_sql_value(value: DbValueRef<'_>) -> Result<Self, DatabaseError> {
165 Ok(value.as_blob()?.to_vec())
166 }
167}
168
169impl ToSqlValue for str {
170 fn to_sql_value(&self) -> DbValue {
171 DbValue::text(self.to_owned())
172 }
173}
174
175impl ToSqlValue for String {
176 fn to_sql_value(&self) -> DbValue {
177 DbValue::text(self.clone())
178 }
179}
180
181impl FromSqlValue for String {
182 fn from_sql_value(value: DbValueRef<'_>) -> Result<Self, DatabaseError> {
183 Ok(value.as_str()?.to_owned())
184 }
185}
186
187impl<T: ToSqlValue> ToSqlValue for Option<T> {
188 fn to_sql_value(&self) -> DbValue {
189 match self {
190 Some(value) => value.to_sql_value(),
191 None => DbValue::null(),
192 }
193 }
194}
195
196impl<T: FromSqlValue> FromSqlValue for Option<T> {
197 fn from_sql_value(value: DbValueRef<'_>) -> Result<Self, DatabaseError> {
198 if value.is_null() {
199 Ok(None)
200 } else {
201 Ok(Some(T::from_sql_value(value)?))
202 }
203 }
204}
205
206#[macro_export]
216macro_rules! impl_blob_codec {
217 ($($t:ty),+ $(,)?) => {
218 $(
219 impl $crate::sqlite::ToSqlValue for $t {
220 fn to_sql_value(&self) -> $crate::sqlite::DbValue {
221 $crate::sqlite::DbValue::blob(
222 ::miden_protocol::utils::serde::Serializable::to_bytes(self),
223 )
224 }
225 }
226
227 impl $crate::sqlite::FromSqlValue for $t {
228 fn from_sql_value(
229 value: $crate::sqlite::DbValueRef<'_>,
230 ) -> ::core::result::Result<Self, $crate::DatabaseError> {
231 let bytes = value.as_blob()?;
232 <$t as ::miden_protocol::utils::serde::Deserializable>::read_from_bytes(bytes)
233 .map_err(|err| {
234 $crate::DatabaseError::deserialization(::core::stringify!($t), err)
235 })
236 }
237 }
238 )+
239 };
240}
241
242impl_blob_codec!(
245 miden_protocol::block::BlockHeader,
246 miden_protocol::account::AccountId,
247 miden_protocol::transaction::TransactionId,
248 miden_protocol::note::Nullifier,
249 miden_protocol::Word,
250);