Skip to content

Commit 0a8dc31

Browse files
committed
feat: implement Encode,Decode,Type for Arc<str> and Arc<[u8]>
1 parent b6521ae commit 0a8dc31

10 files changed

Lines changed: 222 additions & 0 deletions

File tree

sqlx-mysql/src/types/bytes.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::Arc;
2+
13
use crate::decode::Decode;
24
use crate::encode::{Encode, IsNull};
35
use crate::error::BoxDynError;
@@ -73,3 +75,15 @@ impl Decode<'_, MySql> for Vec<u8> {
7375
<&[u8] as Decode<MySql>>::decode(value).map(ToOwned::to_owned)
7476
}
7577
}
78+
79+
impl Encode<'_, MySql> for Arc<[u8]> {
80+
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
81+
<&[u8] as Encode<MySql>>::encode(&**self, buf)
82+
}
83+
}
84+
85+
impl Decode<'_, MySql> for Arc<[u8]> {
86+
fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
87+
<&[u8] as Decode<MySql>>::decode(value).map(Into::into)
88+
}
89+
}

sqlx-mysql/src/types/str.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::protocol::text::{ColumnFlags, ColumnType};
66
use crate::types::Type;
77
use crate::{MySql, MySqlTypeInfo, MySqlValueRef};
88
use std::borrow::Cow;
9+
use std::sync::Arc;
910

1011
impl Type<MySql> for str {
1112
fn type_info() -> MySqlTypeInfo {
@@ -94,3 +95,15 @@ impl<'r> Decode<'r, MySql> for Cow<'r, str> {
9495
value.as_str().map(Cow::Borrowed)
9596
}
9697
}
98+
99+
impl Encode<'_, MySql> for Arc<str> {
100+
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
101+
<&str as Encode<MySql>>::encode(&**self, buf)
102+
}
103+
}
104+
105+
impl Decode<'_, MySql> for Arc<str> {
106+
fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
107+
<&str as Decode<MySql>>::decode(value).map(Into::into)
108+
}
109+
}

sqlx-postgres/src/types/array.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use sqlx_core::bytes::Buf;
22
use sqlx_core::types::Text;
33
use std::borrow::Cow;
4+
use std::sync::Arc;
45

56
use crate::decode::Decode;
67
use crate::encode::{Encode, IsNull};
@@ -192,6 +193,17 @@ where
192193
}
193194
}
194195

196+
impl<'q, T> Encode<'q, Postgres> for Arc<[T]>
197+
where
198+
for<'a> &'a [T]: Encode<'q, Postgres>,
199+
T: Encode<'q, Postgres>,
200+
{
201+
#[inline]
202+
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
203+
<&[T] as Encode<Postgres>>::encode_by_ref(&self.as_ref(), buf)
204+
}
205+
}
206+
195207
impl<'r, T, const N: usize> Decode<'r, Postgres> for [T; N]
196208
where
197209
T: for<'a> Decode<'a, Postgres> + Type<Postgres>,
@@ -354,3 +366,12 @@ where
354366
}
355367
}
356368
}
369+
370+
impl<'r, T> Decode<'r, Postgres> for Arc<[T]>
371+
where
372+
T: for<'a> Decode<'a, Postgres> + Type<Postgres>,
373+
{
374+
fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
375+
<Vec<T> as Decode<Postgres>>::decode(value).map(Into::into)
376+
}
377+
}

sqlx-postgres/src/types/bytes.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::Arc;
2+
13
use crate::decode::Decode;
24
use crate::encode::{Encode, IsNull};
35
use crate::error::BoxDynError;
@@ -28,6 +30,12 @@ impl PgHasArrayType for Vec<u8> {
2830
}
2931
}
3032

33+
impl PgHasArrayType for Arc<[u8]> {
34+
fn array_type_info() -> PgTypeInfo {
35+
<[&[u8]] as Type<Postgres>>::type_info()
36+
}
37+
}
38+
3139
impl<const N: usize> PgHasArrayType for [u8; N] {
3240
fn array_type_info() -> PgTypeInfo {
3341
<[&[u8]] as Type<Postgres>>::type_info()
@@ -60,6 +68,12 @@ impl<const N: usize> Encode<'_, Postgres> for [u8; N] {
6068
}
6169
}
6270

