pub mod adapter;
pub mod error;
pub mod query;
mod rows;
#[doc(hidden)]
pub mod __private;
pub use dactyl_db_macros::query;
pub use crate::error::DactylError;
pub use crate::rows::{Parameter, Row, Rows};
use crate::adapter::Adapter;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
pub struct Statement {
pub sql: String,
pub params: Vec<Parameter>,
}
impl Statement {
pub fn new(sql: &str, params: Vec<Parameter>) -> Self {
Self {
sql: sql.to_string(),
params,
}
}
}
#[doc(hidden)]
pub fn reset() {}
fn resolve_env() -> Result<(&'static str, String, Option<String>), DactylError> {
let kind = std::env::var("DATASTORE").map_err(|_| {
DactylError::Adapter("DATASTORE is not set: set DATASTORE and DATASTORE_ROUTE".into())
})?;
let kind_static: &'static str = match kind.as_str() {
"sqlite" => "sqlite",
"neon" => "neon",
other => {
return Err(DactylError::Adapter(format!(
"invalid DATASTORE value {other:?}: must be 'sqlite' or 'neon'"
)))
}
};
let route = std::env::var("DATASTORE_ROUTE").map_err(|_| {
DactylError::Adapter("DATASTORE_ROUTE is not set: set DATASTORE and DATASTORE_ROUTE".into())
})?;
let token = std::env::var("DATASTORE_TOKEN").ok();
Ok((kind_static, route, token))
}
pub fn query(sql: &str, params: &[Parameter]) -> Result<Rows, DactylError> {
let (kind, route, token) = resolve_env()?;
let adapter = build_adapter(kind, &route, token.as_deref())?;
adapter.execute(sql, params)
}
pub fn execute(sql: &str, params: &[Parameter]) -> Result<u64, DactylError> {
let (kind, route, token) = resolve_env()?;
let adapter = build_adapter(kind, &route, token.as_deref())?;
adapter.execute_raw(sql, params)
}
pub fn transaction(statements: &[Statement]) -> Result<Vec<Rows>, DactylError> {
if statements.is_empty() {
return Ok(Vec::new());
}
let (kind, route, token) = resolve_env()?;
let adapter = build_adapter(kind, &route, token.as_deref())?;
adapter.execute_batch(statements)
}
fn build_adapter(
kind: &str,
route: &str,
token: Option<&str>,
) -> Result<Box<dyn Adapter>, DactylError> {
match kind {
"sqlite" => {
#[cfg(feature = "sqlite")]
{
let a = crate::adapter::sqlite::SqliteAdapter::open(route)
.map_err(|e| DactylError::Adapter(format!("sqlite open: {e}")))?;
Ok(Box::new(a))
}
#[cfg(not(feature = "sqlite"))]
{
let _ = (route, token);
Err(DactylError::Adapter(
"sqlite adapter requested but `sqlite` feature is disabled".into(),
))
}
}
"neon" => {
#[cfg(feature = "neon")]
{
let a = crate::adapter::neon::NeonAdapter::new(route, token.map(|s| s.to_string()));
Ok(Box::new(a))
}
#[cfg(not(feature = "neon"))]
{
let _ = (route, token);
Err(DactylError::Adapter(
"neon adapter requested but `neon` feature is disabled".into(),
))
}
}
other => Err(DactylError::Adapter(format!(
"unknown datastore {other:?}: must be 'sqlite' or 'neon'"
))),
}
}