//! # Nostr Storage
//!
//! This crate will storage events into a database. It will also build index to
//! find events by their tags, kind and references.
#![allow(missing_docs, warnings)]
#![allow(dead_code)]
pub mod cursor;
mod error;
mod event_filter;
mod index;
mod secondary_index;
mod storage;

#[cfg(feature = "test")]
pub mod test;

#[cfg(feature = "test")]
pub use tokio;

pub use crate::{
    error::Error,
    event_filter::*,
    index::{Index, SingleIndex},
    secondary_index::SecondaryIndex,
    storage::Storage,
};

#[macro_export]
/// This macro creates the
macro_rules! storage_test {
    ($type: tt, $init:tt, $destroy:tt) => {
        #[cfg(test)]
        mod test {
            use super::*;
            use futures::executor::block_on;
            use std::sync::atomic::{AtomicUsize, Ordering};

            static LAST_VERSION: AtomicUsize = AtomicUsize::new(0);

            struct DisposableStorage {
                path: String,
                storage: $type,
            }

            impl DisposableStorage {
                pub async fn new() -> Self {
                    let id = LAST_VERSION.fetch_add(1, Ordering::Relaxed);
                    let path = format!("/tmp/nostr/test-{}", id);
                    Self {
                        storage: $init(&path).await,
                        path,
                    }
                }
            }

            impl std::ops::Drop for DisposableStorage {
                fn drop(&mut self) {
                    block_on(async move {
                        $destroy(&self.path).await;
                    });
                }
            }

            use nostr_rs_storage_base::tokio;

            nostr_rs_storage_base::storage_test_name!(store_and_get_by_partial_key);
            nostr_rs_storage_base::storage_test_name!(store_and_get);
            nostr_rs_storage_base::storage_test_name!(records_are_sorted_by_date_desc_by_default);
            nostr_rs_storage_base::storage_test_name!(records_are_sorted_by_date_desc);
            nostr_rs_storage_base::storage_test_name!(filter_by_references);
            nostr_rs_storage_base::storage_test_name!(filter_by_references_zero_match);
            nostr_rs_storage_base::storage_test_name!(filter_by_references_and_kind);
            nostr_rs_storage_base::storage_test_name!(filter_by_authors);
            nostr_rs_storage_base::storage_test_name!(filter_by_author);
            nostr_rs_storage_base::storage_test_name!(filter_by_author_and_kinds);
            nostr_rs_storage_base::storage_test_name!(filter_by_kind);
            nostr_rs_storage_base::storage_test_name!(get_event_and_related_events);
            nostr_rs_storage_base::storage_test_name!(get_local_events);
        }
    };
}

#[macro_export]
/// Creates a
macro_rules! storage_test_name {
    ($name:tt) => {
        #[tokio::test]
        async fn $name() {
            let x = DisposableStorage::new().await;
            nostr_rs_storage_base::test::$name(&x.storage).await;
        }
    };
}
