mirror of
https://github.com/launchbadge/sqlx
synced 2024-11-10 14:34:19 +00:00
query refactors
This commit is contained in:
parent
acca40c88e
commit
193e79569a
16 changed files with 172 additions and 162 deletions
|
@ -41,36 +41,33 @@ where
|
||||||
{
|
{
|
||||||
type Backend = DB;
|
type Backend = DB;
|
||||||
|
|
||||||
fn execute<'e, 'q: 'e, I: 'e>(
|
fn execute<'e, 'q: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: <DB as Backend>::QueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<u64>>
|
) -> BoxFuture<'e, crate::Result<u64>> {
|
||||||
where
|
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
{
|
|
||||||
self.live.execute(query, params)
|
self.live.execute(query, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: <DB as Backend>::QueryParameters,
|
||||||
) -> BoxStream<'e, crate::Result<T>>
|
) -> BoxStream<'e, crate::Result<T>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send + Unpin,
|
T: FromRow<Self::Backend> + Send + Unpin,
|
||||||
{
|
{
|
||||||
self.live.fetch(query, params)
|
self.live.fetch(query, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_optional<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch_optional<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: <DB as Backend>::QueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send,
|
T: FromRow<Self::Backend> + Send,
|
||||||
{
|
{
|
||||||
self.live.fetch_optional(query, params)
|
self.live.fetch_optional(query, params)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
//! Types and traits related to serializing values for the database.
|
//! Types and traits related to serializing values for the database.
|
||||||
use crate::{backend::Backend, types::HasSqlType};
|
use crate::{backend::Backend, types::HasSqlType};
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
/// Annotates the result of [Encode] to differentiate between an empty value and a null value.
|
/// Annotates the result of [Encode] to differentiate between an empty value and a null value.
|
||||||
pub enum IsNull {
|
pub enum IsNull {
|
||||||
/// The value was null (and no data was written to the buffer).
|
/// The value was null (and no data was written to the buffer).
|
||||||
|
@ -26,6 +28,11 @@ pub trait Encode<DB: Backend> {
|
||||||
/// The return value indicates if this value should be represented as `NULL`.
|
/// The return value indicates if this value should be represented as `NULL`.
|
||||||
/// If this is the case, implementations **must not** write anything to `out`.
|
/// If this is the case, implementations **must not** write anything to `out`.
|
||||||
fn encode(&self, buf: &mut Vec<u8>) -> IsNull;
|
fn encode(&self, buf: &mut Vec<u8>) -> IsNull;
|
||||||
|
|
||||||
|
/// Calculate the number of bytes this type will use when encoded.
|
||||||
|
fn size_hint(&self) -> usize {
|
||||||
|
mem::size_of_val(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [Encode] is implemented for `Option<T>` where `T` implements `Encode`. An `Option<T>`
|
/// [Encode] is implemented for `Option<T>` where `T` implements `Encode`. An `Option<T>`
|
||||||
|
@ -43,6 +50,10 @@ where
|
||||||
IsNull::Yes
|
IsNull::Yes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> usize {
|
||||||
|
if self.is_some() { mem::size_of::<T>() } else { 0 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized, DB> Encode<DB> for &'_ T
|
impl<T: ?Sized, DB> Encode<DB> for &'_ T
|
||||||
|
@ -54,4 +65,8 @@ where
|
||||||
fn encode(&self, buf: &mut Vec<u8>) -> IsNull {
|
fn encode(&self, buf: &mut Vec<u8>) -> IsNull {
|
||||||
(*self).encode(buf)
|
(*self).encode(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> usize {
|
||||||
|
(*self).size_hint()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,57 +16,51 @@ pub trait Executor: Send {
|
||||||
Box::pin(
|
Box::pin(
|
||||||
self.execute(
|
self.execute(
|
||||||
"SELECT 1",
|
"SELECT 1",
|
||||||
<Self::Backend as Backend>::QueryParameters::new(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
.map_ok(|_| ()),
|
.map_ok(|_| ()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute<'e, 'q: 'e, I: 'e>(
|
fn execute<'e, 'q: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: <Self::Backend as Backend>::QueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<u64>>
|
) -> BoxFuture<'e, crate::Result<u64>>;
|
||||||
where
|
|
||||||
I: IntoQueryParameters<Self::Backend> + Send;
|
|
||||||
|
|
||||||
fn fetch<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: <Self::Backend as Backend>::QueryParameters,
|
||||||
) -> BoxStream<'e, crate::Result<T>>
|
) -> BoxStream<'e, crate::Result<T>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send + Unpin;
|
T: FromRow<Self::Backend> + Send + Unpin;
|
||||||
|
|
||||||
fn fetch_all<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch_all<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: <Self::Backend as Backend>::QueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<Vec<T>>>
|
) -> BoxFuture<'e, crate::Result<Vec<T>>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send + Unpin,
|
T: FromRow<Self::Backend> + Send + Unpin,
|
||||||
{
|
{
|
||||||
Box::pin(self.fetch(query, params).try_collect())
|
Box::pin(self.fetch(query, params).try_collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_optional<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch_optional<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: <Self::Backend as Backend>::QueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send;
|
T: FromRow<Self::Backend> + Send;
|
||||||
|
|
||||||
fn fetch_one<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch_one<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: <Self::Backend as Backend>::QueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<T>>
|
) -> BoxFuture<'e, crate::Result<T>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send,
|
T: FromRow<Self::Backend> + Send,
|
||||||
{
|
{
|
||||||
let fut = self.fetch_optional(query, params);
|
let fut = self.fetch_optional(query, params);
|
||||||
|
|
|
@ -248,7 +248,7 @@ impl MariaDb {
|
||||||
self.write(ComStmtExecute {
|
self.write(ComStmtExecute {
|
||||||
statement_id,
|
statement_id,
|
||||||
params: ¶ms.params,
|
params: ¶ms.params,
|
||||||
null: ¶ms.null,
|
null: ¶ms.null_bitmap,
|
||||||
flags: StmtExecFlag::NO_CURSOR,
|
flags: StmtExecFlag::NO_CURSOR,
|
||||||
param_types: ¶ms.param_types,
|
param_types: ¶ms.param_types,
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,14 +19,11 @@ use futures_core::{future::BoxFuture, stream::BoxStream};
|
||||||
impl Executor for MariaDb {
|
impl Executor for MariaDb {
|
||||||
type Backend = Self;
|
type Backend = Self;
|
||||||
|
|
||||||
fn execute<'e, 'q: 'e, I: 'e>(
|
fn execute<'e, 'q: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: MariaDbQueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<u64>>
|
) -> BoxFuture<'e, crate::Result<u64>> {
|
||||||
where
|
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
{
|
|
||||||
let params = params.into_params();
|
let params = params.into_params();
|
||||||
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
|
@ -67,13 +64,12 @@ impl Executor for MariaDb {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch<'e, 'q: 'e, I: 'e, O: 'e, T: 'e>(
|
fn fetch<'e, 'q: 'e, O: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: MariaDbQueryParameters,
|
||||||
) -> BoxStream<'e, crate::Result<T>>
|
) -> BoxStream<'e, crate::Result<T>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend, O> + Send + Unpin,
|
T: FromRow<Self::Backend, O> + Send + Unpin,
|
||||||
{
|
{
|
||||||
let params = params.into_params();
|
let params = params.into_params();
|
||||||
|
@ -108,13 +104,12 @@ impl Executor for MariaDb {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_optional<'e, 'q: 'e, I: 'e, O: 'e, T: 'e>(
|
fn fetch_optional<'e, 'q: 'e, O: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: MariaDbQueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend, O> + Send,
|
T: FromRow<Self::Backend, O> + Send,
|
||||||
{
|
{
|
||||||
let params = params.into_params();
|
let params = params.into_params();
|
||||||
|
|
|
@ -6,21 +6,25 @@ use crate::{
|
||||||
types::HasSqlType,
|
types::HasSqlType,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct MariaDbQueryParameters {
|
pub struct MariaDbQueryParameters {
|
||||||
pub(crate) param_types: Vec<MariaDbTypeMetadata>,
|
pub(crate) param_types: Vec<MariaDbTypeMetadata>,
|
||||||
pub(crate) params: Vec<u8>,
|
pub(crate) params: Vec<u8>,
|
||||||
pub(crate) null: Vec<u8>,
|
pub(crate) null_bitmap: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueryParameters for MariaDbQueryParameters {
|
impl QueryParameters for MariaDbQueryParameters {
|
||||||
type Backend = MariaDb;
|
type Backend = MariaDb;
|
||||||
|
|
||||||
fn new() -> Self {
|
fn reserve(&mut self, binds: usize, bytes: usize) {
|
||||||
Self {
|
self.param_types.reserve(binds);
|
||||||
param_types: Vec::with_capacity(4),
|
self.params.reserve(bytes);
|
||||||
params: Vec::with_capacity(32),
|
|
||||||
null: vec![0],
|
// ensure we have enough bytes in the bitmap to hold at least `binds` extra bits
|
||||||
}
|
// the second `& 7` gives us 0 spare bits when param_types.len() is a multiple of 8
|
||||||
|
let spare_bits = (8 - (self.param_types.len()) & 7) & 7;
|
||||||
|
// ensure that if there are no spare bits left, `binds = 1` reserves another byte
|
||||||
|
self.null_bitmap.reserve( (binds + 7 - spare_bits) / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind<T>(&mut self, value: T)
|
fn bind<T>(&mut self, value: T)
|
||||||
|
@ -33,9 +37,10 @@ impl QueryParameters for MariaDbQueryParameters {
|
||||||
let index = self.param_types.len();
|
let index = self.param_types.len();
|
||||||
|
|
||||||
self.param_types.push(metadata);
|
self.param_types.push(metadata);
|
||||||
|
self.null_bitmap.resize(index / 8, 0);
|
||||||
|
|
||||||
if let IsNull::Yes = value.encode(&mut self.params) {
|
if let IsNull::Yes = value.encode(&mut self.params) {
|
||||||
self.null[index / 8] = self.null[index / 8] & (1 << index % 8);
|
self.null_bitmap[index / 8] &= (1 << index % 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
use crate::{backend::Backend, encode::Encode, types::HasSqlType};
|
use crate::{backend::Backend, encode::Encode, types::HasSqlType};
|
||||||
|
|
||||||
pub trait QueryParameters: Send {
|
pub trait QueryParameters: Default + Send {
|
||||||
type Backend: Backend;
|
type Backend: Backend;
|
||||||
|
|
||||||
fn new() -> Self
|
fn reserve(&mut self, binds: usize, bytes: usize);
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
|
|
||||||
fn bind<T>(&mut self, value: T)
|
fn bind<T>(&mut self, value: T)
|
||||||
where
|
where
|
||||||
|
@ -29,8 +27,12 @@ macro_rules! impl_into_query_parameters {
|
||||||
$($T: crate::encode::Encode<$B>,)+
|
$($T: crate::encode::Encode<$B>,)+
|
||||||
{
|
{
|
||||||
fn into_params(self) -> <$B as crate::backend::Backend>::QueryParameters {
|
fn into_params(self) -> <$B as crate::backend::Backend>::QueryParameters {
|
||||||
let mut params = <<$B as crate::backend::Backend>::QueryParameters
|
let mut params = <$B as crate::backend::Backend>::QueryParameters::default();
|
||||||
as crate::params::QueryParameters>::new();
|
|
||||||
|
let binds = 0 $(+ { $idx; 1 } )+;
|
||||||
|
let bytes = 0 $(+ crate::encode::Encode::size_hint(&self.$idx))+;
|
||||||
|
|
||||||
|
params.reserve(binds, bytes);
|
||||||
|
|
||||||
$(crate::params::QueryParameters::bind(&mut params, self.$idx);)+
|
$(crate::params::QueryParameters::bind(&mut params, self.$idx);)+
|
||||||
|
|
||||||
|
@ -57,8 +59,7 @@ macro_rules! impl_into_query_parameters_for_backend {
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_params(self) -> <$B as crate::backend::Backend>::QueryParameters {
|
fn into_params(self) -> <$B as crate::backend::Backend>::QueryParameters {
|
||||||
<<$B as crate::backend::Backend>::QueryParameters
|
Default::default()
|
||||||
as crate::params::QueryParameters>::new()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,24 +11,20 @@ where
|
||||||
{
|
{
|
||||||
type Backend = DB;
|
type Backend = DB;
|
||||||
|
|
||||||
fn execute<'e, 'q: 'e, I: 'e>(
|
fn execute<'e, 'q: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: DB::QueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<u64>>
|
) -> BoxFuture<'e, crate::Result<u64>> {
|
||||||
where
|
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
{
|
|
||||||
Box::pin(async move { <&Pool<DB> as Executor>::execute(&mut &*self, query, params).await })
|
Box::pin(async move { <&Pool<DB> as Executor>::execute(&mut &*self, query, params).await })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: DB::QueryParameters,
|
||||||
) -> BoxStream<'e, crate::Result<T>>
|
) -> BoxStream<'e, crate::Result<T>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send + Unpin,
|
T: FromRow<Self::Backend> + Send + Unpin,
|
||||||
{
|
{
|
||||||
Box::pin(async_stream::try_stream! {
|
Box::pin(async_stream::try_stream! {
|
||||||
|
@ -41,13 +37,12 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_optional<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch_optional<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: DB::QueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send,
|
T: FromRow<Self::Backend> + Send,
|
||||||
{
|
{
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
|
@ -69,24 +64,20 @@ where
|
||||||
{
|
{
|
||||||
type Backend = DB;
|
type Backend = DB;
|
||||||
|
|
||||||
fn execute<'e, 'q: 'e, I: 'e>(
|
fn execute<'e, 'q: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: DB::QueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<u64>>
|
) -> BoxFuture<'e, crate::Result<u64>> {
|
||||||
where
|
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
{
|
|
||||||
Box::pin(async move { self.0.acquire().await?.execute(query, params).await })
|
Box::pin(async move { self.0.acquire().await?.execute(query, params).await })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: DB::QueryParameters,
|
||||||
) -> BoxStream<'e, crate::Result<T>>
|
) -> BoxStream<'e, crate::Result<T>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send + Unpin,
|
T: FromRow<Self::Backend> + Send + Unpin,
|
||||||
{
|
{
|
||||||
Box::pin(async_stream::try_stream! {
|
Box::pin(async_stream::try_stream! {
|
||||||
|
@ -99,13 +90,12 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_optional<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch_optional<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: DB::QueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send,
|
T: FromRow<Self::Backend> + Send,
|
||||||
{
|
{
|
||||||
Box::pin(async move { self.0.acquire().await?.fetch_optional(query, params).await })
|
Box::pin(async move { self.0.acquire().await?.fetch_optional(query, params).await })
|
||||||
|
|
|
@ -8,21 +8,17 @@ use crate::{
|
||||||
url::Url,
|
url::Url,
|
||||||
};
|
};
|
||||||
use futures_core::{future::BoxFuture, stream::BoxStream};
|
use futures_core::{future::BoxFuture, stream::BoxStream};
|
||||||
|
use crate::postgres::query::PostgresQueryParameters;
|
||||||
|
|
||||||
impl Executor for Postgres {
|
impl Executor for Postgres {
|
||||||
type Backend = Self;
|
type Backend = Self;
|
||||||
|
|
||||||
fn execute<'e, 'q: 'e, I: 'e>(
|
fn execute<'e, 'q: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: PostgresQueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<u64>>
|
) -> BoxFuture<'e, crate::Result<u64>> {
|
||||||
where
|
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
{
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let params = params.into_params();
|
|
||||||
|
|
||||||
self.parse("", query, ¶ms);
|
self.parse("", query, ¶ms);
|
||||||
self.bind("", "", ¶ms);
|
self.bind("", "", ¶ms);
|
||||||
self.execute("", 1);
|
self.execute("", 1);
|
||||||
|
@ -40,17 +36,14 @@ impl Executor for Postgres {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: PostgresQueryParameters,
|
||||||
) -> BoxStream<'e, crate::Result<T>>
|
) -> BoxStream<'e, crate::Result<T>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send + Unpin,
|
T: FromRow<Self::Backend> + Send + Unpin,
|
||||||
{
|
{
|
||||||
let params = params.into_params();
|
|
||||||
|
|
||||||
self.parse("", query, ¶ms);
|
self.parse("", query, ¶ms);
|
||||||
self.bind("", "", ¶ms);
|
self.bind("", "", ¶ms);
|
||||||
self.execute("", 0);
|
self.execute("", 0);
|
||||||
|
@ -66,18 +59,15 @@ impl Executor for Postgres {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_optional<'e, 'q: 'e, I: 'e, T: 'e>(
|
fn fetch_optional<'e, 'q: 'e, T: 'e>(
|
||||||
&'e mut self,
|
&'e mut self,
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
params: I,
|
params: PostgresQueryParameters,
|
||||||
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
) -> BoxFuture<'e, crate::Result<Option<T>>>
|
||||||
where
|
where
|
||||||
I: IntoQueryParameters<Self::Backend> + Send,
|
|
||||||
T: FromRow<Self::Backend> + Send,
|
T: FromRow<Self::Backend> + Send,
|
||||||
{
|
{
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let params = params.into_params();
|
|
||||||
|
|
||||||
self.parse("", query, ¶ms);
|
self.parse("", query, ¶ms);
|
||||||
self.bind("", "", ¶ms);
|
self.bind("", "", ¶ms);
|
||||||
self.execute("", 2);
|
self.execute("", 2);
|
||||||
|
@ -104,7 +94,7 @@ impl Executor for Postgres {
|
||||||
query: &'q str,
|
query: &'q str,
|
||||||
) -> BoxFuture<'e, crate::Result<Describe<Self::Backend>>> {
|
) -> BoxFuture<'e, crate::Result<Describe<Self::Backend>>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.parse("", query, &QueryParameters::new());
|
self.parse("", query, &Default::default());
|
||||||
self.describe("");
|
self.describe("");
|
||||||
self.sync().await?;
|
self.sync().await?;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use byteorder::{BigEndian, ByteOrder, NetworkEndian};
|
use byteorder::{BigEndian, ByteOrder, NetworkEndian};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct PostgresQueryParameters {
|
pub struct PostgresQueryParameters {
|
||||||
// OIDs of the bind parameters
|
// OIDs of the bind parameters
|
||||||
pub(super) types: Vec<u32>,
|
pub(super) types: Vec<u32>,
|
||||||
|
@ -17,13 +18,9 @@ pub struct PostgresQueryParameters {
|
||||||
impl QueryParameters for PostgresQueryParameters {
|
impl QueryParameters for PostgresQueryParameters {
|
||||||
type Backend = Postgres;
|
type Backend = Postgres;
|
||||||
|
|
||||||
fn new() -> Self {
|
fn reserve(&mut self, binds: usize, bytes: usize) {
|
||||||
Self {
|
self.types.reserve(binds);
|
||||||
// Estimates for average number of bind parameters were
|
self.buf.reserve(bytes);
|
||||||
// chosen from sampling from internal projects
|
|
||||||
types: Vec::with_capacity(4),
|
|
||||||
buf: Vec::with_capacity(32),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind<T>(&mut self, value: T)
|
fn bind<T>(&mut self, value: T)
|
||||||
|
|
|
@ -31,6 +31,10 @@ impl Encode<Postgres> for Vec<u8> {
|
||||||
fn encode(&self, buf: &mut Vec<u8>) -> IsNull {
|
fn encode(&self, buf: &mut Vec<u8>) -> IsNull {
|
||||||
<[u8] as Encode<Postgres>>::encode(self, buf)
|
<[u8] as Encode<Postgres>>::encode(self, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> usize {
|
||||||
|
self.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode<Postgres> for Vec<u8> {
|
impl Decode<Postgres> for Vec<u8> {
|
||||||
|
|
|
@ -38,6 +38,10 @@ impl Encode<Postgres> for String {
|
||||||
fn encode(&self, buf: &mut Vec<u8>) -> IsNull {
|
fn encode(&self, buf: &mut Vec<u8>) -> IsNull {
|
||||||
<str as Encode<Postgres>>::encode(self.as_str(), buf)
|
<str as Encode<Postgres>>::encode(self.as_str(), buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> usize {
|
||||||
|
self.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decode<Postgres> for String {
|
impl Decode<Postgres> for String {
|
||||||
|
|
|
@ -1,84 +1,68 @@
|
||||||
use crate::{
|
use crate::{backend::Backend, encode::Encode, error::Error, executor::Executor, params::{IntoQueryParameters, QueryParameters}, row::FromRow, types::HasSqlType, Row, Decode};
|
||||||
backend::Backend,
|
|
||||||
encode::Encode,
|
|
||||||
error::Error,
|
|
||||||
executor::Executor,
|
|
||||||
params::{IntoQueryParameters, QueryParameters},
|
|
||||||
row::FromRow,
|
|
||||||
types::HasSqlType,
|
|
||||||
Row,
|
|
||||||
};
|
|
||||||
use bitflags::_core::marker::PhantomData;
|
use bitflags::_core::marker::PhantomData;
|
||||||
use futures_core::{future::BoxFuture, stream::BoxStream};
|
use futures_core::{future::BoxFuture, stream::BoxStream};
|
||||||
|
|
||||||
pub struct Query<'q, DB, I = <DB as Backend>::QueryParameters, O = <DB as Backend>::Row>
|
pub struct Query<'q, DB, P = <DB as Backend>::QueryParameters, R = <DB as Backend>::Row>
|
||||||
where
|
where
|
||||||
DB: Backend,
|
DB: Backend,
|
||||||
{
|
{
|
||||||
#[doc(hidden)]
|
query: &'q str,
|
||||||
pub query: &'q str,
|
params: P,
|
||||||
|
record: PhantomData<R>,
|
||||||
#[doc(hidden)]
|
backend: PhantomData<DB>,
|
||||||
pub input: I,
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub output: PhantomData<O>,
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub backend: PhantomData<DB>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'q, DB, I: 'q, O: 'q> Query<'q, DB, I, O>
|
impl<'q, DB, P: 'q, R: 'q> Query<'q, DB, P, R>
|
||||||
where
|
where
|
||||||
DB: Backend,
|
DB: Backend,
|
||||||
DB::QueryParameters: 'q,
|
DB::QueryParameters: 'q,
|
||||||
I: IntoQueryParameters<DB> + Send,
|
P: IntoQueryParameters<DB> + Send,
|
||||||
O: FromRow<DB> + Send + Unpin,
|
R: FromRow<DB> + Send + Unpin,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn execute<E>(self, executor: &'q mut E) -> BoxFuture<'q, crate::Result<u64>>
|
pub fn execute<E>(self, executor: &'q mut E) -> BoxFuture<'q, crate::Result<u64>>
|
||||||
where
|
where
|
||||||
E: Executor<Backend = DB>,
|
E: Executor<Backend = DB>,
|
||||||
{
|
{
|
||||||
executor.execute(self.query, self.input)
|
executor.execute(self.query, self.params.into_params())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch<E>(self, executor: &'q mut E) -> BoxStream<'q, crate::Result<O>>
|
pub fn fetch<E>(self, executor: &'q mut E) -> BoxStream<'q, crate::Result<R>>
|
||||||
where
|
where
|
||||||
E: Executor<Backend = DB>,
|
E: Executor<Backend = DB>,
|
||||||
{
|
{
|
||||||
executor.fetch(self.query, self.input)
|
executor.fetch(self.query, self.params.into_params())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch_all<E>(self, executor: &'q mut E) -> BoxFuture<'q, crate::Result<Vec<O>>>
|
pub fn fetch_all<E>(self, executor: &'q mut E) -> BoxFuture<'q, crate::Result<Vec<R>>>
|
||||||
where
|
where
|
||||||
E: Executor<Backend = DB>,
|
E: Executor<Backend = DB>,
|
||||||
{
|
{
|
||||||
executor.fetch_all(self.query, self.input)
|
executor.fetch_all(self.query, self.params.into_params())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch_optional<E>(self, executor: &'q mut E) -> BoxFuture<'q, crate::Result<Option<O>>>
|
pub fn fetch_optional<E>(self, executor: &'q mut E) -> BoxFuture<'q, crate::Result<Option<R>>>
|
||||||
where
|
where
|
||||||
E: Executor<Backend = DB>,
|
E: Executor<Backend = DB>,
|
||||||
{
|
{
|
||||||
executor.fetch_optional(self.query, self.input)
|
executor.fetch_optional(self.query, self.params.into_params())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch_one<E>(self, executor: &'q mut E) -> BoxFuture<'q, crate::Result<O>>
|
pub fn fetch_one<E>(self, executor: &'q mut E) -> BoxFuture<'q, crate::Result<R>>
|
||||||
where
|
where
|
||||||
E: Executor<Backend = DB>,
|
E: Executor<Backend = DB>,
|
||||||
{
|
{
|
||||||
executor.fetch_one(self.query, self.input)
|
executor.fetch_one(self.query, self.params.into_params())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DB> Query<'_, DB>
|
impl<'q, DB> Query<'q, DB>
|
||||||
where
|
where
|
||||||
DB: Backend,
|
DB: Backend,
|
||||||
{
|
{
|
||||||
/// Bind a value for use with this SQL query.
|
/// Bind a value for use with this SQL query.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Logic Safety
|
||||||
///
|
///
|
||||||
/// This function should be used with care, as SQLx cannot validate
|
/// This function should be used with care, as SQLx cannot validate
|
||||||
/// that the value is of the right type nor can it validate that you have
|
/// that the value is of the right type nor can it validate that you have
|
||||||
|
@ -88,17 +72,47 @@ where
|
||||||
DB: HasSqlType<T>,
|
DB: HasSqlType<T>,
|
||||||
T: Encode<DB>,
|
T: Encode<DB>,
|
||||||
{
|
{
|
||||||
self.input.bind(value);
|
self.params.bind(value);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'q, DB, I, O> Query<'q, DB, I, O> where DB: Backend {
|
/// Bind all query parameters at once.
|
||||||
pub fn with_output_type<O_>(self) -> Query<'q, DB, I, O_> {
|
///
|
||||||
|
/// If any parameters were previously bound with `.bind()` they are discarded.
|
||||||
|
///
|
||||||
|
/// # Logic Safety
|
||||||
|
///
|
||||||
|
/// This function should be used with care, as SQLx cannot validate
|
||||||
|
/// that the value is of the right type nor can it validate that you have
|
||||||
|
/// passed the correct number of parameters.
|
||||||
|
pub fn bind_all<I>(self, values: I) -> Query<'q, DB, I> where I: IntoQueryParameters<DB> {
|
||||||
Query {
|
Query {
|
||||||
query: self.query,
|
query: self.query,
|
||||||
input: self.input,
|
params: values,
|
||||||
output: PhantomData,
|
record: PhantomData,
|
||||||
|
backend: PhantomData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//noinspection RsSelfConvention
|
||||||
|
impl<'q, DB, I, R> Query<'q, DB, I, R> where DB: Backend {
|
||||||
|
|
||||||
|
/// Change the expected output type of the query to a single scalar value.
|
||||||
|
pub fn as_scalar<R_>(self) -> Query<'q, DB, I, R_> where R_: Decode<DB> {
|
||||||
|
Query {
|
||||||
|
query: self.query,
|
||||||
|
params: self.params,
|
||||||
|
record: PhantomData,
|
||||||
|
backend: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change the expected output of the query to a new type implementing `FromRow`.
|
||||||
|
pub fn as_record<R_>(self) -> Query<'q, DB, I, R_> where R_: FromRow<DB> {
|
||||||
|
Query {
|
||||||
|
query: self.query,
|
||||||
|
params: self.params,
|
||||||
|
record: PhantomData,
|
||||||
backend: PhantomData,
|
backend: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,8 +126,8 @@ where
|
||||||
{
|
{
|
||||||
Query {
|
Query {
|
||||||
query,
|
query,
|
||||||
input: DB::QueryParameters::new(),
|
params: Default::default(),
|
||||||
output: PhantomData,
|
record: PhantomData,
|
||||||
backend: PhantomData,
|
backend: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,13 @@ macro_rules! impl_from_row {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Scalar conversions for rows
|
||||||
|
impl<T, DB> FromRow<DB> for T where DB: Backend + HasSqlType<T>, T: Decode<DB> {
|
||||||
|
fn from_row(row: <DB as Backend>::Row) -> Self {
|
||||||
|
row.get(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
macro_rules! impl_from_row_for_backend {
|
macro_rules! impl_from_row_for_backend {
|
||||||
($B:ident, $row:ident) => {
|
($B:ident, $row:ident) => {
|
||||||
|
|
|
@ -132,12 +132,9 @@ pub async fn process_sql<DB: BackendExt>(
|
||||||
|
|
||||||
#params
|
#params
|
||||||
|
|
||||||
sqlx::Query::<#backend_path, _, (#record_type)> {
|
sqlx::query::<#backend_path>(#query)
|
||||||
query: #query,
|
.bind_all(params)
|
||||||
input: params,
|
.as_record::<#record_type>()
|
||||||
output: ::core::marker::PhantomData,
|
|
||||||
backend: ::core::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}})
|
}})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,12 @@ async fn postgres_query() -> sqlx::Result<()> {
|
||||||
sqlx::Connection::<sqlx::Postgres>::open(&dotenv::var("DATABASE_URL").unwrap()).await?;
|
sqlx::Connection::<sqlx::Postgres>::open(&dotenv::var("DATABASE_URL").unwrap()).await?;
|
||||||
|
|
||||||
let uuid: Uuid = "256ba9c8-0048-11ea-b0f0-8f04859d047e".parse().unwrap();
|
let uuid: Uuid = "256ba9c8-0048-11ea-b0f0-8f04859d047e".parse().unwrap();
|
||||||
let account = sqlx::query!("SELECT * from accounts where id != $1", uuid)
|
let account_id = sqlx::query!("SELECT id from accounts where id != $1", uuid)
|
||||||
|
.as_scalar::<Uuid>()
|
||||||
.fetch_one(&mut conn)
|
.fetch_one(&mut conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
println!("account ID: {:?}", account.id);
|
println!("account ID: {:?}", account_id);
|
||||||
println!("account name: {}", account.name);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue