From 8d0aefecf6da9220de57df7b45fef7ba0696eb7b Mon Sep 17 00:00:00 2001 From: Daniele Date: Fri, 18 Oct 2024 13:29:23 +0200 Subject: [PATCH 1/5] feat: add pg macaddr8 type support --- diesel/src/pg/types/mac_addr_8.rs | 49 +++++++++++++++++++ diesel/src/pg/types/mod.rs | 49 +++++++++++++++++++ diesel_cli/src/print_schema.rs | 1 + .../postgres/schema.rs | 1 + diesel_tests/tests/types.rs | 22 +++++++++ diesel_tests/tests/types_roundtrip.rs | 6 +++ 6 files changed, 128 insertions(+) create mode 100644 diesel/src/pg/types/mac_addr_8.rs diff --git a/diesel/src/pg/types/mac_addr_8.rs b/diesel/src/pg/types/mac_addr_8.rs new file mode 100644 index 000000000000..f6cb32bd79fd --- /dev/null +++ b/diesel/src/pg/types/mac_addr_8.rs @@ -0,0 +1,49 @@ +use std::io::prelude::*; + +use crate::deserialize::{self, FromSql}; +use crate::pg::{Pg, PgValue}; +use crate::serialize::{self, IsNull, Output, ToSql}; +use super::sql_types::MacAddr8; + +#[allow(dead_code)] +mod foreign_derives { + use super::*; + use crate::deserialize::FromSqlRow; + use crate::expression::AsExpression; + + #[derive(AsExpression, FromSqlRow)] + #[diesel(foreign_derive)] + #[diesel(sql_type = MacAddr8)] + struct ByteArrayProxy([u8; 8]); +} + +#[cfg(feature = "postgres_backend")] +impl FromSql for [u8; 8] { + fn from_sql(value: PgValue<'_>) -> deserialize::Result { + value + .as_bytes() + .try_into() + .map_err(|_| "invalid network address format: input isn't 8 bytes.".into()) + } +} + +#[cfg(feature = "postgres_backend")] +impl ToSql for [u8; 8] { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result { + out.write_all(&self[..]) + .map(|_| IsNull::No) + .map_err(Into::into) + } +} + +#[test] +fn macaddr8_roundtrip() { + use crate::query_builder::bind_collector::ByteWrapper; + + let mut buffer = Vec::new(); + let mut bytes = Output::test(ByteWrapper(&mut buffer)); + let input_address = [0x52, 0x54, 0x00, 0xfb, 0xc6, 0x16, 0x17, 0xFF]; + ToSql::::to_sql(&input_address, &mut bytes).unwrap(); + let output_address: [u8; 8] = FromSql::from_sql(PgValue::for_test(&buffer)).unwrap(); + assert_eq!(input_address, output_address); +} diff --git a/diesel/src/pg/types/mod.rs b/diesel/src/pg/types/mod.rs index 513627018c38..0760fccff7d2 100644 --- a/diesel/src/pg/types/mod.rs +++ b/diesel/src/pg/types/mod.rs @@ -11,6 +11,7 @@ mod ipnet_address; #[cfg(feature = "serde_json")] mod json; mod mac_addr; +mod mac_addr_8; #[doc(hidden)] pub(in crate::pg) mod money; mod multirange; @@ -407,6 +408,54 @@ pub mod sql_types { /// Alias for `MacAddr` to be able to use it with `diesel print-schema`. pub type Macaddr = MacAddr; + /// The [`MACADDR8`](https://www.postgresql.org/docs/current/static/datatype-net-types.html) SQL type. + /// + /// ### [`ToSql`] impls + /// + /// - `[u8; 8]` + /// + /// ### [`FromSql`] impls + /// + /// - `[u8; 8]` + /// + /// [`ToSql`]: crate::serialize::ToSql + /// [`FromSql`]: crate::deserialize::FromSql + /// + /// # Examples + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// table! { + /// devices { + /// id -> Integer, + /// macaddr -> MacAddr8, + /// } + /// } + /// + /// # fn main() -> Result<(), Box> { + /// # use diesel::insert_into; + /// # use self::devices::dsl::*; + /// # let connection = &mut connection_no_data(); + /// # diesel::sql_query("CREATE TABLE devices ( + /// # id SERIAL PRIMARY KEY, + /// # macaddr MACADDR8 NOT NULL + /// # )").execute(connection)?; + /// let inserted_macaddr = insert_into(devices) + /// .values(macaddr.eq([0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x05])) + /// .returning(macaddr) + /// .get_result::<[u8; 8]>(connection)?; + /// assert_eq!([0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x0], inserted_macaddr); + /// # Ok(()) + /// # } + /// ``` + #[cfg(feature = "postgres_backend")] + #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] + #[diesel(postgres_type(oid = 774, array_oid = 775))] + pub struct MacAddr8; + + /// Alias for `MacAddr` to be able to use it with `diesel print-schema`. + pub type Macaddr8 = MacAddr8; + /// The [`INET`](https://www.postgresql.org/docs/current/static/datatype-net-types.html) SQL type. This type can only be used with `feature = "network-address"` or `feature = "ipnet-address"`. /// /// ### [`ToSql`] impls diff --git a/diesel_cli/src/print_schema.rs b/diesel_cli/src/print_schema.rs index d72f9bb4e9ba..c25b466d8eb2 100644 --- a/diesel_cli/src/print_schema.rs +++ b/diesel_cli/src/print_schema.rs @@ -99,6 +99,7 @@ fn pg_diesel_types() -> HashSet<&'static str> { types.insert("Inet"); types.insert("Jsonb"); types.insert("MacAddr"); + types.insert("MacAddr8"); types.insert("Money"); types.insert("Oid"); types.insert("Range"); diff --git a/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/schema.rs b/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/schema.rs index 1d49b8e2e8ec..a47dbb364d2b 100644 --- a/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/schema.rs +++ b/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/schema.rs @@ -27,6 +27,7 @@ table! { inet_col -> Inet, jsonb_col -> Jsonb, macaddr_col -> MacAddr, + macaddr8_col -> MacAddr8, money_col -> Money, oid_col -> Oid, timestamptz_col -> Timestamptz, diff --git a/diesel_tests/tests/types.rs b/diesel_tests/tests/types.rs index 9f5d1026bf9d..c318a1b8600a 100644 --- a/diesel_tests/tests/types.rs +++ b/diesel_tests/tests/types.rs @@ -1070,6 +1070,28 @@ fn pg_macaddress_to_sql_macaddress() { )); } +#[test] +#[cfg(feature = "postgres")] +fn pg_macaddress8_from_sql() { + let query = "'08:00:2b:01:02:03:04:05'::macaddr"; + let expected_value = [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x05]; + assert_eq!( + expected_value, + query_single_value::(query) + ); +} + +#[test] +#[cfg(feature = "postgres")] +fn pg_macaddress8_to_sql_macaddress() { + let expected_value = "'08:00:2b:01:02:03:04:05'::macaddr"; + let value = [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x05]; + assert!(query_to_sql_equality::( + expected_value, + value + )); +} + #[test] #[cfg(feature = "postgres")] fn pg_v4address_from_sql() { diff --git a/diesel_tests/tests/types_roundtrip.rs b/diesel_tests/tests/types_roundtrip.rs index 05a48a25f8bc..b3da8f307810 100644 --- a/diesel_tests/tests/types_roundtrip.rs +++ b/diesel_tests/tests/types_roundtrip.rs @@ -186,6 +186,12 @@ mod pg_types { (u8, u8, u8, u8, u8, u8), mk_macaddr ); + test_round_trip!( + macaddr_roundtrips, + MacAddr8, + (u8, u8, u8, u8, u8, u8, u8, u8), + mk_macaddr + ); test_round_trip!(cidr_v4_roundtrips, Cidr, (u8, u8, u8, u8), mk_ipv4); test_round_trip!( cidr_v4_roundtrips_ipnet, From 4720e8e65d02530d2ba95f54eac8de9598778266 Mon Sep 17 00:00:00 2001 From: Daniele Date: Fri, 18 Oct 2024 13:34:22 +0200 Subject: [PATCH 2/5] fix: test macaddr query input type --- diesel_tests/tests/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/diesel_tests/tests/types.rs b/diesel_tests/tests/types.rs index c318a1b8600a..df1999f35cec 100644 --- a/diesel_tests/tests/types.rs +++ b/diesel_tests/tests/types.rs @@ -1073,7 +1073,7 @@ fn pg_macaddress_to_sql_macaddress() { #[test] #[cfg(feature = "postgres")] fn pg_macaddress8_from_sql() { - let query = "'08:00:2b:01:02:03:04:05'::macaddr"; + let query = "'08:00:2b:01:02:03:04:05'::macaddr8"; let expected_value = [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x05]; assert_eq!( expected_value, @@ -1084,7 +1084,7 @@ fn pg_macaddress8_from_sql() { #[test] #[cfg(feature = "postgres")] fn pg_macaddress8_to_sql_macaddress() { - let expected_value = "'08:00:2b:01:02:03:04:05'::macaddr"; + let expected_value = "'08:00:2b:01:02:03:04:05'::macaddr8"; let value = [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x05]; assert!(query_to_sql_equality::( expected_value, From cb88cc34d6f34a1651ede48e6ea1eda1ae7f1187 Mon Sep 17 00:00:00 2001 From: Daniele Date: Fri, 18 Oct 2024 14:32:26 +0200 Subject: [PATCH 3/5] fix: macaddr8 roundtrip --- diesel_tests/tests/types_roundtrip.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diesel_tests/tests/types_roundtrip.rs b/diesel_tests/tests/types_roundtrip.rs index b3da8f307810..0ce3a09ac5e8 100644 --- a/diesel_tests/tests/types_roundtrip.rs +++ b/diesel_tests/tests/types_roundtrip.rs @@ -187,7 +187,7 @@ mod pg_types { mk_macaddr ); test_round_trip!( - macaddr_roundtrips, + macaddr8_roundtrips, MacAddr8, (u8, u8, u8, u8, u8, u8, u8, u8), mk_macaddr From 502bfc139b1e8bde75ba8f1cefab8c9852f7a45d Mon Sep 17 00:00:00 2001 From: Daniele Date: Mon, 28 Oct 2024 18:19:41 +0100 Subject: [PATCH 4/5] fix: macaddr8 tests --- diesel/src/pg/types/mac_addr_8.rs | 2 +- diesel/src/pg/types/mod.rs | 2 +- diesel_cli/src/print_schema.rs | 1 + diesel_tests/tests/types.rs | 4 ++-- diesel_tests/tests/types_roundtrip.rs | 8 +++++++- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/diesel/src/pg/types/mac_addr_8.rs b/diesel/src/pg/types/mac_addr_8.rs index f6cb32bd79fd..217e5985d201 100644 --- a/diesel/src/pg/types/mac_addr_8.rs +++ b/diesel/src/pg/types/mac_addr_8.rs @@ -1,9 +1,9 @@ use std::io::prelude::*; +use super::sql_types::MacAddr8; use crate::deserialize::{self, FromSql}; use crate::pg::{Pg, PgValue}; use crate::serialize::{self, IsNull, Output, ToSql}; -use super::sql_types::MacAddr8; #[allow(dead_code)] mod foreign_derives { diff --git a/diesel/src/pg/types/mod.rs b/diesel/src/pg/types/mod.rs index 0760fccff7d2..947626c0938c 100644 --- a/diesel/src/pg/types/mod.rs +++ b/diesel/src/pg/types/mod.rs @@ -444,7 +444,7 @@ pub mod sql_types { /// .values(macaddr.eq([0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x05])) /// .returning(macaddr) /// .get_result::<[u8; 8]>(connection)?; - /// assert_eq!([0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x0], inserted_macaddr); + /// assert_eq!([0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x05], inserted_macaddr); /// # Ok(()) /// # } /// ``` diff --git a/diesel_cli/src/print_schema.rs b/diesel_cli/src/print_schema.rs index c25b466d8eb2..17a43e27723f 100644 --- a/diesel_cli/src/print_schema.rs +++ b/diesel_cli/src/print_schema.rs @@ -128,6 +128,7 @@ fn pg_diesel_types() -> HashSet<&'static str> { types.insert("Bytea"); types.insert("Bpchar"); types.insert("Macaddr"); + types.insert("Macaddr8"); common_diesel_types(&mut types); types diff --git a/diesel_tests/tests/types.rs b/diesel_tests/tests/types.rs index df1999f35cec..2cf96db1c542 100644 --- a/diesel_tests/tests/types.rs +++ b/diesel_tests/tests/types.rs @@ -1077,7 +1077,7 @@ fn pg_macaddress8_from_sql() { let expected_value = [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x05]; assert_eq!( expected_value, - query_single_value::(query) + query_single_value::(query) ); } @@ -1086,7 +1086,7 @@ fn pg_macaddress8_from_sql() { fn pg_macaddress8_to_sql_macaddress() { let expected_value = "'08:00:2b:01:02:03:04:05'::macaddr8"; let value = [0x08, 0x00, 0x2b, 0x01, 0x02, 0x03, 0x04, 0x05]; - assert!(query_to_sql_equality::( + assert!(query_to_sql_equality::( expected_value, value )); diff --git a/diesel_tests/tests/types_roundtrip.rs b/diesel_tests/tests/types_roundtrip.rs index 0ce3a09ac5e8..61203e09b550 100644 --- a/diesel_tests/tests/types_roundtrip.rs +++ b/diesel_tests/tests/types_roundtrip.rs @@ -190,7 +190,7 @@ mod pg_types { macaddr8_roundtrips, MacAddr8, (u8, u8, u8, u8, u8, u8, u8, u8), - mk_macaddr + mk_macaddr8 ); test_round_trip!(cidr_v4_roundtrips, Cidr, (u8, u8, u8, u8), mk_ipv4); test_round_trip!( @@ -310,6 +310,12 @@ mod pg_types { [data.0, data.1, data.2, data.3, data.4, data.5] } + fn mk_macaddr8(data: (u8, u8, u8, u8, u8, u8, u8, u8)) -> [u8; 8] { + [ + data.0, data.1, data.2, data.3, data.4, data.5, data.6, data.7, + ] + } + fn mk_ipv4(data: (u8, u8, u8, u8)) -> ipnetwork::IpNetwork { use std::net::Ipv4Addr; let ip = Ipv4Addr::new(data.0, data.1, data.2, data.3); From 257bf00e336d733d9575d3570e9dbb4618fdbc7d Mon Sep 17 00:00:00 2001 From: Daniele Date: Mon, 28 Oct 2024 18:43:59 +0100 Subject: [PATCH 5/5] fix: macaddr8 postgres migration --- .../postgres/schema_out.rs/expected.snap | 2 +- .../diff_add_table_all_the_types/postgres/up.sql/expected.snap | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/schema_out.rs/expected.snap b/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/schema_out.rs/expected.snap index 1c58966abf0b..ee3ba62744d8 100644 --- a/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/schema_out.rs/expected.snap +++ b/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/schema_out.rs/expected.snap @@ -35,6 +35,7 @@ diesel::table! { inet_col -> Inet, jsonb_col -> Jsonb, macaddr_col -> Macaddr, + macaddr8_col -> Macaddr8, money_col -> Money, oid_col -> Oid, timestamptz_col -> Timestamptz, @@ -57,4 +58,3 @@ diesel::table! { macaddr2_col -> Macaddr, } } - diff --git a/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/up.sql/expected.snap b/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/up.sql/expected.snap index 0ca4612b7e20..69b6d24ddb49 100644 --- a/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/up.sql/expected.snap +++ b/diesel_cli/tests/generate_migrations/diff_add_table_all_the_types/postgres/up.sql/expected.snap @@ -31,6 +31,7 @@ CREATE TABLE "all_the_types"( "inet_col" INET NOT NULL, "jsonb_col" JSONB NOT NULL, "macaddr_col" MACADDR NOT NULL, + "macaddr8_col" MACADDR8 NOT NULL, "money_col" MONEY NOT NULL, "oid_col" OID NOT NULL, "timestamptz_col" TIMESTAMPTZ NOT NULL,