feat(mysql): add initial Connection and Database types, hookup runtimes

This commit is contained in:
Ryan Leckey 2020-12-28 02:18:05 -08:00
parent 7a323f3471
commit 93bb9cceb0
No known key found for this signature in database
GPG Key ID: F8AA68C235AB08C9
23 changed files with 298 additions and 19 deletions

9
Cargo.lock generated
View File

@ -759,6 +759,7 @@ name = "sqlx"
version = "0.6.0-pre"
dependencies = [
"sqlx-core",
"sqlx-mysql",
]
[[package]]
@ -773,6 +774,14 @@ dependencies = [
"url",
]
[[package]]
name = "sqlx-mysql"
version = "0.6.0-pre"
dependencies = [
"futures-util",
"sqlx-core",
]
[[package]]
name = "syn"
version = "1.0.56"

View File

@ -2,5 +2,6 @@
default-members = ["sqlx"]
members = [
"sqlx-core",
"sqlx-mysql",
"sqlx",
]

View File

@ -1,11 +1,12 @@
use super::{ConnectOptions, Runtime};
use crate::DefaultRuntime;
/// 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>: crate::Connection<Rt>
pub trait Connection<Rt = DefaultRuntime>: crate::Connection<Rt>
where
Rt: Runtime,
{

View File

@ -1,20 +1,23 @@
use super::Runtime;
use super::{Connection, Runtime};
use crate::DefaultRuntime;
/// 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>: crate::ConnectOptions<Rt>
pub trait ConnectOptions<Rt = DefaultRuntime>: crate::ConnectOptions<Rt>
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>
fn connect(&self) -> crate::Result<<Self as ConnectOptions<Rt>>::Connection>
where
Self::Connection: Sized;
<Self as ConnectOptions<Rt>>::Connection: Sized;
}

View File

@ -1,4 +1,4 @@
use crate::{ConnectOptions, Database, Runtime};
use crate::{ConnectOptions, Database, DefaultRuntime, Runtime};
#[cfg(feature = "async")]
use futures_util::future::BoxFuture;
@ -11,7 +11,7 @@ use futures_util::future::BoxFuture;
/// SQL statements will be executed and results returned within the context
/// of this single SQL connection.
///
pub trait Connection<Rt>: 'static + Send
pub trait Connection<Rt = DefaultRuntime>: 'static + Send
where
Rt: Runtime,
{

View File

@ -1,6 +1,6 @@
use std::fmt::Debug;
use crate::{Connection, Runtime};
use crate::{Connection, DefaultRuntime, Runtime};
/// A database driver.
///
@ -8,7 +8,7 @@ use crate::{Connection, Runtime};
/// specific database (e.g., MySQL, PostgreSQL).
///
// 'x: execution
pub trait Database<Rt>: 'static + Sized + Debug + for<'x> HasOutput<'x>
pub trait Database<Rt = DefaultRuntime>: 'static + Sized + Debug + for<'x> HasOutput<'x>
where
Rt: Runtime,
{

View File

@ -7,12 +7,14 @@ pub type Result<T> = std::result::Result<T, Error>;
#[non_exhaustive]
pub enum Error {
InvalidConnectionUrl(url::ParseError),
Network(std::io::Error),
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidConnectionUrl(source) => write!(f, "invalid connection url: {}", source),
Self::Network(source) => write!(f, "network: {}", source),
}
}
}
@ -21,6 +23,13 @@ impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::InvalidConnectionUrl(source) => Some(source),
Self::Network(source) => Some(source),
}
}
}
impl From<std::io::Error> for Error {
fn from(error: std::io::Error) -> Self {
Error::Network(error)
}
}

View File

@ -37,7 +37,7 @@ mod runtime;
pub mod blocking;
pub use connection::Connection;
pub use database::Database;
pub use database::{Database, HasOutput};
pub use error::{Error, Result};
pub use options::ConnectOptions;
pub use runtime::Runtime;
@ -52,7 +52,7 @@ pub use runtime::Tokio;
pub use runtime::Actix;
#[cfg(feature = "async")]
pub(crate) use runtime::Async;
pub use runtime::Async;
#[cfg(feature = "async-std")]
pub type DefaultRuntime = AsyncStd;

View File

