From b14d3da2ee7a4d3005d955e0691c1da3b6b37052 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Fri, 22 Nov 2019 18:33:30 +0000 Subject: [PATCH] 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 --- examples/tide/src/main.rs | 23 ++++++++++++++- sqlx-core/src/backend.rs | 4 +-- sqlx-core/src/compiled.rs | 4 +-- sqlx-core/src/connection.rs | 6 ++-- sqlx-core/src/executor.rs | 10 +++---- sqlx-core/src/lib.rs | 2 +- sqlx-core/src/mariadb/backend.rs | 2 +- sqlx-core/src/mariadb/row.rs | 13 ++------ sqlx-core/src/pool.rs | 10 +++---- sqlx-core/src/postgres/backend.rs | 2 +- sqlx-core/src/postgres/row.rs | 9 ++---- sqlx-core/src/row.rs | 49 ++++++++++++++++++++----------- sqlx-core/src/sql.rs | 10 +++---- 13 files changed, 84 insertions(+), 60 deletions(-) diff --git a/examples/tide/src/main.rs b/examples/tide/src/main.rs index d1afb082..97b9c744 100644 --- a/examples/tide/src/main.rs +++ b/examples/tide/src/main.rs @@ -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>) -> EndpointResult { Ok(response::json(users)) } +async fn get_newest_user(cx: Context>) -> EndpointResult { + let mut pool = cx.state(); + + // This is an example of getting back a dyn row that we ... + let row: Row = 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::(0)])) +} + #[derive(serde::Deserialize)] struct CreateUserRequest { name: String, diff --git a/sqlx-core/src/backend.rs b/sqlx-core/src/backend.rs index 63864646..23519cf6 100644 --- a/sqlx-core/src/backend.rs +++ b/sqlx-core/src/backend.rs @@ -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; /// The concrete `Row` implementation for this backend. - type Row: Row; + type Row: RawRow; /// The identifier for tables; in Postgres this is an `oid` while /// in MariaDB/MySQL this is the qualified name of the table. diff --git a/sqlx-core/src/compiled.rs b/sqlx-core/src/compiled.rs index 97198828..726ac20d 100644 --- a/sqlx-core/src/compiled.rs +++ b/sqlx-core/src/compiled.rs @@ -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 CompiledSql where DB: Backend, P: IntoQueryParameters + Send, - O: FromSqlRow + Send + Unpin, + O: FromRow + Send + Unpin, { #[inline] pub fn execute<'e, E: 'e>(self, executor: &'e mut E) -> BoxFuture<'e, crate::Result> diff --git a/sqlx-core/src/connection.rs b/sqlx-core/src/connection.rs index 28aaaa68..58e3bc35 100644 --- a/sqlx-core/src/connection.rs +++ b/sqlx-core/src/connection.rs @@ -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> where A: IntoQueryParameters + Send, - T: FromSqlRow + Send + Unpin, + T: FromRow + 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, Error>> where A: IntoQueryParameters + Send, - T: FromSqlRow, + T: FromRow, { Box::pin(async move { let row = self diff --git a/sqlx-core/src/executor.rs b/sqlx-core/src/executor.rs index d8130e3e..577da464 100644 --- a/sqlx-core/src/executor.rs +++ b/sqlx-core/src/executor.rs @@ -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> where A: IntoQueryParameters + Send, - T: FromSqlRow + Send + Unpin; + T: FromRow + 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, Error>> where A: IntoQueryParameters + Send, - T: FromSqlRow + Send + Unpin, + T: FromRow + Send + Unpin, { Box::pin(self.fetch(query, params).try_collect()) } @@ -41,7 +41,7 @@ pub trait Executor: Send { ) -> BoxFuture<'c, Result, Error>> where A: IntoQueryParameters + Send, - T: FromSqlRow + Send; + T: FromRow + 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> where A: IntoQueryParameters + Send, - T: FromSqlRow + Send, + T: FromRow + Send, { let fut = self.fetch_optional(query, params); Box::pin(async move { fut.await?.ok_or(Error::NotFound) }) diff --git a/sqlx-core/src/lib.rs b/sqlx-core/src/lib.rs index 7293c72c..787c5872 100644 --- a/sqlx-core/src/lib.rs +++ b/sqlx-core/src/lib.rs @@ -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, }; diff --git a/sqlx-core/src/mariadb/backend.rs b/sqlx-core/src/mariadb/backend.rs index 85031746..5fdd6de9 100644 --- a/sqlx-core/src/mariadb/backend.rs +++ b/sqlx-core/src/mariadb/backend.rs @@ -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); diff --git a/sqlx-core/src/mariadb/row.rs b/sqlx-core/src/mariadb/row.rs index 21fda0a4..721dff3a 100644 --- a/sqlx-core/src/mariadb/row.rs +++ b/sqlx-core/src/mariadb/row.rs @@ -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() diff --git a/sqlx-core/src/pool.rs b/sqlx-core/src/pool.rs index 12115b09..b00ab8a8 100644 --- a/sqlx-core/src/pool.rs +++ b/sqlx-core/src/pool.rs @@ -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> where A: IntoQueryParameters + Send, - T: FromSqlRow + Send + Unpin, + T: FromRow + Send + Unpin, { Box::pin(async_stream::try_stream! { let mut self_ = &*self; @@ -279,7 +279,7 @@ where ) -> BoxFuture<'c, Result, Error>> where A: IntoQueryParameters + Send, - T: FromSqlRow + Send, + T: FromRow + Send, { Box::pin(async move { <&Pool as Executor>::fetch_optional(&mut &*self, query, params).await @@ -315,7 +315,7 @@ where ) -> BoxStream<'c, Result> where A: IntoQueryParameters + Send, - T: FromSqlRow + Send + Unpin, + T: FromRow + Send + Unpin, { Box::pin(async_stream::try_stream! { let mut live = self.0.acquire().await?; @@ -334,7 +334,7 @@ where ) -> BoxFuture<'c, Result, Error>> where A: IntoQueryParameters + Send, - T: FromSqlRow + Send, + T: FromRow + Send, { Box::pin(async move { let mut live = self.0.acquire().await?; diff --git a/sqlx-core/src/postgres/backend.rs b/sqlx-core/src/postgres/backend.rs index 22dcdc4e..2a401713 100644 --- a/sqlx-core/src/postgres/backend.rs +++ b/sqlx-core/src/postgres/backend.rs @@ -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); diff --git a/sqlx-core/src/postgres/row.rs b/sqlx-core/src/postgres/row.rs index 361b49b1..a0139537 100644 --- a/sqlx-core/src/postgres/row.rs +++ b/sqlx-core/src/postgres/row.rs @@ -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() diff --git a/sqlx-core/src/row.rs b/sqlx-core/src/row.rs index 484c636c..cc09eda0 100644 --- a/sqlx-core/src/row.rs +++ b/sqlx-core/src/row.rs @@ -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(&self, index: usize) -> T +pub struct Row(pub(crate) DB::Row) +where + DB: Backend; + +impl Row +where + DB: Backend, +{ + pub fn get(&self, index: usize) -> T where - Self::Backend: HasSqlType, - T: Decode, + DB: HasSqlType, + T: Decode, { - T::decode(self.get_raw(index)) + T::decode(self.0.get_raw(index)) } } -pub trait FromSqlRow { - fn from_row>(row: R) -> Self; +pub trait FromRow { + fn from_row(row: DB::Row) -> Self; } -impl FromSqlRow for T +impl FromRow for T where DB: Backend + HasSqlType, T: Decode, { #[inline] - fn from_row>(row: R) -> Self { - row.get::(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>(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; ); diff --git a/sqlx-core/src/sql.rs b/sqlx-core/src/sql.rs index 1c4419f7..f46269b4 100644 --- a/sqlx-core/src/sql.rs +++ b/sqlx-core/src/sql.rs @@ -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(self, executor: &'q mut E) -> BoxStream<'q, Result> where E: Executor, - T: FromSqlRow + Send + Unpin, + T: FromRow + Send + Unpin, DB::QueryParameters: 'q, { executor.fetch(self.query, self.params) @@ -52,7 +52,7 @@ where pub fn fetch_all(self, executor: &'q mut E) -> BoxFuture<'q, Result, Error>> where E: Executor, - T: FromSqlRow + Send + Unpin, + T: FromRow + Send + Unpin, DB::QueryParameters: 'q, { executor.fetch_all(self.query, self.params) @@ -64,7 +64,7 @@ where ) -> BoxFuture<'q, Result, Error>> where E: Executor, - T: FromSqlRow + Send, + T: FromRow + Send, DB::QueryParameters: 'q, { executor.fetch_optional(self.query, self.params) @@ -73,7 +73,7 @@ where pub fn fetch_one(self, executor: &'q mut E) -> BoxFuture<'q, Result> where E: Executor, - T: FromSqlRow + Send + Unpin, + T: FromRow + Send + Unpin, DB::QueryParameters: 'q, { executor.fetch_one(self.query, self.params)