Support MACADDR in Postgres (#1329)

This commit is contained in:
nomick 2021-07-20 01:55:53 +02:00 committed by GitHub
parent 0abbcc510f
commit be189bd11e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 136 additions and 0 deletions

25
Cargo.lock generated
View file

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "actix-rt"
version = "2.2.0"
@ -1270,6 +1272,16 @@ dependencies = [
"value-bag",
]
[[package]]
name = "mac_address"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d9bb26482176bddeea173ceaa2acec85146d20cdcc631eafaf9d605d3d4fc23"
dependencies = [
"nix",
"winapi",
]
[[package]]
name = "maplit"
version = "1.0.2"
@ -1375,6 +1387,18 @@ dependencies = [
"tempfile",
]
[[package]]
name = "nix"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2"
dependencies = [
"bitflags",
"cc",
"cfg-if 1.0.0",
"libc",
]
[[package]]
name = "nom"
version = "6.1.2"
@ -2343,6 +2367,7 @@ dependencies = [
"libc",
"libsqlite3-sys",
"log",
"mac_address",
"md-5",
"memchr",
"num-bigint 0.3.2",

View file

@ -59,6 +59,7 @@ all-types = [
"time",
"chrono",
"ipnetwork",
"mac_address",
"uuid",
"bit-vec",
"bstr",
@ -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"]

View file

@ -54,6 +54,7 @@ all-types = [
"bigdecimal",
"decimal",
"ipnetwork",
"mac_address",
"json",
"uuid",
"bit-vec",
@ -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",

View file

@ -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 {

View file

@ -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())
}
}

View file

@ -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.
@ -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;

View file

@ -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;

View file

@ -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"]

View file

@ -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,
@ -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],

View file

@ -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,
@ -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::*;