nostr-sqlite 0.45.0-alpha.1

SQLite storage backend for nostr apps
use std::path::Path;
#[cfg(not(target_arch = "wasm32"))]
use std::path::PathBuf;
use std::sync::Arc;

#[cfg(not(target_arch = "wasm32"))]
use async_utility::task;
use rusqlite::{Connection, OpenFlags};
use tokio::sync::Mutex;

use crate::error::Error;
use crate::store::NostrSqliteOptions;

#[derive(Debug, Clone)]
pub(crate) struct Pool {
    conn: Arc<Mutex<Connection>>,
    options: Arc<NostrSqliteOptions>,
}

impl Pool {
    fn new(conn: Connection, options: NostrSqliteOptions) -> Self {
        Self {
            conn: Arc::new(Mutex::new(conn)),
            options: Arc::new(options),
        }
    }

    pub(crate) fn open_in_memory(options: NostrSqliteOptions) -> Result<Self, Error> {
        let conn: Connection = Connection::open_in_memory()?;
        Ok(Self::new(conn, options))
    }

    #[inline]
    #[cfg(not(target_arch = "wasm32"))]
    pub(crate) async fn open_with_path(
        path: PathBuf,
        options: NostrSqliteOptions,
    ) -> Result<Self, Error> {
        let conn: Connection = task::spawn_blocking(move || Connection::open(path)).await??;
        Ok(Self::new(conn, options))
    }

    pub(crate) async fn open_with_vfs<P>(
        path: P,
        vfs: &str,
        options: NostrSqliteOptions,
    ) -> Result<Self, Error>
    where
        P: AsRef<Path>,
    {
        let flags = OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE;
        let conn: Connection = Connection::open_with_flags_and_vfs(path, flags, vfs)?;
        Ok(Self::new(conn, options))
    }

    #[cfg(not(target_arch = "wasm32"))]
    pub async fn interact<F, R>(&self, f: F) -> Result<R, Error>
    where
        F: FnOnce(&mut Connection) -> Result<R, Error> + Send + 'static,
        R: Send + 'static,
    {
        let arc: Arc<Mutex<Connection>> = self.conn.clone();
        let mut conn = arc.lock_owned().await;
        task::spawn_blocking(move || f(&mut conn)).await?
    }

    #[cfg(target_arch = "wasm32")]
    pub async fn interact<F, R>(&self, f: F) -> Result<R, Error>
    where
        F: FnOnce(&mut Connection) -> Result<R, Error> + 'static,
        R: 'static,
    {
        let mut conn = self.conn.lock().await;
        f(&mut conn)
    }

    #[cfg(not(target_arch = "wasm32"))]
    pub async fn interact_options<F, R>(&self, f: F) -> Result<R, Error>
    where
        F: FnOnce(&mut Connection, &NostrSqliteOptions) -> Result<R, Error> + Send + 'static,
        R: Send + 'static,
    {
        let arc: Arc<Mutex<Connection>> = self.conn.clone();
        let mut conn = arc.lock_owned().await;
        let options: Arc<NostrSqliteOptions> = self.options.clone();
        task::spawn_blocking(move || f(&mut conn, &options)).await?
    }

    #[cfg(target_arch = "wasm32")]
    pub async fn interact_options<F, R>(&self, f: F) -> Result<R, Error>
    where
        F: FnOnce(&mut Connection, &NostrSqliteOptions) -> Result<R, Error> + 'static,
        R: 'static,
    {
        let mut conn = self.conn.lock().await;
        f(&mut conn, &self.options)
    }
}