@ -1,10 +1,10 @@
use std::fmt::Debug;
use std::str::FromStr;
use crate::{Connection, Runtime};
use crate::{Connection, DefaultRuntime, Runtime};
/// Options which can be used to configure how a SQL connection is opened.
pub trait ConnectOptions<Rt>:
pub trait ConnectOptions<Rt = DefaultRuntime>:
'static + Send + Sync + Default + Debug + Clone + FromStr<Err = crate::Error>
where
Rt: Runtime,

View File

@ -18,8 +18,8 @@ pub use self::actix::Actix;
/// Describes a set of types and functions used to open and manage
/// resources within SQLx.
pub trait Runtime {
type TcpStream;
pub trait Runtime: 'static + Send + Sync {
type TcpStream: Send;
/// Opens a TCP connection to a remote host at the specified port.
#[cfg(feature = "async")]

31
sqlx-mysql/Cargo.toml Normal file
View File

@ -0,0 +1,31 @@
[package]
name = "sqlx-mysql"
version = "0.6.0-pre"
repository = "https://github.com/launchbadge/sqlx"
description = "MySQL database driver for SQLx, the Rust SQL Toolkit."
license = "MIT OR Apache-2.0"
edition = "2018"
keywords = ["mysql", "sqlx", "database"]
categories = ["database", "asynchronous"]
authors = [
"LaunchBadge <contact@launchbadge.com>"
]
[package.metadata.docs.rs]
# > RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --no-deps --open
all-features = true
rustdoc-args = ["--cfg", "doc_cfg"]
[features]
default = []
# blocking (std) runtime
blocking = ["sqlx-core/blocking"]
# async runtime
# not meant to be used directly
async = ["futures-util", "sqlx-core/async"]
[dependencies]
sqlx-core = { version = "0.6.0-pre", path = "../sqlx-core" }
futures-util = { version = "0.3.8", optional = true }

2
sqlx-mysql/src/async.rs Normal file
View File

@ -0,0 +1,2 @@
mod connection;
mod options;

View File

@ -0,0 +1,27 @@
use futures_util::future::BoxFuture;
use sqlx_core::{Async, Connection, Result, Runtime};
use crate::{MySql, MySqlConnectOptions, MySqlConnection};
impl<Rt> Connection<Rt> for MySqlConnection<Rt>
where
Rt: Runtime,
{
type Database = MySql;
type Options = MySqlConnectOptions<Rt>;
fn close(self) -> BoxFuture<'static, Result<()>>
where
Rt: Async,
{
unimplemented!()
}
fn ping(&mut self) -> BoxFuture<'_, Result<()>>
where
Rt: Async,
{
unimplemented!()
}
}

View File

@ -0,0 +1,23 @@
use futures_util::{future::BoxFuture, FutureExt};
use sqlx_core::{Async, ConnectOptions, Result, Runtime};
use crate::{MySqlConnectOptions, MySqlConnection};
impl<Rt> ConnectOptions<Rt> for MySqlConnectOptions<Rt>
where
Rt: Runtime,
{
type Connection = MySqlConnection<Rt>;
fn connect(&self) -> BoxFuture<'_, Result<Self::Connection>>
where
Self::Connection: Sized,
Rt: Async,
{
FutureExt::boxed(async move {
let stream = Rt::connect_tcp(&self.host, self.port).await?;
Ok(MySqlConnection { stream })
})
}
}

View File

@ -0,0 +1,2 @@
mod connection;
mod options;

View File

@ -0,0 +1,19 @@
use sqlx_core::blocking::{Connection, Runtime};
use sqlx_core::Result;
use crate::{MySqlConnectOptions, MySqlConnection};
impl<Rt> Connection<Rt> for MySqlConnection<Rt>
where
Rt: Runtime,
{
type Options = MySqlConnectOptions<Rt>;
fn close(self) -> Result<()> {
unimplemented!()
}
fn ping(&mut self) -> Result<()> {
unimplemented!()
}
}

View File

@ -0,0 +1,17 @@
use sqlx_core::blocking::{ConnectOptions, Runtime};
use sqlx_core::Result;
use crate::{MySqlConnectOptions, MySqlConnection};
impl<Rt> ConnectOptions<Rt> for MySqlConnectOptions<Rt>
where
Rt: Runtime,
{
type Connection = MySqlConnection<Rt>;
fn connect(&self) -> Result<MySqlConnection<Rt>> {
let stream = <Rt as Runtime>::connect_tcp(&self.host, self.port)?;
Ok(MySqlConnection { stream })
}
}

View File

@ -0,0 +1,19 @@
use std::fmt::{self, Debug, Formatter};
use sqlx_core::{DefaultRuntime, Runtime};
pub struct MySqlConnection<Rt = DefaultRuntime>
where
Rt: Runtime,
{
pub(crate) stream: Rt::TcpStream,
}
impl<Rt> Debug for MySqlConnection<Rt>
where
Rt: Runtime,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("MySqlConnection").finish()
}
}

