mirror of
				https://github.com/launchbadge/sqlx.git
				synced 2025-11-04 07:22:53 +00:00 
			
		
		
		
	Add sqlx::Row
- Rename the existing trait to an internal RawRow trait - Row is used for selecting a dyn and deferring pulling its values out till later - FromSqlRow -> FromRow
This commit is contained in:
		
							parent
							
								
									1b92fe733b
								
							
						
					
					
						commit
						b14d3da2ee
					
				@ -1,4 +1,4 @@
 | 
			
		||||
use sqlx::{Pool, Postgres};
 | 
			
		||||
use sqlx::{Row, Pool, Postgres};
 | 
			
		||||
use std::env;
 | 
			
		||||
use tide::error::ResultExt;
 | 
			
		||||
use tide::http::StatusCode;
 | 
			
		||||
@ -19,6 +19,8 @@ async fn main() -> anyhow::Result<()> {
 | 
			
		||||
 | 
			
		||||
    app.at("/v1/user").get(get_all_users).post(create_user);
 | 
			
		||||
 | 
			
		||||
    app.at("/v1/user/latest").get(get_newest_user);
 | 
			
		||||
 | 
			
		||||
    app.serve(("localhost", 8080))?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
@ -51,6 +53,25 @@ async fn get_all_users(cx: Context<Pool<Postgres>>) -> EndpointResult {
 | 
			
		||||
    Ok(response::json(users))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn get_newest_user(cx: Context<Pool<Postgres>>) -> EndpointResult {
 | 
			
		||||
    let mut pool = cx.state();
 | 
			
		||||
 | 
			
		||||
    // This is an example of getting back a dyn row that we ...
 | 
			
		||||
    let row: Row<Postgres> = sqlx::query(
 | 
			
		||||
        r#"
 | 
			
		||||
SELECT id
 | 
			
		||||
FROM users
 | 
			
		||||
ORDER BY created_at DESC
 | 
			
		||||
LIMIT 1
 | 
			
		||||
        "#)
 | 
			
		||||
        .fetch_one(&mut pool)
 | 
			
		||||
        .await
 | 
			
		||||
        .server_err()?;
 | 
			
		||||
 | 
			
		||||
    // ... can later ask its values by index
 | 
			
		||||
    Ok(response::json(vec![row.get::<i32>(0)]))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize)]
 | 
			
		||||
struct CreateUserRequest {
 | 
			
		||||
    name: String,
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
use crate::describe::Describe;
 | 
			
		||||
use crate::{query::QueryParameters, row::Row, types::HasTypeMetadata};
 | 
			
		||||
use crate::{query::QueryParameters, row::RawRow, types::HasTypeMetadata};
 | 
			
		||||
use async_trait::async_trait;
 | 
			
		||||
use futures_core::stream::BoxStream;
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ pub trait Backend: HasTypeMetadata + Send + Sync + Sized {
 | 
			
		||||
    type QueryParameters: QueryParameters<Backend = Self>;
 | 
			
		||||
 | 
			
		||||
    /// The concrete `Row` implementation for this backend.
 | 
			
		||||
    type Row: Row<Backend = Self>;
 | 
			
		||||
    type Row: RawRow<Backend = Self>;
 | 
			
		||||
 | 
			
		||||
    /// The identifier for tables; in Postgres this is an `oid` while
 | 
			
		||||
    /// in MariaDB/MySQL this is the qualified name of the table.
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
use crate::{query::IntoQueryParameters, Backend, Executor, FromSqlRow};
 | 
			
		||||
use crate::{query::IntoQueryParameters, Backend, Executor, FromRow};
 | 
			
		||||
use futures_core::{future::BoxFuture, stream::BoxStream};
 | 
			
		||||
use std::marker::PhantomData;
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ impl<DB, P, O> CompiledSql<P, O, DB>
 | 
			
		||||
where
 | 
			
		||||
    DB: Backend,
 | 
			
		||||
    P: IntoQueryParameters<DB> + Send,
 | 
			
		||||
    O: FromSqlRow<DB> + Send + Unpin,
 | 
			
		||||
    O: FromRow<DB> + Send + Unpin,
 | 
			
		||||
{
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn execute<'e, E: 'e>(self, executor: &'e mut E) -> BoxFuture<'e, crate::Result<u64>>
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ use crate::{
 | 
			
		||||
    executor::Executor,
 | 
			
		||||
    pool::{Live, SharedPool},
 | 
			
		||||
    query::IntoQueryParameters,
 | 
			
		||||
    row::FromSqlRow,
 | 
			
		||||
    row::FromRow,
 | 
			
		||||
};
 | 
			
		||||
use futures_core::{future::BoxFuture, stream::BoxStream};
 | 
			
		||||
use futures_util::stream::StreamExt;
 | 
			
		||||
@ -70,7 +70,7 @@ where
 | 
			
		||||
    ) -> BoxStream<'c, Result<T, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        A: IntoQueryParameters<Self::Backend> + Send,
 | 
			
		||||
        T: FromSqlRow<Self::Backend> + Send + Unpin,
 | 
			
		||||
        T: FromRow<Self::Backend> + Send + Unpin,
 | 
			
		||||
    {
 | 
			
		||||
        Box::pin(async_stream::try_stream! {
 | 
			
		||||
            let mut s = self.live.fetch(query, params.into_params());
 | 
			
		||||
@ -88,7 +88,7 @@ where
 | 
			
		||||
    ) -> BoxFuture<'c, Result<Option<T>, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        A: IntoQueryParameters<Self::Backend> + Send,
 | 
			
		||||
        T: FromSqlRow<Self::Backend>,
 | 
			
		||||
        T: FromRow<Self::Backend>,
 | 
			
		||||
    {
 | 
			
		||||
        Box::pin(async move {
 | 
			
		||||
            let row = self
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
use crate::{backend::Backend, error::Error, query::IntoQueryParameters, row::FromSqlRow};
 | 
			
		||||
use crate::{backend::Backend, error::Error, query::IntoQueryParameters, row::FromRow};
 | 
			
		||||
use futures_core::{future::BoxFuture, stream::BoxStream};
 | 
			
		||||
use futures_util::TryStreamExt;
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@ pub trait Executor: Send {
 | 
			
		||||
    ) -> BoxStream<'c, Result<T, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        A: IntoQueryParameters<Self::Backend> + Send,
 | 
			
		||||
        T: FromSqlRow<Self::Backend> + Send + Unpin;
 | 
			
		||||
        T: FromRow<Self::Backend> + Send + Unpin;
 | 
			
		||||
 | 
			
		||||
    fn fetch_all<'c, 'q: 'c, T: 'c, A: 'c>(
 | 
			
		||||
        &'c mut self,
 | 
			
		||||
@ -29,7 +29,7 @@ pub trait Executor: Send {
 | 
			
		||||
    ) -> BoxFuture<'c, Result<Vec<T>, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        A: IntoQueryParameters<Self::Backend> + Send,
 | 
			
		||||
        T: FromSqlRow<Self::Backend> + Send + Unpin,
 | 
			
		||||
        T: FromRow<Self::Backend> + Send + Unpin,
 | 
			
		||||
    {
 | 
			
		||||
        Box::pin(self.fetch(query, params).try_collect())
 | 
			
		||||
    }
 | 
			
		||||
@ -41,7 +41,7 @@ pub trait Executor: Send {
 | 
			
		||||
    ) -> BoxFuture<'c, Result<Option<T>, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        A: IntoQueryParameters<Self::Backend> + Send,
 | 
			
		||||
        T: FromSqlRow<Self::Backend> + Send;
 | 
			
		||||
        T: FromRow<Self::Backend> + Send;
 | 
			
		||||
 | 
			
		||||
    fn fetch_one<'c, 'q: 'c, T: 'c, A: 'c>(
 | 
			
		||||
        &'c mut self,
 | 
			
		||||
@ -50,7 +50,7 @@ pub trait Executor: Send {
 | 
			
		||||
    ) -> BoxFuture<'c, Result<T, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        A: IntoQueryParameters<Self::Backend> + Send,
 | 
			
		||||
        T: FromSqlRow<Self::Backend> + Send,
 | 
			
		||||
        T: FromRow<Self::Backend> + Send,
 | 
			
		||||
    {
 | 
			
		||||
        let fut = self.fetch_optional(query, params);
 | 
			
		||||
        Box::pin(async move { fut.await?.ok_or(Error::NotFound) })
 | 
			
		||||
 | 
			
		||||
@ -42,7 +42,7 @@ pub use self::{
 | 
			
		||||
    error::{Error, Result},
 | 
			
		||||
    executor::Executor,
 | 
			
		||||
    pool::Pool,
 | 
			
		||||
    row::{FromSqlRow, Row},
 | 
			
		||||
    row::{FromRow, Row},
 | 
			
		||||
    sql::{query, SqlQuery},
 | 
			
		||||
    types::HasSqlType,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -84,5 +84,5 @@ impl Backend for MariaDb {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl_from_sql_row_tuples_for_backend!(MariaDb);
 | 
			
		||||
impl_from_row_for_backend!(MariaDb);
 | 
			
		||||
impl_into_query_parameters_for_backend!(MariaDb);
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,11 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    mariadb::{protocol::ResultRow, MariaDb},
 | 
			
		||||
    row::Row,
 | 
			
		||||
};
 | 
			
		||||
use crate::mariadb::{protocol::ResultRow, MariaDb};
 | 
			
		||||
use crate::row::RawRow;
 | 
			
		||||
 | 
			
		||||
pub struct MariaDbRow(pub(super) ResultRow);
 | 
			
		||||
 | 
			
		||||
impl Row for MariaDbRow {
 | 
			
		||||
impl RawRow for MariaDbRow {
 | 
			
		||||
    type Backend = MariaDb;
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn is_empty(&self) -> bool {
 | 
			
		||||
        self.0.values.is_empty()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn len(&self) -> usize {
 | 
			
		||||
        self.0.values.len()
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    backend::Backend, connection::Connection, error::Error, executor::Executor,
 | 
			
		||||
    query::IntoQueryParameters, row::FromSqlRow,
 | 
			
		||||
    query::IntoQueryParameters, row::FromRow,
 | 
			
		||||
};
 | 
			
		||||
use futures_channel::oneshot;
 | 
			
		||||
use futures_core::{future::BoxFuture, stream::BoxStream};
 | 
			
		||||
@ -258,7 +258,7 @@ where
 | 
			
		||||
    ) -> BoxStream<'c, Result<T, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        A: IntoQueryParameters<Self::Backend> + Send,
 | 
			
		||||
        T: FromSqlRow<Self::Backend> + Send + Unpin,
 | 
			
		||||
        T: FromRow<Self::Backend> + Send + Unpin,
 | 
			
		||||
    {
 | 
			
		||||
        Box::pin(async_stream::try_stream! {
 | 
			
		||||
            let mut self_ = &*self;
 | 
			
		||||
@ -279,7 +279,7 @@ where
 | 
			
		||||
    ) -> BoxFuture<'c, Result<Option<T>, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        A: IntoQueryParameters<Self::Backend> + Send,
 | 
			
		||||
        T: FromSqlRow<Self::Backend> + Send,
 | 
			
		||||
        T: FromRow<Self::Backend> + Send,
 | 
			
		||||
    {
 | 
			
		||||
        Box::pin(async move {
 | 
			
		||||
            <&Pool<DB> as Executor>::fetch_optional(&mut &*self, query, params).await
 | 
			
		||||
@ -315,7 +315,7 @@ where
 | 
			
		||||
    ) -> BoxStream<'c, Result<T, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        A: IntoQueryParameters<Self::Backend> + Send,
 | 
			
		||||
        T: FromSqlRow<Self::Backend> + Send + Unpin,
 | 
			
		||||
        T: FromRow<Self::Backend> + Send + Unpin,
 | 
			
		||||
    {
 | 
			
		||||
        Box::pin(async_stream::try_stream! {
 | 
			
		||||
            let mut live = self.0.acquire().await?;
 | 
			
		||||
@ -334,7 +334,7 @@ where
 | 
			
		||||
    ) -> BoxFuture<'c, Result<Option<T>, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        A: IntoQueryParameters<Self::Backend> + Send,
 | 
			
		||||
        T: FromSqlRow<Self::Backend> + Send,
 | 
			
		||||
        T: FromRow<Self::Backend> + Send,
 | 
			
		||||
    {
 | 
			
		||||
        Box::pin(async move {
 | 
			
		||||
            let mut live = self.0.acquire().await?;
 | 
			
		||||
 | 
			
		||||
@ -146,5 +146,5 @@ impl Backend for Postgres {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl_from_sql_row_tuples_for_backend!(Postgres);
 | 
			
		||||
impl_from_row_for_backend!(Postgres);
 | 
			
		||||
impl_into_query_parameters_for_backend!(Postgres);
 | 
			
		||||
 | 
			
		||||
@ -1,17 +1,12 @@
 | 
			
		||||
use super::{protocol::DataRow, Postgres};
 | 
			
		||||
use crate::row::Row;
 | 
			
		||||
use crate::row::RawRow;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct PostgresRow(pub(crate) DataRow);
 | 
			
		||||
 | 
			
		||||
impl Row for PostgresRow {
 | 
			
		||||
impl RawRow for PostgresRow {
 | 
			
		||||
    type Backend = Postgres;
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn is_empty(&self) -> bool {
 | 
			
		||||
        self.0.is_empty()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn len(&self) -> usize {
 | 
			
		||||
        self.0.len()
 | 
			
		||||
 | 
			
		||||
@ -1,58 +1,73 @@
 | 
			
		||||
use crate::{backend::Backend, decode::Decode, types::HasSqlType};
 | 
			
		||||
 | 
			
		||||
pub trait Row: Send {
 | 
			
		||||
pub trait RawRow: Send {
 | 
			
		||||
    type Backend: Backend;
 | 
			
		||||
 | 
			
		||||
    fn is_empty(&self) -> bool;
 | 
			
		||||
 | 
			
		||||
    fn len(&self) -> usize;
 | 
			
		||||
 | 
			
		||||
    fn get_raw(&self, index: usize) -> Option<&[u8]>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn get<T>(&self, index: usize) -> T
 | 
			
		||||
pub struct Row<DB>(pub(crate) DB::Row)
 | 
			
		||||
where
 | 
			
		||||
    DB: Backend;
 | 
			
		||||
 | 
			
		||||
impl<DB> Row<DB>
 | 
			
		||||
where
 | 
			
		||||
    DB: Backend,
 | 
			
		||||
{
 | 
			
		||||
    pub fn get<T>(&self, index: usize) -> T
 | 
			
		||||
    where
 | 
			
		||||
        Self::Backend: HasSqlType<T>,
 | 
			
		||||
        T: Decode<Self::Backend>,
 | 
			
		||||
        DB: HasSqlType<T>,
 | 
			
		||||
        T: Decode<DB>,
 | 
			
		||||
    {
 | 
			
		||||
        T::decode(self.get_raw(index))
 | 
			
		||||
        T::decode(self.0.get_raw(index))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait FromSqlRow<DB: Backend> {
 | 
			
		||||
    fn from_row<R: Row<Backend = DB>>(row: R) -> Self;
 | 
			
		||||
pub trait FromRow<DB: Backend> {
 | 
			
		||||
    fn from_row(row: DB::Row) -> Self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T, DB> FromSqlRow<DB> for T
 | 
			
		||||
impl<T, DB> FromRow<DB> for T
 | 
			
		||||
where
 | 
			
		||||
    DB: Backend + HasSqlType<T>,
 | 
			
		||||
    T: Decode<DB>,
 | 
			
		||||
{
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn from_row<R: Row<Backend = DB>>(row: R) -> Self {
 | 
			
		||||
        row.get::<T>(0)
 | 
			
		||||
    fn from_row(row: DB::Row) -> Self {
 | 
			
		||||
        T::decode(row.get_raw(0))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(unused)]
 | 
			
		||||
macro_rules! impl_from_sql_row_tuple {
 | 
			
		||||
    ($B:ident: $( ($idx:tt) -> $T:ident );+;) => {
 | 
			
		||||
        impl<$($T,)+> crate::row::FromSqlRow<$B> for ($($T,)+)
 | 
			
		||||
        impl<$($T,)+> crate::row::FromRow<$B> for ($($T,)+)
 | 
			
		||||
        where
 | 
			
		||||
            $($B: crate::types::HasSqlType<$T>,)+
 | 
			
		||||
            $($T: crate::decode::Decode<$B>,)+
 | 
			
		||||
        {
 | 
			
		||||
            #[inline]
 | 
			
		||||
            fn from_row<R: crate::row::Row<Backend = $B>>(row: R) -> Self {
 | 
			
		||||
                ($(row.get($idx),)+)
 | 
			
		||||
            fn from_row(row: <$B as crate::Backend>::Row) -> Self {
 | 
			
		||||
                use crate::row::RawRow;
 | 
			
		||||
 | 
			
		||||
                ($($T::decode(row.get_raw($idx)),)+)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(unused)]
 | 
			
		||||
macro_rules! impl_from_sql_row_tuples_for_backend {
 | 
			
		||||
macro_rules! impl_from_row_for_backend {
 | 
			
		||||
    ($B:ident) => {
 | 
			
		||||
        impl crate::row::FromRow<$B> for crate::row::Row<$B> where $B: crate::Backend {
 | 
			
		||||
            #[inline]
 | 
			
		||||
            fn from_row(row: <$B as crate::Backend>::Row) -> Self {
 | 
			
		||||
                Self(row)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl_from_sql_row_tuple!($B:
 | 
			
		||||
            (0) -> T1;
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    backend::Backend, encode::Encode, error::Error, executor::Executor, query::QueryParameters,
 | 
			
		||||
    row::FromSqlRow, types::HasSqlType,
 | 
			
		||||
    row::FromRow, types::HasSqlType,
 | 
			
		||||
};
 | 
			
		||||
use futures_core::{future::BoxFuture, stream::BoxStream};
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ where
 | 
			
		||||
    pub fn fetch<E, T: 'q>(self, executor: &'q mut E) -> BoxStream<'q, Result<T, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        E: Executor<Backend = DB>,
 | 
			
		||||
        T: FromSqlRow<DB> + Send + Unpin,
 | 
			
		||||
        T: FromRow<DB> + Send + Unpin,
 | 
			
		||||
        DB::QueryParameters: 'q,
 | 
			
		||||
    {
 | 
			
		||||
        executor.fetch(self.query, self.params)
 | 
			
		||||
@ -52,7 +52,7 @@ where
 | 
			
		||||
    pub fn fetch_all<E, T: 'q>(self, executor: &'q mut E) -> BoxFuture<'q, Result<Vec<T>, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        E: Executor<Backend = DB>,
 | 
			
		||||
        T: FromSqlRow<DB> + Send + Unpin,
 | 
			
		||||
        T: FromRow<DB> + Send + Unpin,
 | 
			
		||||
        DB::QueryParameters: 'q,
 | 
			
		||||
    {
 | 
			
		||||
        executor.fetch_all(self.query, self.params)
 | 
			
		||||
@ -64,7 +64,7 @@ where
 | 
			
		||||
    ) -> BoxFuture<'q, Result<Option<T>, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        E: Executor<Backend = DB>,
 | 
			
		||||
        T: FromSqlRow<DB> + Send,
 | 
			
		||||
        T: FromRow<DB> + Send,
 | 
			
		||||
        DB::QueryParameters: 'q,
 | 
			
		||||
    {
 | 
			
		||||
        executor.fetch_optional(self.query, self.params)
 | 
			
		||||
@ -73,7 +73,7 @@ where
 | 
			
		||||
    pub fn fetch_one<E, T: 'q>(self, executor: &'q mut E) -> BoxFuture<'q, Result<T, Error>>
 | 
			
		||||
    where
 | 
			
		||||
        E: Executor<Backend = DB>,
 | 
			
		||||
        T: FromSqlRow<DB> + Send + Unpin,
 | 
			
		||||
        T: FromRow<DB> + Send + Unpin,
 | 
			
		||||
        DB::QueryParameters: 'q,
 | 
			
		||||
    {
 | 
			
		||||
        executor.fetch_one(self.query, self.params)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user