make macros work again

This commit is contained in:
Austin Bonander 2020-02-21 19:43:28 -08:00 committed by Ryan Leckey
parent 55ffd989e1
commit 0cb7bd1185
20 changed files with 328 additions and 154 deletions

82
Cargo.lock generated
View file

@ -67,8 +67,8 @@ dependencies = [
"crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-timer 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"kv-log-macro 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -88,7 +88,7 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"async-stream-impl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -470,22 +470,22 @@ name = "futures"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-channel 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-executor 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-task 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-channel"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -499,7 +499,7 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -521,19 +521,19 @@ name = "futures-executor"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-task 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-io"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-macro"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -544,7 +544,7 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -554,7 +554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-task"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -564,16 +564,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-util"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-channel 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-macro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-task 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1480,9 +1480,9 @@ dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-channel 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"md-5 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1507,9 +1507,9 @@ dependencies = [
"crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-channel 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
"hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1763,7 +1763,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2112,19 +2112,19 @@ dependencies = [
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
"checksum futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6f16056ecbb57525ff698bb955162d0cd03bee84e6241c27ff75c08d8ca5987"
"checksum futures-channel 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fcae98ca17d102fd8a3603727b9259fcf7fa4239b603d2142926189bc8999b86"
"checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8"
"checksum futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e5f4df964fa9c1c2f8bddeb5c3611631cacd93baf810fc8bb2fb4b495c263a"
"checksum futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "79564c427afefab1dfb3298535b21eda083ef7935b4f0ecbfcb121f0aec10866"
"checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
"checksum futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b35b6263fb1ef523c3056565fa67b1d16f0a8604ff12b11b08c25f28a734c60a"
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum futures-executor 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e274736563f686a837a0568b478bdabfeaec2dca794b5649b04e2fe1627c231"
"checksum futures-io 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e676577d229e70952ab25f3945795ba5b16d63ca794ca9d2c860e5595d20b5ff"
"checksum futures-macro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "52e7c56c15537adb4f76d0b7a76ad131cb4d2f4f32d3b0bcabcbe1c7c5e87764"
"checksum futures-sink 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "171be33efae63c2d59e6dbba34186fe0d6394fb378069a76dfd80fdcffd43c16"
"checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6"
"checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7"
"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6"
"checksum futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "86f148ef6b69f75bb610d4f9a2336d4fc88c4b5b67129d1a340dd0fd362efeec"
"checksum futures-task 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0bae52d6b29cf440e298856fec3965ee6fa71b06aa7495178615953fd669e5f9"
"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
"checksum futures-timer 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6"
"checksum futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76"
"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
"checksum futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"

View file

@ -33,9 +33,9 @@ crossbeam-queue = "0.2.1"
crossbeam-utils = { version = "0.7.0", default-features = false }
chrono = { version = "0.4.10", default-features = false, features = [ "clock" ], optional = true }
digest = { version = "0.8.1", default-features = false, optional = true, features = [ "std" ] }
futures-channel = { version = "0.3.1", default-features = false, features = [ "alloc" ] }
futures-core = { version = "0.3.1", default-features = false }
futures-util = { version = "0.3.1", default-features = false }
futures-channel = { version = "0.3.4", default-features = false, features = [ "alloc" ] }
futures-core = { version = "0.3.4", default-features = false }
futures-util = { version = "0.3.4", default-features = false }
# generic-array must match version that digest crates use
generic-array = { version = "0.12.3", default-features = false, optional = true }
log = { version = "0.4.8", default-features = false }

View file

@ -18,30 +18,3 @@ pub trait Arguments: Send + Sized + Default + 'static {
T: Type<Self::Database>,
T: Encode<Self::Database>;
}
pub trait IntoArguments<DB>
where
DB: Database,
{
fn into_arguments(self) -> DB::Arguments;
}
impl<A> IntoArguments<A::Database> for A
where
A: Arguments,
A::Database: Database<Arguments = Self> + Sized,
{
#[inline]
fn into_arguments(self) -> Self {
self
}
}
#[doc(hidden)]
pub struct ImmutableArguments<DB: Database>(pub DB::Arguments);
impl<DB: Database> IntoArguments<DB> for ImmutableArguments<DB> {
fn into_arguments(self) -> <DB as Database>::Arguments {
self.0
}
}