71+
impl Encode<'_, Postgres> for Arc<[u8]> {
72+
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
73+
<&[u8] as Encode<Postgres>>::encode(self, buf)
74+
}
75+
}
76+
6377
impl<'r> Decode<'r, Postgres> for &'r [u8] {
6478
fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
6579
match value.format() {
@@ -110,3 +124,12 @@ impl<const N: usize> Decode<'_, Postgres> for [u8; N] {
110124
Ok(bytes)
111125
}
112126
}
127+
128+
impl Decode<'_, Postgres> for Arc<[u8]> {
129+
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
130+
Ok(match value.format() {
131+
PgValueFormat::Binary => value.as_bytes()?.into(),
132+
PgValueFormat::Text => hex::decode(text_hex_decode_input(value)?)?.into(),
133+
})
134+
}
135+
}

sqlx-postgres/src/types/str.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::types::array_compatible;
55
use crate::types::Type;
66
use crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres};
77
use std::borrow::Cow;
8+
use std::sync::Arc;
89

910
impl Type<Postgres> for str {
1011
fn type_info() -> PgTypeInfo {
@@ -74,6 +75,16 @@ impl PgHasArrayType for String {
7475
}
7576
}
7677

78+
impl PgHasArrayType for Arc<str> {
79+
fn array_type_info() -> PgTypeInfo {
80+
<&str as PgHasArrayType>::array_type_info()
81+
}
82+
83+
fn array_compatible(ty: &PgTypeInfo) -> bool {
84+
<&str as PgHasArrayType>::array_compatible(ty)
85+
}
86+
}
87+
7788
impl Encode<'_, Postgres> for &'_ str {
7889
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
7990
buf.extend(self.as_bytes());
@@ -103,6 +114,12 @@ impl Encode<'_, Postgres> for String {
103114
}
104115
}
105116

117+
impl Encode<'_, Postgres> for Arc<str> {
118+
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
119+
<&str as Encode<Postgres>>::encode(&**self, buf)
120+
}
121+
}
122+
106123
impl<'r> Decode<'r, Postgres> for &'r str {
107124
fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
108125
value.as_str()
@@ -126,3 +143,9 @@ impl Decode<'_, Postgres> for String {
126143
Ok(value.as_str()?.to_owned())
127144
}
128145
}
146+
147+
impl Decode<'_, Postgres> for Arc<str> {
148+
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
149+
Ok(value.as_str()?.into())
150+
}
151+
}

sqlx-sqlite/src/types/bytes.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::borrow::Cow;
2+
use std::sync::Arc;
23

34
use crate::decode::Decode;
45
use crate::encode::{Encode, IsNull};
@@ -91,3 +92,26 @@ impl<'r> Decode<'r, Sqlite> for Vec<u8> {
9192
Ok(value.blob().to_owned())
9293
}
9394
}
95+
96+
impl<'q> Encode<'q, Sqlite> for Arc<[u8]> {
97+
fn encode(self, args: &mut Vec<SqliteArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
98+
args.push(SqliteArgumentValue::Blob(Cow::Owned(self.to_vec())));
99+
100+
Ok(IsNull::No)
101+
}
102+
103+
fn encode_by_ref(
104+
&self,
105+
args: &mut Vec<SqliteArgumentValue<'q>>,
106+
) -> Result<IsNull, BoxDynError> {
107+
args.push(SqliteArgumentValue::Blob(Cow::Owned(self.to_vec())));
108+
109+
Ok(IsNull::No)
110+
}
111+
}
112+
113+
impl<'r> Decode<'r, Sqlite> for Arc<[u8]> {
114+
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
115+
Ok(value.blob().into())
116+
}
117+
}

sqlx-sqlite/src/types/str.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::borrow::Cow;
2+
use std::sync::Arc;
23

34
use crate::decode::Decode;
45
use crate::encode::{Encode, IsNull};
@@ -106,3 +107,26 @@ impl<'r> Decode<'r, Sqlite> for Cow<'r, str> {
106107
value.text().map(Cow::Borrowed)
107108
}
108109
}
110+
111+
impl<'q> Encode<'q, Sqlite> for Arc<str> {
112+
fn encode(self, args: &mut Vec<SqliteArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
113+
args.push(SqliteArgumentValue::Text(Cow::Owned(self.to_string())));
114+
115+
Ok(IsNull::No)
116+
}
117+
118+
fn encode_by_ref(
119+
&self,
120+
args: &mut Vec<SqliteArgumentValue<'q>>,
121+
) -> Result<IsNull, BoxDynError> {
122+
args.push(SqliteArgumentValue::Text(Cow::Owned(self.to_string())));
123+
124+
Ok(IsNull::No)
125+
}
126+
}
127+
128+
impl<'r> Decode<'r, Sqlite> for Arc<str> {
129+
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
130+
value.text().map(Into::into)
131+
}
132+
}

