commit ec5e59445a0e475ef3b41040d98cdaaaa1f498b0
parent cb167a7004167bf131efcb0a5e9815e35ad756c2
Author: triesap <tyson@radroots.org>
Date: Thu, 19 Feb 2026 18:24:32 +0000
nostr-ndb: add runtime event store adapter
- add an ndb-backed event store adapter for runtime integration
- implement runtime trait ingestion for default client-origin events
- support configurable relay or client source behavior on the adapter
- add unit tests for adapter ingestion and trait object usage
Diffstat:
2 files changed, 94 insertions(+), 0 deletions(-)
diff --git a/nostr-ndb/src/lib.rs b/nostr-ndb/src/lib.rs
@@ -13,6 +13,8 @@ pub mod error;
pub mod ingest;
#[cfg(feature = "ndb")]
pub mod ndb;
+#[cfg(all(feature = "ndb", feature = "runtime-adapter"))]
+pub mod runtime_adapter;
pub mod prelude {
#[cfg(feature = "ndb")]
@@ -22,4 +24,6 @@ pub mod prelude {
pub use crate::ingest::RadrootsNostrNdbIngestSource;
#[cfg(feature = "ndb")]
pub use crate::ndb::RadrootsNostrNdb;
+ #[cfg(all(feature = "ndb", feature = "runtime-adapter"))]
+ pub use crate::runtime_adapter::RadrootsNostrNdbEventStoreAdapter;
}
diff --git a/nostr-ndb/src/runtime_adapter.rs b/nostr-ndb/src/runtime_adapter.rs
@@ -0,0 +1,90 @@
+use crate::ingest::RadrootsNostrNdbIngestSource;
+use crate::ndb::RadrootsNostrNdb;
+use radroots_nostr::prelude::RadrootsNostrEvent;
+use radroots_nostr_runtime::prelude::RadrootsNostrEventStore;
+use std::sync::Arc;
+
+#[derive(Clone)]
+pub struct RadrootsNostrNdbEventStoreAdapter {
+ ndb: RadrootsNostrNdb,
+ source: RadrootsNostrNdbIngestSource,
+}
+
+impl RadrootsNostrNdbEventStoreAdapter {
+ pub fn new(ndb: RadrootsNostrNdb) -> Self {
+ Self {
+ ndb,
+ source: RadrootsNostrNdbIngestSource::client(),
+ }
+ }
+
+ pub fn with_source(mut self, source: RadrootsNostrNdbIngestSource) -> Self {
+ self.source = source;
+ self
+ }
+
+ pub fn into_event_store(self) -> Arc<dyn RadrootsNostrEventStore> {
+ Arc::new(self)
+ }
+}
+
+impl RadrootsNostrEventStore for RadrootsNostrNdb {
+ fn ingest_event(&self, event: &RadrootsNostrEvent) -> Result<(), String> {
+ RadrootsNostrNdb::ingest_event(self, event, RadrootsNostrNdbIngestSource::client())
+ .map_err(|source| source.to_string())
+ }
+}
+
+impl RadrootsNostrEventStore for RadrootsNostrNdbEventStoreAdapter {
+ fn ingest_event(&self, event: &RadrootsNostrEvent) -> Result<(), String> {
+ self.ndb
+ .ingest_event(event, self.source.clone())
+ .map_err(|source| source.to_string())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::config::RadrootsNostrNdbConfig;
+ use radroots_nostr::prelude::{RadrootsNostrEventBuilder, RadrootsNostrKeys};
+ use tempfile::TempDir;
+
+ #[test]
+ fn runtime_adapter_accepts_signed_events() {
+ let tmp_dir = TempDir::new().expect("tempdir should open");
+ let db_dir = tmp_dir.path().join("ndb");
+ let config = RadrootsNostrNdbConfig::new(&db_dir);
+ let ndb = RadrootsNostrNdb::open(config).expect("database should open");
+ let adapter = RadrootsNostrNdbEventStoreAdapter::new(ndb);
+
+ let keys = RadrootsNostrKeys::generate();
+ let event = RadrootsNostrEventBuilder::text_note("hello from runtime adapter")
+ .sign_with_keys(&keys)
+ .expect("event should sign");
+
+ adapter
+ .ingest_event(&event)
+ .expect("adapter should ingest event");
+ }
+
+ #[test]
+ fn runtime_adapter_can_be_boxed_as_store_trait() {
+ let tmp_dir = TempDir::new().expect("tempdir should open");
+ let db_dir = tmp_dir.path().join("ndb");
+ let config = RadrootsNostrNdbConfig::new(&db_dir);
+ let ndb = RadrootsNostrNdb::open(config).expect("database should open");
+ let store = RadrootsNostrNdbEventStoreAdapter::new(ndb)
+ .with_source(RadrootsNostrNdbIngestSource::relay("wss://relay.radroots.org"))
+ .into_event_store();
+
+ let keys = RadrootsNostrKeys::generate();
+ let event = RadrootsNostrEventBuilder::text_note("hello trait object")
+ .sign_with_keys(&keys)
+ .expect("event should sign");
+
+ store
+ .ingest_event(&event)
+ .expect("boxed store should ingest event");
+ }
+}