View file

@ -49,17 +49,4 @@ where
/// Fetch the next row in the result. Returns `None` if there are no more rows.
fn next(&mut self) -> BoxFuture<crate::Result<Option<<DB as HasRow>::Row>>>;
/// Map the `Row`s in this result to a different type, returning a [`Stream`] of the results.
fn map<'a, T, F>(self, f: F) -> BoxStream<'a, crate::Result<T>>
where
Self: Sized,
F: Send + Sync + 'static,
T: Send + Unpin + 'static,
F: for<'r> Fn(<DB as HasRow<'r>>::Row) -> T,
{
unimplemented!(
"Cursor::map is currently supplied by inherent methods to work around not having GATs"
)
}
}

View file

@ -61,3 +61,18 @@ where
(self, None)
}
}
macro_rules! impl_execute_for_query {
($db:ty) => {
impl<'q> $crate::executor::Execute<'q, $db> for $crate::query::Query<'q, $db> {
fn into_parts(
self,
) -> (
&'q str,
Option<<$db as $crate::database::Database>::Arguments>,
) {
(self.query, Some(self.arguments))
}
}
};
}

View file

@ -15,8 +15,10 @@ mod cache;
mod connection;
mod cursor;
mod database;
#[macro_use]
mod executor;
mod query;
mod transaction;
mod url;
@ -32,6 +34,7 @@ pub mod decode;
pub mod describe;
pub mod encode;
pub mod pool;
pub mod query;
pub mod types;
#[macro_use]
@ -53,7 +56,6 @@ pub use error::{Error, Result};
pub use connection::{Connect, Connection};
pub use cursor::Cursor;
pub use executor::{Execute, Executor};
pub use query::{query, Query};
pub use transaction::Transaction;
#[doc(inline)]

View file

@ -338,3 +338,5 @@ impl Executor for MySqlConnection {
Box::pin(self.describe(query))
}
}
impl_execute_for_query!(MySql);

View file

@ -32,24 +32,6 @@ pub struct PgCursor<'c, 'q> {
state: State<'c, 'q>,
}
impl<'c, 'q> PgCursor<'c, 'q> {
#[doc(hidden)]
pub fn map<'a, T, F>(mut self, f: F) -> impl Stream<Item = crate::Result<T>> + 'a + 'c
where
F: Send + Sync + 'static,
T: Send + Unpin + 'static,
F: for<'r> Fn(PgRow<'r>) -> T,
'q: 'c,
'c: 'a,
{
try_stream! {
while let Some(row) = next(&mut self).await? {
yield f(row);
}
}
}
}
impl<'c, 'q> Cursor<'c, 'q, Postgres> for PgCursor<'c, 'q> {
#[doc(hidden)]
fn from_pool<E>(pool: &Pool<PgConnection>, query: E) -> Self

View file

@ -74,3 +74,5 @@ impl<'e> Executor<'e> for &'e mut super::PgConnection {
self.execute(query)
}
}
impl_execute_for_query!(Postgres);

View file

@ -56,3 +56,14 @@ impl<'c> RowIndex<'c, PgRow<'c>> for &'_ str {
}
// TODO: impl_from_row_for_row!(PgRow);
impl<O: Unpin, F> crate::query::MapRow<Postgres> for F
where
F: for<'c> FnMut(PgRow<'c>) -> crate::Result<O>,
{
type Mapped = O;
fn map_row(&mut self, row: PgRow) -> crate::Result<O> {
(self)(row)
}
}

View file

