use crate::error::Result;
use crate::local_storage::LocalStorage;
use crate::session_storage::SessionStorage;
use dioxus::hooks::*;
use dioxus_signals::*;
use serde::{de::DeserializeOwned, Serialize};
#[cfg(feature = "indexeddb")]
use dioxus_indexeddb::{Database, DatabaseConfig};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StorageBackend {
Local,
Session,
#[cfg(feature = "indexeddb")]
IndexedDb,
}
#[derive(Debug, Clone)]
pub struct StorageConfig {
pub backend: StorageBackend,
pub key_prefix: Option<String>,
}
impl StorageConfig {
pub fn local() -> Self {
Self {
backend: StorageBackend::Local,
key_prefix: None,
}
}
pub fn session() -> Self {
Self {
backend: StorageBackend::Session,
key_prefix: None,
}
}
#[cfg(feature = "indexeddb")]
pub fn indexed_db() -> Self {
Self {
backend: StorageBackend::IndexedDb,
key_prefix: None,
}
}
pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
self.key_prefix = Some(prefix.into());
self
}
}
#[derive(Debug, Clone)]
pub struct Storage {
config: StorageConfig,
}
impl Storage {
pub fn new(config: StorageConfig) -> Self {
Self { config }
}
fn full_key(&self, key: &str) -> String {
match &self.config.key_prefix {
Some(prefix) => format!("{}:{}", prefix, key),
None => key.to_string(),
}
}
pub fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>> {
let key = self.full_key(key);
match self.config.backend {
StorageBackend::Local => LocalStorage::get(&key),
StorageBackend::Session => SessionStorage::get(&key),
#[cfg(feature = "indexeddb")]
StorageBackend::IndexedDb => {
panic!("Use get_async for IndexedDB backend")
}
}
}
pub fn set<T: Serialize>(&self, key: &str, value: &T) -> Result<()> {
let key = self.full_key(key);
match self.config.backend {
StorageBackend::Local => LocalStorage::set(&key, value),
StorageBackend::Session => SessionStorage::set(&key, value),
#[cfg(feature = "indexeddb")]
StorageBackend::IndexedDb => {
panic!("Use set_async for IndexedDB backend")
}
}
}
pub fn remove(&self, key: &str) -> Result<()> {
let key = self.full_key(key);
match self.config.backend {
StorageBackend::Local => LocalStorage::remove(&key),
StorageBackend::Session => SessionStorage::remove(&key),
#[cfg(feature = "indexeddb")]
StorageBackend::IndexedDb => {
panic!("Use remove_async for IndexedDB backend")
}
}
}
pub fn is_available(&self) -> bool {
match self.config.backend {
StorageBackend::Local => LocalStorage::is_available(),
StorageBackend::Session => SessionStorage::is_available(),
#[cfg(feature = "indexeddb")]
StorageBackend::IndexedDb => Database::is_available(),
}
}
}
pub fn use_storage(config: StorageConfig) -> Signal<Storage> {
use_signal(|| Storage::new(config))
}
#[cfg(feature = "indexeddb")]
pub fn _use_storage_db(_config: DatabaseConfig) -> Signal<Option<Database>> {
use_signal(|| None::<Database>)
}