coven_foundation/
uuid_text.rs1use crate::id_source::{CircleId, DeviceId, FileId, KeyId, MemberId, ObjectId, StoreId};
6use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, Value, ValueRef};
7use rusqlite::ToSql;
8use uuid::Uuid;
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub struct UuidText(
14 pub Uuid,
16);
17
18impl From<UuidText> for Value {
19 fn from(value: UuidText) -> Self {
20 Self::Text(value.0.to_string())
21 }
22}
23
24impl ToSql for UuidText {
25 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
26 Ok(ToSqlOutput::Owned((*self).into()))
27 }
28}
29
30impl FromSql for UuidText {
31 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
32 crate::id_source::canonical_uuid(value.as_str()?)
33 .map(Self)
34 .map_err(|error| FromSqlError::Other(Box::new(error)))
35 }
36}
37
38impl ToSql for CircleId {
39 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
40 Ok(ToSqlOutput::Owned(UuidText(self.0).into()))
41 }
42}
43
44impl FromSql for CircleId {
45 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
46 UuidText::column_result(value).map(|id| Self(id.0))
47 }
48}
49
50impl ToSql for MemberId {
53 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
54 Ok(ToSqlOutput::Owned(UuidText(self.0).into()))
55 }
56}
57
58impl FromSql for MemberId {
59 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
60 UuidText::column_result(value).map(|id| Self(id.0))
61 }
62}
63
64impl ToSql for FileId {
67 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
68 Ok(ToSqlOutput::Owned(UuidText(self.0).into()))
69 }
70}
71
72impl FromSql for FileId {
73 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
74 UuidText::column_result(value).map(|id| Self(id.0))
75 }
76}
77
78fn uuid_blob(id: &Uuid) -> ToSqlOutput<'_> {
80 ToSqlOutput::Borrowed(ValueRef::Blob(id.as_bytes()))
81}
82
83fn uuid_from_blob(value: ValueRef<'_>) -> FromSqlResult<Uuid> {
85 let bytes = value.as_blob()?;
86 let bytes = <[u8; 16]>::try_from(bytes).map_err(|_wrong_size| {
87 FromSqlError::InvalidBlobSize { expected_size: 16, blob_size: bytes.len() }
88 })?;
89 Ok(Uuid::from_bytes(bytes))
90}
91
92impl ToSql for ObjectId {
95 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
96 Ok(uuid_blob(&self.0))
97 }
98}
99
100impl FromSql for ObjectId {
101 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
102 uuid_from_blob(value).map(Self)
103 }
104}
105
106impl ToSql for StoreId {
108 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
109 Ok(uuid_blob(&self.0))
110 }
111}
112
113impl FromSql for StoreId {
114 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
115 uuid_from_blob(value).map(Self)
116 }
117}
118
119impl ToSql for KeyId {
122 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
123 Ok(uuid_blob(&self.0))
124 }
125}
126
127impl FromSql for KeyId {
128 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
129 uuid_from_blob(value).map(Self)
130 }
131}
132
133impl ToSql for DeviceId {
137 fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
138 Ok(ToSqlOutput::Owned(Value::Blob(self.0.to_be_bytes().to_vec())))
139 }
140}
141
142impl FromSql for DeviceId {
143 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
144 let bytes = value.as_blob()?;
145 let bytes = <[u8; 8]>::try_from(bytes).map_err(|_wrong_size| {
146 FromSqlError::InvalidBlobSize { expected_size: 8, blob_size: bytes.len() }
147 })?;
148 Ok(Self(u64::from_be_bytes(bytes)))
149 }
150}
151
152#[cfg(test)]
153#[path = "uuid_text_tests.rs"]
154mod tests;