nostr_sdk_sqlite/
store.rs

1// Copyright (c) 2022-2023 Yuki Kishimoto
2// Distributed under the MIT software license
3
4//! Store
5
6use std::net::SocketAddr;
7use std::path::Path;
8
9use nostr::{Event, Url};
10use r2d2_sqlite::SqliteConnectionManager;
11use rusqlite::OpenFlags;
12
13use crate::migration::{self, MigrationError, STARTUP_SQL};
14
15pub(crate) type SqlitePool = r2d2::Pool<SqliteConnectionManager>;
16pub(crate) type PooledConnection = r2d2::PooledConnection<SqliteConnectionManager>;
17
18/// Store error
19#[derive(Debug, thiserror::Error)]
20pub enum Error {
21    /// Sqlite error
22    #[error(transparent)]
23    Sqlite(#[from] rusqlite::Error),
24    /// Sqlite Pool error
25    #[error(transparent)]
26    Pool(#[from] r2d2::Error),
27    /// Migration error
28    #[error(transparent)]
29    Migration(#[from] MigrationError),
30}
31
32/// Store
33#[derive(Debug, Clone)]
34pub struct Store {
35    pool: SqlitePool,
36}
37
38impl Drop for Store {
39    fn drop(&mut self) {}
40}
41
42impl Store {
43    /// Open new database
44    pub fn open<P>(path: P) -> Result<Self, Error>
45    where
46        P: AsRef<Path>,
47    {
48        let manager = SqliteConnectionManager::file(path.as_ref())
49            .with_flags(OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE)
50            .with_init(|c| c.execute_batch(STARTUP_SQL));
51        let pool = r2d2::Pool::new(manager)?;
52        migration::run(&mut pool.get()?)?;
53        Ok(Self { pool })
54    }
55
56    /// Close SQLite connection
57    pub fn close(self) {
58        drop(self);
59    }
60
61    /// Insert new relay
62    pub fn insert_relay(&self, url: Url, proxy: Option<SocketAddr>) -> Result<(), Error> {
63        let conn = self.pool.get()?;
64        conn.execute(
65            "INSERT OR IGNORE INTO relays (url, proxy) VALUES (?, ?);",
66            (url, proxy.map(|a| a.to_string())),
67        )?;
68        Ok(())
69    }
70
71    /// Get relays
72    pub fn get_relays(&self, enabled: bool) -> Result<Vec<(Url, Option<SocketAddr>)>, Error> {
73        let conn = self.pool.get()?;
74        let mut stmt = conn.prepare("SELECT url, proxy FROM relays WHERE enabled = ?")?;
75        let mut rows = stmt.query([enabled])?;
76
77        let mut relays: Vec<(Url, Option<SocketAddr>)> = Vec::new();
78        while let Ok(Some(row)) = rows.next() {
79            let url: Url = row.get(0)?;
80            let proxy: Option<String> = row.get(1)?;
81            relays.push((
82                url,
83                proxy
84                    .map(|p| p.parse())
85                    .filter(|r| r.is_ok())
86                    .map(|r| r.unwrap()),
87            ));
88        }
89        Ok(relays)
90    }
91
92    /// Delete relay
93    pub fn delete_relay(&self, url: Url) -> Result<(), Error> {
94        let conn = self.pool.get()?;
95        conn.execute("DELETE FROM relays WHERE url = ?;", [url])?;
96        Ok(())
97    }
98
99    /// Enable relay
100    pub fn enable_relay(&self, url: Url) -> Result<(), Error> {
101        let conn = self.pool.get()?;
102        conn.execute("UPDATE relays SET enabled = ? WHERE url = ?;", (1, url))?;
103        Ok(())
104    }
105
106    /// Disbale relay
107    pub fn disable_relay(&self, url: Url) -> Result<(), Error> {
108        let conn = self.pool.get()?;
109        conn.execute("UPDATE relays SET enabled = ? WHERE url = ?;", (0, url))?;
110        Ok(())
111    }
112
113    /// Insert new event
114    pub fn insert_event(&self, event: Event) -> Result<(), Error> {
115        let conn = self.pool.get()?;
116        // Insert event
117        conn.execute(
118            "INSERT OR IGNORE INTO events (id, pubkey, created_at, kind, content, sig) VALUES (?, ?, ?, ?, ?, ?);",
119            (event.id.to_hex(), &event.pubkey.to_string(), event.created_at.as_u64(), event.kind.as_u64(), event.content, event.sig.to_string()),
120        )?;
121        // Insert tags
122        let mut stmt =
123            conn.prepare("INSERT OR IGNORE INTO tags (event_id, kind, value) VALUES (?, ?, ?)")?;
124        for tag in event.tags.into_iter() {
125            let tag: Vec<String> = tag.as_vec();
126            let kind = &tag[0];
127            let value = tag.get(1..);
128            stmt.execute((event.id.as_bytes(), kind, serde_json::json!(value)))?;
129        }
130        Ok(())
131    }
132}