feat(core): refine runtime abstraction

- traits from sqlx::blocking::_ have sqlx::_ traits as dependents

 - methods in sqlx::_ traits are cfg-d on "async" with an additional Rt: Async bound
This commit is contained in:
Ryan Leckey 2020-12-28 00:16:44 -08:00
parent fb4f2ca602
commit 7a323f3471
No known key found for this signature in database
GPG Key ID: F8AA68C235AB08C9
13 changed files with 145 additions and 69 deletions

View File

@ -1,11 +1,18 @@
//! Types and traits used to implement a database driver with **blocking** I/O.
//!
pub(crate) mod runtime;
mod connection;
mod options;
mod runtime;
pub use connection::Connection;
pub use options::ConnectOptions;
pub use runtime::Runtime;
pub use runtime::{Blocking, Runtime};
pub mod prelude {
pub use crate::Database as _;
pub use super::ConnectOptions as _;
pub use super::Connection as _;
pub use super::Runtime as _;
}

View File

@ -5,7 +5,7 @@ use super::{ConnectOptions, Runtime};
/// For detailed information, refer to the asynchronous version of
/// this: [`Connection`][crate::Connection].
///
pub trait Connection<Rt>: 'static + Send
pub trait Connection<Rt>: crate::Connection<Rt>
where
Rt: Runtime,
{
@ -20,7 +20,7 @@ where
where
Self: Sized,
{
url.parse::<Self::Options>()?.connect()
url.parse::<<Self as Connection<Rt>>::Options>()?.connect()
}
/// Explicitly close this database connection.

View File

@ -1,20 +1,14 @@
use std::fmt::Debug;
use std::str::FromStr;
use super::{Connection, Runtime};
use super::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>
pub trait ConnectOptions<Rt>: 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

View File

@ -2,23 +2,25 @@ use std::io;
use std::net::TcpStream;
/// Describes a set of types and functions used to open and manage
/// resources within SQLx using blocking I/O.
/// resources within SQLx.
///
pub trait Runtime {
type TcpStream;
/// For detailed information, refer to the asynchronous version of
/// this: [`Runtime`][crate::Runtime].
///
pub trait Runtime: crate::Runtime {
/// Opens a TCP connection to a remote host at the specified port.
fn connect_tcp(host: &str, port: u16) -> io::Result<Self::TcpStream>;
}
/// Uses the `std::net` primitives to implement a blocking runtime for SQLx.
#[cfg_attr(doc_cfg, doc(cfg(feature = "blocking")))]
#[derive(Debug)]
pub struct Blocking;
impl Runtime for Blocking {
impl crate::Runtime for Blocking {
type TcpStream = TcpStream;
}
impl Runtime for Blocking {
fn connect_tcp(host: &str, port: u16) -> io::Result<Self::TcpStream> {
TcpStream::connect((host, port))
}

View File

@ -1,6 +1,7 @@
use futures_util::future::BoxFuture;
use crate::{ConnectOptions, Database, Runtime};
use crate::{ConnectOptions, Runtime};
#[cfg(feature = "async")]
use futures_util::future::BoxFuture;
/// A unique connection (session) with a specific database.
///
@ -14,6 +15,8 @@ pub trait Connection<Rt>: 'static + Send
where
Rt: Runtime,
{
type Database: Database<Rt, Connection = Self>;
type Options: ConnectOptions<Rt, Connection = Self>;
/// Establish a new database connection.
@ -43,9 +46,11 @@ where
/// .connect().await?;
/// ```
///
#[cfg(feature = "async")]
fn connect(url: &str) -> BoxFuture<'_, crate::Result<Self>>
where
Self: Sized,
Rt: crate::Async,
{
let options = url.parse::<Self::Options>();
Box::pin(async move { options?.connect().await })
@ -57,7 +62,10 @@ where
/// 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<()>>;
#[cfg(feature = "async")]
fn close(self) -> BoxFuture<'static, crate::Result<()>>
where
Rt: crate::Async;
/// Checks if a connection to the database is still valid.
///
@ -66,5 +74,8 @@ where
/// 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<()>>;
#[cfg(feature = "async")]
fn ping(&mut self) -> BoxFuture<'_, crate::Result<()>>
where
Rt: crate::Async;
}

25
sqlx-core/src/database.rs Normal file
View File

@ -0,0 +1,25 @@
use std::fmt::Debug;
use crate::{Connection, Runtime};
/// A database driver.
///
/// This trait encapsulates a complete set of traits that implement a driver for a
/// specific database (e.g., MySQL, PostgreSQL).
///
// 'x: execution
pub trait Database<Rt>: 'static + Sized + Debug + for<'x> HasOutput<'x>
where
Rt: Runtime,
{
/// The concrete [`Connection`] implementation for this database.
type Connection: Connection<Rt, Database = Self> + ?Sized;
}
/// Associates [`Database`] with a `Output` of a generic lifetime.
/// 'x: single execution
pub trait HasOutput<'x> {
/// The concrete type to hold the output for `Encode` for this database. This may be
/// a simple alias to `&'x mut Vec<u8>`.
type Output;
}

View File

@ -27,34 +27,51 @@ extern crate _async_std as async_std;
#[cfg(feature = "tokio")]
extern crate _tokio as tokio;
mod connection;
mod database;
mod error;
pub use error::{Error, Result};
#[cfg(feature = "async")]
mod options;
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;
#[cfg(feature = "blocking")]
pub use blocking::runtime::Blocking;
pub use connection::Connection;
pub use database::Database;
pub use error::{Error, Result};
pub use options::ConnectOptions;
pub use runtime::Runtime;
#[cfg(feature = "async-std")]
pub use runtime::AsyncStd;
#[cfg(feature = "tokio")]
pub use runtime::Tokio;
#[cfg(feature = "actix")]
pub use runtime::Actix;
#[cfg(feature = "async")]
pub use {connection::Connection, options::ConnectOptions, runtime::Runtime};
pub(crate) use runtime::Async;
#[cfg(all(feature = "async", feature = "async-std"))]
pub use runtime::async_std::AsyncStd;
#[cfg(feature = "async-std")]
pub type DefaultRuntime = AsyncStd;
#[cfg(all(feature = "async", feature = "tokio"))]
pub use runtime::tokio::Tokio;
#[cfg(all(not(feature = "async-std"), feature = "tokio"))]
pub type DefaultRuntime = Tokio;
#[cfg(all(feature = "async", feature = "actix"))]
pub use runtime::actix::Actix;
#[cfg(all(not(all(feature = "async-std", feature = "tokio")), feature = "actix"))]
pub type DefaultRuntime = Actix;
#[cfg(not(feature = "async"))]
pub type DefaultRuntime = blocking::Blocking;
pub mod prelude {
pub use super::ConnectOptions as _;
pub use super::Connection as _;
pub use super::Database as _;
pub use super::Runtime as _;
#[cfg(all(not(feature = "async"), feature = "blocking"))]
pub use super::blocking::prelude::*;
}

View File

@ -1,8 +1,6 @@
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.
@ -14,7 +12,9 @@ where
type Connection: Connection<Rt> + ?Sized;
/// Establish a connection to the database.
fn connect(&self) -> BoxFuture<'_, crate::Result<Self::Connection>>
#[cfg(feature = "async")]
fn connect(&self) -> futures_util::future::BoxFuture<'_, crate::Result<Self::Connection>>
where
Self::Connection: Sized;
Self::Connection: Sized,
Rt: crate::Async;
}

View File

@ -1,25 +1,40 @@
use std::io;
use futures_util::future::BoxFuture;
#[cfg(feature = "async-std")]
pub(crate) mod async_std;
mod async_std;
#[cfg(feature = "actix")]
pub(crate) mod actix;
mod actix;
#[cfg(feature = "tokio")]
pub(crate) mod tokio;
mod tokio;
#[cfg(feature = "async-std")]
pub use self::async_std::AsyncStd;
#[cfg(feature = "tokio")]
pub use self::tokio::Tokio;
#[cfg(feature = "actix")]
pub use self::actix::Actix;
/// Describes a set of types and functions used to open and manage
/// resources within SQLx using asynchronous I/O.
#[cfg_attr(
doc_cfg,
doc(cfg(any(feature = "async-std", feature = "tokio", feature = "actix")))
)]
/// resources within SQLx.
pub trait Runtime {
type TcpStream;
/// Opens a TCP connection to a remote host at the specified port.
fn connect_tcp(host: &str, port: u16) -> BoxFuture<'_, io::Result<Self::TcpStream>>;
#[cfg(feature = "async")]
#[allow(unused_variables)]
fn connect_tcp(
host: &str,
port: u16,
) -> futures_util::future::BoxFuture<'_, std::io::Result<Self::TcpStream>>
where
Self: Async,
{
unimplemented!()
}
}
/// Marker trait that identifies a `Runtime` as supporting asynchronous I/O.
#[cfg(feature = "async")]
pub trait Async: Runtime {}

View File

@ -3,7 +3,7 @@ use std::io;
use actix_rt::net::TcpStream;
use futures_util::{future::BoxFuture, FutureExt};
use crate::runtime::Runtime;
use crate::{Async, Runtime};
/// Actix SQLx runtime. Uses [`actix-rt`][actix_rt] to provide [`Runtime`].
///
@ -15,6 +15,8 @@ use crate::runtime::Runtime;
#[derive(Debug)]
pub struct Actix;
impl Async for Actix {}
impl Runtime for Actix {
type TcpStream = TcpStream;

View File

@ -3,13 +3,15 @@ use std::io;
use async_std::{net::TcpStream, task::block_on};
use futures_util::{future::BoxFuture, FutureExt};
use crate::runtime::Runtime;
use crate::{Async, Runtime};
/// [`async-std`](async_std) implementation of [`Runtime`].
#[cfg_attr(doc_cfg, doc(cfg(feature = "async-std")))]
#[derive(Debug)]
pub struct AsyncStd;
impl Async for AsyncStd {}
impl Runtime for AsyncStd {
type TcpStream = TcpStream;
@ -20,8 +22,6 @@ impl Runtime for AsyncStd {
#[cfg(feature = "blocking")]
impl crate::blocking::Runtime for AsyncStd {
type TcpStream = TcpStream;
fn connect_tcp(host: &str, port: u16) -> io::Result<Self::TcpStream> {
block_on(<AsyncStd as Runtime>::connect_tcp(host, port))
}

View File

@ -3,7 +3,7 @@ use std::io;
use futures_util::{future::BoxFuture, FutureExt};
use tokio::net::TcpStream;
use crate::runtime::Runtime;
use crate::{Async, Runtime};
/// Tokio SQLx runtime. Uses [`tokio`] to provide [`Runtime`].
///
@ -13,6 +13,8 @@ use crate::runtime::Runtime;
#[derive(Debug)]
pub struct Tokio;
impl Async for Tokio {}
impl Runtime for Tokio {
type TcpStream = TcpStream;

View File

@ -16,11 +16,12 @@
#![warn(clippy::useless_let_if_seq)]
#![allow(clippy::doc_markdown)]
#[cfg(feature = "blocking")]
pub use sqlx_core::{blocking, Blocking};
pub use sqlx_core::{
prelude, ConnectOptions, Connection, Database, DefaultRuntime, Error, Result, Runtime,
};
#[cfg(any(feature = "async-std", feature = "tokio", feature = "actix"))]
pub use sqlx_core::Runtime;
#[cfg(feature = "blocking")]
pub use sqlx_core::blocking;
#[cfg(feature = "async-std")]
pub use sqlx_core::AsyncStd;