@ -1,42 +1,118 @@
use std::future::Future;
use std::marker::PhantomData;
use std::mem;
use std::pin::Pin;
use std::task::{Context, Poll};
use async_stream::try_stream;
use futures_core::stream::BoxStream;
use futures_core::Stream;
use futures_util::future::ready;
use futures_util::ready;
use futures_util::stream::try_unfold;
use futures_util::TryFutureExt;
use futures_util::TryStreamExt;
use crate::arguments::Arguments;
use crate::arguments::IntoArguments;
use crate::cursor::Cursor;
use crate::database::{Database, HasCursor, HasRow};
use crate::encode::Encode;
use crate::executor::{Execute, Executor};
use crate::types::Type;
use futures_core::stream::BoxStream;
use futures_util::future::ready;
use futures_util::TryFutureExt;
use futures_util::TryStreamExt;
use std::future::Future;
use std::marker::PhantomData;
use std::mem;
use crate::{Error, FromRow};
use futures_core::future::BoxFuture;
/// Raw SQL query with bind parameters. Returned by [`query`].
pub struct Query<'q, DB, T = <DB as Database>::Arguments>
/// Raw SQL query with bind parameters. Returned by [`query`][crate::query::query].
pub struct Query<'q, DB, A = <DB as Database>::Arguments>
where
DB: Database,
{
query: &'q str,
arguments: T,
pub(crate) query: &'q str,
pub(crate) arguments: A,
database: PhantomData<DB>,
}
impl<'q, DB, P> Execute<'q, DB> for Query<'q, DB, P>
/// SQL query that will map its results to owned Rust types.
///
/// Returned by [Query::map], `query!()`, etc. Has most of the same methods as [Query] but
/// the return types are changed to reflect the mapping. However, there is no equivalent of
/// [Query::execute] as it doesn't make much sense to map the result type and then ignore it.
pub struct Map<'q, DB, F, A = <DB as Database>::Arguments>
where
DB: Database,
{
query: Query<'q, DB, A>,
mapper: F,
}
#[doc(hidden)]
pub struct ImmutableArguments<DB: Database>(DB::Arguments);
// necessary because we can't have a blanket impl for `Query<'q, DB>`
// the compiler thinks that `ImmutableArguments<DB>` could be `DB::Arguments` even though
// that would be an infinitely recursive type
impl<'q, DB> Execute<'q, DB> for Query<'q, DB, ImmutableArguments<DB>>
where
DB: Database,
P: IntoArguments<DB> + Send,
{
fn into_parts(self) -> (&'q str, Option<<DB as Database>::Arguments>) {
(self.query, Some(self.arguments.into_arguments()))
(self.query, Some(self.arguments.0))
}
}
impl<'q, DB, P> Query<'q, DB, P>
impl<'q, DB> Query<'q, DB>
where
DB: Database,
P: IntoArguments<DB> + Send,
{
/// Bind a value for use with this SQL query.
pub fn bind<T>(mut self, value: T) -> Self
where
T: Type<DB>,
T: Encode<DB>,
{
self.arguments.add(value);
self
}
#[doc(hidden)]
pub fn bind_all(self, arguments: DB::Arguments) -> Query<'q, DB, ImmutableArguments<DB>> {
Query {
query: self.query,
arguments: ImmutableArguments(arguments),
database: PhantomData,
}
}
}
impl<'q, DB, A> Query<'q, DB, A>
where
DB: Database,
{
/// Map each row in the result to another type.
///
/// The returned type has most of the same methods but does not have [`.execute()`][Query::execute].
///
/// The mapping function returns [`crate::Result`] so [`Row::try_get`] can be used.
///
/// Stylistically, we recommend placing this call after any [`.bind()`][Query::bind]
/// calls, just before [`.fetch()`][Query::fetch], etc.
///
/// See also: [query_as].
pub fn map<F>(self, mapper: F) -> Map<'q, DB, F, A>
where
F: MapRow<DB>,
{
Map {
query: self,
mapper,
}
}
}
impl<'q, DB, A> Query<'q, DB, A>
where
DB: Database,
Self: Execute<'q, DB>,
{
pub async fn execute<'e, E>(self, executor: E) -> crate::Result<u64>
where
@ -77,7 +153,7 @@ where
}
}
impl<'q, DB> Query<'q, DB>
impl<'q, DB, F> Map<'q, DB, F>
where
DB: Database,
{
@ -87,9 +163,107 @@ where
T: Type<DB>,
T: Encode<DB>,
{
self.arguments.add(value);
self.query.arguments.add(value);
self
}
#[doc(hidden)]
pub fn bind_all(self, arguments: DB::Arguments) -> Map<'q, DB, F, ImmutableArguments<DB>> {
Map {
query: self.query.bind_all(arguments),
mapper: self.mapper,
}
}
}
impl<'q, DB, F, A> Map<'q, DB, F, A>
where
DB: Database,
Query<'q, DB, A>: Execute<'q, DB>,
F: MapRow<DB>,
{
/// Execute the query and get a [Stream] of the results, returning our mapped type.
pub fn fetch<'e: 'q, E>(
mut self,
executor: E,
) -> impl Stream<Item = crate::Result<F::Mapped>> + 'e
where
'q: 'e,
E: Executor<'e, Database = DB> + 'e,
F: 'e,
F::Mapped: 'e,
A: 'e,
{
try_stream! {
let mut cursor = executor.execute(self.query);
while let Some(next) = cursor.next().await? {
let mapped = self.mapper.map_row(next)?;
yield mapped;
}
}
}
/// Get the first row in the result
pub async fn fetch_optional<'e, E>(mut self, executor: E) -> crate::Result<Option<F::Mapped>>
where
E: Executor<'e, Database = DB>,
'q: 'e,
{
// could be implemented in terms of `fetch()` but this avoids overhead from `try_stream!`
let mut cursor = executor.execute(self.query);
let mut mapper = self.mapper;
let val = cursor.next().await?;
val.map(|row| mapper.map_row(row)).transpose()
}
pub async fn fetch_one<'e, E>(self, executor: E) -> crate::Result<F::Mapped>
where
E: Executor<'e, Database = DB>,
'q: 'e,
{
self.fetch_optional(executor)
.and_then(|row| match row {
Some(row) => ready(Ok(row)),
None => ready(Err(crate::Error::NotFound)),
})
.await
}
pub async fn fetch_all<'e, E>(mut self, executor: E) -> crate::Result<Vec<F::Mapped>>
where
E: Executor<'e, Database = DB>,
'q: 'e,
{
let mut cursor = executor.execute(self.query);
let mut out = vec![];
while let Some(row) = cursor.next().await? {
out.push(self.mapper.map_row(row)?);
}
Ok(out)
}
}
/// 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 MapRow<DB: Database> {
type Mapped: Unpin;
fn map_row(&mut self, row: <DB as HasRow>::Row) -> crate::Result<Self::Mapped>;
}
impl<O: Unpin, DB> MapRow<DB> for for<'c> fn(<DB as HasRow<'c>>::Row) -> crate::Result<O>
where
DB: Database,
{
type Mapped = O;
fn map_row(&mut self, row: <DB as HasRow>::Row) -> crate::Result<O> {
(self)(row)
}
}
/// Construct a raw SQL query that can be chained to bind parameters and executed.
@ -103,3 +277,13 @@ where
query: sql,
}
}
pub fn query_as<T, DB>(
sql: &str,
) -> Map<DB, for<'c> fn(<DB as HasRow<'c>>::Row) -> crate::Result<T>>
where
DB: Database,
T: Unpin + for<'c> FromRow<'c, <DB as HasRow<'c>>::Row>,
{
query(sql).map(|row| Ok(T::from_row(row)))
}

