Skip to content

Commit be189bd

Browse files
authored
Support MACADDR in Postgres (#1329)
1 parent 0abbcc5 commit be189bd

File tree

10 files changed

+136
-0
lines changed

10 files changed

+136
-0
lines changed

Cargo.lock

+25
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ all-types = [
5959
"time",
6060
"chrono",
6161
"ipnetwork",
62+
"mac_address",
6263
"uuid",
6364
"bit-vec",
6465
"bstr",
@@ -121,6 +122,7 @@ bigdecimal = ["sqlx-core/bigdecimal", "sqlx-macros/bigdecimal"]
121122
decimal = ["sqlx-core/decimal", "sqlx-macros/decimal"]
122123
chrono = ["sqlx-core/chrono", "sqlx-macros/chrono"]
123124
ipnetwork = ["sqlx-core/ipnetwork", "sqlx-macros/ipnetwork"]
125+
mac_address = ["sqlx-core/mac_address", "sqlx-macros/mac_address"]
124126
uuid = ["sqlx-core/uuid", "sqlx-macros/uuid"]
125127
json = ["sqlx-core/json", "sqlx-macros/json"]
126128
time = ["sqlx-core/time", "sqlx-macros/time"]

sqlx-core/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ all-types = [
5454
"bigdecimal",
5555
"decimal",
5656
"ipnetwork",
57+
"mac_address",
5758
"json",
5859
"uuid",
5960
"bit-vec",
@@ -125,6 +126,7 @@ hex = "0.4.2"
125126
hmac = { version = "0.10.1", default-features = false, optional = true }
126127
itoa = "0.4.5"
127128
ipnetwork = { version = "0.17.0", default-features = false, optional = true }
129+
mac_address = { version = "1.1", default-features = false, optional = true }
128130
libc = "0.2.71"
129131
libsqlite3-sys = { version = "0.22.0", optional = true, default-features = false, features = [
130132
"pkg-config",

sqlx-core/src/postgres/type_info.rs

+2
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ impl PgTypeInfo {
198198
.contains(self)
199199
{
200200
Some("ipnetwork")
201+
} else if [PgTypeInfo::MACADDR].contains(self) {
202+
Some("mac_address")
201203
} else if [PgTypeInfo::NUMERIC, PgTypeInfo::NUMERIC_ARRAY].contains(self) {
202204
Some("bigdecimal")
203205
} else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use mac_address::MacAddress;
2+
3+
use std::convert::TryInto;
4+
5+
use crate::decode::Decode;
6+
use crate::encode::{Encode, IsNull};
7+
use crate::error::BoxDynError;
8+
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
9+
use crate::types::Type;
10+
11+
impl Type<Postgres> for MacAddress {
12+
fn type_info() -> PgTypeInfo {
13+
PgTypeInfo::MACADDR
14+
}
15+
16+
fn compatible(ty: &PgTypeInfo) -> bool {
17+
*ty == PgTypeInfo::MACADDR
18+
}
19+
}
20+
21+
impl Type<Postgres> for [MacAddress] {
22+
fn type_info() -> PgTypeInfo {
23+
PgTypeInfo::MACADDR_ARRAY
24+
}
25+
}
26+
27+
impl Type<Postgres> for Vec<MacAddress> {
28+
fn type_info() -> PgTypeInfo {
29+
<[MacAddress] as Type<Postgres>>::type_info()
30+
}
31+
32+
fn compatible(ty: &PgTypeInfo) -> bool {
33+
<[MacAddress] as Type<Postgres>>::compatible(ty)
34+
}
35+
}
36+
37+
impl Encode<'_, Postgres> for MacAddress {
38+
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
39+
buf.extend_from_slice(&self.bytes()); // write just the address
40+
IsNull::No
41+
}
42+
43+
fn size_hint(&self) -> usize {
44+
6
45+
}
46+
}
47+
48+
impl Decode<'_, Postgres> for MacAddress {
49+
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
50+
let bytes = match value.format() {
51+
PgValueFormat::Binary => value.as_bytes()?,
52+
PgValueFormat::Text => {
53+
return Ok(value.as_str()?.parse()?);
54+
}
55+
};
56+
57+
if bytes.len() == 6 {
58+
return Ok(MacAddress::new(bytes.try_into().unwrap()));
59+
}
60+
61+
Err("invalid data received when expecting an MACADDR".into())
62+
}
63+
}

sqlx-core/src/postgres/types/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@
7373
//! |---------------------------------------|------------------------------------------------------|
7474
//! | `ipnetwork::IpNetwork` | INET, CIDR |
7575
//!
76+
//! ### [`mac_address`](https://crates.io/crates/mac_address)
77+
//!
78+
//! Requires the `mac_address` Cargo feature flag.
79+
//!
80+
//! | Rust type | Postgres type(s) |
81+
//! |---------------------------------------|------------------------------------------------------|
82+
//! | `mac_address::MacAddress` | MACADDR |
83+
//!
7684
//! ### [`bit-vec`](https://crates.io/crates/bit-vec)
7785
//!
7886
//! Requires the `bit-vec` Cargo feature flag.
@@ -194,6 +202,9 @@ mod json;
194202
#[cfg(feature = "ipnetwork")]
195203
mod ipnetwork;
196204

205+
#[cfg(feature = "mac_address")]
206+
mod mac_address;
207+
197208
#[cfg(feature = "bit-vec")]
198209
mod bit_vec;
199210

sqlx-core/src/types/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ pub mod ipnetwork {
7575
pub use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
7676
}
7777

78+
#[cfg(feature = "mac_address")]
79+
#[cfg_attr(docsrs, doc(cfg(feature = "mac_address")))]
80+
pub mod mac_address {
81+
#[doc(no_inline)]
82+
pub use mac_address::MacAddress;
83+
}
84+
7885
#[cfg(feature = "json")]
7986
pub use json::Json;
8087

sqlx-macros/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ decimal = ["sqlx-core/decimal"]
7272
chrono = ["sqlx-core/chrono"]
7373
time = ["sqlx-core/time"]
7474
ipnetwork = ["sqlx-core/ipnetwork"]
75+
mac_address = ["sqlx-core/mac_address"]
7576
uuid = ["sqlx-core/uuid"]
7677
bit-vec = ["sqlx-core/bit-vec"]
7778
json = ["sqlx-core/json", "serde_json"]

sqlx-macros/src/database/postgres.rs

+6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ impl_database_ext! {
6060
#[cfg(feature = "ipnetwork")]
6161
sqlx::types::ipnetwork::IpNetwork,
6262

63+
#[cfg(feature = "mac_address")]
64+
sqlx::types::mac_address::MacAddress,
65+
6366
#[cfg(feature = "json")]
6467
serde_json::Value,
6568

@@ -113,6 +116,9 @@ impl_database_ext! {
113116
#[cfg(feature = "ipnetwork")]
114117
Vec<sqlx::types::ipnetwork::IpNetwork> | &[sqlx::types::ipnetwork::IpNetwork],
115118

119+
#[cfg(feature = "mac_address")]
120+
Vec<sqlx::types::mac_address::MacAddress> | &[sqlx::types::mac_address::MacAddress],
121+
116122
#[cfg(feature = "json")]
117123
Vec<serde_json::Value> | &[serde_json::Value],
118124

tests/postgres/types.rs

+17
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,14 @@ test_type!(ipnetwork<sqlx::types::ipnetwork::IpNetwork>(Postgres,
167167
.unwrap(),
168168
));
169169

170+
#[cfg(feature = "mac_address")]
171+
test_type!(mac_address<sqlx::types::mac_address::MacAddress>(Postgres,
172+
"'00:01:02:03:04:05'::macaddr"
173+
== "00:01:02:03:04:05"
174+
.parse::<sqlx::types::mac_address::MacAddress>()
175+
.unwrap()
176+
));
177+
170178
#[cfg(feature = "bit-vec")]
171179
test_type!(bitvec<sqlx::types::BitVec>(
172180
Postgres,
@@ -201,6 +209,15 @@ test_type!(ipnetwork_vec<Vec<sqlx::types::ipnetwork::IpNetwork>>(Postgres,
201209
]
202210
));
203211

212+
#[cfg(feature = "mac_address")]
213+
test_type!(mac_address_vec<Vec<sqlx::types::mac_address::MacAddress>>(Postgres,
214+
"'{01:02:03:04:05:06,FF:FF:FF:FF:FF:FF}'::inet[]"
215+
== vec![
216+
"01:02:03:04:05:06".parse::<sqlx::types::mac_address::MacAddress>().unwrap(),
217+
"FF:FF:FF:FF:FF:FF".parse::<sqlx::types::mac_address::MacAddress>().unwrap()
218+
]
219+
));
220+
204221
#[cfg(feature = "chrono")]
205222
mod chrono {
206223
use super::*;

0 commit comments

Comments
 (0)