Skip to content

Commit 158d5fc

Browse files
committed
database: add downcasting support for NostrDatabase
Implement downcasting for `NostrDatabase`, allowing access to concrete database types. Pull-Request: #845 Signed-off-by: Yuki Kishimoto <yukikishimoto@protonmail.com>
1 parent 507b002 commit 158d5fc

File tree

6 files changed

+112
-56
lines changed

6 files changed

+112
-56
lines changed

Cargo.lock

Lines changed: 1 addition & 0 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
@@ -33,6 +33,7 @@ nostr-relay-builder = { version = "0.42", path = "./crates/nostr-relay-builder",
3333
nostr-relay-pool = { version = "0.42", path = "./crates/nostr-relay-pool", default-features = false }
3434
nostr-sdk = { version = "0.42", path = "./crates/nostr-sdk", default-features = false }
3535
reqwest = { version = "0.12", default-features = false }
36+
rustversion = "1.0"
3637
serde = { version = "1.0", default-features = false }
3738
serde_json = { version = "1.0", default-features = false }
3839
tempfile = "3.19"

crates/nostr-database/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ flatbuf = ["dep:flatbuffers"]
1919
flatbuffers = { version = "23.5", optional = true }
2020
lru.workspace = true
2121
nostr = { workspace = true, features = ["std"] }
22+
rustversion.workspace = true
2223
tokio = { workspace = true, features = ["sync"] }
2324

2425
[dev-dependencies]

crates/nostr-database/src/lib.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,43 @@ pub trait NostrDatabase: Any + Debug + Send + Sync {
193193
fn wipe(&self) -> BoxedFuture<Result<(), DatabaseError>>;
194194
}
195195

196+
#[rustversion::since(1.86)]
197+
impl dyn NostrDatabase {
198+
/// Upcast to [`Any`].
199+
#[inline]
200+
fn as_any(&self) -> &dyn Any {
201+
self
202+
}
203+
204+
/// Upcast to [`Any`].
205+
#[inline]
206+
fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
207+
self
208+
}
209+
210+
/// Downcast [`NostrDatabase`] to a concrete type reference.
211+
///
212+
/// **Requires rustc >= 1.86!**
213+
#[inline]
214+
pub fn downcast_ref<T>(&self) -> Option<&T>
215+
where
216+
T: NostrDatabase,
217+
{
218+
self.as_any().downcast_ref()
219+
}
220+
221+
/// Downcast [`NostrDatabase`] to a concrete type.
222+
///
223+
/// **Requires rustc >= 1.86!**
224+
#[inline]
225+
pub fn downcast<T>(self: Arc<Self>) -> Option<Arc<T>>
226+
where
227+
T: NostrDatabase,
228+
{
229+
self.as_any_arc().downcast().ok()
230+
}
231+
}
232+
196233
#[cfg(test)]
197234
mod tests {
198235
use super::*;

crates/nostr-sdk/examples/lmdb.rs

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,58 @@ async fn main() -> Result<()> {
1616
.database(database)
1717
.build();
1818

19-
client.add_relay("wss://relay.damus.io").await?;
20-
client.add_relay("wss://nostr.wine").await?;
21-
client.add_relay("wss://nostr.oxtr.dev").await?;
22-
23-
client.connect().await;
24-
25-
// Publish a text note
26-
let builder = EventBuilder::text_note("Hello world");
27-
client.send_event_builder(builder).await?;
28-
29-
// Negentropy sync
30-
let filter = Filter::new().author(keys.public_key());
31-
let (tx, mut rx) = SyncProgress::channel();
32-
let opts = SyncOptions::default().progress(tx);
33-
34-
tokio::spawn(async move {
35-
while rx.changed().await.is_ok() {
36-
let progress = *rx.borrow_and_update();
37-
if progress.total > 0 {
38-
println!("{:.2}%", progress.percentage() * 100.0);
39-
}
40-
}
41-
});
42-
let output = client.sync(filter, &opts).await?;
43-
44-
println!("Local: {}", output.local.len());
45-
println!("Remote: {}", output.remote.len());
46-
println!("Sent: {}", output.sent.len());
47-
println!("Received: {}", output.received.len());
48-
println!("Failures:");
49-
for (url, map) in output.send_failures.iter() {
50-
println!("* '{url}':");
51-
for (id, e) in map.iter() {
52-
println!(" - {id}: {e}");
53-
}
54-
}
19+
// client.add_relay("wss://relay.damus.io").await?;
20+
// client.add_relay("wss://nostr.wine").await?;
21+
// client.add_relay("wss://nostr.oxtr.dev").await?;
22+
//
23+
// client.connect().await;
24+
25+
// // Publish a text note
26+
// let builder = EventBuilder::text_note("Hello world");
27+
// client.send_event_builder(builder).await?;
28+
29+
// // Negentropy sync
30+
// let filter = Filter::new().author(keys.public_key());
31+
// let (tx, mut rx) = SyncProgress::channel();
32+
// let opts = SyncOptions::default().progress(tx);
33+
//
34+
// tokio::spawn(async move {
35+
// while rx.changed().await.is_ok() {
36+
// let progress = *rx.borrow_and_update();
37+
// if progress.total > 0 {
38+
// println!("{:.2}%", progress.percentage() * 100.0);
39+
// }
40+
// }
41+
// });
42+
// let output = client.sync(filter, &opts).await?;
43+
//
44+
// println!("Local: {}", output.local.len());
45+
// println!("Remote: {}", output.remote.len());
46+
// println!("Sent: {}", output.sent.len());
47+
// println!("Received: {}", output.received.len());
48+
// println!("Failures:");
49+
// for (url, map) in output.send_failures.iter() {
50+
// println!("* '{url}':");
51+
// for (id, e) in map.iter() {
52+
// println!(" - {id}: {e}");
53+
// }
54+
// }
55+
//
56+
// // Query events from database
57+
// let filter = Filter::new().author(keys.public_key()).limit(10);
58+
// let events = client.database().query(filter).await?;
59+
// println!("Events: {events:?}");
5560

56-
// Query events from database
57-
let filter = Filter::new().author(keys.public_key()).limit(10);
58-
let events = client.database().query(filter).await?;
59-
println!("Events: {events:?}");
61+
// Database downcasting
62+
// let database = client.database().clone();
63+
// let upcast = database as Arc<dyn Any + Send + Sync>;
64+
// let lmdb: &NostrLMDB = upcast.downcast_ref().unwrap();
65+
//let lmdb: &NostrLMDB = (database as &dyn Any).downcast_ref::<NostrLMDB>().unwrap();
66+
67+
// Database downcasting to access to specific APIs
68+
if let Some(_lmdb) = client.database().downcast_ref::<NostrLMDB>() {
69+
// Access specific APIs here
70+
}
6071

6172
Ok(())
6273
}

crates/nostr-sdk/examples/nostrdb.rs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,27 @@ async fn main() -> Result<()> {
1818
.database(database)
1919
.build();
2020

21-
client.add_relay("wss://relay.damus.io").await?;
22-
client.add_relay("wss://atl.purplerelay.com").await?;
23-
client.connect().await;
24-
25-
// Publish a text note
26-
let builder = EventBuilder::text_note("Hello world");
27-
client.send_event_builder(builder).await?;
28-
29-
// Negentropy reconcile
30-
let filter = Filter::new().author(keys.public_key());
31-
client.sync(filter, &SyncOptions::default()).await?;
32-
33-
// Query events from database
34-
let filter = Filter::new().author(keys.public_key()).limit(10);
35-
let events = client.database().query(filter).await?;
36-
println!("Events: {events:?}");
21+
// client.add_relay("wss://relay.damus.io").await?;
22+
// client.add_relay("wss://atl.purplerelay.com").await?;
23+
// client.connect().await;
24+
//
25+
// // Publish a text note
26+
// let builder = EventBuilder::text_note("Hello world");
27+
// client.send_event_builder(builder).await?;
28+
//
29+
// // Negentropy reconcile
30+
// let filter = Filter::new().author(keys.public_key());
31+
// client.sync(filter, &SyncOptions::default()).await?;
32+
//
33+
// // Query events from database
34+
// let filter = Filter::new().author(keys.public_key()).limit(10);
35+
// let events = client.database().query(filter).await?;
36+
// println!("Events: {events:?}");
37+
38+
// Database downcasting to access to specific APIs
39+
if let Some(ndb) = client.database().downcast_ref::<NdbDatabase>() {
40+
println!("Subscription counts: {}", ndb.subscription_count());
41+
}
3742

3843
Ok(())
3944
}

0 commit comments

Comments
 (0)