View file

@ -9,22 +9,28 @@ pub enum ParamChecking {
pub trait DatabaseExt: Database {
const DATABASE_PATH: &'static str;
const ROW_PATH: &'static str;
const PARAM_CHECKING: ParamChecking;
fn quotable_path() -> syn::Path {
fn db_path() -> syn::Path {
syn::parse_str(Self::DATABASE_PATH).unwrap()
}
fn row_path() -> syn::Path {
syn::parse_str(Self::ROW_PATH).unwrap()
}
fn param_type_for_id(id: &Self::TypeInfo) -> Option<&'static str>;
fn return_type_for_id(id: &Self::TypeInfo) -> Option<&'static str>;
}
macro_rules! impl_database_ext {
($database:path { $($(#[$meta:meta])? $ty:ty $(| $input:ty)?),*$(,)? }, ParamChecking::$param_checking:ident) => {
($database:path { $($(#[$meta:meta])? $ty:ty $(| $input:ty)?),*$(,)? }, ParamChecking::$param_checking:ident, row = $row:path) => {
impl $crate::database::DatabaseExt for $database {
const DATABASE_PATH: &'static str = stringify!($database);
const ROW_PATH: &'static str = stringify!($row);
const PARAM_CHECKING: $crate::database::ParamChecking = $crate::database::ParamChecking::$param_checking;
fn param_type_for_id(info: &Self::TypeInfo) -> Option<&'static str> {

View file

@ -29,5 +29,6 @@ impl_database_ext! {
#[cfg(feature = "chrono")]
sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>,
},
ParamChecking::Weak
ParamChecking::Weak,
row = sqlx::mysql::MySqlRow
}

View file

@ -26,5 +26,6 @@ impl_database_ext! {
#[cfg(feature = "chrono")]
sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc> | sqlx::types::chrono::DateTime<_>,
},
ParamChecking::Strong
ParamChecking::Strong,
row = sqlx::postgres::PgRow
}

View file

@ -1,7 +1,7 @@
use std::fmt::Display;
use proc_macro2::TokenStream;
use quote::quote;
use quote::{format_ident, quote};
pub use input::{QueryAsMacroInput, QueryMacroInput};
pub use query::expand_query;
@ -48,14 +48,17 @@ where
let args_tokens = args::quote_args(&input.query_input, &describe)?;
let arg_names = &input.query_input.arg_names;
let query_args = format_ident!("query_args");
let columns = output::columns_to_rust(&describe)?;
let output = output::quote_query_as::<C::Database>(
&input.query_input.source,
&input.as_ty.path,
&query_args,
&columns,
);
let db_path = <C::Database as DatabaseExt>::quotable_path();
let db_path = <C::Database as DatabaseExt>::db_path();
let args_count = arg_names.len();
let arg_indices = (0..args_count).map(|i| syn::Index::from(i));
let arg_indices_2 = arg_indices.clone();
@ -67,14 +70,14 @@ where
#args_tokens
let mut query_args = <#db_path as sqlx::Database>::Arguments::default();
query_args.reserve(
let mut #query_args = <#db_path as sqlx::Database>::Arguments::default();
#query_args.reserve(
#args_count,
0 #(+ sqlx::encode::Encode::<#db_path>::size_hint(args.#arg_indices))*
);
#(query_args.add(args.#arg_indices_2);)*
#(#query_args.add(args.#arg_indices_2);)*
#output.bind_all(query_args)
#output
}}
}
})

View file

@ -37,6 +37,7 @@ pub fn columns_to_rust<DB: DatabaseExt>(describe: &Describe<DB>) -> crate::Resul
pub fn quote_query_as<DB: DatabaseExt>(
sql: &str,
out_ty: &Path,
bind_args: &Ident,
columns: &[RustColumn],
) -> TokenStream {
let instantiations = columns.iter().enumerate().map(
@ -47,14 +48,15 @@ pub fn quote_query_as<DB: DatabaseExt>(
ref type_,
..
},
)| { quote!( #ident: #i.try_get::<#type_>(&row).try_unwrap_optional()? ) },
)| { quote!( #ident: row.try_get::<#type_, _>(#i).try_unwrap_optional()? ) },
);
let db_path = DB::quotable_path();
let db_path = DB::db_path();
let row_path = DB::row_path();
quote! {
sqlx::query_as_mapped::<#db_path, _>(#sql, |row| {
use sqlx::row::RowIndex as _;
sqlx::query::<#db_path>(#sql).bind_all(#bind_args).map(|row: #row_path| {
use sqlx::row::Row as _;
use sqlx::result_ext::ResultExt as _;
Ok(#out_ty { #(#instantiations),* })
})

View file

@ -4,7 +4,7 @@ use proc_macro2::Span;
use proc_macro2::TokenStream;
use syn::{Ident, Path};
use quote::quote;
use quote::{format_ident, quote};
use sqlx::{Connection, Database};
use super::{args, output, QueryMacroInput};
@ -29,7 +29,7 @@ where
let args_count = arg_names.len();
let arg_indices = (0..args_count).map(|i| syn::Index::from(i));
let arg_indices_2 = arg_indices.clone();
let db_path = <C::Database as DatabaseExt>::quotable_path();
let db_path = <C::Database as DatabaseExt>::db_path();
if describe.result_columns.is_empty() {
return Ok(quote! {
@ -47,7 +47,7 @@ where
#(query_args.add(args.#arg_indices_2);)*
sqlx::query_as_mapped(#sql, |_| Ok(())).bind_all(query_args)
sqlx::query::<#db_path>(#sql).bind_all(query_args)
}
}}
});
@ -70,7 +70,8 @@ where
)
.collect::<TokenStream>();
let output = output::quote_query_as::<C::Database>(sql, &record_type, &columns);
let query_args = format_ident!("query_args");
let output = output::quote_query_as::<C::Database>(sql, &record_type, &query_args, &columns);
Ok(quote! {
macro_rules! macro_result {
@ -84,15 +85,15 @@ where
#args
let mut query_args = <#db_path as sqlx::Database>::Arguments::default();
query_args.reserve(
let mut #query_args = <#db_path as sqlx::Database>::Arguments::default();
#query_args.reserve(
#args_count,
0 #(+ sqlx::encode::Encode::<#db_path>::size_hint(args.#arg_indices))*
);
#(query_args.add(args.#arg_indices_2);)*
#(#query_args.add(args.#arg_indices_2);)*
#output.bind_all(query_args)
#output
}
}}
})

View file

@ -8,16 +8,16 @@ compile_error!("one of 'runtime-async-std' or 'runtime-tokio' features must be e
compile_error!("only one of 'runtime-async-std' or 'runtime-tokio' features must be enabled");
// Modules
pub use sqlx_core::{arguments, describe, error, pool, row, types};
pub use sqlx_core::{arguments, describe, error, pool, query, row, types};
// Types
pub use sqlx_core::{
Connect, Connection, Cursor, Database, Error, Executor, FromRow, Pool, Query, QueryAs, Result, Row,
Transaction,
query::Query, Connect, Connection, Cursor, Database, Error, Execute, Executor, FromRow, Pool,
Result, Row, Transaction
};
// Functions
pub use sqlx_core::query;
pub use query::{query, query_as};
#[cfg(feature = "mysql")]
#[cfg_attr(docsrs, doc(cfg(feature = "mysql")))]

View file

@ -1,5 +1,7 @@
use futures::TryStreamExt;
use sqlx::{postgres::PgConnection, Connect, Connection, Cursor, Executor, Row};
use sqlx::{
postgres::PgConnection, Connect, Connection, Cursor, Database, Executor, Postgres, Row,
};
use sqlx_core::postgres::{PgPool, PgRow};
use std::time::Duration;
@ -10,7 +12,7 @@ async fn it_connects() -> anyhow::Result<()> {
let row = sqlx::query("select 1 + 1").fetch_one(&mut conn).await?;
assert_eq!(2, row.get(0));
assert_eq!(2i32, row.get::<i32, _>(0));
conn.close().await?;
@ -39,9 +41,9 @@ CREATE TEMPORARY TABLE users (id INTEGER PRIMARY KEY);
assert_eq!(cnt, 1);
}
let sum: i32 = sqlx::query("SELECT id FROM users")
let sum: i32 = sqlx::query::<Postgres>("SELECT id FROM users")
.map(|row: PgRow| Ok(row.get::<i32, _>(0)))
.fetch(&mut conn)
.map(|row| row.get::<i32, _>(0))
.try_fold(0_i32, |acc, x| async move { Ok(acc + x) })
.await?;

View file

@ -4,4 +4,4 @@ error: "\'1" is not a valid Rust identifier
2 | let query = sqlx::query!("select 1 as \"'1\"");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)