Skip to content

Commit 112d6a6

Browse files
committed
WIP
Signed-off-by: Yuki Kishimoto <[email protected]>
1 parent 8de58f6 commit 112d6a6

File tree

8 files changed

+238
-391
lines changed

8 files changed

+238
-391
lines changed

Cargo.lock

Lines changed: 66 additions & 62 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ nostr-gossip-memory = { version = "0.44", path = "./gossip/nostr-gossip-memory",
5252
nostr-gossip-test-suite = { path = "./gossip/nostr-gossip-test-suite" }
5353
nostr-lmdb = { version = "0.44", path = "./database/nostr-lmdb", default-features = false }
5454
nostr-ndb = { version = "0.44", path = "./database/nostr-ndb", default-features = false }
55+
nostr-sqldb = { version = "0.44", path = "./database/nostr-sqldb", default-features = false }
5556
nostr-relay-builder = { version = "0.44", path = "./crates/nostr-relay-builder", default-features = false }
5657
nostr-relay-pool = { version = "0.44", path = "./crates/nostr-relay-pool", default-features = false }
5758
reqwest = { version = "0.12", default-features = false }

database/nostr-sqldb/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "nostr-sqldb"
3-
version = "0.42.0"
3+
version = "0.44.0"
44
edition = "2021"
55
description = "SQL storage backend for Nostr apps"
66
authors.workspace = true
@@ -31,6 +31,7 @@ sqlx = { version = "0.8", features = ["migrate", "runtime-tokio"] }
3131
tokio = { workspace = true, features = ["sync"] }
3232

3333
[dev-dependencies]
34+
nostr-database-test-suite.workspace = true
3435
nostr-relay-builder.workspace = true
3536
tempfile.workspace = true
3637
tokio.workspace = true

database/nostr-sqldb/examples/sqlite-relay.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ async fn main() -> Result<()> {
2121
let builder = RelayBuilder::default().database(db);
2222

2323
// Create local relay
24-
let relay = LocalRelay::run(builder).await?;
25-
println!("Url: {}", relay.url());
24+
let relay = LocalRelay::new(builder);
25+
relay.run().await?;
26+
println!("Url: {}", relay.url().await);
2627

2728
// Keep up the program
2829
loop {

database/nostr-sqldb/src/db.rs

Lines changed: 47 additions & 325 deletions
Large diffs are not rendered by default.

database/nostr-sqldb/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@ compile_error!("At least one database backend must be enabled");
1616
pub mod db;
1717
pub mod error;
1818
mod model;
19+
// #[cfg(feature = "sqlite")]
20+
// pub mod sqlite;
1921

2022
pub use self::db::{NostrSql, NostrSqlBackend};

database/nostr-sqldb/src/model.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ pub(crate) struct EventDb {
1616
pub deleted: bool,
1717
}
1818

19+
impl EventDb {
20+
#[inline]
21+
pub(super) fn is_deleted(&self) -> bool {
22+
self.deleted
23+
}
24+
}
25+
1926
#[derive(Debug, Clone, FromRow)]
2027
pub(crate) struct EventTagDb {
2128
pub tag: String,
@@ -36,7 +43,7 @@ impl EventDataDb {
3643
event: EventDb {
3744
id: event.id.as_bytes().to_vec(),
3845
pubkey: event.pubkey.as_bytes().to_vec(),
39-
created_at: event.created_at.as_u64() as i64,
46+
created_at: event.created_at.as_secs() as i64,
4047
kind: event.kind.as_u16() as i64,
4148
payload: event.encode(fbb).to_vec(),
4249
deleted: false,

database/nostr-sqldb/src/sqlite.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
use std::path::Path;
2+
use std::sync::Arc;
3+
4+
use sqlx::{Sqlite, SqlitePool};
5+
use sqlx::migrate::Migrator;
6+
use sqlx::sqlite::SqliteConnectOptions;
7+
use tokio::sync::Mutex;
8+
use nostr::{Event, EventId, Filter};
9+
use nostr::prelude::BoxedFuture;
10+
use nostr_database::{Backend, DatabaseError, DatabaseEventStatus, Events, FlatBufferBuilder, NostrDatabase, SaveEventStatus};
11+
12+
use crate::db::NostrSql;
13+
use crate::error::Error;
14+
15+
#[derive(Debug, Clone)]
16+
pub struct NostrSqlite {
17+
db: NostrSql<Sqlite>
18+
}
19+
20+
impl NostrSqlite {
21+
/// Open SQLite database
22+
pub async fn open<P>(path: P) -> Result<Self, Error>
23+
where
24+
P: AsRef<Path>,
25+
{
26+
// Build SQLite connection options
27+
let opts: SqliteConnectOptions =
28+
SqliteConnectOptions::new().create_if_missing(true).filename(path);
29+
30+
// Connect to SQLite database
31+
let pool: SqlitePool = SqlitePool::connect_with(opts).await?;
32+
33+
// Run migrations
34+
let migrator: Migrator = sqlx::migrate!("migrations/sqlite");
35+
migrator.run(&pool).await?;
36+
37+
Ok(Self {
38+
db: NostrSql::new(pool),
39+
})
40+
}
41+
}
42+
43+
impl NostrDatabase for NostrSqlite {
44+
fn backend(&self) -> Backend {
45+
self.db.backend()
46+
}
47+
48+
fn save_event<'a>(&'a self, event: &'a Event) -> BoxedFuture<'a, Result<SaveEventStatus, DatabaseError>> {
49+
self.db.save_event(event)
50+
}
51+
52+
fn check_id<'a>(&'a self, event_id: &'a EventId) -> BoxedFuture<'a, Result<DatabaseEventStatus, DatabaseError>> {
53+
self.db.check_id(event_id)
54+
}
55+
56+
fn event_by_id<'a>(&'a self, event_id: &'a EventId) -> BoxedFuture<'a, Result<Option<Event>, DatabaseError>> {
57+
self.db.event_by_id(event_id)
58+
}
59+
60+
fn count(&self, filter: Filter) -> BoxedFuture<Result<usize, DatabaseError>> {
61+
self.db.count(filter)
62+
}
63+
64+
fn query(&self, filter: Filter) -> BoxedFuture<Result<Events, DatabaseError>> {
65+
self.db.query(filter)
66+
}
67+
68+
fn delete(&self, filter: Filter) -> BoxedFuture<Result<(), DatabaseError>> {
69+
self.db.delete(filter)
70+
}
71+
72+
fn wipe(&self) -> BoxedFuture<Result<(), DatabaseError>> {
73+
self.db.wipe()
74+
}
75+
}
76+
77+
#[cfg(test)]
78+
mod tests {
79+
use nostr_database_test_suite::database_unit_tests;
80+
use tempfile::TempDir;
81+
82+
use super::*;
83+
84+
struct TempDatabase {
85+
db: NostrSqlite,
86+
// Needed to avoid the drop and deletion of temp folder
87+
_temp: TempDir,
88+
}
89+
90+
impl Deref for TempDatabase {
91+
type Target = NostrSqlite;
92+
93+
fn deref(&self) -> &Self::Target {
94+
&self.db
95+
}
96+
}
97+
98+
impl TempDatabase {
99+
async fn new() -> Self {
100+
let path = tempfile::tempdir().unwrap();
101+
Self {
102+
db: NostrSqlite::open(path.path().join("temp.db")).await.unwrap(),
103+
_temp: path,
104+
}
105+
}
106+
}
107+
108+
database_unit_tests!(TempDatabase, TempDatabase::new);
109+
}

0 commit comments

Comments
 (0)