Skip to main content

xmtp_db/encrypted_store/
database.rs

1#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
2pub mod native;
3
4use diesel::SqliteConnection;
5#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
6pub use native::*;
7
8#[cfg(all(target_family = "wasm", target_os = "unknown"))]
9pub mod wasm;
10#[cfg(all(target_family = "wasm", target_os = "unknown"))]
11pub use wasm::*;
12
13#[cfg(all(target_family = "wasm", target_os = "unknown"))]
14pub use wasm_exports::*;
15
16#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
17pub use native_exports::*;
18
19use super::ConnectionExt;
20
21#[cfg(all(target_family = "wasm", target_os = "unknown"))]
22pub mod wasm_exports {
23    pub type RawDbConnection = diesel::prelude::SqliteConnection;
24    pub type DefaultDatabase = super::wasm::WasmDb;
25}
26
27#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
28pub mod native_exports {
29    pub type DefaultDatabase = super::native::NativeDb;
30    pub use super::native::EncryptedConnection;
31}
32
33mod instrumentation;
34
35#[derive(Debug)]
36pub enum PersistentOrMem<P, S, M> {
37    Persistent(P),
38    Single(S),
39    Mem(M),
40}
41
42// P, S and M must share connection & error types
43impl<P, S, M> ConnectionExt for PersistentOrMem<P, S, M>
44where
45    P: ConnectionExt,
46    S: ConnectionExt,
47    M: ConnectionExt,
48{
49    fn raw_query<T, F>(&self, fun: F) -> Result<T, crate::ConnectionError>
50    where
51        F: FnOnce(&mut SqliteConnection) -> Result<T, diesel::result::Error>,
52        Self: Sized,
53    {
54        match self {
55            Self::Persistent(p) => p.raw_query(fun),
56            Self::Single(s) => s.raw_query(fun),
57            Self::Mem(m) => m.raw_query(fun),
58        }
59    }
60
61    fn disconnect(&self) -> Result<(), crate::ConnectionError> {
62        match self {
63            Self::Persistent(p) => p.disconnect(),
64            Self::Single(s) => s.disconnect(),
65            Self::Mem(m) => m.disconnect(),
66        }
67    }
68
69    fn reconnect(&self) -> Result<(), crate::ConnectionError> {
70        match self {
71            Self::Persistent(p) => p.reconnect(),
72            Self::Single(s) => s.reconnect(),
73            Self::Mem(m) => m.reconnect(),
74        }
75    }
76}
77
78/// `std::convert::Infallible` is used as the `Single` type parameter on targets
79/// (wasm) that have no single-connection mode. It is uninhabited, so the
80/// `Single` arm is statically impossible to construct.
81impl ConnectionExt for std::convert::Infallible {
82    fn raw_query<T, F>(&self, _fun: F) -> Result<T, crate::ConnectionError>
83    where
84        F: FnOnce(&mut SqliteConnection) -> Result<T, diesel::result::Error>,
85        Self: Sized,
86    {
87        match *self {}
88    }
89
90    fn disconnect(&self) -> Result<(), crate::ConnectionError> {
91        match *self {}
92    }
93
94    fn reconnect(&self) -> Result<(), crate::ConnectionError> {
95        match *self {}
96    }
97}
98
99#[cfg(test)]
100mod persistent_or_mem_tests {
101    use super::*;
102
103    // A trivial in-memory ConnectionExt used to exercise enum dispatch without a real DB.
104    struct CountingConn;
105    impl ConnectionExt for CountingConn {
106        fn raw_query<T, F>(&self, _fun: F) -> Result<T, crate::ConnectionError>
107        where
108            F: FnOnce(&mut SqliteConnection) -> Result<T, diesel::result::Error>,
109            Self: Sized,
110        {
111            // Not exercised in this test; we only verify disconnect/reconnect dispatch.
112            unreachable!("raw_query not used in this test")
113        }
114        fn disconnect(&self) -> Result<(), crate::ConnectionError> {
115            Ok(())
116        }
117        fn reconnect(&self) -> Result<(), crate::ConnectionError> {
118            Ok(())
119        }
120    }
121
122    #[test]
123    fn single_arm_dispatches() {
124        // Single arm with a real (CountingConn) type dispatches correctly.
125        let c: PersistentOrMem<CountingConn, CountingConn, CountingConn> =
126            PersistentOrMem::Single(CountingConn);
127        assert!(c.disconnect().is_ok());
128        assert!(c.reconnect().is_ok());
129    }
130
131    #[test]
132    fn infallible_single_arm_compiles() {
133        // The wasm-shaped type: Single = Infallible. Must construct a non-Single arm.
134        let c: PersistentOrMem<CountingConn, std::convert::Infallible, CountingConn> =
135            PersistentOrMem::Mem(CountingConn);
136        assert!(c.disconnect().is_ok());
137    }
138}