View File

@ -0,0 +1,15 @@
use sqlx_core::{Database, HasOutput, Runtime};
#[derive(Debug)]
pub struct MySql;
impl<Rt> Database<Rt> for MySql
where
Rt: Runtime,
{
type Connection = super::MySqlConnection<Rt>;
}
impl<'x> HasOutput<'x> for MySql {
type Output = &'x mut Vec<u8>;
}

34
sqlx-mysql/src/lib.rs Normal file
View File

@ -0,0 +1,34 @@
//! [MySQL] database driver for [SQLx][sqlx_core], the Rust SQL toolkit.
//!
//! [MySQL]: https://www.mysql.com/
//!
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![deny(unsafe_code)]
#![warn(rust_2018_idioms)]
#![warn(future_incompatible)]
#![warn(clippy::pedantic)]
#![warn(clippy::cargo_common_metadata)]
#![warn(clippy::multiple_crate_versions)]
#![warn(clippy::cognitive_complexity)]
#![warn(clippy::future_not_send)]
#![warn(clippy::missing_const_for_fn)]
#![warn(clippy::needless_borrow)]
#![warn(clippy::redundant_pub_crate)]
#![warn(clippy::string_lit_as_bytes)]
#![warn(clippy::use_self)]
#![warn(clippy::useless_let_if_seq)]
#![allow(clippy::doc_markdown)]
mod connection;
mod database;
mod options;
#[cfg(feature = "blocking")]
mod blocking;
#[cfg(feature = "async")]
mod r#async;
pub use connection::MySqlConnection;
pub use database::MySql;
pub use options::MySqlConnectOptions;

60
sqlx-mysql/src/options.rs Normal file
View File

@ -0,0 +1,60 @@
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::str::FromStr;
use sqlx_core::{DefaultRuntime, Runtime};
pub struct MySqlConnectOptions<Rt = DefaultRuntime>
where
Rt: Runtime,
{
runtime: PhantomData<Rt>,
pub(crate) host: String,
pub(crate) port: u16,
}
impl<Rt> Default for MySqlConnectOptions<Rt>
where
Rt: Runtime,
{
fn default() -> Self {
Self {
host: "localhost".to_owned(),
runtime: PhantomData,
port: 3306,
}
}
}
impl<Rt> Clone for MySqlConnectOptions<Rt>
where
Rt: Runtime,
{
fn clone(&self) -> Self {
unimplemented!()
}
}
impl<Rt> Debug for MySqlConnectOptions<Rt>
where
Rt: Runtime,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("MySqlConnectOptions").finish()
}
}
impl<Rt> FromStr for MySqlConnectOptions<Rt>
where
Rt: Runtime,
{
type Err = sqlx_core::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self {
host: "localhost".to_owned(),
runtime: PhantomData,
port: 3306,
})
}
}

View File

@ -16,12 +16,16 @@ authors = [
default = []
# blocking (std) runtime
blocking = ["sqlx-core/blocking"]
blocking = ["sqlx-core/blocking", "sqlx-mysql/blocking"]
# async runtimes
async-std = ["sqlx-core/async-std"]
actix = ["sqlx-core/actix"]
tokio = ["sqlx-core/tokio"]
async-std = ["sqlx-core/async-std", "sqlx-mysql/async"]
actix = ["sqlx-core/actix", "sqlx-mysql/async"]
tokio = ["sqlx-core/tokio", "sqlx-mysql/async"]
# databases
mysql = ["sqlx-mysql"]
[dependencies]
sqlx-core = { version = "0.6.0-pre", path = "../sqlx-core" }
sqlx-mysql = { version = "0.6.0-pre", path = "../sqlx-mysql", optional = true }

View File

@ -31,3 +31,6 @@ pub use sqlx_core::Tokio;
#[cfg(feature = "actix")]
pub use sqlx_core::Actix;
#[cfg(feature = "mysql")]
pub use sqlx_mysql as mysql;