Skip to content

Commit 3a73ece

Browse files
committed
feat: implement Decode,Encode,Type for Box,Arc,Cow
1 parent 6b33766 commit 3a73ece

File tree

4 files changed

+206
-0
lines changed

4 files changed

+206
-0
lines changed

sqlx-core/src/decode.rs

+37
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
//! Provides [`Decode`] for decoding values from the database.
22
3+
use std::borrow::Cow;
4+
use std::sync::Arc;
5+
36
use crate::database::Database;
47
use crate::error::BoxDynError;
58

@@ -77,3 +80,37 @@ where
7780
}
7881
}
7982
}
83+
84+
// implement `Decode` for Arc<T> for all SQL types
85+
impl<'r, DB, T> Decode<'r, DB> for Arc<T>
86+
where
87+
DB: Database,
88+
T: Decode<'r, DB>,
89+
{
90+
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
91+
Ok(Arc::new(T::decode(value)?))
92+
}
93+
}
94+
95+
// implement `Decode` for Cow<T> for all SQL types
96+
impl<'r, DB, T> Decode<'r, DB> for Cow<'_, T>
97+
where
98+
DB: Database,
99+
T: Decode<'r, DB>,
100+
T: ToOwned<Owned = T>,
101+
{
102+
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
103+
Ok(Cow::Owned(T::decode(value)?))
104+
}
105+
}
106+
107+
// implement `Decode` for Box<T> for all SQL types
108+
impl<'r, DB, T> Decode<'r, DB> for Box<T>
109+
where
110+
DB: Database,
111+
T: Decode<'r, DB>,
112+
{
113+
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
114+
Ok(Box::new(T::decode(value)?))
115+
}
116+
}

sqlx-core/src/encode.rs

+87
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Provides [`Encode`] for encoding values for the database.
22
3+
use std::borrow::Cow;
34
use std::mem;
5+
use std::sync::Arc;
46

57
use crate::database::Database;
68
use crate::error::BoxDynError;
@@ -129,3 +131,88 @@ macro_rules! impl_encode_for_option {
129131
}
130132
};
131133
}
134+
135+
impl<'q, T, DB: Database> Encode<'q, DB> for Arc<T>
136+
where
137+
T: Encode<'q, DB>,
138+
{
139+
#[inline]
140+
fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer<'q>) -> Result<IsNull, BoxDynError> {
141+
<T as Encode<DB>>::encode_by_ref(self.as_ref(), buf)
142+
}
143+
144+
#[inline]
145+
fn encode_by_ref(
146+
&self,
147+
buf: &mut <DB as Database>::ArgumentBuffer<'q>,
148+
) -> Result<IsNull, BoxDynError> {
149+
<&T as Encode<DB>>::encode(self, buf)
150+
}
151+
152+
#[inline]
153+
fn produces(&self) -> Option<DB::TypeInfo> {
154+
(**self).produces()
155+
}
156+
157+
#[inline]
158+
fn size_hint(&self) -> usize {
159+
(**self).size_hint()
160+
}
161+
}
162+
163+
impl<'q, T, DB: Database> Encode<'q, DB> for Cow<'_, T>
164+
where
165+
T: Encode<'q, DB>,
166+
T: ToOwned<Owned = T>,
167+
{
168+
#[inline]
169+
fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer<'q>) -> Result<IsNull, BoxDynError> {
170+
<T as Encode<DB>>::encode_by_ref(self.as_ref(), buf)
171+
}
172+
173+
#[inline]
174+
fn encode_by_ref(
175+
&self,
176+
buf: &mut <DB as Database>::ArgumentBuffer<'q>,
177+
) -> Result<IsNull, BoxDynError> {
178+
<&T as Encode<DB>>::encode(self, buf)
179+
}
180+
181+
#[inline]
182+
fn produces(&self) -> Option<DB::TypeInfo> {
183+
(**self).produces()
184+
}
185+
186+
#[inline]
187+
fn size_hint(&self) -> usize {
188+
(**self).size_hint()
189+
}
190+
}
191+
192+
impl<'q, T, DB: Database> Encode<'q, DB> for Box<T>
193+
where
194+
T: Encode<'q, DB>,
195+
{
196+
#[inline]
197+
fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer<'q>) -> Result<IsNull, BoxDynError> {
198+
<T as Encode<DB>>::encode_by_ref(self.as_ref(), buf)
199+
}
200+
201+
#[inline]
202+
fn encode_by_ref(
203+
&self,
204+
buf: &mut <DB as Database>::ArgumentBuffer<'q>,
205+
) -> Result<IsNull, BoxDynError> {
206+
<&T as Encode<DB>>::encode(self, buf)
207+
}
208+
209+
#[inline]
210+
fn produces(&self) -> Option<DB::TypeInfo> {
211+
(**self).produces()
212+
}
213+
214+
#[inline]
215+
fn size_hint(&self) -> usize {
216+
(**self).size_hint()
217+
}
218+
}

