use crate::{Driver, ErrorContext, Executor, Result, truncate_long};
use anyhow::anyhow;
use std::{
borrow::Cow,
future::{self, Future},
};
use url::Url;
pub trait Connection: Executor {
fn sanitize_url(_driver: &Self::Driver, mut url: Cow<'static, str>) -> Result<Url>
where
Self: Sized,
{
let mut in_memory = false;
if let Some((scheme, host)) = url.split_once("://")
&& host.starts_with(":memory:")
{
url = format!("{scheme}://localhost{}", &host[8..]).into();
in_memory = true;
}
let make_context = || format!("While parsing the connection URL:\n{}", truncate_long!(url));
let mut result = Url::parse(&url).with_context(make_context)?;
if in_memory {
result.query_pairs_mut().append_pair("mode", "memory");
}
let names = <Self::Driver as Driver>::NAME;
if !names
.iter()
.any(|name| url.starts_with(name) && url[name.len()..].starts_with("://"))
{
let error = anyhow!("Connection URL must start with: {}", names.join(", "))
.context(make_context());
log::error!("{error:#}");
return Err(error);
}
Ok(result)
}
fn connect(
driver: &Self::Driver,
url: Cow<'static, str>,
) -> impl Future<Output = Result<<Self::Driver as Driver>::Connection>> + Send
where
Self: Sized;
fn begin(
&mut self,
) -> impl Future<Output = Result<<Self::Driver as Driver>::Transaction<'_>>> + Send;
fn disconnect(self) -> impl Future<Output = Result<()>> + Send
where
Self: Sized,
{
future::ready(Ok(()))
}
}
impl<S: Connection> Connection for &mut S {
fn connect(
driver: &Self::Driver,
url: Cow<'static, str>,
) -> impl Future<Output = Result<<Self::Driver as Driver>::Connection>> + Send
where
Self: Sized,
{
S::connect(driver, url)
}
fn begin(
&mut self,
) -> impl Future<Output = Result<<Self::Driver as Driver>::Transaction<'_>>> + Send {
(**self).begin()
}
fn disconnect(self) -> impl Future<Output = Result<()>> + Send
where
Self: Sized,
{
future::ready(Err(anyhow!(
"Cannot disconnect using `&mut Connection`, use the actual object.",
)))
}
}