From 7240964e201882c7beddc256d0c597f3a06b5d1d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 17 Nov 2020 20:28:36 +0100 Subject: [PATCH 1/2] Remove TryMapRow and MapRow These traits were a workaround for a bug in rustc that an earlier revision of the API triggered, but the API has since been changed. --- sqlx-core/src/any/mod.rs | 1 - sqlx-core/src/mssql/mod.rs | 1 - sqlx-core/src/mysql/mod.rs | 1 - sqlx-core/src/postgres/mod.rs | 1 - sqlx-core/src/query.rs | 81 ++++++----------------------------- sqlx-core/src/sqlite/mod.rs | 1 - src/lib.rs | 1 - 7 files changed, 12 insertions(+), 75 deletions(-) diff --git a/sqlx-core/src/any/mod.rs b/sqlx-core/src/any/mod.rs index 214a2a69e6..5acc023fa2 100644 --- a/sqlx-core/src/any/mod.rs +++ b/sqlx-core/src/any/mod.rs @@ -54,7 +54,6 @@ impl_acquire!(Any, AnyConnection); impl_column_index_for_row!(AnyRow); impl_column_index_for_statement!(AnyStatement); impl_into_maybe_pool!(Any, AnyConnection); -impl_map_row!(Any, AnyRow); // required because some databases have a different handling of NULL impl_encode_for_option!(Any); diff --git a/sqlx-core/src/mssql/mod.rs b/sqlx-core/src/mssql/mod.rs index 4c7fa9410c..3c11821614 100644 --- a/sqlx-core/src/mssql/mod.rs +++ b/sqlx-core/src/mssql/mod.rs @@ -36,7 +36,6 @@ pub type MssqlPool = crate::pool::Pool; impl_into_arguments_for_arguments!(MssqlArguments); impl_executor_for_pool_connection!(Mssql, MssqlConnection, MssqlRow); impl_executor_for_transaction!(Mssql, MssqlRow); -impl_map_row!(Mssql, MssqlRow); impl_acquire!(Mssql, MssqlConnection); impl_column_index_for_row!(MssqlRow); impl_column_index_for_statement!(MssqlStatement); diff --git a/sqlx-core/src/mysql/mod.rs b/sqlx-core/src/mysql/mod.rs index 95e3b43a89..023e95def7 100644 --- a/sqlx-core/src/mysql/mod.rs +++ b/sqlx-core/src/mysql/mod.rs @@ -43,7 +43,6 @@ pub type MySqlPoolOptions = crate::pool::PoolOptions; impl_into_arguments_for_arguments!(MySqlArguments); impl_executor_for_pool_connection!(MySql, MySqlConnection, MySqlRow); impl_executor_for_transaction!(MySql, MySqlRow); -impl_map_row!(MySql, MySqlRow); impl_acquire!(MySql, MySqlConnection); impl_column_index_for_row!(MySqlRow); impl_column_index_for_statement!(MySqlStatement); diff --git a/sqlx-core/src/postgres/mod.rs b/sqlx-core/src/postgres/mod.rs index ff20b28d27..59cbf7ad6c 100644 --- a/sqlx-core/src/postgres/mod.rs +++ b/sqlx-core/src/postgres/mod.rs @@ -44,7 +44,6 @@ pub type PgPoolOptions = crate::pool::PoolOptions; impl_into_arguments_for_arguments!(PgArguments); impl_executor_for_pool_connection!(Postgres, PgConnection, PgRow); impl_executor_for_transaction!(Postgres, PgRow); -impl_map_row!(Postgres, PgRow); impl_acquire!(Postgres, PgConnection); impl_column_index_for_row!(PgRow); impl_column_index_for_statement!(PgStatement); diff --git a/sqlx-core/src/query.rs b/sqlx-core/src/query.rs index a29104542e..96297967f4 100644 --- a/sqlx-core/src/query.rs +++ b/sqlx-core/src/query.rs @@ -114,12 +114,15 @@ where /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using /// a [`FromRow`](super::from_row::FromRow) implementation. #[inline] - pub fn map(self, f: F) -> Map<'q, DB, impl TryMapRow, A> + pub fn map( + self, + mut f: F, + ) -> Map<'q, DB, impl FnMut(DB::Row) -> Result + Send, A> where - F: MapRow, + F: FnMut(DB::Row) -> O + Send, O: Unpin, { - self.try_map(MapRowAdapter(f)) + self.try_map(move |row| Ok(f(row))) } /// Map each row in the result to another type. @@ -127,9 +130,10 @@ where /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using /// a [`FromRow`](super::from_row::FromRow) implementation. #[inline] - pub fn try_map(self, f: F) -> Map<'q, DB, F, A> + pub fn try_map(self, f: F) -> Map<'q, DB, F, A> where - F: TryMapRow, + F: FnMut(DB::Row) -> Result + Send, + O: Unpin, { Map { inner: self, @@ -251,7 +255,7 @@ where impl<'q, DB, F, O, A> Map<'q, DB, F, A> where DB: Database, - F: TryMapRow, + F: FnMut(DB::Row) -> Result + Send, O: Send + Unpin, A: 'q + Send + IntoArguments<'q, DB>, { @@ -294,7 +298,7 @@ where r#yield!(match v { Either::Left(v) => Either::Left(v), Either::Right(row) => { - Either::Right(self.mapper.try_map_row(row)?) + Either::Right((self.mapper)(row)?) } }); } @@ -344,47 +348,13 @@ where let row = executor.fetch_optional(self.inner).await?; if let Some(row) = row { - self.mapper.try_map_row(row).map(Some) + (self.mapper)(row).map(Some) } else { Ok(None) } } } -// A (hopefully) temporary workaround for an internal compiler error (ICE) involving higher-ranked -// trait bounds (HRTBs), associated types and closures. -// -// See https://github.com/rust-lang/rust/issues/62529 - -pub trait TryMapRow: Send { - type Output: Unpin; - - fn try_map_row(&mut self, row: DB::Row) -> Result; -} - -pub trait MapRow: Send { - type Output: Unpin; - - fn map_row(&mut self, row: DB::Row) -> Self::Output; -} - -// A private adapter that implements [MapRow] in terms of [TryMapRow] -// Just ends up Ok wrapping it - -struct MapRowAdapter(F); - -impl TryMapRow for MapRowAdapter -where - O: Unpin, - F: MapRow, -{ - type Output = O; - - fn try_map_row(&mut self, row: DB::Row) -> Result { - Ok(self.0.map_row(row)) - } -} - // Make a SQL query from a statement. pub(crate) fn query_statement<'q, DB>( statement: &'q >::Statement, @@ -443,30 +413,3 @@ where persistent: true, } } - -#[allow(unused_macros)] -macro_rules! impl_map_row { - ($DB:ident, $R:ident) => { - impl crate::query::MapRow<$DB> for F - where - F: Send + FnMut($R) -> O, - { - type Output = O; - - fn map_row(&mut self, row: $R) -> O { - (self)(row) - } - } - - impl crate::query::TryMapRow<$DB> for F - where - F: Send + FnMut($R) -> Result, - { - type Output = O; - - fn try_map_row(&mut self, row: $R) -> Result { - (self)(row) - } - } - }; -} diff --git a/sqlx-core/src/sqlite/mod.rs b/sqlx-core/src/sqlite/mod.rs index c407c7f12b..de75db085c 100644 --- a/sqlx-core/src/sqlite/mod.rs +++ b/sqlx-core/src/sqlite/mod.rs @@ -45,7 +45,6 @@ pub type SqlitePoolOptions = crate::pool::PoolOptions; impl_into_arguments_for_arguments!(SqliteArguments<'q>); impl_executor_for_pool_connection!(Sqlite, SqliteConnection, SqliteRow); impl_executor_for_transaction!(Sqlite, SqliteRow); -impl_map_row!(Sqlite, SqliteRow); impl_column_index_for_row!(SqliteRow); impl_column_index_for_statement!(SqliteStatement); impl_acquire!(Sqlite, SqliteConnection); diff --git a/src/lib.rs b/src/lib.rs index e2a404b074..34a5157b21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,7 +130,6 @@ pub use self::decode::Decode; /// Types and traits for the `query` family of functions and macros. pub mod query { pub use sqlx_core::query::{Map, Query}; - pub use sqlx_core::query::{MapRow, TryMapRow}; pub use sqlx_core::query_as::QueryAs; pub use sqlx_core::query_scalar::QueryScalar; } From c08ec142c1fc4e1c6f2e49d13d6cbdef753a8d7a Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 17 Nov 2020 20:40:02 +0100 Subject: [PATCH 2/2] Allow chaining map / try_map on queries To support `.map()` / `.try_map()` on `query!()` (and `query_as!()`). --- sqlx-core/src/query.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/sqlx-core/src/query.rs b/sqlx-core/src/query.rs index 96297967f4..3160c9423c 100644 --- a/sqlx-core/src/query.rs +++ b/sqlx-core/src/query.rs @@ -259,6 +259,44 @@ where O: Send + Unpin, A: 'q + Send + IntoArguments<'q, DB>, { + /// Map each row in the result to another type. + /// + /// See [`try_map`](Map::try_map) for a fallible version of this method. + /// + /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using + /// a [`FromRow`](super::from_row::FromRow) implementation. + #[inline] + pub fn map( + self, + mut g: G, + ) -> Map<'q, DB, impl FnMut(DB::Row) -> Result + Send, A> + where + G: FnMut(O) -> P + Send, + P: Unpin, + { + self.try_map(move |data| Ok(g(data))) + } + + /// Map each row in the result to another type. + /// + /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using + /// a [`FromRow`](super::from_row::FromRow) implementation. + #[inline] + pub fn try_map( + self, + mut g: G, + ) -> Map<'q, DB, impl FnMut(DB::Row) -> Result + Send, A> + where + G: FnMut(O) -> Result + Send, + P: Unpin, + { + let mut f = self.mapper; + Map { + inner: self.inner, + mapper: move |row| f(row).and_then(|o| g(o)), + } + } + /// Execute the query and return the generated results as a stream. pub fn fetch<'e, 'c: 'e, E>(self, executor: E) -> BoxStream<'e, Result> where