feat(core): add minimal Connection and ConnectOptions traits

This commit is contained in:
Ryan Leckey 2020-12-27 17:46:11 -08:00
parent f613b3c7b5
commit fb4f2ca602
No known key found for this signature in database
GPG Key ID: F8AA68C235AB08C9
9 changed files with 277 additions and 1 deletions

79
Cargo.lock generated
View File

@ -261,6 +261,16 @@ dependencies = [
"instant",
]
[[package]]
name = "form_urlencoded"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
@ -372,6 +382,17 @@ dependencies = [
"libc",
]
[[package]]
name = "idna"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "instant"
version = "0.1.9"
@ -448,6 +469,12 @@ dependencies = [
"cfg-if 0.1.10",
]
[[package]]
name = "matches"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
name = "memchr"
version = "2.3.4"
@ -596,6 +623,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pin-project"
version = "1.0.2"
@ -737,6 +770,7 @@ dependencies = [
"futures-util",
"tokio 0.2.24",
"tokio 1.0.1",
"url",
]
[[package]]
@ -759,6 +793,21 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "tinyvec"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "0.2.24"
@ -790,12 +839,42 @@ dependencies = [
"pin-project-lite 0.2.0",
]
[[package]]
name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
dependencies = [
"matches",
]
[[package]]
name = "unicode-normalization"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "url"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "vec-arena"
version = "1.0.0"

View File

@ -39,3 +39,4 @@ _async-std = { version = "1.8.0", optional = true, package = "async-std" }
futures-util = { version = "0.3.8", optional = true }
_tokio = { version = "1.0.1", optional = true, package = "tokio", features = ["net"] }
tokio_02 = { version = "0.2.24", optional = true, package = "tokio", features = ["net"] }
url = "2.2.0"

View File

@ -3,4 +3,9 @@
pub(crate) mod runtime;
mod connection;
mod options;
pub use connection::Connection;
pub use options::ConnectOptions;
pub use runtime::Runtime;

View File

@ -0,0 +1,39 @@
use super::{ConnectOptions, Runtime};
/// A unique connection (session) with a specific database.
///
/// For detailed information, refer to the asynchronous version of
/// this: [`Connection`][crate::Connection].
///
pub trait Connection<Rt>: 'static + Send
where
Rt: Runtime,
{
type Options: ConnectOptions<Rt, Connection = Self>;
/// Establish a new database connection.
///
/// For detailed information, refer to the asynchronous version of
/// this: [`connect()`][crate::Connection::connect].
///
fn connect(url: &str) -> crate::Result<Self>
where
Self: Sized,
{
url.parse::<Self::Options>()?.connect()
}
/// Explicitly close this database connection.
///
/// For detailed information, refer to the asynchronous version of
/// this: [`close()`][crate::Connection::close].
///
fn close(self) -> crate::Result<()>;
/// Checks if a connection to the database is still valid.
///
/// For detailed information, refer to the asynchronous version of
/// this: [`ping()`][crate::Connection::ping].
///
fn ping(&mut self) -> crate::Result<()>;
}

View File

@ -0,0 +1,26 @@
use std::fmt::Debug;
use std::str::FromStr;
use super::{Connection, Runtime};
/// Options which can be used to configure how a SQL connection is opened.
///
/// For detailed information, refer to the asynchronous version of
/// this: [`ConnectOptions`][crate::ConnectOptions].
///
pub trait ConnectOptions<Rt>:
'static + Send + Sync + Default + Debug + Clone + FromStr<Err = crate::Error>
where
Rt: Runtime,
{
type Connection: Connection<Rt> + ?Sized;
/// Establish a connection to the database.
///
/// For detailed information, refer to the asynchronous version of
/// this: [`connect()`][crate::ConnectOptions::connect].
///
fn connect(&self) -> crate::Result<Self::Connection>
where
Self::Connection: Sized;
}

View File

