Skip to main content

p2panda_store/spaces/
sqlite.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use std::borrow::Borrow;
4use std::marker::PhantomData;
5use std::str::FromStr;
6
7use p2panda_auth::group::GroupCrdtState;
8use p2panda_auth::traits::{Conditions, Operation as AuthOperation};
9use p2panda_core::cbor::{decode_cbor, encode_cbor};
10use p2panda_core::{Extensions, Hash, Operation, VerifyingKey};
11use p2panda_encryption::key_manager::PreKeyBundlesState;
12use p2panda_encryption::key_registry::KeyRegistryState;
13use serde::{Deserialize, Serialize};
14use sqlx::{query, query_as};
15
16use crate::groups::GroupsStore;
17use crate::key_registry::KeyRegistryStore;
18use crate::key_secrets::KeySecretsStore;
19use crate::operations::OperationStore;
20use crate::spaces::traits::SpacesMessageStore;
21use crate::spaces::{SpacesMessage, SpacesStore};
22use crate::sqlite::TransactionPermit;
23use crate::{SqliteError, SqliteStore};
24
25#[derive(Clone)]
26pub struct SqliteSpacesStore<E> {
27    store: SqliteStore,
28    _phantom: PhantomData<E>,
29}
30
31impl<E> SqliteSpacesStore<E> {
32    pub fn new(store: SqliteStore) -> Self {
33        Self {
34            store,
35            _phantom: PhantomData,
36        }
37    }
38}
39
40impl<ARG, E> SpacesMessageStore<ARG> for SqliteSpacesStore<E>
41where
42    ARG: Clone,
43    E: Extensions + Borrow<ARG>,
44{
45    type Error = SqliteError;
46
47    async fn get_spaces_message(
48        &self,
49        id: &Hash,
50    ) -> Result<Option<SpacesMessage<ARG>>, Self::Error> {
51        match <SqliteStore as OperationStore<Operation<E>, Hash>>::get_operation(&self.store, id)
52            .await?
53        {
54            Some(operation) => {
55                let args = operation.header().extensions.borrow().clone();
56                let message = SpacesMessage {
57                    id: operation.hash,
58                    author: operation.header().verifying_key,
59                    args,
60                };
61                Ok(Some(message))
62            }
63            None => Ok(None),
64        }
65    }
66}
67
68impl<S, E> SpacesStore<S> for SqliteSpacesStore<E>
69where
70    S: for<'a> Deserialize<'a> + Serialize,
71{
72    type Error = SqliteError;
73
74    async fn get_space_state_tx(&self, id: &Hash) -> Result<Option<S>, Self::Error> {
75        let row = self
76            .store
77            .tx(async |tx| {
78                query_as::<_, (Vec<u8>,)>(
79                    "
80                    SELECT
81                        state
82                    FROM
83                        spaces_v1
84                    WHERE
85                        id = ?
86                    ",
87                )
88                .bind(id.to_hex())
89                .fetch_optional(&mut **tx)
90                .await
91                .map_err(SqliteError::Sqlite)
92            })
93            .await?;
94
95        let Some((state_bytes,)) = row else {
96            return Ok(None);
97        };
98
99        let state = decode_cbor(&state_bytes[..])
100            .map_err(|err| SqliteError::Decode("state".into(), err.into()))?;
101
102        Ok(Some(state))
103    }
104
105    async fn set_space_state_tx(&self, id: &Hash, state: &S) -> Result<(), Self::Error> {
106        self.store
107            .tx(async |tx| {
108                query(
109                    "
110                INSERT OR REPLACE
111                INTO
112                    spaces_v1 (
113                        id,
114                        state
115                    )
116                VALUES
117                    (?, ?)
118                ",
119                )
120                .bind(id.to_hex())
121                .bind(
122                    encode_cbor(&state)
123                        .map_err(|err| SqliteError::Encode("state".to_string(), err))?,
124                )
125                .execute(&mut **tx)
126                .await
127                .map_err(SqliteError::Sqlite)
128            })
129            .await?;
130
131        Ok(())
132    }
133
134    async fn has_space(&self, id: &Hash) -> Result<bool, Self::Error> {
135        let result = self
136            .store
137            .execute(async |pool| {
138                query_as::<_, (Vec<u8>,)>(
139                    "
140                    SELECT
141                        id
142                    FROM
143                        spaces_v1
144                    WHERE
145                        id = ?
146                    ",
147                )
148                .bind(id.to_hex())
149                .fetch_optional(pool)
150                .await
151                .map_err(SqliteError::Sqlite)
152            })
153            .await?;
154
155        Ok(result.is_some())
156    }
157
158    async fn space_ids(&self) -> Result<Vec<Hash>, Self::Error> {
159        let result = self
160            .store
161            .execute(async |pool| {
162                query_as::<_, (String,)>(
163                    "
164                    SELECT
165                        id
166                    FROM
167                        spaces_v1
168                    ",
169                )
170                .fetch_all(pool)
171                .await
172                .map_err(SqliteError::Sqlite)
173            })
174            .await?;
175
176        let result: Result<Vec<Hash>, _> = result
177            .iter()
178            .map(|(id_str,)| Hash::from_str(id_str))
179            .collect();
180
181        result.map_err(|err| SqliteError::Decode("state".into(), err.into()))
182    }
183}
184
185impl<E> KeyRegistryStore for SqliteSpacesStore<E> {
186    type Error = SqliteError;
187
188    async fn get_key_registry(
189        &self,
190    ) -> Result<Option<KeyRegistryState<VerifyingKey>>, Self::Error> {
191        self.store.get_key_registry().await
192    }
193
194    async fn set_key_registry(
195        &self,
196        state: &KeyRegistryState<VerifyingKey>,
197    ) -> Result<(), Self::Error> {
198        self.store.set_key_registry(state).await
199    }
200}
201
202impl<E> KeySecretsStore for SqliteSpacesStore<E> {
203    type Error = SqliteError;
204
205    async fn get_prekey_secrets(&self) -> Result<Option<PreKeyBundlesState>, Self::Error> {
206        self.store.get_prekey_secrets().await
207    }
208
209    async fn set_prekey_secrets(&self, state: &PreKeyBundlesState) -> Result<(), Self::Error> {
210        self.store.set_prekey_secrets(state).await
211    }
212}
213
214impl<E, M, C> GroupsStore<M, C> for SqliteSpacesStore<E>
215where
216    C: Conditions + Serialize + for<'a> Deserialize<'a>,
217    M: AuthOperation<VerifyingKey, Hash, C> + Serialize + for<'a> Deserialize<'a>,
218{
219    type Error = SqliteError;
220
221    async fn set_groups_state_tx(
222        &self,
223        id: Hash,
224        state: &GroupCrdtState<VerifyingKey, Hash, M, C>,
225    ) -> Result<(), SqliteError> {
226        self.store.set_groups_state_tx(id, state).await
227    }
228
229    async fn get_groups_state_tx(
230        &self,
231        id: Hash,
232    ) -> Result<Option<GroupCrdtState<VerifyingKey, Hash, M, C>>, SqliteError> {
233        self.store.get_groups_state_tx(id).await
234    }
235}
236
237impl<E> crate::traits::Transaction for SqliteSpacesStore<E> {
238    type Error = SqliteError;
239
240    type Permit = TransactionPermit;
241
242    async fn begin(&self) -> Result<TransactionPermit, SqliteError> {
243        self.store.begin().await
244    }
245
246    async fn rollback(&self, permit: TransactionPermit) -> Result<(), SqliteError> {
247        self.store.rollback(permit).await
248    }
249
250    async fn commit(&self, permit: TransactionPermit) -> Result<(), SqliteError> {
251        self.store.commit(permit).await
252    }
253}