From a016cc75e28a35b296bf80f1bbebeb168c0f4e81 Mon Sep 17 00:00:00 2001 From: Marc Coleman Date: Tue, 16 Jan 2024 16:07:11 -0500 Subject: [PATCH 1/5] Include more detail for implementing custom types for diesel::MultiConnection --- diesel_derives/src/lib.rs | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/diesel_derives/src/lib.rs b/diesel_derives/src/lib.rs index b1dceb5f86fd..083cd72cd062 100644 --- a/diesel_derives/src/lib.rs +++ b/diesel_derives/src/lib.rs @@ -1630,8 +1630,43 @@ pub fn table_proc(input: TokenStream) -> TokenStream { /// * `diesel::sql_types::Timestamp` /// /// Support for additional types can be added by providing manual implementations of -/// `HasSqlType`, `FromSql` and `ToSql` for the corresponding type + the generated -/// database backend. +/// `HasSqlType`, `FromSql` and `ToSql` for the corresponding type, all databases included +/// in your enum, and the backend generated by this derive called MultiBackend. +/// For example to support `diesel::sql_types::TimestamptzSqlite` with the `time` crate: +/// ``` +/// use diesel::backend::Backend; +/// use diesel::deserialize::{self, FromSql}; +/// use diesel::serialize::{self, IsNull, ToSql}; +/// use diesel::sql_types::HasSqlType; +/// +/// #[derive(diesel::MultiConnection)] +/// pub enum AnyConnection { +/// # #[cfg(feature = "sqlite")] +/// Sqlite(diesel::SqliteConnection), +/// } +/// +/// # #[cfg(all("sqlite", "time"))] +/// impl HasSqlType for MultiBackend { +/// fn metadata(lookup: &mut Self::MetadataLookup) -> Self::TypeMetadata { +/// MultiBackend::lookup_sql_type::(lookup) +/// } +/// } +/// +/// # #[cfg(all("sqlite", "time"))] +/// impl FromSql for time::OffsetDateTime { +/// fn from_sql(bytes: ::RawValue<'_>) -> deserialize::Result { +/// bytes.from_sql::() +/// } +/// } +/// +/// # #[cfg(all("sqlite", "time"))] +/// impl ToSql for time::OffsetDateTime { +/// fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, MultiBackend>) -> serialize::Result { +/// out.set_value((diesel::sql_types::TimestamptzSqlite, self)); +/// Ok(IsNull::No) +/// } +/// } +/// ``` #[proc_macro_derive(MultiConnection)] pub fn derive_multiconnection(input: TokenStream) -> TokenStream { multiconnection::derive(syn::parse_macro_input!(input)).into() From e6db7d71ca7cc7c1cf0c48b9ef4b2f9ae3f6c92c Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Mon, 22 Jan 2024 14:00:10 +0100 Subject: [PATCH 2/5] Fix config flags --- diesel_derives/src/lib.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/diesel_derives/src/lib.rs b/diesel_derives/src/lib.rs index 083cd72cd062..1f108ad07be3 100644 --- a/diesel_derives/src/lib.rs +++ b/diesel_derives/src/lib.rs @@ -1634,6 +1634,8 @@ pub fn table_proc(input: TokenStream) -> TokenStream { /// in your enum, and the backend generated by this derive called MultiBackend. /// For example to support `diesel::sql_types::TimestamptzSqlite` with the `time` crate: /// ``` +/// # #[cfg(all(feature = "sqlite", feature = "time"))] +/// # fn main() { /// use diesel::backend::Backend; /// use diesel::deserialize::{self, FromSql}; /// use diesel::serialize::{self, IsNull, ToSql}; @@ -1641,31 +1643,31 @@ pub fn table_proc(input: TokenStream) -> TokenStream { /// /// #[derive(diesel::MultiConnection)] /// pub enum AnyConnection { -/// # #[cfg(feature = "sqlite")] /// Sqlite(diesel::SqliteConnection), /// } /// -/// # #[cfg(all("sqlite", "time"))] /// impl HasSqlType for MultiBackend { /// fn metadata(lookup: &mut Self::MetadataLookup) -> Self::TypeMetadata { /// MultiBackend::lookup_sql_type::(lookup) /// } /// } /// -/// # #[cfg(all("sqlite", "time"))] /// impl FromSql for time::OffsetDateTime { /// fn from_sql(bytes: ::RawValue<'_>) -> deserialize::Result { /// bytes.from_sql::() /// } /// } /// -/// # #[cfg(all("sqlite", "time"))] /// impl ToSql for time::OffsetDateTime { /// fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, MultiBackend>) -> serialize::Result { /// out.set_value((diesel::sql_types::TimestamptzSqlite, self)); /// Ok(IsNull::No) /// } /// } +/// # } +/// +/// # #[cfg(not(all(feature = "sqlite", feature = "time")))] +/// # fn main() {} /// ``` #[proc_macro_derive(MultiConnection)] pub fn derive_multiconnection(input: TokenStream) -> TokenStream { From d9a441bd0c04ceb590d2a2ed16ed8e04f19dcfa7 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Mon, 22 Jan 2024 14:06:29 +0100 Subject: [PATCH 3/5] Add some more documentation about some function calls --- diesel_derives/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/diesel_derives/src/lib.rs b/diesel_derives/src/lib.rs index 1f108ad07be3..e6ef0077b12c 100644 --- a/diesel_derives/src/lib.rs +++ b/diesel_derives/src/lib.rs @@ -1631,7 +1631,7 @@ pub fn table_proc(input: TokenStream) -> TokenStream { /// /// Support for additional types can be added by providing manual implementations of /// `HasSqlType`, `FromSql` and `ToSql` for the corresponding type, all databases included -/// in your enum, and the backend generated by this derive called MultiBackend. +/// in your enum, and the backend generated by this derive called `MultiBackend`. /// For example to support `diesel::sql_types::TimestamptzSqlite` with the `time` crate: /// ``` /// # #[cfg(all(feature = "sqlite", feature = "time"))] @@ -1646,20 +1646,26 @@ pub fn table_proc(input: TokenStream) -> TokenStream { /// Sqlite(diesel::SqliteConnection), /// } /// +/// // The `MultiBackend` type is generated by `#[derive(diesel::MultiConnection)]` /// impl HasSqlType for MultiBackend { /// fn metadata(lookup: &mut Self::MetadataLookup) -> Self::TypeMetadata { +/// // The `lookup_sql_type` function is exposed by the `MultiBackend` type /// MultiBackend::lookup_sql_type::(lookup) /// } /// } /// /// impl FromSql for time::OffsetDateTime { /// fn from_sql(bytes: ::RawValue<'_>) -> deserialize::Result { +/// // The `from_sql` function is exposed by the `RawValue` type of the +/// // `MultiBackend` type /// bytes.from_sql::() /// } /// } /// /// impl ToSql for time::OffsetDateTime { /// fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, MultiBackend>) -> serialize::Result { +/// /// `set_value` expects a tuple consisting of the target SQL type +/// /// and self for `MultiBackend` /// out.set_value((diesel::sql_types::TimestamptzSqlite, self)); /// Ok(IsNull::No) /// } From b6050c5217b8d5e4a6f185dd9cdf742eed613224 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 26 Jan 2024 12:26:23 +0100 Subject: [PATCH 4/5] Finally fix the doc test --- diesel_derives/src/lib.rs | 74 ++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/diesel_derives/src/lib.rs b/diesel_derives/src/lib.rs index e6ef0077b12c..7503c2d49f43 100644 --- a/diesel_derives/src/lib.rs +++ b/diesel_derives/src/lib.rs @@ -1632,47 +1632,95 @@ pub fn table_proc(input: TokenStream) -> TokenStream { /// Support for additional types can be added by providing manual implementations of /// `HasSqlType`, `FromSql` and `ToSql` for the corresponding type, all databases included /// in your enum, and the backend generated by this derive called `MultiBackend`. -/// For example to support `diesel::sql_types::TimestamptzSqlite` with the `time` crate: +/// For example to support a custom enum `MyEnum` with the custom SQL type `MyInteger`: /// ``` -/// # #[cfg(all(feature = "sqlite", feature = "time"))] -/// # fn main() { +/// extern crate diesel; /// use diesel::backend::Backend; -/// use diesel::deserialize::{self, FromSql}; +/// use diesel::deserialize::{self, FromSql, FromSqlRow}; /// use diesel::serialize::{self, IsNull, ToSql}; -/// use diesel::sql_types::HasSqlType; +/// use diesel::AsExpression; +/// use diesel::sql_types::{HasSqlType, SqlType}; +/// use diesel::prelude::*; /// /// #[derive(diesel::MultiConnection)] /// pub enum AnyConnection { +/// # #[cfg(feature = "postgres")] +/// Postgresql(diesel::PgConnection), +/// # #[cfg(feature = "mysql")] +/// Mysql(diesel::MysqlConnection), +/// # #[cfg(feature = "sqlite")] /// Sqlite(diesel::SqliteConnection), /// } /// +/// // defining an custom SQL type is optional +/// // you can also use types from `diesel::sql_types` +/// #[derive(Copy, Clone, Debug, SqlType)] +/// #[diesel(postgres_type(name = "Int4"))] +/// #[diesel(mysql_type(name = "Long"))] +/// #[diesel(sqlite_type(name = "Integer"))] +/// struct MyInteger; +/// +/// +/// // our custom enum +/// #[repr(i32)] +/// #[derive(Debug, Clone, Copy, AsExpression, FromSqlRow)] +/// #[diesel(sql_type = MyInteger)] +/// pub enum MyEnum { +/// A = 1, +/// B = 2, +/// } +/// /// // The `MultiBackend` type is generated by `#[derive(diesel::MultiConnection)]` -/// impl HasSqlType for MultiBackend { +/// // This part is only required if you define a custom sql type +/// impl HasSqlType for MultiBackend { /// fn metadata(lookup: &mut Self::MetadataLookup) -> Self::TypeMetadata { /// // The `lookup_sql_type` function is exposed by the `MultiBackend` type -/// MultiBackend::lookup_sql_type::(lookup) +/// MultiBackend::lookup_sql_type::(lookup) /// } /// } /// -/// impl FromSql for time::OffsetDateTime { +/// impl FromSql for MyEnum { /// fn from_sql(bytes: ::RawValue<'_>) -> deserialize::Result { /// // The `from_sql` function is exposed by the `RawValue` type of the /// // `MultiBackend` type -/// bytes.from_sql::() +/// // This requires a `FromSql` impl for each backend +/// bytes.from_sql::() /// } /// } /// -/// impl ToSql for time::OffsetDateTime { +/// impl ToSql for MyEnum { /// fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, MultiBackend>) -> serialize::Result { /// /// `set_value` expects a tuple consisting of the target SQL type /// /// and self for `MultiBackend` -/// out.set_value((diesel::sql_types::TimestamptzSqlite, self)); +/// /// This requires a `ToSql` impl for each backend +/// out.set_value((MyInteger, self)); /// Ok(IsNull::No) /// } /// } +/// # #[cfg(feature = "postgres")] +/// # impl ToSql for MyEnum { +/// # fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, diesel::pg::Pg>) -> serialize::Result { todo!() } +/// # } +/// # #[cfg(feature = "mysql")] +/// # impl ToSql for MyEnum { +/// # fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, diesel::mysql::Mysql>) -> serialize::Result { todo!() } +/// # } +/// # #[cfg(feature = "sqlite")] +/// # impl ToSql for MyEnum { +/// # fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, diesel::sqlite::Sqlite>) -> serialize::Result { todo!() } +/// # } +/// # #[cfg(feature = "postgres")] +/// # impl FromSql for MyEnum { +/// # fn from_sql(bytes: ::RawValue<'_>) -> deserialize::Result { todo!() } +/// # } +/// # #[cfg(feature = "mysql")] +/// # impl FromSql for MyEnum { +/// # fn from_sql(bytes: ::RawValue<'_>) -> deserialize::Result { todo!() } +/// # } +/// # #[cfg(feature = "sqlite")] +/// # impl FromSql for MyEnum { +/// # fn from_sql(bytes: ::RawValue<'_>) -> deserialize::Result { todo!() } /// # } -/// -/// # #[cfg(not(all(feature = "sqlite", feature = "time")))] /// # fn main() {} /// ``` #[proc_macro_derive(MultiConnection)] From 4c7b6ea61705ef18c3465354d4d1e9d925661b0c Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 26 Jan 2024 14:01:38 +0100 Subject: [PATCH 5/5] Workaround a breaking change in chrono https://github.com/chronotope/chrono/issues/1389 --- diesel/src/pg/types/date_and_time/chrono.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/diesel/src/pg/types/date_and_time/chrono.rs b/diesel/src/pg/types/date_and_time/chrono.rs index 6dc9bef95485..a19b871286f2 100644 --- a/diesel/src/pg/types/date_and_time/chrono.rs +++ b/diesel/src/pg/types/date_and_time/chrono.rs @@ -280,8 +280,8 @@ mod tests { let query = select(sql::("'J0'::date").eq(julian_epoch)); assert!(query.get_result::(connection).unwrap()); - let max_date = NaiveDate::MAX; - let query = select(sql::("'262143-12-31'::date").eq(max_date)); + let max_date = NaiveDate::from_ymd_opt(262142, 12, 31).unwrap(); + let query = select(sql::("'262142-12-31'::date").eq(max_date)); assert!(query.get_result::(connection).unwrap()); let january_first_2018 = NaiveDate::from_ymd_opt(2018, 1, 1).unwrap(); @@ -311,8 +311,8 @@ mod tests { let query = select(sql::("'J0'::date")); assert_eq!(Ok(julian_epoch), query.get_result::(connection)); - let max_date = NaiveDate::MAX; - let query = select(sql::("'262143-12-31'::date")); + let max_date = NaiveDate::from_ymd_opt(262142, 12, 31).unwrap(); + let query = select(sql::("'262142-12-31'::date")); assert_eq!(Ok(max_date), query.get_result::(connection)); let january_first_2018 = NaiveDate::from_ymd_opt(2018, 1, 1).unwrap();