tests/mysql/types.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ extern crate time_ as time;
33
use std::net::SocketAddr;
44
#[cfg(feature = "rust_decimal")]
55
use std::str::FromStr;
6+
use std::sync::Arc;
67

78
use sqlx::mysql::MySql;
89
use sqlx::{Executor, Row};
@@ -384,3 +385,33 @@ CREATE TEMPORARY TABLE user_login (
384385

385386
Ok(())
386387
}
388+
389+
#[sqlx_macros::test]
390+
async fn test_arc_str() -> anyhow::Result<()> {
391+
let mut conn = new::<MySql>().await?;
392+
393+
let name: Arc<str> = "Harold".into();
394+
395+
let username: Arc<str> = sqlx::query_scalar("SELECT ? AS username")
396+
.bind(&name)
397+
.fetch_one(&mut conn)
398+
.await?;
399+
400+
assert!(username == name);
401+
Ok(())
402+
}
403+
404+
#[sqlx_macros::test]
405+
async fn test_arc_slice() -> anyhow::Result<()> {
406+
let mut conn = new::<MySql>().await?;
407+
408+
let name: Arc<[u8]> = [5, 0].into();
409+
410+
let username: Arc<[u8]> = sqlx::query_scalar("SELECT ?")
411+
.bind(&name)
412+
.fetch_one(&mut conn)
413+
.await?;
414+
415+
assert!(username == name);
416+
Ok(())
417+
}

tests/postgres/types.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::sync::Arc;
88

99
use sqlx::postgres::types::{Oid, PgCiText, PgInterval, PgMoney, PgRange};
1010
use sqlx::postgres::Postgres;
11+
use sqlx_macros::FromRow;
1112
use sqlx_test::{new, test_decode_type, test_prepared_type, test_type};
1213

1314
use sqlx_core::executor::Executor;
@@ -701,3 +702,20 @@ async fn test_arc() -> anyhow::Result<()> {
701702
assert!(user_age.3 == 4);
702703
Ok(())
703704
}
705+
706+
#[sqlx_macros::test]
707+
async fn test_arc_slice_2() -> anyhow::Result<()> {
708+
let mut conn = new::<Postgres>().await?;
709+
710+
#[derive(FromRow)]
711+
struct Nested {
712+
inner: Arc<[i32]>,
713+
}
714+
715+
let username: Nested = sqlx::query_as("SELECT ARRAY[1, 2, 3]::INT4[] as inner")
716+
.fetch_one(&mut conn)
717+
.await?;
718+
719+
assert!(username.inner.as_ref() == &[1, 2, 3]);
720+
Ok(())
721+
}

tests/sqlite/types.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use sqlx_core::types::Text;
77
use sqlx_test::new;
88
use sqlx_test::test_type;
99
use std::net::SocketAddr;
10+
use std::sync::Arc;
1011

1112
test_type!(null<Option<i32>>(Sqlite,
1213
"NULL" == None::<i32>
@@ -250,3 +251,33 @@ CREATE TEMPORARY TABLE user_login (
250251

251252
Ok(())
252253
}
254+
255+
#[sqlx_macros::test]
256+
async fn test_arc_str() -> anyhow::Result<()> {
257+
let mut conn = new::<Sqlite>().await?;
258+
259+
let name: Arc<str> = "Harold".into();
260+
261+
let username: Arc<str> = sqlx::query_scalar("SELECT $1 AS username")
262+
.bind(&name)
263+
.fetch_one(&mut conn)
264+
.await?;
265+
266+
assert!(username == name);
267+
Ok(())
268+
}
269+
270+
#[sqlx_macros::test]
271+
async fn test_arc_slice() -> anyhow::Result<()> {
272+
let mut conn = new::<Sqlite>().await?;
273+
274+
let name: Arc<[u8]> = [5, 0].into();
275+
276+
let username: Arc<[u8]> = sqlx::query_scalar("SELECT $1")
277+
.bind(&name)
278+
.fetch_one(&mut conn)
279+
.await?;
280+
281+
assert!(username == name);
282+
Ok(())
283+
}

0 commit comments

Comments
 (0)