diff --git a/sqlx-core/src/any/mod.rs b/sqlx-core/src/any/mod.rs index f3f548e0..a5cd03e4 100644 --- a/sqlx-core/src/any/mod.rs +++ b/sqlx-core/src/any/mod.rs @@ -35,7 +35,7 @@ pub type AnyPool = crate::pool::Pool; impl_into_arguments_for_arguments!(AnyArguments<'q>); impl_executor_for_pool_connection!(Any, AnyConnection, AnyRow); impl_executor_for_transaction!(Any, AnyRow); +impl_map_row!(Any, AnyRow); -// required because some databases have a different handling -// of NULL +// required because some databases have a different handling of NULL impl_encode_for_option!(Any); diff --git a/sqlx-core/src/lib.rs b/sqlx-core/src/lib.rs index 5db5b076..efbb69e4 100644 --- a/sqlx-core/src/lib.rs +++ b/sqlx-core/src/lib.rs @@ -43,6 +43,9 @@ pub mod decode; #[macro_use] pub mod types; +#[macro_use] +pub mod query; + mod common; pub mod database; pub mod describe; @@ -50,7 +53,6 @@ pub mod executor; pub mod from_row; mod io; mod net; -pub mod query; pub mod query_as; pub mod query_scalar; pub mod row; diff --git a/sqlx-core/src/mssql/mod.rs b/sqlx-core/src/mssql/mod.rs index 9708f229..22cc58de 100644 --- a/sqlx-core/src/mssql/mod.rs +++ b/sqlx-core/src/mssql/mod.rs @@ -30,6 +30,4 @@ 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); - -// FIXME: RPC NULL parameter values / results -// FIXME: RPC Empty String parameter values +impl_map_row!(Mssql, MssqlRow); diff --git a/sqlx-core/src/mysql/mod.rs b/sqlx-core/src/mysql/mod.rs index 64a5bbba..aca0cf22 100644 --- a/sqlx-core/src/mysql/mod.rs +++ b/sqlx-core/src/mysql/mod.rs @@ -30,7 +30,7 @@ pub type MySqlPool = crate::pool::Pool; 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); -// required because some databases have a different handling -// of NULL +// required because some databases have a different handling of NULL impl_encode_for_option!(MySql); diff --git a/sqlx-core/src/postgres/mod.rs b/sqlx-core/src/postgres/mod.rs index c49cc7a6..60c335a4 100644 --- a/sqlx-core/src/postgres/mod.rs +++ b/sqlx-core/src/postgres/mod.rs @@ -33,7 +33,7 @@ pub type PgPool = crate::pool::Pool; 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); -// required because some databases have a different handling -// of NULL +// required because some databases have a different handling of NULL impl_encode_for_option!(Postgres); diff --git a/sqlx-core/src/query.rs b/sqlx-core/src/query.rs index 84e4f29c..61dec8cd 100644 --- a/sqlx-core/src/query.rs +++ b/sqlx-core/src/query.rs @@ -302,6 +302,40 @@ where } } +// 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 { + type Output: Unpin; + + fn try_map_row(&mut self, row: DB::Row) -> Result; +} + +pub trait MapRow { + 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. #[inline] pub fn query(sql: &str) -> Query<'_, DB, >::Arguments> @@ -328,3 +362,30 @@ where query: sql, } } + +#[allow(unused_macros)] +macro_rules! impl_map_row { + ($DB:ident, $R:ident) => { + impl crate::query::MapRow<$DB> for F + where + F: 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: 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 bb25f45f..ff891dc8 100644 --- a/sqlx-core/src/sqlite/mod.rs +++ b/sqlx-core/src/sqlite/mod.rs @@ -34,7 +34,7 @@ pub type SqlitePool = crate::pool::Pool; 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); -// required because some databases have a different handling -// of NULL +// required because some databases have a different handling of NULL impl_encode_for_option!(Sqlite); diff --git a/src/lib.rs b/src/lib.rs index 5d9d9b52..5c9803be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -113,6 +113,7 @@ pub mod decode { /// Return types 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; } diff --git a/tests/sqlite/sqlite.db b/tests/sqlite/sqlite.db index fa00c6fb..77339064 100644 Binary files a/tests/sqlite/sqlite.db and b/tests/sqlite/sqlite.db differ