1use crate::{Driver, Error, Executor, Result};
2use anyhow::Context;
3use convert_case::{Case, Casing};
4use std::{
5 borrow::Cow,
6 future::{self, Future},
7};
8use url::Url;
9
10pub trait Connection: Executor {
20 fn sanitize_url(driver: &Self::Driver, mut url: Cow<'static, str>) -> Result<Url>
22 where
23 Self: Sized,
24 {
25 let mut in_memory = false;
26 if let Some((scheme, host)) = url.split_once("://")
27 && host.starts_with(":memory:")
28 {
29 url = format!("{scheme}://localhost{}", &host[8..]).into();
30 in_memory = true;
31 }
32 let context = || {
33 format!(
34 "While trying to connect to {}",
35 driver.name().to_case(Case::Title)
36 )
37 };
38 let mut result = Url::parse(&url).with_context(context)?;
39 if in_memory {
40 result.query_pairs_mut().append_pair("mode", "memory");
41 }
42 let names = <Self::Driver as Driver>::NAME;
43 'prefix: {
44 for name in names {
45 let prefix = format!("{}://", name);
46 if url.starts_with(&prefix) {
47 break 'prefix prefix;
48 }
49 }
50 let error = Error::msg(format!(
51 "Connection URL must start with: {}",
52 names.join(", ")
53 ))
54 .context(context());
55 log::error!("{:#}", error);
56 return Err(error);
57 };
58 Ok(result)
59 }
60
61 fn connect(
66 driver: &Self::Driver,
67 url: Cow<'static, str>,
68 ) -> impl Future<Output = Result<<Self::Driver as Driver>::Connection>>
69 where
70 Self: Sized;
71
72 fn begin(&mut self) -> impl Future<Output = Result<<Self::Driver as Driver>::Transaction<'_>>>;
76
77 fn disconnect(self) -> impl Future<Output = Result<()>>
79 where
80 Self: Sized,
81 {
82 future::ready(Ok(()))
83 }
84}