From 4204f1dc1683618d55aafa2615a21d7183e41f44 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Sun, 28 Feb 2021 12:18:42 -0800 Subject: [PATCH] feat: expose Connection::describe --- sqlx-core/src/blocking/connection.rs | 10 ++++++ sqlx-core/src/connection.rs | 12 ++++++- sqlx-core/src/describe.rs | 17 ++++++++++ sqlx-core/src/lib.rs | 2 ++ sqlx-mysql/src/connection.rs | 32 +++++++++++++++++-- .../src/connection/executor/raw_prepare.rs | 4 +-- sqlx-mysql/src/raw_statement.rs | 14 +++++++- sqlx/src/lib.rs | 2 +- sqlx/src/mysql/blocking/connection.rs | 14 +++++++- sqlx/src/mysql/connection.rs | 16 +++++++++- 10 files changed, 113 insertions(+), 10 deletions(-) create mode 100644 sqlx-core/src/describe.rs diff --git a/sqlx-core/src/blocking/connection.rs b/sqlx-core/src/blocking/connection.rs index 66a1fae3..d7dd7be9 100644 --- a/sqlx-core/src/blocking/connection.rs +++ b/sqlx-core/src/blocking/connection.rs @@ -1,3 +1,5 @@ +use crate::Describe; + use super::{Close, Connect, ConnectOptions, Runtime}; /// A unique connection (session) with a specific database. @@ -16,4 +18,12 @@ where /// this: [`ping()`][crate::Connection::ping]. /// fn ping(&mut self) -> crate::Result<()>; + + fn describe<'x, 'e, 'q>( + &'e mut self, + query: &'q str + ) -> crate::Result> + where + 'e: 'x, + 'q: 'x; } diff --git a/sqlx-core/src/connection.rs b/sqlx-core/src/connection.rs index 64575271..48cf4632 100644 --- a/sqlx-core/src/connection.rs +++ b/sqlx-core/src/connection.rs @@ -1,7 +1,7 @@ #[cfg(feature = "async")] use futures_util::future::BoxFuture; -use crate::{Close, Connect, Database, Runtime}; +use crate::{Close, Connect, Database, Describe, Runtime}; /// A single connection (also known as a session) with a specific database. /// @@ -29,4 +29,14 @@ where fn ping(&mut self) -> BoxFuture<'_, crate::Result<()>> where Rt: crate::Async; + + #[cfg(feature = "async")] + fn describe<'x, 'e, 'q>( + &'e mut self, + query: &'q str + ) -> BoxFuture<'x, crate::Result>> + where + Rt: crate::Async, + 'e: 'x, + 'q: 'x; } diff --git a/sqlx-core/src/describe.rs b/sqlx-core/src/describe.rs new file mode 100644 index 00000000..31696834 --- /dev/null +++ b/sqlx-core/src/describe.rs @@ -0,0 +1,17 @@ +use crate::Database; + +#[derive(Debug)] +#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr( + feature = "offline", + serde(bound( + serialize = "DB::TypeInfo: serde::Serialize, DB::Column: serde::Serialize", + deserialize = "DB::TypeInfo: serde::de::DeserializeOwned, DB::Column: serde::de::DeserializeOwned", + )) +)] +#[doc(hidden)] +pub struct Describe { + pub columns: Vec, + pub parameters: Vec, + pub nullable: Vec>, +} diff --git a/sqlx-core/src/lib.rs b/sqlx-core/src/lib.rs index 3fb3d656..919666a6 100644 --- a/sqlx-core/src/lib.rs +++ b/sqlx-core/src/lib.rs @@ -22,6 +22,7 @@ mod acquire; pub mod arguments; mod close; +mod describe; mod column; mod connect; mod connection; @@ -85,3 +86,4 @@ pub use runtime::Runtime; #[cfg(feature = "tokio")] pub use runtime::Tokio; pub use type_info::TypeInfo; +pub use describe::Describe; diff --git a/sqlx-mysql/src/connection.rs b/sqlx-mysql/src/connection.rs index 42d96fb7..e238bce9 100644 --- a/sqlx-mysql/src/connection.rs +++ b/sqlx-mysql/src/connection.rs @@ -1,7 +1,7 @@ use std::fmt::{self, Debug, Formatter}; #[cfg(feature = "async")] -use futures_util::future::{BoxFuture, FutureExt}; +use futures_util::future::{BoxFuture, FutureExt, TryFutureExt}; use sqlx_core::net::Stream as NetStream; use sqlx_core::{Close, Connect, Connection, Runtime}; @@ -13,9 +13,11 @@ use crate::{MySql, MySqlConnectOptions}; #[macro_use] mod flush; +#[macro_use] +mod executor; + mod command; mod connect; -mod executor; mod ping; /// A single connection (also known as a session) to a MySQL database server. @@ -88,6 +90,19 @@ where { Box::pin(self.ping_async()) } + + #[cfg(feature = "async")] + fn describe<'x, 'e, 'q>( + &'e mut self, + query: &'q str, + ) -> BoxFuture<'x, sqlx_core::Result>> + where + Rt: sqlx_core::Async, + 'e: 'x, + 'q: 'x, + { + self.raw_prepare_async(query).map_ok(Into::into).boxed() + } } impl Connect for MySqlConnection { @@ -121,13 +136,24 @@ impl Close for MySqlConnection { mod blocking { use sqlx_core::blocking::{Close, Connect, Connection, Runtime}; - use super::{MySqlConnectOptions, MySqlConnection}; + use super::{MySqlConnectOptions, MySqlConnection, MySql}; impl Connection for MySqlConnection { #[inline] fn ping(&mut self) -> sqlx_core::Result<()> { self.ping_blocking() } + + fn describe<'x, 'e, 'q>( + &'e mut self, + query: &'q str, + ) -> sqlx_core::Result> + where + 'e: 'x, + 'q: 'x, + { + self.raw_prepare_blocking(query).map(Into::into) + } } impl Connect for MySqlConnection { diff --git a/sqlx-mysql/src/connection/executor/raw_prepare.rs b/sqlx-mysql/src/connection/executor/raw_prepare.rs index 253e84e6..edbf4ecd 100644 --- a/sqlx-mysql/src/connection/executor/raw_prepare.rs +++ b/sqlx-mysql/src/connection/executor/raw_prepare.rs @@ -56,7 +56,7 @@ macro_rules! impl_raw_prepare { impl super::MySqlConnection { #[cfg(feature = "async")] - pub(super) async fn raw_prepare_async(&mut self, sql: &str) -> Result + pub(crate) async fn raw_prepare_async(&mut self, sql: &str) -> Result where Rt: sqlx_core::Async, { @@ -65,7 +65,7 @@ impl super::MySqlConnection { } #[cfg(feature = "blocking")] - pub(super) fn raw_prepare_blocking(&mut self, sql: &str) -> Result + pub(crate) fn raw_prepare_blocking(&mut self, sql: &str) -> Result where Rt: sqlx_core::blocking::Runtime, { diff --git a/sqlx-mysql/src/raw_statement.rs b/sqlx-mysql/src/raw_statement.rs index 32a21a7c..6751b61b 100644 --- a/sqlx-mysql/src/raw_statement.rs +++ b/sqlx-mysql/src/raw_statement.rs @@ -1,5 +1,7 @@ +use sqlx_core::Describe; + use crate::protocol::PrepareOk; -use crate::{MySqlColumn, MySqlTypeInfo}; +use crate::{MySql, MySqlColumn, MySqlTypeInfo}; #[derive(Debug, Clone)] pub(crate) struct RawStatement { @@ -37,3 +39,13 @@ impl RawStatement { &mut self.parameters } } + +impl From for Describe { + fn from(stmt: RawStatement) -> Self { + Self { + nullable: stmt.columns.iter().map(|col| Some(col.is_nullable())).collect(), + columns: stmt.columns, + parameters: stmt.parameters, + } + } +} diff --git a/sqlx/src/lib.rs b/sqlx/src/lib.rs index 393b7889..5114a566 100644 --- a/sqlx/src/lib.rs +++ b/sqlx/src/lib.rs @@ -71,5 +71,5 @@ pub use sqlx_core::AsyncStd; pub use sqlx_core::Tokio; pub use sqlx_core::{ Acquire, Arguments, Close, Connect, ConnectOptions, Connection, Database, Decode, Encode, - Error, Execute, Executor, FromRow, Result, Row, Runtime, Type, + Error, Execute, Executor, FromRow, Result, Row, Runtime, Type, Describe, }; diff --git a/sqlx/src/mysql/blocking/connection.rs b/sqlx/src/mysql/blocking/connection.rs index ebda3db2..a1caf47c 100644 --- a/sqlx/src/mysql/blocking/connection.rs +++ b/sqlx/src/mysql/blocking/connection.rs @@ -1,7 +1,7 @@ use crate::blocking::{Close, Connect, Connection, Executor, Runtime}; use crate::mysql::connection::MySqlConnection; use crate::mysql::{MySql, MySqlConnectOptions, MySqlQueryResult, MySqlRow}; -use crate::{Blocking, Execute, Result}; +use crate::{Blocking, Execute, Result, Describe}; impl MySqlConnection { /// Open a new database connection. @@ -68,6 +68,18 @@ impl Connection for MySqlConnection { fn ping(&mut self) -> Result<()> { self.0.ping() } + + #[inline] + fn describe<'x, 'e, 'q>( + &'e mut self, + query: &'q str, + ) -> Result> + where + 'e: 'x, + 'q: 'x, + { + self.0.describe(query) + } } impl Executor for MySqlConnection { diff --git a/sqlx/src/mysql/connection.rs b/sqlx/src/mysql/connection.rs index ec562dd1..44f5f3e2 100644 --- a/sqlx/src/mysql/connection.rs +++ b/sqlx/src/mysql/connection.rs @@ -8,7 +8,7 @@ use sqlx_core::{Execute, Executor}; use super::{MySql, MySqlConnectOptions, MySqlQueryResult, MySqlRow}; #[cfg(feature = "blocking")] use crate::blocking; -use crate::{Arguments, Close, Connect, Connection, DefaultRuntime, Runtime}; +use crate::{Arguments, Describe, Close, Connect, Connection, DefaultRuntime, Runtime}; #[cfg(feature = "async")] use crate::{Async, Result}; @@ -131,6 +131,20 @@ impl Connection for MySqlConnection { { self.0.ping() } + + #[cfg(feature = "async")] + #[inline] + fn describe<'x, 'e, 'q>( + &'e mut self, + query: &'q str, + ) -> BoxFuture<'x, Result>> + where + Rt: Async, + 'e: 'x, + 'q: 'x, + { + self.0.describe(query) + } } impl Executor for MySqlConnection {