sqlx-core/src/types/mod.rs

+40
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
//! To represent nullable SQL types, `Option<T>` is supported where `T` implements `Type`.
1818
//! An `Option<T>` represents a potentially `NULL` value from SQL.
1919
20+
use std::{borrow::Cow, sync::Arc};
21+
2022
use crate::database::Database;
2123
use crate::type_info::TypeInfo;
2224

@@ -238,3 +240,41 @@ impl<T: Type<DB>, DB: Database> Type<DB> for Option<T> {
238240
ty.is_null() || <T as Type<DB>>::compatible(ty)
239241
}
240242
}
243+
244+
impl<T, DB: Database> Type<DB> for Arc<T>
245+
where
246+
T: Type<DB>,
247+
T: ?Sized,
248+
{
249+
fn type_info() -> DB::TypeInfo {
250+
<T as Type<DB>>::type_info()
251+
}
252+
253+
fn compatible(ty: &DB::TypeInfo) -> bool {
254+
ty.is_null() || <T as Type<DB>>::compatible(ty)
255+
}
256+
}
257+
258+
impl<T, DB: Database> Type<DB> for Cow<'_, T>
259+
where
260+
T: Type<DB>,
261+
T: ToOwned<Owned = T>,
262+
{
263+
fn type_info() -> DB::TypeInfo {
264+
<T as Type<DB>>::type_info()
265+
}
266+
267+
fn compatible(ty: &DB::TypeInfo) -> bool {
268+
ty.is_null() || <T as Type<DB>>::compatible(ty)
269+
}
270+
}
271+
272+
impl<T: Type<DB>, DB: Database> Type<DB> for Box<T> {
273+
fn type_info() -> DB::TypeInfo {
274+
<T as Type<DB>>::type_info()
275+
}
276+
277+
fn compatible(ty: &DB::TypeInfo) -> bool {
278+
ty.is_null() || <T as Type<DB>>::compatible(ty)
279+
}
280+
}

tests/postgres/types.rs

+42
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
extern crate time_ as time;
22

3+
use std::borrow::Cow;
34
use std::net::SocketAddr;
45
use std::ops::Bound;
6+
use std::sync::Arc;
57

68
use sqlx::postgres::types::{Oid, PgCiText, PgInterval, PgMoney, PgRange};
79
use sqlx::postgres::Postgres;
@@ -657,3 +659,43 @@ CREATE TEMPORARY TABLE user_login (
657659

658660
Ok(())
659661
}
662+
663+
#[sqlx_macros::test]
664+
async fn test_arc() -> anyhow::Result<()> {
665+
let mut conn = new::<Postgres>().await?;
666+
667+
let user_age: Arc<i32> = sqlx::query_scalar("select $1 as age ")
668+
.bind(Arc::new(1i32))
669+
.fetch_one(&mut conn)
670+
.await?;
671+
assert!(user_age.as_ref() == &1);
672+
Ok(())
673+
}
674+
675+
#[sqlx_macros::test]
676+
async fn test_cow() -> anyhow::Result<()> {
677+
let mut conn = new::<Postgres>().await?;
678+
679+
let age: Cow<'_, i32> = Cow::Owned(1i32);
680+
681+
let user_age: Cow<'static, i32> = sqlx::query_scalar("select $1 as age ")
682+
.bind(age)
683+
.fetch_one(&mut conn)
684+
.await?;
685+
686+
assert!(user_age.as_ref() == &1);
687+
Ok(())
688+
}
689+
690+
#[sqlx_macros::test]
691+
async fn test_box() -> anyhow::Result<()> {
692+
let mut conn = new::<Postgres>().await?;
693+
694+
let user_age: Box<i32> = sqlx::query_scalar("select $1 as age ")
695+
.bind(Box::new(1))
696+
.fetch_one(&mut conn)
697+
.await?;
698+
699+
assert!(user_age.as_ref() == &1);
700+
Ok(())
701+
}

0 commit comments

Comments
 (0)