mirror of
https://github.com/launchbadge/sqlx
synced 2024-11-10 06:24:16 +00:00
make macros work again
This commit is contained in:
parent
55ffd989e1
commit
0cb7bd1185
20 changed files with 328 additions and 154 deletions
82
Cargo.lock
generated
82
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -338,3 +338,5 @@ impl Executor for MySqlConnection {
|
|||
Box::pin(self.describe(query))
|
||||
}
|
||||
}
|
||||
|
||||
impl_execute_for_query!(MySql);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -74,3 +74,5 @@ impl<'e> Executor<'e> for &'e mut super::PgConnection {
|
|||
self.execute(query)
|
||||
}
|
||||
}
|
||||
|
||||
impl_execute_for_query!(Postgres);
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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),* })
|
||||
})
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}}
|
||||
})
|
||||
|
|
|
@ -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")))]
|
||||
|
|
|
@ -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?;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue