Skip to content

Commit 73a6da5

Browse files
authored
Merge pull request diesel-rs#925 from KeenS/mac_addr
implement macaddr
2 parents 2701c1c + 9e14061 commit 73a6da5

5 files changed

Lines changed: 121 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
88

99
### Added
1010

11+
* Added support for the [PostgreSQL network types][pg-network-0.13.1] `MACADDR`.
12+
1113
* Added a function which maps to SQL `NOT`. See [the docs][not-0.14.0] for more
1214
details.
1315

16+
[pg-network-0.13.1]: https://www.postgresql.org/docs/9.6/static/datatype-net-types.html
1417
[not-0.14.0]: http://docs.diesel.rs/diesel/expression/dsl/fn.not.html
1518

1619
## [0.13.0] - 2017-05-15

diesel/src/pg/types/mod.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,72 @@ pub mod sql_types {
280280
/// ```
281281
#[derive(Debug, Clone, Copy, Default)] pub struct Money;
282282

283+
#[cfg(feature = "network-address")]
284+
/// The [`MACADDR`](https://www.postgresql.org/docs/9.6/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"`
285+
///
286+
/// ### [`ToSql`](/diesel/types/trait.ToSql.html) impls
287+
///
288+
/// - `[u8; 6]`
289+
///
290+
/// ### [`FromSql`](/diesel/types/trait.FromSql.html) impls
291+
///
292+
/// - `[u8; 6]`
293+
///
294+
/// # Examples
295+
///
296+
/// ```rust
297+
/// # #![allow(dead_code)]
298+
/// # #[macro_use] extern crate diesel_codegen;
299+
/// # #[macro_use] extern crate diesel;
300+
/// # include!("src/doctest_setup.rs");
301+
/// #
302+
/// # table! {
303+
/// # users {
304+
/// # id -> Serial,
305+
/// # name -> VarChar,
306+
/// # }
307+
/// # }
308+
/// #
309+
/// # use diesel::types::MacAddr;
310+
///
311+
/// #[derive(Queryable)]
312+
/// struct Device {
313+
/// id: i32,
314+
/// macaddr: [u8; 6],
315+
/// }
316+
///
317+
/// #[derive(Insertable)]
318+
/// #[table_name="devices"]
319+
/// struct NewDevice {
320+
/// macaddr: [u8;6],
321+
/// }
322+
///
323+
/// table! {
324+
/// devices {
325+
/// id -> Integer,
326+
/// macaddr -> MacAddr,
327+
/// }
328+
/// }
329+
///
330+
/// # fn main() {
331+
/// # use self::diesel::insert;
332+
/// # use self::devices::dsl::*;
333+
/// # let connection = connection_no_data();
334+
/// # connection.execute("CREATE TABLE devices (
335+
/// # id SERIAL PRIMARY KEY,
336+
/// # macaddr MACADDR NOT NULL
337+
/// # )").unwrap();
338+
/// let new_device = NewDevice {
339+
/// macaddr: [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03],
340+
/// };
341+
/// let inserted_device = insert(&new_device).into(devices)
342+
/// .get_result::<Device>(&connection).unwrap();
343+
/// assert_eq!([0x08, 0x00, 0x2b, 0x01, 0x02, 0x03], inserted_device.macaddr);
344+
/// # }
345+
/// ```
346+
#[derive(Debug, Clone, Copy, Default)]
347+
pub struct MacAddr;
348+
283349
/// The [`CIDR`](https://www.postgresql.org/docs/9.6/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"`
284350
///
285351
/// ### [`ToSql`](/diesel/types/trait.ToSql.html) impls

diesel/src/pg/types/network_address.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ const AF_INET: u8 = libc::AF_INET as u8;
2121
const PGSQL_AF_INET: u8 = AF_INET;
2222
const PGSQL_AF_INET6: u8 = AF_INET + 1;
2323

24+
// https://github.com/postgres/postgres/blob/502a3832cc54c7115dacb8a2dae06f0620995ac6/src/include/catalog/pg_type.h#L435-L443
25+
primitive_impls!(MacAddr -> ([u8; 6], pg: (829, 1040)));
2426
primitive_impls!(Cidr -> (IpNetwork, pg: (650, 651)));
2527
primitive_impls!(Inet -> (IpNetwork, pg: (869, 1041)));
2628

@@ -39,6 +41,23 @@ macro_rules! assert_or_error {
3941
};
4042
}
4143

44+
impl FromSql<types::MacAddr, Pg> for [u8; 6] {
45+
fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<Error + Send + Sync>> {
46+
let bytes = not_none!(bytes);
47+
assert_or_error!(6 == bytes.len(), "input isn't 6 bytes.");
48+
Ok([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]])
49+
}
50+
51+
}
52+
53+
impl ToSql<types::MacAddr, Pg> for [u8; 6] {
54+
fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error + Send + Sync>> {
55+
out.write_all(&self[..])
56+
.map(|_| IsNull::No)
57+
.map_err(|e| Box::new(e) as Box<Error + Send + Sync>)
58+
59+
}
60+
}
4261
macro_rules! impl_Sql {
4362
($ty: ty, $net_type: expr) => {
4463
impl FromSql<$ty, Pg> for IpNetwork {
@@ -115,6 +134,15 @@ impl_Sql!(types::Inet, 0);
115134
impl_Sql!(types::Cidr, 1);
116135

117136

137+
#[test]
138+
fn macaddr_roundtrip() {
139+
let mut bytes = vec![];
140+
let input_address = [0x52, 0x54,0x00, 0xfb, 0xc6, 0x16];
141+
ToSql::<types::MacAddr, Pg>::to_sql(&input_address, &mut bytes).unwrap();
142+
let output_address:[u8; 6] = FromSql::from_sql(Some(bytes.as_ref())).unwrap();
143+
assert_eq!(input_address, output_address);
144+
}
145+
118146
#[test]
119147
fn v4address_to_sql() {
120148
macro_rules! test_to_sql {

diesel_tests/tests/types.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,24 @@ fn pg_uuid_to_sql_uuid() {
453453
assert!(!query_to_sql_equality::<Uuid, uuid::Uuid>(expected_non_equal_value, value));
454454
}
455455

456+
#[test]
457+
#[cfg(feature = "postgres")]
458+
fn pg_macaddress_from_sql() {
459+
let query = "'08:00:2b:01:02:03'::macaddr";
460+
let expected_value = [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03];
461+
assert_eq!(expected_value,
462+
query_single_value::<MacAddr, [u8; 6]>(query));
463+
}
464+
465+
#[test]
466+
#[cfg(feature = "postgres")]
467+
fn pg_macaddress_to_sql_macaddress() {
468+
let expected_value = "'08:00:2b:01:02:03'::macaddr";
469+
let value = [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03];
470+
assert!(query_to_sql_equality::<MacAddr, [u8; 6]>(expected_value, value));
471+
}
472+
473+
456474
#[test]
457475
#[cfg(feature = "postgres")]
458476
fn pg_v4address_from_sql() {

diesel_tests/tests/types_roundtrip.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,18 @@ mod pg_types {
107107
test_round_trip!(array_of_bigint_roundtrips, Array<BigInt>, Vec<i64>);
108108
test_round_trip!(array_of_dynamic_size_roundtrips, Array<Text>, Vec<String>);
109109
test_round_trip!(array_of_nullable_roundtrips, Array<Nullable<Text>>, Vec<Option<String>>);
110+
test_round_trip!(macaddr_roundtrips, MacAddr, (u8, u8, u8, u8, u8, u8), mk_macaddr);
110111

111112
fn mk_uuid(data: (u32, u16, u16, (u8, u8, u8, u8, u8, u8, u8, u8))) -> self::uuid::Uuid {
112113
let a = data.3;
113114
let b = [a.0, a.1, a.2, a.3, a.4, a.5, a.6, a.7];
114115
uuid::Uuid::from_fields(data.0, data.1, data.2, &b).unwrap()
115116
}
117+
118+
fn mk_macaddr(data: (u8, u8, u8, u8, u8, u8)) -> [u8; 6] {
119+
[data.0, data.1, data.2, data.3, data.4, data.5]
120+
}
121+
116122
}
117123

118124
#[cfg(feature = "mysql")]

0 commit comments

Comments
 (0)