@ -0,0 +1,70 @@
use futures_util::future::BoxFuture;
use crate::{ConnectOptions, Runtime};
/// A unique connection (session) with a specific database.
///
/// With a client/server model, this is equivalent to a network connection
/// to the server.
///
/// SQL statements will be executed and results returned within the context
/// of this single SQL connection.
///
pub trait Connection<Rt>: 'static + Send
where
Rt: Runtime,
{
type Options: ConnectOptions<Rt, Connection = Self>;
/// Establish a new database connection.
///
/// A value of [`Options`](#associatedtype.Options) is parsed from the provided connection string. This parsing
/// is database-specific.
///
/// ```rust,ignore
/// use sqlx::postgres::PgConnection;
/// use sqlx::ConnectOptions;
///
/// let mut conn = PgConnection::connect(
/// "postgres://postgres:password@localhost/database",
/// ).await?;
/// ```
///
/// You may alternatively build the connection options imperatively.
///
/// ```rust,ignore
/// use sqlx::mysql::{MySqlConnection, MySqlConnectOptions};
/// use sqlx::ConnectOptions;
///
/// let mut conn: MySqlConnection = MySqlConnectOptions::builder()
/// .host("localhost")
/// .username("root")
/// .password("password")
/// .connect().await?;
/// ```
///
fn connect(url: &str) -> BoxFuture<'_, crate::Result<Self>>
where
Self: Sized,
{
let options = url.parse::<Self::Options>();
Box::pin(async move { options?.connect().await })
}
/// Explicitly close this database connection.
///
/// This method is **not required** for safe and consistent operation. However, it is
/// recommended to call it instead of letting a connection `drop` as the database backend
/// will be faster at cleaning up resources.
///
fn close(self) -> BoxFuture<'static, crate::Result<()>>;
/// Checks if a connection to the database is still valid.
///
/// The method of operation greatly depends on the database driver. In MySQL, there is an
/// explicit [`COM_PING`](https://dev.mysql.com/doc/internals/en/com-ping.html) command. In
/// PostgreSQL, `ping` will issue a query consisting of a comment `/* SQLx ping */` which,
/// in effect, does nothing apart from getting a response from the server.
///
fn ping(&mut self) -> BoxFuture<'_, crate::Result<()>>;
}

26
sqlx-core/src/error.rs Normal file
View File

@ -0,0 +1,26 @@
use std::error::Error as StdError;
use std::fmt::{self, Display, Formatter};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
InvalidConnectionUrl(url::ParseError),
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidConnectionUrl(source) => write!(f, "invalid connection url: {}", source),
}
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::InvalidConnectionUrl(source) => Some(source),
}
}
}

View File

@ -27,9 +27,19 @@ extern crate _async_std as async_std;
#[cfg(feature = "tokio")]
extern crate _tokio as tokio;
mod error;
pub use error::{Error, Result};
#[cfg(feature = "async")]
mod runtime;
#[cfg(feature = "async")]
mod connection;
#[cfg(feature = "async")]
mod options;
#[cfg(feature = "blocking")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "blocking")))]
pub mod blocking;
@ -38,7 +48,7 @@ pub mod blocking;
pub use blocking::runtime::Blocking;
#[cfg(feature = "async")]
pub use runtime::Runtime;
pub use {connection::Connection, options::ConnectOptions, runtime::Runtime};
#[cfg(all(feature = "async", feature = "async-std"))]
pub use runtime::async_std::AsyncStd;

20
sqlx-core/src/options.rs Normal file
View File

@ -0,0 +1,20 @@
use std::fmt::Debug;
use std::str::FromStr;
use futures_util::future::BoxFuture;
use crate::{Connection, Runtime};
/// Options which can be used to configure how a SQL connection is opened.
pub trait ConnectOptions<Rt>:
'static + Send + Sync + Default + Debug + Clone + FromStr<Err = crate::Error>
where
Rt: Runtime,
{
type Connection: Connection<Rt> + ?Sized;
/// Establish a connection to the database.
fn connect(&self) -> BoxFuture<'_, crate::Result<Self::Connection>>
where
Self::Connection: Sized;
}