Skip to content

Commit

Permalink
Support MACADDR in Postgres (#1329)
Browse files Browse the repository at this point in the history
  • Loading branch information
nomick authored Jul 19, 2021
1 parent 0abbcc5 commit be189bd
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 0 deletions.
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ all-types = [
"time",
"chrono",
"ipnetwork",
"mac_address",
"uuid",
"bit-vec",
"bstr",
Expand Down Expand Up @@ -121,6 +122,7 @@ bigdecimal = ["sqlx-core/bigdecimal", "sqlx-macros/bigdecimal"]
decimal = ["sqlx-core/decimal", "sqlx-macros/decimal"]
chrono = ["sqlx-core/chrono", "sqlx-macros/chrono"]
ipnetwork = ["sqlx-core/ipnetwork", "sqlx-macros/ipnetwork"]
mac_address = ["sqlx-core/mac_address", "sqlx-macros/mac_address"]
uuid = ["sqlx-core/uuid", "sqlx-macros/uuid"]
json = ["sqlx-core/json", "sqlx-macros/json"]
time = ["sqlx-core/time", "sqlx-macros/time"]
Expand Down
2 changes: 2 additions & 0 deletions sqlx-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ all-types = [
"bigdecimal",
"decimal",
"ipnetwork",
"mac_address",
"json",
"uuid",
"bit-vec",
Expand Down Expand Up @@ -125,6 +126,7 @@ hex = "0.4.2"
hmac = { version = "0.10.1", default-features = false, optional = true }
itoa = "0.4.5"
ipnetwork = { version = "0.17.0", default-features = false, optional = true }
mac_address = { version = "1.1", default-features = false, optional = true }
libc = "0.2.71"
libsqlite3-sys = { version = "0.22.0", optional = true, default-features = false, features = [
"pkg-config",
Expand Down
2 changes: 2 additions & 0 deletions sqlx-core/src/postgres/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ impl PgTypeInfo {
.contains(self)
{
Some("ipnetwork")
} else if [PgTypeInfo::MACADDR].contains(self) {
Some("mac_address")
} else if [PgTypeInfo::NUMERIC, PgTypeInfo::NUMERIC_ARRAY].contains(self) {
Some("bigdecimal")
} else {
Expand Down
63 changes: 63 additions & 0 deletions sqlx-core/src/postgres/types/mac_address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use mac_address::MacAddress;

use std::convert::TryInto;

use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::types::Type;

impl Type<Postgres> for MacAddress {
fn type_info() -> PgTypeInfo {
PgTypeInfo::MACADDR
}

fn compatible(ty: &PgTypeInfo) -> bool {
*ty == PgTypeInfo::MACADDR
}
}

impl Type<Postgres> for [MacAddress] {
fn type_info() -> PgTypeInfo {
PgTypeInfo::MACADDR_ARRAY
}
}

impl Type<Postgres> for Vec<MacAddress> {
fn type_info() -> PgTypeInfo {
<[MacAddress] as Type<Postgres>>::type_info()
}

fn compatible(ty: &PgTypeInfo) -> bool {
<[MacAddress] as Type<Postgres>>::compatible(ty)
}
}

impl Encode<'_, Postgres> for MacAddress {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend_from_slice(&self.bytes()); // write just the address
IsNull::No
}

fn size_hint(&self) -> usize {
6
}
}

impl Decode<'_, Postgres> for MacAddress {
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
let bytes = match value.format() {
PgValueFormat::Binary => value.as_bytes()?,
PgValueFormat::Text => {
return Ok(value.as_str()?.parse()?);
}
};

if bytes.len() == 6 {
return Ok(MacAddress::new(bytes.try_into().unwrap()));
}

Err("invalid data received when expecting an MACADDR".into())
}
}
11 changes: 11 additions & 0 deletions sqlx-core/src/postgres/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@
//! |---------------------------------------|------------------------------------------------------|
//! | `ipnetwork::IpNetwork` | INET, CIDR |
//!
//! ### [`mac_address`](https://crates.io/crates/mac_address)
//!
//! Requires the `mac_address` Cargo feature flag.
//!
//! | Rust type | Postgres type(s) |
//! |---------------------------------------|------------------------------------------------------|
//! | `mac_address::MacAddress` | MACADDR |
//!
//! ### [`bit-vec`](https://crates.io/crates/bit-vec)
//!
//! Requires the `bit-vec` Cargo feature flag.
Expand Down Expand Up @@ -194,6 +202,9 @@ mod json;
#[cfg(feature = "ipnetwork")]
mod ipnetwork;

#[cfg(feature = "mac_address")]
mod mac_address;

#[cfg(feature = "bit-vec")]
mod bit_vec;

Expand Down
7 changes: 7 additions & 0 deletions sqlx-core/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ pub mod ipnetwork {
pub use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
}

#[cfg(feature = "mac_address")]
#[cfg_attr(docsrs, doc(cfg(feature = "mac_address")))]
pub mod mac_address {
#[doc(no_inline)]
pub use mac_address::MacAddress;
}

#[cfg(feature = "json")]
pub use json::Json;

Expand Down
1 change: 1 addition & 0 deletions sqlx-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ decimal = ["sqlx-core/decimal"]
chrono = ["sqlx-core/chrono"]
time = ["sqlx-core/time"]
ipnetwork = ["sqlx-core/ipnetwork"]
mac_address = ["sqlx-core/mac_address"]
uuid = ["sqlx-core/uuid"]
bit-vec = ["sqlx-core/bit-vec"]
json = ["sqlx-core/json", "serde_json"]
Expand Down
6 changes: 6 additions & 0 deletions sqlx-macros/src/database/postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ impl_database_ext! {
#[cfg(feature = "ipnetwork")]
sqlx::types::ipnetwork::IpNetwork,

#[cfg(feature = "mac_address")]
sqlx::types::mac_address::MacAddress,

#[cfg(feature = "json")]
serde_json::Value,

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

#[cfg(feature = "mac_address")]
Vec<sqlx::types::mac_address::MacAddress> | &[sqlx::types::mac_address::MacAddress],

#[cfg(feature = "json")]
Vec<serde_json::Value> | &[serde_json::Value],

Expand Down
17 changes: 17 additions & 0 deletions tests/postgres/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ test_type!(ipnetwork<sqlx::types::ipnetwork::IpNetwork>(Postgres,
.unwrap(),
));

#[cfg(feature = "mac_address")]
test_type!(mac_address<sqlx::types::mac_address::MacAddress>(Postgres,
"'00:01:02:03:04:05'::macaddr"
== "00:01:02:03:04:05"
.parse::<sqlx::types::mac_address::MacAddress>()
.unwrap()
));

#[cfg(feature = "bit-vec")]
test_type!(bitvec<sqlx::types::BitVec>(
Postgres,
Expand Down Expand Up @@ -201,6 +209,15 @@ test_type!(ipnetwork_vec<Vec<sqlx::types::ipnetwork::IpNetwork>>(Postgres,
]
));

#[cfg(feature = "mac_address")]
test_type!(mac_address_vec<Vec<sqlx::types::mac_address::MacAddress>>(Postgres,
"'{01:02:03:04:05:06,FF:FF:FF:FF:FF:FF}'::inet[]"
== vec![
"01:02:03:04:05:06".parse::<sqlx::types::mac_address::MacAddress>().unwrap(),
"FF:FF:FF:FF:FF:FF".parse::<sqlx::types::mac_address::MacAddress>().unwrap()
]
));

#[cfg(feature = "chrono")]
mod chrono {
use super::*;
Expand Down

0 comments on commit be189bd

Please sign in to comment.