#[cfg(feature = "cloud")]
pub mod cloud;
pub mod csv;
pub mod json;
pub mod jsonl;
#[cfg(feature = "mysql")]
pub mod mysql;
#[cfg(feature = "postgres")]
pub mod postgres;
#[cfg(feature = "sqlite")]
pub mod sqlite;
pub mod stdout;
#[cfg(feature = "cloud")]
pub use cloud::{CloudFormat, CloudStore, CloudStoreBuilder};
pub use csv::CsvStore;
pub use json::JsonStore;
pub use jsonl::JsonlStore;
#[cfg(feature = "mysql")]
pub use mysql::{MySqlStore, MySqlStoreBuilder};
#[cfg(feature = "postgres")]
pub use postgres::{PostgresStore, PostgresStoreBuilder};
#[cfg(feature = "sqlite")]
pub use sqlite::{SqliteStore, SqliteStoreBuilder};
pub use stdout::StdoutStore;
use crate::error::KumoError;
#[async_trait::async_trait]
pub trait ItemStore: Send + Sync {
async fn store(&self, item: &serde_json::Value) -> Result<(), KumoError>;
async fn flush(&self) -> Result<(), KumoError> {
Ok(())
}
}
#[cfg(any(feature = "postgres", feature = "sqlite", feature = "mysql"))]
pub(super) fn validate_table_name(name: &str) -> Result<(), crate::error::KumoError> {
if name.is_empty() || name.len() > 63 {
return Err(crate::error::KumoError::store_msg(format!(
"table name must be 1–63 characters, got {}",
name.len()
)));
}
if !name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
return Err(crate::error::KumoError::store_msg(format!(
"table name '{}' contains invalid characters (only a-z, A-Z, 0-9, _ allowed)",
name
)));
}
Ok(())
}
#[cfg(any(feature = "postgres", feature = "sqlite", feature = "mysql"))]
pub(super) fn json_val_to_sql_string(val: Option<&serde_json::Value>) -> Option<String> {
val.and_then(|v| {
if v.is_null() {
None
} else if let Some(s) = v.as_str() {
Some(s.to_string())
} else {
Some(v.to_string())
}
})
}