Skip to content

Commit 37ecab1

Browse files
committed
feat: implement Encode,Decode,Type for Arc<str> and Arc<[u8]>
1 parent 676e11e commit 37ecab1

File tree

10 files changed

+311
-0
lines changed

10 files changed

+311
-0
lines changed

sqlx-mysql/src/types/bytes.rs

Lines changed: 24 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;
@@ -83,3 +85,25 @@ impl Decode<'_, MySql> for Vec<u8> {
8385
<&[u8] as Decode<MySql>>::decode(value).map(ToOwned::to_owned)
8486
}
8587
}
88+
89+
impl Type<MySql> for Arc<[u8]> {
90+
fn type_info() -> MySqlTypeInfo {
91+
<[u8] as Type<MySql>>::type_info()
92+
}
93+
94+
fn compatible(ty: &MySqlTypeInfo) -> bool {
95+
<&[u8] as Type<MySql>>::compatible(ty)
96+
}
97+
}
98+
99+
impl Encode<'_, MySql> for Arc<[u8]> {
100+
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
101+
<&[u8] as Encode<MySql>>::encode(&**self, buf)
102+
}
103+
}
104+
105+
impl Decode<'_, MySql> for Arc<[u8]> {
106+
fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
107+
<&[u8] as Decode<MySql>>::decode(value).map(Into::into)
108+
}
109+
}

sqlx-mysql/src/types/str.rs

Lines changed: 23 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 {
@@ -114,3 +115,25 @@ impl<'r> Decode<'r, MySql> for Cow<'r, str> {
114115
value.as_str().map(Cow::Borrowed)
115116
}
116117
}
118+
119+
impl Type<MySql> for Arc<str> {
120+
fn type_info() -> MySqlTypeInfo {
121+
<str as Type<MySql>>::type_info()
122+
}
123+
124+
fn compatible(ty: &MySqlTypeInfo) -> bool {
125+
<str as Type<MySql>>::compatible(ty)
126+
}
127+
}
128+
129+
impl Encode<'_, MySql> for Arc<str> {
130+
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
131+
<&str as Encode<MySql>>::encode(&**self, buf)
132+
}
133+
}
134+
135+
impl Decode<'_, MySql> for Arc<str> {
136+
fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
137+
<&str as Decode<MySql>>::decode(value).map(Into::into)
138+
}
139+
}

sqlx-postgres/src/types/array.rs

Lines changed: 34 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};
@@ -130,6 +131,19 @@ where
130131
}
131132
}
132133

134+
impl<T> Type<Postgres> for Arc<[T]>
135+
where
136+
T: PgHasArrayType,
137+
{
138+
fn type_info() -> PgTypeInfo {
139+
T::array_type_info()
140+
}
141+
142+
fn compatible(ty: &PgTypeInfo) -> bool {
143+
T::array_compatible(ty)
144+
}
145+
}
146+
133147
impl<'q, T> Encode<'q, Postgres> for Vec<T>
134148
where
135149
for<'a> &'a [T]: Encode<'q, Postgres>,
@@ -192,6 +206,17 @@ where
192206
}
193207
}
194208

209+
impl<'q, T> Encode<'q, Postgres> for Arc<[T]>
210+
where
211+
for<'a> &'a [T]: Encode<'q, Postgres>,
212+
T: Encode<'q, Postgres>,
213+
{
214+
#[inline]
215+
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
216+
<&[T] as Encode<Postgres>>::encode_by_ref(&self.as_ref(), buf)
217+
}
218+
}
219+
195220
impl<'r, T, const N: usize> Decode<'r, Postgres> for [T; N]
196221
where
197222
T: for<'a> Decode<'a, Postgres> + Type<Postgres>,
@@ -354,3 +379,12 @@ where
354379
}
355380
}
356381
}
382+
383+
impl<'r, T> Decode<'r, Postgres> for Arc<[T]>
384+
where
385+
T: for<'a> Decode<'a, Postgres> + Type<Postgres>,
386+
{
387+
fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
388+
<Vec<T> as Decode<Postgres>>::decode(value).map(Into::into)
389+
}
390+
}

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: 33 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 {
@@ -54,6 +55,16 @@ impl Type<Postgres> for String {
5455
}
5556
}
5657

