mirror of
https://github.com/launchbadge/sqlx
synced 2024-11-14 00:07:05 +00:00
Wrap the query in a top-level SqlQuery to facilitate type inference.
This commit is contained in:
parent
154cb51bf6
commit
6a18d0effd
11 changed files with 111 additions and 74 deletions
|
@ -2,10 +2,7 @@
|
|||
|
||||
use failure::Fallible;
|
||||
use futures::{future, TryStreamExt};
|
||||
use sqlx::{
|
||||
pg::{Pg, PgQuery},
|
||||
Connection, Query,
|
||||
};
|
||||
use sqlx::{pg::Pg, Connection};
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
|
@ -51,10 +48,10 @@ async fn main() -> Fallible<()> {
|
|||
}
|
||||
|
||||
async fn ensure_schema(conn: &mut Connection<Pg>) -> Fallible<()> {
|
||||
sqlx::query::<PgQuery>("BEGIN").execute(conn).await?;
|
||||
sqlx::query("BEGIN").execute(conn).await?;
|
||||
|
||||
// language=sql
|
||||
sqlx::query::<PgQuery>(
|
||||
sqlx::query(
|
||||
r#"
|
||||
CREATE TABLE IF NOT EXISTS tasks (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
|
@ -67,14 +64,14 @@ CREATE TABLE IF NOT EXISTS tasks (
|
|||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
sqlx::query::<PgQuery>("COMMIT").execute(conn).await?;
|
||||
sqlx::query("COMMIT").execute(conn).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn print_all_tasks(conn: &mut Connection<Pg>) -> Fallible<()> {
|
||||
// language=sql
|
||||
sqlx::query::<PgQuery>(
|
||||
sqlx::query(
|
||||
r#"
|
||||
SELECT id, text
|
||||
FROM tasks
|
||||
|
@ -95,7 +92,7 @@ WHERE done_at IS NULL
|
|||
|
||||
async fn add_task(conn: &mut Connection<Pg>, text: &str) -> Fallible<()> {
|
||||
// language=sql
|
||||
sqlx::query::<PgQuery>(
|
||||
sqlx::query(
|
||||
r#"
|
||||
INSERT INTO tasks ( text )
|
||||
VALUES ( $1 )
|
||||
|
@ -110,7 +107,7 @@ VALUES ( $1 )
|
|||
|
||||
async fn mark_task_as_done(conn: &mut Connection<Pg>, id: i64) -> Fallible<()> {
|
||||
// language=sql
|
||||
sqlx::query::<PgQuery>(
|
||||
sqlx::query(
|
||||
r#"
|
||||
UPDATE tasks
|
||||
SET done_at = now()
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
use crate::{connection::RawConnection, row::Row};
|
||||
pub(crate) use self::internal::BackendAssocRawQuery;
|
||||
use crate::{connection::RawConnection, query::RawQuery, row::Row};
|
||||
|
||||
mod internal {
|
||||
pub trait BackendAssocRawQuery<'q, DB>
|
||||
where
|
||||
DB: super::Backend,
|
||||
{
|
||||
type RawQuery: super::RawQuery<'q, Backend = DB>;
|
||||
}
|
||||
}
|
||||
|
||||
/// A database backend.
|
||||
///
|
||||
|
@ -6,7 +16,7 @@ use crate::{connection::RawConnection, row::Row};
|
|||
/// e.g., implementing `ToSql for Uuid` differently for MySQL and Postgres) and
|
||||
/// to query capabilities within a database backend (e.g., with a specific
|
||||
/// `Connection` can we `bind` a `i64`?).
|
||||
pub trait Backend: Sized {
|
||||
pub trait Backend: Sized + for<'q> BackendAssocRawQuery<'q, Self> {
|
||||
type RawConnection: RawConnection<Backend = Self>;
|
||||
type Row: Row<Backend = Self>;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{backend::Backend, executor::Executor, query::Query, row::FromRow};
|
||||
use crate::{backend::Backend, executor::Executor, query::RawQuery, row::FromRow};
|
||||
use crossbeam_queue::SegQueue;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use futures::{
|
||||
|
@ -30,21 +30,21 @@ pub trait RawConnection: Send {
|
|||
|
||||
fn execute<'c, 'q, Q: 'q>(&'c mut self, query: Q) -> BoxFuture<'c, io::Result<u64>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>;
|
||||
Q: RawQuery<'q, Backend = Self::Backend>;
|
||||
|
||||
fn fetch<'c, 'q, Q: 'q>(
|
||||
&'c mut self,
|
||||
query: Q,
|
||||
) -> BoxStream<'c, io::Result<<Self::Backend as Backend>::Row>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>;
|
||||
Q: RawQuery<'q, Backend = Self::Backend>;
|
||||
|
||||
fn fetch_optional<'c, 'q, Q: 'q>(
|
||||
&'c mut self,
|
||||
query: Q,
|
||||
) -> BoxFuture<'c, io::Result<Option<<Self::Backend as Backend>::Row>>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>;
|
||||
Q: RawQuery<'q, Backend = Self::Backend>;
|
||||
}
|
||||
|
||||
pub struct Connection<DB>(Arc<SharedConnection<DB>>)
|
||||
|
@ -92,7 +92,7 @@ where
|
|||
|
||||
fn execute<'c, 'q, Q: 'q + 'c>(&'c self, query: Q) -> BoxFuture<'c, io::Result<u64>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let mut conn = self.get().await;
|
||||
|
@ -102,7 +102,7 @@ where
|
|||
|
||||
fn fetch<'c, 'q, A: 'c, T: 'c, Q: 'q + 'c>(&'c self, query: Q) -> BoxStream<'c, io::Result<T>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
T: FromRow<A, Self::Backend> + Send + Unpin,
|
||||
{
|
||||
Box::pin(async_stream::try_stream! {
|
||||
|
@ -120,7 +120,7 @@ where
|
|||
query: Q,
|
||||
) -> BoxFuture<'c, io::Result<Option<T>>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
T: FromRow<A, Self::Backend>,
|
||||
{
|
||||
Box::pin(async move {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{backend::Backend, row::FromRow, Query};
|
||||
use crate::{backend::Backend, query::RawQuery, row::FromRow};
|
||||
use futures::{future::BoxFuture, stream::BoxStream};
|
||||
use std::io;
|
||||
|
||||
|
@ -7,11 +7,11 @@ pub trait Executor: Send {
|
|||
|
||||
fn execute<'c, 'q, Q: 'q + 'c>(&'c self, query: Q) -> BoxFuture<'c, io::Result<u64>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>;
|
||||
Q: RawQuery<'q, Backend = Self::Backend>;
|
||||
|
||||
fn fetch<'c, 'q, A: 'c, T: 'c, Q: 'q + 'c>(&'c self, query: Q) -> BoxStream<'c, io::Result<T>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
T: FromRow<A, Self::Backend> + Send + Unpin;
|
||||
|
||||
fn fetch_optional<'c, 'q, A: 'c, T: 'c, Q: 'q + 'c>(
|
||||
|
@ -19,7 +19,7 @@ pub trait Executor: Send {
|
|||
query: Q,
|
||||
) -> BoxFuture<'c, io::Result<Option<T>>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
T: FromRow<A, Self::Backend>;
|
||||
}
|
||||
|
||||
|
@ -32,14 +32,14 @@ where
|
|||
#[inline]
|
||||
fn execute<'c, 'q, Q: 'q + 'c>(&'c self, query: Q) -> BoxFuture<'c, io::Result<u64>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
{
|
||||
(*self).execute(query)
|
||||
}
|
||||
|
||||
fn fetch<'c, 'q, A: 'c, T: 'c, Q: 'q + 'c>(&'c self, query: Q) -> BoxStream<'c, io::Result<T>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
T: FromRow<A, Self::Backend> + Send + Unpin,
|
||||
{
|
||||
(*self).fetch(query)
|
||||
|
@ -50,7 +50,7 @@ where
|
|||
query: Q,
|
||||
) -> BoxFuture<'c, io::Result<Option<T>>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
T: FromRow<A, Self::Backend>,
|
||||
{
|
||||
(*self).fetch_optional(query)
|
||||
|
|
|
@ -38,7 +38,7 @@ mod query;
|
|||
pub use self::{
|
||||
connection::Connection,
|
||||
pool::Pool,
|
||||
query::{query, Query},
|
||||
query::{query, SqlQuery},
|
||||
};
|
||||
|
||||
// TODO: Remove after Mariadb transitions to URIs
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
use crate::backend::Backend;
|
||||
use crate::backend::{Backend, BackendAssocRawQuery};
|
||||
|
||||
pub struct Pg;
|
||||
|
||||
impl<'q> BackendAssocRawQuery<'q, Pg> for Pg {
|
||||
type RawQuery = super::PgRawQuery<'q>;
|
||||
}
|
||||
|
||||
impl Backend for Pg {
|
||||
type RawConnection = super::PgRawConnection;
|
||||
type Row = super::PgRow;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use super::{
|
||||
protocol::{Authentication, Encode, Message, PasswordMessage, StartupMessage, Terminate},
|
||||
Pg, PgQuery, PgRow,
|
||||
Pg, PgRawQuery, PgRow,
|
||||
};
|
||||
use crate::{connection::RawConnection, query::Query, row::FromRow};
|
||||
use crate::{connection::RawConnection, query::RawQuery, row::FromRow};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use futures::{
|
||||
future::BoxFuture,
|
||||
|
@ -169,7 +169,7 @@ impl RawConnection for PgRawConnection {
|
|||
|
||||
fn execute<'c, 'q, Q: 'q>(&'c mut self, query: Q) -> BoxFuture<'c, io::Result<u64>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
{
|
||||
query.finish(self);
|
||||
|
||||
|
@ -178,7 +178,7 @@ impl RawConnection for PgRawConnection {
|
|||
|
||||
fn fetch<'c, 'q, Q: 'q>(&'c mut self, query: Q) -> BoxStream<'c, io::Result<PgRow>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
{
|
||||
query.finish(self);
|
||||
|
||||
|
@ -190,7 +190,7 @@ impl RawConnection for PgRawConnection {
|
|||
query: Q,
|
||||
) -> BoxFuture<'c, io::Result<Option<PgRow>>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
{
|
||||
query.finish(self);
|
||||
|
||||
|
|
|
@ -6,4 +6,4 @@ mod query;
|
|||
mod row;
|
||||
pub mod types;
|
||||
|
||||
pub use self::{backend::Pg, connection::PgRawConnection, query::PgQuery, row::PgRow};
|
||||
pub use self::{backend::Pg, connection::PgRawConnection, query::PgRawQuery, row::PgRow};
|
||||
|
|
|
@ -3,7 +3,7 @@ use super::{
|
|||
Pg, PgRawConnection, PgRow,
|
||||
};
|
||||
use crate::{
|
||||
query::Query,
|
||||
query::RawQuery,
|
||||
row::FromRow,
|
||||
serialize::{IsNull, ToSql},
|
||||
types::HasSqlType,
|
||||
|
@ -16,7 +16,7 @@ use futures::{
|
|||
};
|
||||
use std::io;
|
||||
|
||||
pub struct PgQuery<'q> {
|
||||
pub struct PgRawQuery<'q> {
|
||||
limit: i32,
|
||||
query: &'q str,
|
||||
// OIDs of the bind parameters
|
||||
|
@ -25,7 +25,7 @@ pub struct PgQuery<'q> {
|
|||
buf: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<'q> Query<'q> for PgQuery<'q> {
|
||||
impl<'q> RawQuery<'q> for PgRawQuery<'q> {
|
||||
type Backend = Pg;
|
||||
|
||||
fn new(query: &'q str) -> Self {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
backend::Backend, connection::RawConnection, executor::Executor, query::Query, row::FromRow,
|
||||
backend::Backend, connection::RawConnection, executor::Executor, query::RawQuery, row::FromRow,
|
||||
Connection,
|
||||
};
|
||||
use crossbeam_queue::{ArrayQueue, SegQueue};
|
||||
|
@ -136,7 +136,7 @@ where
|
|||
|
||||
fn execute<'c, 'q, Q: 'q + 'c>(&'c self, query: Q) -> BoxFuture<'c, io::Result<u64>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let live = self.0.acquire().await?;
|
||||
|
@ -148,7 +148,7 @@ where
|
|||
|
||||
fn fetch<'c, 'q, A: 'c, T: 'c, Q: 'q + 'c>(&'c self, query: Q) -> BoxStream<'c, io::Result<T>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
T: FromRow<A, Self::Backend> + Send + Unpin,
|
||||
{
|
||||
Box::pin(async_stream::try_stream! {
|
||||
|
@ -167,7 +167,7 @@ where
|
|||
query: Q,
|
||||
) -> BoxFuture<'c, io::Result<Option<T>>>
|
||||
where
|
||||
Q: Query<'q, Backend = Self::Backend>,
|
||||
Q: RawQuery<'q, Backend = Self::Backend>,
|
||||
T: FromRow<A, Self::Backend>,
|
||||
{
|
||||
Box::pin(async move {
|
||||
|
|
92
src/query.rs
92
src/query.rs
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
backend::Backend,
|
||||
backend::{Backend, BackendAssocRawQuery},
|
||||
executor::Executor,
|
||||
pool::Pool,
|
||||
row::FromRow,
|
||||
|
@ -9,65 +9,91 @@ use crate::{
|
|||
use futures::{future::BoxFuture, stream::BoxStream};
|
||||
use std::io;
|
||||
|
||||
pub trait Query<'q>: Sized + Send + Sync {
|
||||
pub trait RawQuery<'q>: Sized + Send + Sync {
|
||||
type Backend: Backend;
|
||||
|
||||
fn new(query: &'q str) -> Self;
|
||||
|
||||
#[inline]
|
||||
fn bind<T>(self, value: T) -> Self
|
||||
where
|
||||
Self::Backend: HasSqlType<<T as AsSqlType<Self::Backend>>::SqlType>,
|
||||
T: AsSqlType<Self::Backend>
|
||||
+ ToSql<<T as AsSqlType<Self::Backend>>::SqlType, Self::Backend>,
|
||||
{
|
||||
self.bind_as::<T::SqlType, T>(value)
|
||||
}
|
||||
|
||||
fn bind_as<ST, T>(self, value: T) -> Self
|
||||
where
|
||||
Self::Backend: HasSqlType<ST>,
|
||||
T: ToSql<ST, Self::Backend>;
|
||||
|
||||
fn finish(self, conn: &mut <Self::Backend as Backend>::RawConnection);
|
||||
}
|
||||
|
||||
pub struct SqlQuery<'q, E>
|
||||
where
|
||||
E: Executor,
|
||||
{
|
||||
inner:
|
||||
<<E as Executor>::Backend as BackendAssocRawQuery<'q, <E as Executor>::Backend>>::RawQuery,
|
||||
}
|
||||
|
||||
impl<'q, E> SqlQuery<'q, E>
|
||||
where
|
||||
E: Executor,
|
||||
{
|
||||
#[inline]
|
||||
fn execute<'c, C>(self, executor: &'c C) -> BoxFuture<'c, io::Result<u64>>
|
||||
where
|
||||
Self: 'c + 'q,
|
||||
C: Executor<Backend = Self::Backend>,
|
||||
{
|
||||
executor.execute(self)
|
||||
pub fn new(query: &'q str) -> Self {
|
||||
Self {
|
||||
inner: <<E as Executor>::Backend as BackendAssocRawQuery<
|
||||
'q,
|
||||
<E as Executor>::Backend,
|
||||
>>::RawQuery::new(query),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fetch<'c, A: 'c, T: 'c, C>(self, executor: &'c C) -> BoxStream<'c, io::Result<T>>
|
||||
pub fn bind<T>(self, value: T) -> Self
|
||||
where
|
||||
Self: 'c + 'q,
|
||||
C: Executor<Backend = Self::Backend>,
|
||||
T: FromRow<A, Self::Backend> + Send + Unpin,
|
||||
E::Backend: HasSqlType<<T as AsSqlType<E::Backend>>::SqlType>,
|
||||
T: AsSqlType<E::Backend> + ToSql<<T as AsSqlType<E::Backend>>::SqlType, E::Backend>,
|
||||
{
|
||||
executor.fetch(self)
|
||||
self.bind_as::<T::SqlType, T>(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fetch_optional<'c, A: 'c, T: 'c, C>(
|
||||
pub fn bind_as<ST, T>(mut self, value: T) -> Self
|
||||
where
|
||||
E::Backend: HasSqlType<ST>,
|
||||
T: ToSql<ST, E::Backend>,
|
||||
{
|
||||
self.inner = self.inner.bind_as::<ST, T>(value);
|
||||
self
|
||||
}
|
||||
|
||||
// TODO: These methods should go on a [Execute] trait (so more execut-able things can be defined)
|
||||
|
||||
#[inline]
|
||||
pub fn execute(self, executor: &'q E) -> BoxFuture<'q, io::Result<u64>> {
|
||||
executor.execute(self.inner)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn fetch<A: 'q, T: 'q>(self, executor: &'q E) -> BoxStream<'q, io::Result<T>>
|
||||
where
|
||||
T: FromRow<A, E::Backend> + Send + Unpin,
|
||||
{
|
||||
executor.fetch(self.inner)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn fetch_optional<A: 'q, T: 'q>(
|
||||
self,
|
||||
executor: &'c C,
|
||||
) -> BoxFuture<'c, io::Result<Option<T>>>
|
||||
executor: &'q E,
|
||||
) -> BoxFuture<'q, io::Result<Option<T>>>
|
||||
where
|
||||
Self: 'c + 'q,
|
||||
C: Executor<Backend = Self::Backend>,
|
||||
T: FromRow<A, Self::Backend>,
|
||||
T: FromRow<A, E::Backend>,
|
||||
{
|
||||
executor.fetch_optional(self)
|
||||
executor.fetch_optional(self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn query<'q, Q>(query: &'q str) -> Q
|
||||
pub fn query<'q, E>(query: &'q str) -> SqlQuery<'q, E>
|
||||
where
|
||||
Q: Query<'q>,
|
||||
E: Executor,
|
||||
{
|
||||
Q::new(query)
|
||||
SqlQuery::new(query)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue