mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-09-29 22:12:04 +00:00
Integrate FromRow while maintaining type fallback for query!
This commit is contained in:
parent
ab32d0a5c4
commit
73ca673bf2
@ -1,4 +1,3 @@
|
||||
use futures::TryStreamExt;
|
||||
use sqlx::{FromRow, Pool, Postgres};
|
||||
use std::env;
|
||||
use tide::error::ResultExt;
|
||||
@ -22,6 +21,8 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
app.at("/v1/user/first").get(get_first_user);
|
||||
|
||||
app.at("/v1/user/last").get(get_last_user);
|
||||
|
||||
app.serve(("localhost", 8080))?;
|
||||
|
||||
Ok(())
|
||||
@ -47,19 +48,28 @@ async fn get_all_users(cx: Context<Pool<Postgres>>) -> EndpointResult {
|
||||
let mut pool = cx.state();
|
||||
|
||||
let users: Vec<(i32, String)> = sqlx::query(r#"SELECT id, name FROM users"#)
|
||||
.fetch(&mut pool) // -> Stream<Row>
|
||||
.map_ok(FromRow::from_row)
|
||||
.try_collect()
|
||||
.fetch_all(&mut pool)
|
||||
.await
|
||||
.server_err()?;
|
||||
|
||||
Ok(response::json(users))
|
||||
}
|
||||
|
||||
// TODO: #[derive(FromRow)]
|
||||
struct UserRow {
|
||||
id: i32,
|
||||
}
|
||||
|
||||
impl FromRow<Postgres, (i32,)> for UserRow {
|
||||
fn from_row(row: sqlx::Row<Postgres>) -> Self {
|
||||
Self { id: row.get(0) }
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_first_user(cx: Context<Pool<Postgres>>) -> EndpointResult {
|
||||
let mut pool = cx.state();
|
||||
|
||||
let (user_id,) /* : (i32,) */ = sqlx::query!(
|
||||
let row: UserRow = sqlx::query!(
|
||||
r#"
|
||||
SELECT id
|
||||
FROM users
|
||||
@ -71,6 +81,24 @@ LIMIT 1
|
||||
.await
|
||||
.server_err()?;
|
||||
|
||||
Ok(response::json(vec![row.id]))
|
||||
}
|
||||
|
||||
async fn get_last_user(cx: Context<Pool<Postgres>>) -> EndpointResult {
|
||||
let mut pool = cx.state();
|
||||
|
||||
let (user_id,) = sqlx::query!(
|
||||
r#"
|
||||
SELECT id
|
||||
FROM users
|
||||
ORDER BY created_at ASC
|
||||
LIMIT 1
|
||||
"#,
|
||||
)
|
||||
.fetch_one(&mut pool)
|
||||
.await
|
||||
.server_err()?;
|
||||
|
||||
Ok(response::json(vec![user_id]))
|
||||
}
|
||||
|
||||
|
@ -53,25 +53,25 @@ where
|
||||
{
|
||||
type Backend = DB;
|
||||
|
||||
fn execute<'c, 'q: 'c, A: 'c>(
|
||||
fn execute<'c, 'q: 'c, I: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxFuture<'c, Result<u64, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
{
|
||||
Box::pin(async move { self.live.execute(query, params.into_params()).await })
|
||||
}
|
||||
|
||||
fn fetch<'c, 'q: 'c, T: 'c, A: 'c>(
|
||||
fn fetch<'c, 'q: 'c, I: 'c, O: 'c, T: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxStream<'c, Result<T, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend> + Send + Unpin,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend, O> + Send + Unpin,
|
||||
{
|
||||
Box::pin(async_stream::try_stream! {
|
||||
let mut s = self.live.fetch(query, params.into_params());
|
||||
@ -82,14 +82,14 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn fetch_optional<'c, 'q: 'c, T: 'c, A: 'c>(
|
||||
fn fetch_optional<'c, 'q: 'c, I: 'c, O: 'c, T: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxFuture<'c, Result<Option<T>, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend>,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend, O>,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let row = self
|
||||
|
@ -5,52 +5,52 @@ use futures_util::TryStreamExt;
|
||||
pub trait Executor: Send {
|
||||
type Backend: Backend;
|
||||
|
||||
fn execute<'c, 'q: 'c, A: 'c>(
|
||||
fn execute<'c, 'q: 'c, I: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxFuture<'c, Result<u64, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send;
|
||||
I: IntoQueryParameters<Self::Backend> + Send;
|
||||
|
||||
fn fetch<'c, 'q: 'c, T: 'c, A: 'c>(
|
||||
fn fetch<'c, 'q: 'c, I: 'c, O: 'c, T: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxStream<'c, Result<T, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend> + Send + Unpin;
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend, O> + Send + Unpin;
|
||||
|
||||
fn fetch_all<'c, 'q: 'c, T: 'c, A: 'c>(
|
||||
fn fetch_all<'c, 'q: 'c, I: 'c, O: 'c, T: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxFuture<'c, Result<Vec<T>, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend> + Send + Unpin,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend, O> + Send + Unpin,
|
||||
{
|
||||
Box::pin(self.fetch(query, params).try_collect())
|
||||
}
|
||||
|
||||
fn fetch_optional<'c, 'q: 'c, T: 'c, A: 'c>(
|
||||
fn fetch_optional<'c, 'q: 'c, I: 'c, O: 'c, T: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxFuture<'c, Result<Option<T>, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend> + Send;
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend, O> + Send;
|
||||
|
||||
fn fetch_one<'c, 'q: 'c, T: 'c, A: 'c>(
|
||||
fn fetch_one<'c, 'q: 'c, I: 'c, O: 'c, T: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxFuture<'c, Result<T, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend> + Send,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend, O> + Send,
|
||||
{
|
||||
let fut = self.fetch_optional(query, params);
|
||||
Box::pin(async move { fut.await?.ok_or(Error::NotFound) })
|
||||
|
@ -244,25 +244,25 @@ where
|
||||
{
|
||||
type Backend = DB;
|
||||
|
||||
fn execute<'c, 'q: 'c, A: 'c>(
|
||||
fn execute<'c, 'q: 'c, I: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxFuture<'c, Result<u64, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
{
|
||||
Box::pin(async move { <&Pool<DB> as Executor>::execute(&mut &*self, query, params).await })
|
||||
}
|
||||
|
||||
fn fetch<'c, 'q: 'c, T: 'c, A: 'c>(
|
||||
fn fetch<'c, 'q: 'c, I: 'c, O: 'c, T: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxStream<'c, Result<T, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend> + Send + Unpin,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend, O> + Send + Unpin,
|
||||
{
|
||||
Box::pin(async_stream::try_stream! {
|
||||
let mut self_ = &*self;
|
||||
@ -276,14 +276,14 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn fetch_optional<'c, 'q: 'c, T: 'c, A: 'c>(
|
||||
fn fetch_optional<'c, 'q: 'c, I: 'c, O: 'c, T: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxFuture<'c, Result<Option<T>, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend> + Send,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend, O> + Send,
|
||||
{
|
||||
Box::pin(async move {
|
||||
<&Pool<DB> as Executor>::fetch_optional(&mut &*self, query, params).await
|
||||
@ -297,13 +297,13 @@ where
|
||||
{
|
||||
type Backend = DB;
|
||||
|
||||
fn execute<'c, 'q: 'c, A: 'c>(
|
||||
fn execute<'c, 'q: 'c, I: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxFuture<'c, Result<u64, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let mut live = self.0.acquire().await?;
|
||||
@ -312,14 +312,14 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn fetch<'c, 'q: 'c, T: 'c, A: 'c>(
|
||||
fn fetch<'c, 'q: 'c, I: 'c, O: 'c, T: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxStream<'c, Result<T, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend> + Send + Unpin,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend, O> + Send + Unpin,
|
||||
{
|
||||
Box::pin(async_stream::try_stream! {
|
||||
let mut live = self.0.acquire().await?;
|
||||
@ -331,14 +331,14 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn fetch_optional<'c, 'q: 'c, T: 'c, A: 'c>(
|
||||
fn fetch_optional<'c, 'q: 'c, I: 'c, O: 'c, T: 'c>(
|
||||
&'c mut self,
|
||||
query: &'q str,
|
||||
params: A,
|
||||
params: I,
|
||||
) -> BoxFuture<'c, Result<Option<T>, Error>>
|
||||
where
|
||||
A: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend> + Send,
|
||||
I: IntoQueryParameters<Self::Backend> + Send,
|
||||
T: FromRow<Self::Backend, O> + Send,
|
||||
{
|
||||
Box::pin(async move {
|
||||
Ok(self
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
use bitflags::_core::marker::PhantomData;
|
||||
use futures_core::{future::BoxFuture, stream::BoxStream};
|
||||
|
||||
pub struct Query<'q, DB, I = <DB as Backend>::QueryParameters, O = Row<DB>>
|
||||
pub struct Query<'q, DB, I = <DB as Backend>::QueryParameters, O = Row<DB>, T = O>
|
||||
where
|
||||
DB: Backend,
|
||||
{
|
||||
@ -19,6 +19,9 @@ where
|
||||
#[doc(hidden)]
|
||||
pub output: PhantomData<O>,
|
||||
|
||||
#[doc(hidden)]
|
||||
pub target: PhantomData<T>,
|
||||
|
||||
#[doc(hidden)]
|
||||
pub backend: PhantomData<DB>,
|
||||
}
|
||||
@ -28,20 +31,7 @@ where
|
||||
DB: Backend,
|
||||
DB::QueryParameters: 'q,
|
||||
I: IntoQueryParameters<DB> + Send,
|
||||
O: FromRow<DB> + Send + Unpin,
|
||||
{
|
||||
pub fn cast<U>(self) -> Query<'q, DB, I, U>
|
||||
where
|
||||
U: FromRow<DB> + Send + Unpin,
|
||||
{
|
||||
Query {
|
||||
query: self.query,
|
||||
input: self.input,
|
||||
output: PhantomData,
|
||||
backend: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn execute<E>(self, executor: &'q mut E) -> BoxFuture<'q, crate::Result<u64>>
|
||||
where
|
||||
@ -49,29 +39,37 @@ where
|
||||
{
|
||||
executor.execute(self.query, self.input)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch<E>(self, executor: &'q mut E) -> BoxStream<'q, crate::Result<O>>
|
||||
impl<'q, DB, I: 'q, O: 'q, T: 'q> Query<'q, DB, I, O, T>
|
||||
where
|
||||
DB: Backend,
|
||||
DB::QueryParameters: 'q,
|
||||
I: IntoQueryParameters<DB> + Send,
|
||||
T: FromRow<DB, O> + Send + Unpin,
|
||||
{
|
||||
pub fn fetch<E>(self, executor: &'q mut E) -> BoxStream<'q, crate::Result<T>>
|
||||
where
|
||||
E: Executor<Backend = DB>,
|
||||
{
|
||||
executor.fetch(self.query, self.input)
|
||||
}
|
||||
|
||||
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<T>>>
|
||||
where
|
||||
E: Executor<Backend = DB>,
|
||||
{
|
||||
executor.fetch_all(self.query, self.input)
|
||||
}
|
||||
|
||||
pub fn fetch_optional<E>(self, executor: &'q mut E) -> BoxFuture<'q, Result<Option<O>, Error>>
|
||||
pub fn fetch_optional<E>(self, executor: &'q mut E) -> BoxFuture<'q, Result<Option<T>, Error>>
|
||||
where
|
||||
E: Executor<Backend = DB>,
|
||||
{
|
||||
executor.fetch_optional(self.query, self.input)
|
||||
}
|
||||
|
||||
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<T>>
|
||||
where
|
||||
E: Executor<Backend = DB>,
|
||||
{
|
||||
@ -102,7 +100,7 @@ where
|
||||
|
||||
/// Construct a full SQL query using raw SQL.
|
||||
#[inline]
|
||||
pub fn query<DB>(query: &str) -> Query<'_, DB, DB::QueryParameters, Row<DB>>
|
||||
pub fn query<DB, T>(query: &str) -> Query<'_, DB, DB::QueryParameters, Row<DB>, T>
|
||||
where
|
||||
DB: Backend,
|
||||
{
|
||||
@ -111,5 +109,6 @@ where
|
||||
input: DB::QueryParameters::new(),
|
||||
output: PhantomData,
|
||||
backend: PhantomData,
|
||||
target: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -33,13 +33,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FromRow<DB: Backend> {
|
||||
pub trait FromRow<DB: Backend, O = Row<DB>> {
|
||||
fn from_row(row: Row<DB>) -> Self;
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! impl_from_row {
|
||||
($B:ident: $( ($idx:tt) -> $T:ident );+;) => {
|
||||
// Row -> (T1, T2, ...)
|
||||
impl<$($T,)+> crate::row::FromRow<$B> for ($($T,)+)
|
||||
where
|
||||
$($B: crate::types::HasSqlType<$T>,)+
|
||||
@ -50,6 +51,18 @@ macro_rules! impl_from_row {
|
||||
($(row.get($idx),)+)
|
||||
}
|
||||
}
|
||||
|
||||
// (T1, T2, ...) -> (T1, T2, ...)
|
||||
impl<$($T,)+> crate::row::FromRow<$B, ($($T,)+)> for ($($T,)+)
|
||||
where
|
||||
$($B: crate::types::HasSqlType<$T>,)+
|
||||
$($T: crate::decode::Decode<$B>,)+
|
||||
{
|
||||
#[inline]
|
||||
fn from_row(row: crate::row::Row<$B>) -> Self {
|
||||
($(row.get($idx),)+)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -188,10 +188,11 @@ where
|
||||
Ok(quote! {{
|
||||
#params
|
||||
|
||||
sqlx::Query::<#backend_path, _, (#(#output_types),*,)> {
|
||||
sqlx::Query::<#backend_path, _, (#(#output_types),*,), _> {
|
||||
query: #query,
|
||||
input: params,
|
||||
output: ::core::marker::PhantomData,
|
||||
target: ::core::marker::PhantomData,
|
||||
backend: ::core::marker::PhantomData,
|
||||
}
|
||||
}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user