58+
impl Type<Postgres> for Arc<str> {
59+
fn type_info() -> PgTypeInfo {
60+
<&str as Type<Postgres>>::type_info()
61+
}
62+
63+
fn compatible(ty: &PgTypeInfo) -> bool {
64+
<&str as Type<Postgres>>::compatible(ty)
65+
}
66+
}
67+
5768
impl PgHasArrayType for &'_ str {
5869
fn array_type_info() -> PgTypeInfo {
5970
PgTypeInfo::TEXT_ARRAY
@@ -94,6 +105,16 @@ impl PgHasArrayType for String {
94105
}
95106
}
96107

108+
impl PgHasArrayType for Arc<str> {
109+
fn array_type_info() -> PgTypeInfo {
110+
<&str as PgHasArrayType>::array_type_info()
111+
}
112+
113+
fn array_compatible(ty: &PgTypeInfo) -> bool {
114+
<&str as PgHasArrayType>::array_compatible(ty)
115+
}
116+
}
117+
97118
impl Encode<'_, Postgres> for &'_ str {
98119
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
99120
buf.extend(self.as_bytes());
@@ -123,6 +144,12 @@ impl Encode<'_, Postgres> for String {
123144
}
124145
}
125146

147+
impl Encode<'_, Postgres> for Arc<str> {
148+
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
149+
<&str as Encode<Postgres>>::encode(&**self, buf)
150+
}
151+
}
152+
126153
impl<'r> Decode<'r, Postgres> for &'r str {
127154
fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
128155
value.as_str()
@@ -146,3 +173,9 @@ impl Decode<'_, Postgres> for String {
146173
Ok(value.as_str()?.to_owned())
147174
}
148175
}
176+
177+
impl Decode<'_, Postgres> for Arc<str> {
178+
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
179+
Ok(value.as_str()?.into())
180+
}
181+
}

sqlx-sqlite/src/types/bytes.rs

Lines changed: 34 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};
@@ -101,3 +102,36 @@ impl<'r> Decode<'r, Sqlite> for Vec<u8> {
101102
Ok(value.blob().to_owned())
102103
}
103104
}
105+
106+
impl Type<Sqlite> for Arc<[u8]> {
107+
fn type_info() -> SqliteTypeInfo {
108+
<&[u8] as Type<Sqlite>>::type_info()
109+
}
110+
111+
fn compatible(ty: &SqliteTypeInfo) -> bool {
112+
<&[u8] as Type<Sqlite>>::compatible(ty)
113+
}
114+
}
115+
116+
impl<'q> Encode<'q, Sqlite> for Arc<[u8]> {
117+
fn encode(self, args: &mut Vec<SqliteArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
118+
args.push(SqliteArgumentValue::Blob(Cow::Owned(self.to_vec())));
119+
120+
Ok(IsNull::No)
121+
}
122+
123+
fn encode_by_ref(
124+
&self,
125+
args: &mut Vec<SqliteArgumentValue<'q>>,
126+
) -> Result<IsNull, BoxDynError> {
127+
args.push(SqliteArgumentValue::Blob(Cow::Owned(self.to_vec())));
128+
129+
Ok(IsNull::No)
130+
}
131+
}
132+
133+
impl<'r> Decode<'r, Sqlite> for Arc<[u8]> {
134+
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
135+
Ok(value.blob().into())
136+
}
137+
}

sqlx-sqlite/src/types/str.rs

Lines changed: 30 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};
@@ -122,3 +123,32 @@ impl<'r> Decode<'r, Sqlite> for Cow<'r, str> {
122123
value.text().map(Cow::Borrowed)
123124
}
124125
}
126+
127+
impl Type<Sqlite> for Arc<str> {
128+
fn type_info() -> SqliteTypeInfo {
129+
<&str as Type<Sqlite>>::type_info()
130+
}
131+
}
132+
133+
impl<'q> Encode<'q, Sqlite> for Arc<str> {
134+
fn encode(self, args: &mut Vec<SqliteArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
135+
args.push(SqliteArgumentValue::Text(Cow::Owned(self.to_string())));
136+
137+
Ok(IsNull::No)
138+
}
139+
140+
fn encode_by_ref(
141+
&self,
142+
args: &mut Vec<SqliteArgumentValue<'q>>,
143+
) -> Result<IsNull, BoxDynError> {
144+
args.push(SqliteArgumentValue::Text(Cow::Owned(self.to_string())));
145+
146+
Ok(IsNull::No)
147+
}
148+
}
149+
150+
impl<'r> Decode<'r, Sqlite> for Arc<str> {
151+
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
152+
value.text().map(Into::into)
153+
}
154+
}

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+
}

0 commit comments

Comments
 (0)