diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cda0d0a9b80a..74fc0fbadb0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -193,6 +193,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: version + - name: Test diesel (nightly) if: matrix.rust == 'nightly' uses: actions-rs/cargo@v1 @@ -302,7 +303,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2021-04-01 + toolchain: 1.51.0 profile: minimal override: true - name: Cache cargo registry diff --git a/diesel/src/associations/belongs_to.rs b/diesel/src/associations/belongs_to.rs index 1f5228b71a70..2d124979551d 100644 --- a/diesel/src/associations/belongs_to.rs +++ b/diesel/src/associations/belongs_to.rs @@ -58,7 +58,7 @@ pub trait BelongsTo { /// # /// # #[derive(Debug, PartialEq)] /// # #[derive(Identifiable, Queryable, Associations)] -/// # #[belongs_to(User)] +/// # #[diesel(belongs_to(User))] /// # pub struct Post { /// # id: i32, /// # user_id: i32, diff --git a/diesel/src/associations/mod.rs b/diesel/src/associations/mod.rs index 5f711e590f34..a5d9f571bdcc 100644 --- a/diesel/src/associations/mod.rs +++ b/diesel/src/associations/mod.rs @@ -1,7 +1,7 @@ //! Traits related to relationships between multiple tables. //! //! Associations in Diesel are always child-to-parent. -//! You can declare an association between two records with `#[belongs_to]`. +//! You can declare an association between two records with `#[diesel(belongs_to)]`. //! Unlike other ORMs, Diesel has no concept of `has many` //! //! ```rust @@ -9,15 +9,15 @@ //! use schema::{posts, users}; //! //! #[derive(Identifiable, Queryable, PartialEq, Debug)] -//! #[table_name = "users"] +//! #[diesel(table_name = users)] //! pub struct User { //! id: i32, //! name: String, //! } //! //! #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] -//! #[belongs_to(User)] -//! #[table_name = "posts"] +//! #[diesel(belongs_to(User))] +//! #[diesel(table_name = posts)] //! pub struct Post { //! id: i32, //! user_id: i32, @@ -40,12 +40,12 @@ //! # } //! ``` //! -//! Note that in addition to the `#[belongs_to]` annotation, we also need to +//! Note that in addition to the `#[diesel(belongs_to)]` annotation, we also need to //! `#[derive(Associations)]` //! -//! `#[belongs_to]` is given the name of the struct that represents the parent. +//! `#[diesel(belongs_to)]` is given the name of the struct that represents the parent. //! Both the parent and child must implement [`Identifiable`]. -//! The struct given to `#[belongs_to]` must be in scope, +//! The struct given to `#[diesel(belongs_to)]` must be in scope, //! so you will need `use some_module::User` if `User` is defined in another module. //! //! If the parent record is generic over lifetimes, they can be written as `'_`. @@ -58,15 +58,15 @@ //! # use std::borrow::Cow; //! # //! #[derive(Identifiable)] -//! #[table_name = "users"] +//! #[diesel(table_name = users)] //! pub struct User<'a> { //! id: i32, //! name: Cow<'a, str>, //! } //! //! #[derive(Associations)] -//! #[belongs_to(parent = "User<'_>")] -//! #[table_name = "posts"] +//! #[diesel(belongs_to(User<'_>))] +//! #[diesel(table_name = posts)] //! pub struct Post { //! id: i32, //! user_id: i32, @@ -79,8 +79,8 @@ //! //! By default, Diesel assumes that your foreign keys will follow the convention `table_name_id`. //! If your foreign key has a different name, -//! you can provide the `foreign_key` argument to `#[belongs_to]`. -//! For example, `#[belongs_to(Foo, foreign_key = "mykey")]`. +//! you can provide the `foreign_key` argument to `#[diesel(belongs_to)]`. +//! For example, `#[diesel(belongs_to(Foo, foreign_key = mykey))]`. //! //! Associated data is typically loaded in multiple queries (one query per table). //! This is usually more efficient than using a join, @@ -106,7 +106,7 @@ //! # } //! # //! # #[derive(Debug, PartialEq, Identifiable, Queryable, Associations)] -//! # #[belongs_to(User)] +//! # #[diesel(belongs_to(User))] //! # pub struct Post { //! # id: i32, //! # user_id: i32, @@ -160,7 +160,7 @@ //! # //! # #[derive(Debug, PartialEq)] //! # #[derive(Identifiable, Queryable, Associations)] -//! # #[belongs_to(User)] +//! # #[diesel(belongs_to(User))] //! # pub struct Post { //! # id: i32, //! # user_id: i32, @@ -214,7 +214,7 @@ //! # //! # #[derive(Debug, PartialEq)] //! # #[derive(Identifiable, Queryable, Associations)] -//! # #[belongs_to(User)] +//! # #[diesel(belongs_to(User))] //! # pub struct Post { //! # id: i32, //! # user_id: i32, @@ -274,7 +274,7 @@ //! # } //! # //! # #[derive(Debug, PartialEq, Identifiable, Queryable, Associations)] -//! # #[belongs_to(User)] +//! # #[diesel(belongs_to(User))] //! # pub struct Post { //! # id: i32, //! # user_id: i32, @@ -282,7 +282,7 @@ //! # } //! # //! # #[derive(Debug, PartialEq, Identifiable, Queryable, Associations)] -//! # #[belongs_to(Post)] +//! # #[diesel(belongs_to(Post))] //! # pub struct Comment { //! # id: i32, //! # post_id: i32, diff --git a/diesel/src/deserialize.rs b/diesel/src/deserialize.rs index 3ee1b034b016..5a626ef4884e 100644 --- a/diesel/src/deserialize.rs +++ b/diesel/src/deserialize.rs @@ -179,7 +179,7 @@ pub type Result = result::Result>; /// #[derive(Queryable, PartialEq, Debug)] /// struct User { /// id: i32, -/// #[diesel(deserialize_as = "LowercaseString")] +/// #[diesel(deserialize_as = LowercaseString)] /// name: String, /// } /// @@ -273,7 +273,7 @@ pub use diesel_derives::Queryable; /// # use diesel::sql_query; /// # /// #[derive(QueryableByName, PartialEq, Debug)] -/// #[table_name = "users"] +/// #[diesel(table_name = users)] /// struct User { /// id: i32, /// name: String, @@ -323,10 +323,10 @@ pub use diesel_derives::Queryable; /// } /// /// #[derive(QueryableByName, PartialEq, Debug)] -/// #[table_name = "users"] +/// #[diesel(table_name = users)] /// struct User { /// id: i32, -/// #[diesel(deserialize_as = "LowercaseString")] +/// #[diesel(deserialize_as = LowercaseString)] /// name: String, /// } /// diff --git a/diesel/src/migration/mod.rs b/diesel/src/migration/mod.rs index a6ca916ca5f2..70ffd4a66b82 100644 --- a/diesel/src/migration/mod.rs +++ b/diesel/src/migration/mod.rs @@ -21,7 +21,7 @@ pub type Result = std::result::Result>; /// in order, therefore two different instances of this type /// must be sortable #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, FromSqlRow, AsExpression)] -#[sql_type = "Text"] +#[diesel(sql_type = Text)] pub struct MigrationVersion<'a>(Cow<'a, str>); impl<'a> MigrationVersion<'a> { diff --git a/diesel/src/mysql/types/date_and_time.rs b/diesel/src/mysql/types/date_and_time.rs index 4eb439e462b3..76609753fee6 100644 --- a/diesel/src/mysql/types/date_and_time.rs +++ b/diesel/src/mysql/types/date_and_time.rs @@ -20,10 +20,10 @@ use crate::sql_types::{Date, Datetime, Time, Timestamp}; #[repr(C)] #[derive(Debug, Clone, Copy, AsExpression, FromSqlRow)] #[non_exhaustive] -#[sql_type = "Timestamp"] -#[sql_type = "Time"] -#[sql_type = "Date"] -#[sql_type = "Datetime"] +#[diesel(sql_type = Timestamp)] +#[diesel(sql_type = Time)] +#[diesel(sql_type = Date)] +#[diesel(sql_type = Datetime)] pub struct MysqlTime { /// [Year field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#af585231d3ed0bc2fa389856e61e15d4e) pub year: libc::c_uint, diff --git a/diesel/src/mysql/types/mod.rs b/diesel/src/mysql/types/mod.rs index cb22e58aa139..edd5683d2128 100644 --- a/diesel/src/mysql/types/mod.rs +++ b/diesel/src/mysql/types/mod.rs @@ -177,5 +177,5 @@ impl HasSqlType> for Mysql { doc = " [`chrono::NaiveDateTime`]: https://docs.rs/chrono/0.4.19/chrono/naive/struct.NaiveDateTime.html" )] #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[mysql_type = "DateTime"] +#[diesel(mysql_type(name = "DateTime"))] pub struct Datetime; diff --git a/diesel/src/pg/serialize/write_tuple.rs b/diesel/src/pg/serialize/write_tuple.rs index 5c2f55cdcbcc..de64cf38f520 100644 --- a/diesel/src/pg/serialize/write_tuple.rs +++ b/diesel/src/pg/serialize/write_tuple.rs @@ -24,7 +24,7 @@ use crate::serialize::{self, Output}; /// # use std::io::Write; /// # /// #[derive(SqlType)] -/// #[postgres(type_name = "my_type")] +/// #[diesel(postgres_type(name = "my_type"))] /// struct MyType; /// /// #[derive(Debug)] diff --git a/diesel/src/pg/types/date_and_time/mod.rs b/diesel/src/pg/types/date_and_time/mod.rs index 578055234bae..5952ee59acfd 100644 --- a/diesel/src/pg/types/date_and_time/mod.rs +++ b/diesel/src/pg/types/date_and_time/mod.rs @@ -14,15 +14,15 @@ mod quickcheck_impls; mod std_time; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)] -#[sql_type = "Timestamp"] -#[sql_type = "Timestamptz"] +#[diesel(sql_type = Timestamp)] +#[diesel(sql_type = Timestamptz)] /// Timestamps are represented in Postgres as a 64 bit signed integer representing the number of /// microseconds since January 1st 2000. This struct is a dumb wrapper type, meant only to indicate /// the integer's meaning. pub struct PgTimestamp(pub i64); #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)] -#[sql_type = "Date"] +#[diesel(sql_type = Date)] /// Dates are represented in Postgres as a 32 bit signed integer representing the number of julian /// days since January 1st 2000. This struct is a dumb wrapper type, meant only to indicate the /// integer's meaning. @@ -32,7 +32,7 @@ pub struct PgDate(pub i32); /// microseconds since midnight. This struct is a dumb wrapper type, meant only to indicate the /// integer's meaning. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)] -#[sql_type = "Time"] +#[diesel(sql_type = Time)] pub struct PgTime(pub i64); /// Intervals in Postgres are separated into 3 parts. A 64 bit integer representing time in @@ -40,7 +40,7 @@ pub struct PgTime(pub i64); /// representing number of months. This struct is a dumb wrapper type, meant only to indicate the /// meaning of these parts. #[derive(Debug, Clone, Copy, PartialEq, Eq, AsExpression, FromSqlRow)] -#[sql_type = "Interval"] +#[diesel(sql_type = Interval)] pub struct PgInterval { /// The number of whole microseconds pub microseconds: i64, diff --git a/diesel/src/pg/types/floats/mod.rs b/diesel/src/pg/types/floats/mod.rs index aa1387946ce3..4d7974d05d0c 100644 --- a/diesel/src/pg/types/floats/mod.rs +++ b/diesel/src/pg/types/floats/mod.rs @@ -12,7 +12,7 @@ use crate::sql_types; mod quickcheck_impls; #[derive(Debug, Clone, PartialEq, Eq, AsExpression, FromSqlRow)] -#[sql_type = "sql_types::Numeric"] +#[diesel(sql_type = sql_types::Numeric)] /// Represents a NUMERIC value, closely mirroring the PG wire protocol /// representation pub enum PgNumeric { diff --git a/diesel/src/pg/types/mac_addr.rs b/diesel/src/pg/types/mac_addr.rs index d7230f99878b..a0e5975afcd0 100644 --- a/diesel/src/pg/types/mac_addr.rs +++ b/diesel/src/pg/types/mac_addr.rs @@ -14,7 +14,7 @@ mod foreign_derives { #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "MacAddr"] + #[diesel(sql_type = MacAddr)] struct ByteArrayProxy([u8; 6]); } diff --git a/diesel/src/pg/types/mod.rs b/diesel/src/pg/types/mod.rs index d232b50d0015..f99fb094c624 100644 --- a/diesel/src/pg/types/mod.rs +++ b/diesel/src/pg/types/mod.rs @@ -41,7 +41,7 @@ pub mod sql_types { /// [`FromSql`]: crate::deserialize::FromSql /// [`u32`]: https://doc.rust-lang.org/nightly/std/primitive.u32.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] - #[postgres(oid = "26", array_oid = "1018")] + #[diesel(postgres_type(oid = 26, array_oid = 1018))] pub struct Oid; /// The "timestamp with time zone" SQL type, which PostgreSQL abbreviates @@ -76,7 +76,7 @@ pub mod sql_types { doc = " [`chrono::DateTime`]: https://docs.rs/chrono/0.4.19/chrono/struct.DateTime.html" )] #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] - #[postgres(oid = "1184", array_oid = "1185")] + #[diesel(postgres_type(oid = 1184, array_oid = 1185))] pub struct Timestamptz; /// The `Array` SQL type. @@ -170,7 +170,7 @@ pub mod sql_types { /// /// [`WriteTuple`]: super::super::super::serialize::WriteTuple #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] - #[postgres(oid = "2249", array_oid = "2287")] + #[diesel(postgres_type(oid = 2249, array_oid = 2287))] pub struct Record(ST); /// Alias for `SmallInt` @@ -196,7 +196,7 @@ pub mod sql_types { /// [`FromSql`]: crate::deserialize::FromSql /// [Uuid]: https://docs.rs/uuid/*/uuid/struct.Uuid.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] - #[postgres(oid = "2950", array_oid = "2951")] + #[diesel(postgres_type(oid = 2950, array_oid = 2951))] pub struct Uuid; /// Alias for `Binary`, to ensure `infer_schema!` works @@ -287,7 +287,7 @@ pub mod sql_types { /// # fn main() {} /// ``` #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] - #[postgres(oid = "3802", array_oid = "3807")] + #[diesel(postgres_type(oid = 3802, array_oid = 3807))] pub struct Jsonb; /// The PostgreSQL [Money](https://www.postgresql.org/docs/9.1/static/datatype-money.html) type. @@ -335,7 +335,7 @@ pub mod sql_types { /// # } /// ``` #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] - #[postgres(oid = "790", array_oid = "791")] + #[diesel(postgres_type(oid = 790, array_oid = 791))] pub struct Money; /// The [`MACADDR`](https://www.postgresql.org/docs/9.6/static/datatype-net-types.html) SQL type. @@ -379,7 +379,7 @@ pub mod sql_types { /// # } /// ``` #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] - #[postgres(oid = "829", array_oid = "1040")] + #[diesel(postgres_type(oid = 829, array_oid = 1040))] pub struct MacAddr; #[doc(hidden)] @@ -440,7 +440,7 @@ pub mod sql_types { /// # fn main() {} /// ``` #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] - #[postgres(oid = "869", array_oid = "1041")] + #[diesel(postgres_type(oid = 869, array_oid = 1041))] pub struct Inet; /// 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"` @@ -496,7 +496,7 @@ pub mod sql_types { /// # fn main() {} /// ``` #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] - #[postgres(oid = "650", array_oid = "651")] + #[diesel(postgres_type(oid = 650, array_oid = 651))] pub struct Cidr; } diff --git a/diesel/src/pg/types/money.rs b/diesel/src/pg/types/money.rs index 14c3752b946b..5facaffa48b8 100644 --- a/diesel/src/pg/types/money.rs +++ b/diesel/src/pg/types/money.rs @@ -21,7 +21,7 @@ use crate::sql_types::{BigInt, Money}; /// use diesel::data_types::PgMoney as Fils; // 1/1000th unit of Dinar /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)] -#[sql_type = "Money"] +#[diesel(sql_type = Money)] pub struct PgMoney(pub i64); impl FromSql for PgMoney { diff --git a/diesel/src/pg/types/network_address.rs b/diesel/src/pg/types/network_address.rs index 115811455c80..fd08c8eec776 100644 --- a/diesel/src/pg/types/network_address.rs +++ b/diesel/src/pg/types/network_address.rs @@ -28,8 +28,8 @@ mod foreign_derives { #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "Inet"] - #[sql_type = "Cidr"] + #[diesel(sql_type = Inet)] + #[diesel(sql_type = Cidr)] struct IpNetworkProxy(IpNetwork); } diff --git a/diesel/src/pg/types/record.rs b/diesel/src/pg/types/record.rs index 0b5e9186e7c5..1d060b42b1f7 100644 --- a/diesel/src/pg/types/record.rs +++ b/diesel/src/pg/types/record.rs @@ -222,11 +222,11 @@ mod tests { #[test] fn serializing_named_composite_types() { #[derive(SqlType, QueryId, Debug, Clone, Copy)] - #[postgres(type_name = "my_type")] + #[diesel(postgres_type(name = "my_type"))] struct MyType; #[derive(Debug, AsExpression)] - #[sql_type = "MyType"] + #[diesel(sql_type = MyType)] struct MyStruct<'a>(i32, &'a str); impl<'a> ToSql for MyStruct<'a> { diff --git a/diesel/src/pg/types/uuid.rs b/diesel/src/pg/types/uuid.rs index d2577cebde8a..ee4afb883653 100644 --- a/diesel/src/pg/types/uuid.rs +++ b/diesel/src/pg/types/uuid.rs @@ -8,7 +8,7 @@ use crate::sql_types::Uuid; #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] -#[sql_type = "Uuid"] +#[diesel(sql_type = Uuid)] #[allow(dead_code)] struct UuidProxy(uuid::Uuid); diff --git a/diesel/src/query_builder/functions.rs b/diesel/src/query_builder/functions.rs index c9c58b55c5fb..2b7930e14051 100644 --- a/diesel/src/query_builder/functions.rs +++ b/diesel/src/query_builder/functions.rs @@ -208,7 +208,7 @@ pub fn delete(source: T) -> DeleteStatement { /// name: &'a str, /// } @@ -255,7 +255,7 @@ pub fn delete(source: T) -> DeleteStatement, /// } @@ -301,7 +301,7 @@ pub fn delete(source: T) -> DeleteStatement>, /// } @@ -533,7 +533,7 @@ pub fn replace_into(target: T) -> IncompleteInsertStatement { /// # use schema::users; /// # /// # #[derive(QueryableByName, Debug, PartialEq)] -/// # #[table_name="users"] +/// # #[diesel(table_name = users)] /// # struct User { /// # id: i32, /// # name: String, diff --git a/diesel/src/query_builder/sql_query.rs b/diesel/src/query_builder/sql_query.rs index c682bcd7c8f9..a35904ce4551 100644 --- a/diesel/src/query_builder/sql_query.rs +++ b/diesel/src/query_builder/sql_query.rs @@ -48,7 +48,7 @@ impl SqlQuery { /// # use schema::users; /// # /// # #[derive(QueryableByName, Debug, PartialEq)] - /// # #[table_name="users"] + /// # #[diesel(table_name = users)] /// # struct User { /// # id: i32, /// # name: String, @@ -178,7 +178,7 @@ impl UncheckedBind { /// # use schema::users; /// # /// # #[derive(QueryableByName, Debug, PartialEq)] - /// # #[table_name="users"] + /// # #[diesel(table_name = users)] /// # struct User { /// # id: i32, /// # name: String, diff --git a/diesel/src/query_dsl/belonging_to_dsl.rs b/diesel/src/query_dsl/belonging_to_dsl.rs index c49ca54233e4..95fef4d5688f 100644 --- a/diesel/src/query_dsl/belonging_to_dsl.rs +++ b/diesel/src/query_dsl/belonging_to_dsl.rs @@ -14,7 +14,7 @@ /// # /// # #[derive(Debug, PartialEq)] /// # #[derive(Identifiable, Queryable, Associations)] -/// # #[belongs_to(User)] +/// # #[diesel(belongs_to(User))] /// # pub struct Post { /// # id: i32, /// # user_id: i32, diff --git a/diesel/src/query_dsl/save_changes_dsl.rs b/diesel/src/query_dsl/save_changes_dsl.rs index 9dc7c2cac8cc..5266a2640032 100644 --- a/diesel/src/query_dsl/save_changes_dsl.rs +++ b/diesel/src/query_dsl/save_changes_dsl.rs @@ -113,7 +113,7 @@ where /// } /// /// #[derive(AsChangeset, Identifiable)] -/// #[table_name = "animals"] +/// #[diesel(table_name = animals)] /// struct AnimalForm<'a> { /// id: i32, /// name: &'a str, diff --git a/diesel/src/serialize.rs b/diesel/src/serialize.rs index 9111f02d0521..4911e262a5dc 100644 --- a/diesel/src/serialize.rs +++ b/diesel/src/serialize.rs @@ -164,7 +164,7 @@ where /// # /// #[repr(i32)] /// #[derive(Debug, Clone, Copy, AsExpression)] -/// #[sql_type = "Integer"] +/// #[diesel(sql_type = Integer)] /// pub enum MyEnum { /// A = 1, /// B = 2, diff --git a/diesel/src/sql_types/mod.rs b/diesel/src/sql_types/mod.rs index bfeedfb63d7d..30d81545d122 100644 --- a/diesel/src/sql_types/mod.rs +++ b/diesel/src/sql_types/mod.rs @@ -38,9 +38,9 @@ use crate::query_builder::QueryId; /// /// [bool]: https://doc.rust-lang.org/nightly/std/primitive.bool.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "16", array_oid = "1000")] -#[sqlite_type = "Integer"] -#[mysql_type = "Tiny"] +#[diesel(postgres_type(oid = 16, array_oid = 1000))] +#[diesel(sqlite_type(name = "Integer"))] +#[diesel(mysql_type(name = "Tiny"))] pub struct Bool; /// The tiny integer SQL type. @@ -59,7 +59,7 @@ pub struct Bool; /// /// [i8]: https://doc.rust-lang.org/nightly/std/primitive.i8.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[mysql_type = "Tiny"] +#[diesel(mysql_type(name = "Tiny"))] pub struct TinyInt; #[doc(hidden)] pub type Tinyint = TinyInt; @@ -76,9 +76,9 @@ pub type Tinyint = TinyInt; /// /// [i16]: https://doc.rust-lang.org/nightly/std/primitive.i16.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "21", array_oid = "1005")] -#[sqlite_type = "SmallInt"] -#[mysql_type = "Short"] +#[diesel(postgres_type(oid = 21, array_oid = 1005))] +#[diesel(sqlite_type(name = "SmallInt"))] +#[diesel(mysql_type(name = "Short"))] pub struct SmallInt; #[doc(hidden)] pub type Int2 = SmallInt; @@ -97,9 +97,9 @@ pub type Smallint = SmallInt; /// /// [i32]: https://doc.rust-lang.org/nightly/std/primitive.i32.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "23", array_oid = "1007")] -#[sqlite_type = "Integer"] -#[mysql_type = "Long"] +#[diesel(postgres_type(oid = 23, array_oid = 1007))] +#[diesel(sqlite_type(name = "Integer"))] +#[diesel(mysql_type(name = "Long"))] pub struct Integer; #[doc(hidden)] pub type Int4 = Integer; @@ -116,9 +116,9 @@ pub type Int4 = Integer; /// /// [i64]: https://doc.rust-lang.org/nightly/std/primitive.i64.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "20", array_oid = "1016")] -#[sqlite_type = "Long"] -#[mysql_type = "LongLong"] +#[diesel(postgres_type(oid = 20, array_oid = 1016))] +#[diesel(sqlite_type(name = "Long"))] +#[diesel(mysql_type(name = "LongLong"))] pub struct BigInt; #[doc(hidden)] pub type Int8 = BigInt; @@ -137,9 +137,9 @@ pub type Bigint = BigInt; /// /// [f32]: https://doc.rust-lang.org/nightly/std/primitive.f32.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "700", array_oid = "1021")] -#[sqlite_type = "Float"] -#[mysql_type = "Float"] +#[diesel(postgres_type(oid = 700, array_oid = 1021))] +#[diesel(sqlite_type(name = "Float"))] +#[diesel(mysql_type(name = "Float"))] pub struct Float; #[doc(hidden)] pub type Float4 = Float; @@ -156,9 +156,9 @@ pub type Float4 = Float; /// /// [f64]: https://doc.rust-lang.org/nightly/std/primitive.f64.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "701", array_oid = "1022")] -#[sqlite_type = "Double"] -#[mysql_type = "Double"] +#[diesel(postgres_type(oid = 701, array_oid = 1022))] +#[diesel(sqlite_type(name = "Double"))] +#[diesel(mysql_type(name = "Double"))] pub struct Double; #[doc(hidden)] pub type Float8 = Double; @@ -178,9 +178,9 @@ pub type Float8 = Double; /// /// [`bigdecimal::BigDecimal`]: /bigdecimal/struct.BigDecimal.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "1700", array_oid = "1231")] -#[mysql_type = "Numeric"] -#[sqlite_type = "Double"] +#[diesel(postgres_type(oid = 1700, array_oid = 1231))] +#[diesel(mysql_type(name = "Numeric"))] +#[diesel(sqlite_type(name = "Double"))] pub struct Numeric; /// Alias for `Numeric` @@ -206,9 +206,9 @@ pub type Decimal = Numeric; /// [String]: std::string::String /// [str]: https://doc.rust-lang.org/nightly/std/primitive.str.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "25", array_oid = "1009")] -#[sqlite_type = "Text"] -#[mysql_type = "String"] +#[diesel(postgres_type(oid = 25, array_oid = 1009))] +#[diesel(sqlite_type(name = "Text"))] +#[diesel(mysql_type(name = "String"))] pub struct Text; /// The SQL `VARCHAR` type @@ -249,9 +249,9 @@ pub type Longtext = Text; /// [Vec]: std::vec::Vec /// [slice]: https://doc.rust-lang.org/nightly/std/primitive.slice.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "17", array_oid = "1001")] -#[sqlite_type = "Binary"] -#[mysql_type = "Blob"] +#[diesel(postgres_type(oid = 17, array_oid = 1001))] +#[diesel(sqlite_type(name = "Binary"))] +#[diesel(mysql_type(name = "Blob"))] pub struct Binary; #[doc(hidden)] @@ -279,9 +279,9 @@ pub type Bit = Binary; /// /// [NaiveDate]: https://docs.rs/chrono/*/chrono/naive/struct.NaiveDate.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "1082", array_oid = "1182")] -#[sqlite_type = "Text"] -#[mysql_type = "Date"] +#[diesel(postgres_type(oid = 1082, array_oid = 1182))] +#[diesel(sqlite_type(name = "Text"))] +#[diesel(mysql_type(name = "Date"))] pub struct Date; /// The interval SQL type. @@ -299,7 +299,7 @@ pub struct Date; /// [`PgInterval`]: ../pg/data_types/struct.PgInterval.html /// [`IntervalDsl`]: ../pg/expression/extensions/trait.IntervalDsl.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "1186", array_oid = "1187")] +#[diesel(postgres_type(oid = 1186, array_oid = 1187))] pub struct Interval; /// The time SQL type. @@ -314,9 +314,9 @@ pub struct Interval; /// /// [NaiveTime]: /chrono/naive/time/struct.NaiveTime.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "1083", array_oid = "1183")] -#[sqlite_type = "Text"] -#[mysql_type = "Time"] +#[diesel(postgres_type(oid = 1083, array_oid = 1183))] +#[diesel(sqlite_type(name = "Text"))] +#[diesel(mysql_type(name = "Time"))] pub struct Time; /// The timestamp SQL type. @@ -344,9 +344,9 @@ pub struct Time; )] /// [Timespec]: /time/struct.Timespec.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "1114", array_oid = "1115")] -#[sqlite_type = "Text"] -#[mysql_type = "Timestamp"] +#[diesel(postgres_type(oid = 1114, array_oid = 1115))] +#[diesel(sqlite_type(name = "Text"))] +#[diesel(mysql_type(name = "Timestamp"))] pub struct Timestamp; /// The JSON SQL type. This type can only be used with `feature = @@ -367,8 +367,8 @@ pub struct Timestamp; /// [`FromSql`]: /deserialize/trait.FromSql.html /// [`serde_json::Value`]: /../serde_json/value/enum.Value.html #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)] -#[postgres(oid = "114", array_oid = "199")] -#[mysql_type = "String"] +#[diesel(postgres_type(oid = 114, array_oid = 199))] +#[diesel(mysql_type(name = "String"))] pub struct Json; /// The nullable SQL type. @@ -408,9 +408,9 @@ pub use crate::mysql::types::*; /// /// ```rust /// #[derive(diesel::sql_types::SqlType)] -/// #[postgres(oid = "23", array_oid = "1007")] -/// #[sqlite_type = "Integer"] -/// #[mysql_type = "Long"] +/// #[diesel(postgres_type(oid = 23, array_oid = 1007))] +/// #[diesel(sqlite_type(name = "Integer"))] +/// #[diesel(mysql_type(name = "Long"))] /// pub struct Integer; /// ``` pub trait HasSqlType: TypeMetadata { diff --git a/diesel/src/type_impls/date_and_time.rs b/diesel/src/type_impls/date_and_time.rs index 870f02e4bc5d..555ad501779e 100644 --- a/diesel/src/type_impls/date_and_time.rs +++ b/diesel/src/type_impls/date_and_time.rs @@ -6,7 +6,7 @@ use std::time::SystemTime; #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] -#[sql_type = "crate::sql_types::Timestamp"] +#[diesel(sql_type = crate::sql_types::Timestamp)] struct SystemTimeProxy(SystemTime); #[cfg(feature = "chrono")] @@ -19,29 +19,30 @@ mod chrono { #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "Date"] + #[diesel(sql_type = Date)] struct NaiveDateProxy(NaiveDate); #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "Time"] + #[diesel(sql_type = Time)] struct NaiveTimeProxy(NaiveTime); #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "Timestamp"] + #[diesel(sql_type = Timestamp)] #[cfg_attr( feature = "postgres_backend", - sql_type = "crate::sql_types::Timestamptz" + diesel(sql_type = crate::sql_types::Timestamptz) )] - #[cfg_attr(feature = "mysql_backend", sql_type = "crate::sql_types::Datetime")] + #[cfg_attr(feature = "mysql_backend", diesel(sql_type = crate::sql_types::Datetime))] struct NaiveDateTimeProxy(NaiveDateTime); - #[derive(AsExpression, FromSqlRow)] + #[derive(FromSqlRow)] + #[cfg_attr(feature = "postgres_backend", derive(AsExpression))] #[diesel(foreign_derive)] #[cfg_attr( feature = "postgres_backend", - sql_type = "crate::sql_types::Timestamptz" + diesel(sql_type = crate::sql_types::Timestamptz) )] struct DateTimeProxy(DateTime); } diff --git a/diesel/src/type_impls/decimal.rs b/diesel/src/type_impls/decimal.rs index 3bce367e4098..5507fb272cac 100644 --- a/diesel/src/type_impls/decimal.rs +++ b/diesel/src/type_impls/decimal.rs @@ -10,6 +10,6 @@ mod bigdecimal { #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "Numeric"] + #[diesel(sql_type = Numeric)] struct BigDecimalProxy(BigDecimal); } diff --git a/diesel/src/type_impls/json.rs b/diesel/src/type_impls/json.rs index 45d127c5be3c..b2abaeed1a37 100644 --- a/diesel/src/type_impls/json.rs +++ b/diesel/src/type_impls/json.rs @@ -8,6 +8,6 @@ use crate::sql_types::Jsonb; #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] -#[sql_type = "Json"] -#[cfg_attr(feature = "postgres", sql_type = "Jsonb")] +#[diesel(sql_type = Json)] +#[cfg_attr(feature = "postgres", diesel(sql_type = Jsonb))] struct SerdeJsonValueProxy(serde_json::Value); diff --git a/diesel/src/type_impls/primitives.rs b/diesel/src/type_impls/primitives.rs index 5661f3e96162..b9d72daa4f51 100644 --- a/diesel/src/type_impls/primitives.rs +++ b/diesel/src/type_impls/primitives.rs @@ -15,86 +15,85 @@ mod foreign_impls { #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "Bool"] + #[diesel(sql_type = Bool)] struct BoolProxy(bool); - #[derive(AsExpression, FromSqlRow)] + #[derive(FromSqlRow)] + #[cfg_attr(feature = "mysql_backend", derive(AsExpression))] #[diesel(foreign_derive)] - #[cfg_attr(feature = "mysql_backend", sql_type = "crate::sql_types::TinyInt")] + #[cfg_attr(feature = "mysql_backend", diesel(sql_type = crate::sql_types::TinyInt))] struct I8Proxy(i8); #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "SmallInt"] + #[diesel(sql_type = SmallInt)] struct I16Proxy(i16); #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "Integer"] + #[diesel(sql_type = Integer)] struct I32Proxy(i32); #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "BigInt"] + #[diesel(sql_type = BigInt)] struct I64Proxy(i64); - #[derive(AsExpression, FromSqlRow)] + #[derive(FromSqlRow)] + #[cfg_attr(feature = "mysql_backend", derive(AsExpression))] #[diesel(foreign_derive)] #[cfg_attr( feature = "mysql_backend", - sql_type = "crate::sql_types::Unsigned" + diesel(sql_type = crate::sql_types::Unsigned) )] struct U8Proxy(u8); - #[derive(AsExpression, FromSqlRow)] + #[derive(FromSqlRow)] + #[cfg_attr(feature = "mysql_backend", derive(AsExpression))] #[diesel(foreign_derive)] - #[cfg_attr( - feature = "mysql_backend", - sql_type = "crate::sql_types::Unsigned" - )] + #[cfg_attr(feature = "mysql_backend", diesel(sql_type = crate::sql_types::Unsigned))] struct U16Proxy(u16); - #[derive(AsExpression, FromSqlRow)] - #[diesel(foreign_derive)] + #[derive(FromSqlRow)] #[cfg_attr( - feature = "mysql_backend", - sql_type = "crate::sql_types::Unsigned" + any(feature = "mysql_backend", feature = "postgres_backend"), + derive(AsExpression) )] - #[cfg_attr(feature = "postgres_backend", sql_type = "crate::sql_types::Oid")] + #[diesel(foreign_derive)] + #[cfg_attr(feature = "mysql_backend", diesel(sql_type = crate::sql_types::Unsigned))] + #[cfg_attr(feature = "postgres_backend", diesel(sql_type = crate::sql_types::Oid))] struct U32Proxy(u32); - #[derive(AsExpression, FromSqlRow)] + #[derive(FromSqlRow)] + #[cfg_attr(feature = "mysql_backend", derive(AsExpression))] #[diesel(foreign_derive)] - #[cfg_attr( - feature = "mysql_backend", - sql_type = "crate::sql_types::Unsigned" - )] + #[cfg_attr(feature = "mysql_backend", diesel(sql_type = crate::sql_types::Unsigned))] struct U64Proxy(u64); #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "Float"] + #[diesel(sql_type = Float)] struct F32Proxy(f32); #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "Double"] + #[diesel(sql_type = Double)] struct F64Proxy(f64); #[derive(AsExpression, FromSqlRow)] #[diesel(foreign_derive)] - #[sql_type = "Text"] - #[cfg_attr(feature = "sqlite", sql_type = "crate::sql_types::Date")] - #[cfg_attr(feature = "sqlite", sql_type = "crate::sql_types::Time")] - #[cfg_attr(feature = "sqlite", sql_type = "crate::sql_types::Timestamp")] + #[diesel(sql_type = Text)] + #[cfg_attr(feature = "sqlite", diesel(sql_type = crate::sql_types::Date))] + #[cfg_attr(feature = "sqlite", diesel(sql_type = crate::sql_types::Time))] + #[cfg_attr(feature = "sqlite", diesel(sql_type = crate::sql_types::Timestamp))] struct StringProxy(String); #[derive(AsExpression)] #[diesel(foreign_derive, not_sized)] - #[sql_type = "Text"] - #[cfg_attr(feature = "sqlite", sql_type = "crate::sql_types::Date")] - #[cfg_attr(feature = "sqlite", sql_type = "crate::sql_types::Time")] - #[cfg_attr(feature = "sqlite", sql_type = "crate::sql_types::Timestamp")] + #[diesel(sql_type = Text)] + #[cfg_attr(feature = "sqlite", diesel(sql_type = crate::sql_types::Date))] + #[cfg_attr(feature = "sqlite", diesel(sql_type = crate::sql_types::Time))] + #[cfg_attr(feature = "sqlite", diesel(sql_type = crate::sql_types::Timestamp))] struct StrProxy(str); #[derive(FromSqlRow)] @@ -103,12 +102,12 @@ mod foreign_impls { #[derive(AsExpression)] #[diesel(foreign_derive)] - #[sql_type = "Binary"] + #[diesel(sql_type = Binary)] struct BinaryVecProxy(Vec); #[derive(AsExpression)] #[diesel(foreign_derive, not_sized)] - #[sql_type = "Binary"] + #[diesel(sql_type = Binary)] struct BinarySliceProxy([u8]); } diff --git a/diesel/src/upsert/on_conflict_docs_setup.rs b/diesel/src/upsert/on_conflict_docs_setup.rs index fa92060131ff..a7da999b01e2 100644 --- a/diesel/src/upsert/on_conflict_docs_setup.rs +++ b/diesel/src/upsert/on_conflict_docs_setup.rs @@ -2,7 +2,7 @@ include!("../doctest_setup.rs"); use crate::schema::users; #[derive(Clone, Copy, Insertable, AsChangeset)] -#[table_name="users"] +#[diesel(table_name = users)] struct User<'a> { id: i32, name: &'a str, diff --git a/diesel/src/upsert/on_conflict_extension.rs b/diesel/src/upsert/on_conflict_extension.rs index f0fae6a62972..9bb4af4379bf 100644 --- a/diesel/src/upsert/on_conflict_extension.rs +++ b/diesel/src/upsert/on_conflict_extension.rs @@ -143,7 +143,7 @@ where /// # } /// # /// # #[derive(Clone, Copy, Insertable)] - /// # #[table_name="users"] + /// # #[diesel(table_name = users)] /// # struct User<'a> { /// # id: i32, /// # name: &'a str, diff --git a/diesel_bench/benches/diesel_benches.rs b/diesel_bench/benches/diesel_benches.rs index 6a7d181d3d44..9e04c5f51450 100644 --- a/diesel_bench/benches/diesel_benches.rs +++ b/diesel_bench/benches/diesel_benches.rs @@ -42,7 +42,7 @@ allow_tables_to_appear_in_same_query!(users, posts, comments); #[derive( PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Insertable, AsChangeset, QueryableByName, )] -#[table_name = "users"] +#[diesel(table_name = users)] pub struct User { pub id: i32, pub name: String, @@ -50,8 +50,8 @@ pub struct User { } #[derive(Debug, PartialEq, Eq, Queryable, Clone, Insertable, AsChangeset)] -#[table_name = "users"] -#[diesel(treat_none_as_default_value = "false")] +#[diesel(table_name = users)] +#[diesel(treat_none_as_default_value = false)] pub struct NewUser { pub name: String, pub hair_color: Option, @@ -67,8 +67,8 @@ impl NewUser { } #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName)] -#[belongs_to(User)] -#[table_name = "posts"] +#[diesel(belongs_to(User))] +#[diesel(table_name = posts)] pub struct Post { pub id: i32, pub user_id: i32, @@ -77,7 +77,7 @@ pub struct Post { } #[derive(Insertable)] -#[table_name = "posts"] +#[diesel(table_name = posts)] pub struct NewPost { user_id: i32, title: String, @@ -95,7 +95,7 @@ impl NewPost { } #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)] -#[belongs_to(Post)] +#[diesel(belongs_to(Post))] pub struct Comment { id: i32, post_id: i32, @@ -103,10 +103,10 @@ pub struct Comment { } #[derive(Debug, Clone, Copy, Insertable)] -#[table_name = "comments"] +#[diesel(table_name = comments)] pub struct NewComment<'a>( - #[column_name = "post_id"] pub i32, - #[column_name = "text"] pub &'a str, + #[diesel(column_name = post_id)] pub i32, + #[diesel(column_name = text)] pub &'a str, ); #[cfg(feature = "mysql")] diff --git a/diesel_cli/src/print_schema.rs b/diesel_cli/src/print_schema.rs index 768120264ed3..a4b5a9694015 100644 --- a/diesel_cli/src/print_schema.rs +++ b/diesel_cli/src/print_schema.rs @@ -276,11 +276,11 @@ impl Display for CustomTypeList { if let Some(ref schema) = t.schema { writeln!( out, - "#[postgres(type_name = \"{}\", type_schema = \"{}\")]", + "#[diesel(postgres_type(name = \"{}\", schema = \"{}\"))]", t.sql_name, schema )?; } else { - writeln!(out, "#[postgres(type_name = \"{}\")]", t.sql_name)?; + writeln!(out, "#[diesel(postgres_type(name = \"{}\"))]", t.sql_name)?; } writeln!(out, "pub struct {};", t.rust_name)?; } diff --git a/diesel_cli/tests/print_schema/print_schema_default_is_to_generate_custom_types/postgres/expected.rs b/diesel_cli/tests/print_schema/print_schema_default_is_to_generate_custom_types/postgres/expected.rs index 43e6567524c5..363d8566703b 100644 --- a/diesel_cli/tests/print_schema/print_schema_default_is_to_generate_custom_types/postgres/expected.rs +++ b/diesel_cli/tests/print_schema/print_schema_default_is_to_generate_custom_types/postgres/expected.rs @@ -8,14 +8,14 @@ pub mod sql_types { /// /// (Automatically generated by Diesel.) #[derive(diesel::sql_types::SqlType)] - #[postgres(type_name = "my_type")] + #[diesel(postgres_type(name = "my_type"))] pub struct MyType; /// The `my_type2` SQL type /// /// (Automatically generated by Diesel.) #[derive(diesel::sql_types::SqlType)] - #[postgres(type_name = "my_type2")] + #[diesel(postgres_type(name = "my_type2"))] pub struct MyType2; } diff --git a/diesel_cli/tests/print_schema/print_schema_specifying_schema_name_with_custom_type/postgres/expected.rs b/diesel_cli/tests/print_schema/print_schema_specifying_schema_name_with_custom_type/postgres/expected.rs index e30b4ab7ab4c..facb57544573 100644 --- a/diesel_cli/tests/print_schema/print_schema_specifying_schema_name_with_custom_type/postgres/expected.rs +++ b/diesel_cli/tests/print_schema/print_schema_specifying_schema_name_with_custom_type/postgres/expected.rs @@ -9,7 +9,7 @@ pub mod custom_schema { /// /// (Automatically generated by Diesel.) #[derive(diesel::sql_types::SqlType)] - #[postgres(type_name = "my_enum", type_schema = "custom_schema")] + #[diesel(postgres_type(name = "my_enum", schema = "custom_schema"))] pub struct MyEnum; } diff --git a/diesel_cli/tests/print_schema/print_schema_type_renaming/postgres/expected.rs b/diesel_cli/tests/print_schema/print_schema_type_renaming/postgres/expected.rs index 32d0eccc789f..f0fd7fe16952 100644 --- a/diesel_cli/tests/print_schema/print_schema_type_renaming/postgres/expected.rs +++ b/diesel_cli/tests/print_schema/print_schema_type_renaming/postgres/expected.rs @@ -8,7 +8,7 @@ pub mod sql_types { /// /// (Automatically generated by Diesel.) #[derive(diesel::sql_types::SqlType)] - #[postgres(type_name = "user_job")] + #[diesel(postgres_type(name = "user_job"))] pub struct UserJob; } diff --git a/diesel_compile_tests/Cargo.lock b/diesel_compile_tests/Cargo.lock index efa838bbbdae..9e6ab27b72df 100644 --- a/diesel_compile_tests/Cargo.lock +++ b/diesel_compile_tests/Cargo.lock @@ -86,6 +86,7 @@ dependencies = [ name = "diesel_derives" version = "2.0.0" dependencies = [ + "proc-macro-error", "proc-macro2", "quote", "syn", @@ -274,6 +275,30 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.32" @@ -473,6 +498,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "winapi" version = "0.3.9" diff --git a/diesel_compile_tests/Cargo.toml b/diesel_compile_tests/Cargo.toml index d084de0a7a02..d4a284f2a9e9 100644 --- a/diesel_compile_tests/Cargo.toml +++ b/diesel_compile_tests/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Sean Griffin "] [dependencies] -diesel = { version = "2.0.0", default-features = false, features = ["extras", "sqlite", "postgres", "mysql", "unstable", "with-deprecated"], path = "../diesel" } +diesel = { version = "2.0.0", default-features = false, features = ["extras", "sqlite", "postgres", "mysql", "with-deprecated"], path = "../diesel" } trybuild = "1.0.41" [workspace] diff --git a/diesel_compile_tests/rust-toolchain b/diesel_compile_tests/rust-toolchain deleted file mode 100644 index f39e6cba5143..000000000000 --- a/diesel_compile_tests/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly-2021-04-01 diff --git a/diesel_compile_tests/tests/fail/as_changeset_bad_column_name.rs b/diesel_compile_tests/tests/fail/as_changeset_bad_column_name.rs deleted file mode 100644 index eccee4f70e33..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_bad_column_name.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[macro_use] -extern crate diesel; - -table! { - users { - id -> Integer, - } -} - -#[derive(AsChangeset)] -#[table_name = "users"] -struct UserStruct { - name: String, - #[column_name = "hair_color"] - color_de_pelo: String, -} - -#[derive(AsChangeset)] -#[table_name = "users"] -struct UserTuple(#[column_name = "name"] String); - -fn main() {} diff --git a/diesel_compile_tests/tests/fail/as_changeset_bad_column_name.stderr b/diesel_compile_tests/tests/fail/as_changeset_bad_column_name.stderr deleted file mode 100644 index 2ddd2033f28f..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_bad_column_name.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0412]: cannot find type `name` in module `users` - --> $DIR/as_changeset_bad_column_name.rs:13:5 - | -13 | name: String, - | ^^^^ not found in `users` - -error[E0412]: cannot find type `hair_color` in module `users` - --> $DIR/as_changeset_bad_column_name.rs:14:21 - | -14 | #[column_name = "hair_color"] - | ^^^^^^^^^^^^ not found in `users` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0425]: cannot find value `name` in module `users` - --> $DIR/as_changeset_bad_column_name.rs:13:5 - | -13 | name: String, - | ^^^^ not found in `users` - -error[E0425]: cannot find value `hair_color` in module `users` - --> $DIR/as_changeset_bad_column_name.rs:14:21 - | -14 | #[column_name = "hair_color"] - | ^^^^^^^^^^^^ not found in `users` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0412]: cannot find type `name` in module `users` - --> $DIR/as_changeset_bad_column_name.rs:20:34 - | -20 | struct UserTuple(#[column_name = "name"] String); - | ^^^^^^ not found in `users` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0425]: cannot find value `name` in module `users` - --> $DIR/as_changeset_bad_column_name.rs:20:34 - | -20 | struct UserTuple(#[column_name = "name"] String); - | ^^^^^^ not found in `users` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/as_changeset_bad_column_name_syntax.stderr b/diesel_compile_tests/tests/fail/as_changeset_bad_column_name_syntax.stderr deleted file mode 100644 index 8bcceeb2cc6a..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_bad_column_name_syntax.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: `column_name` must be in the form `column_name = "value"` - --> $DIR/as_changeset_bad_column_name_syntax.rs:14:7 - | -14 | #[column_name] - | ^^^^^^^^^^^ - -error[E0412]: cannot find type `column_name` in module `users` - --> $DIR/as_changeset_bad_column_name_syntax.rs:14:7 - | -14 | #[column_name] - | ^^^^^^^^^^^ not found in `users` - -error[E0425]: cannot find value `column_name` in module `users` - --> $DIR/as_changeset_bad_column_name_syntax.rs:14:7 - | -14 | #[column_name] - | ^^^^^^^^^^^ not found in `users` diff --git a/diesel_compile_tests/tests/fail/as_changeset_bad_options.rs b/diesel_compile_tests/tests/fail/as_changeset_bad_options.rs deleted file mode 100644 index 37be81f72926..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_bad_options.rs +++ /dev/null @@ -1,59 +0,0 @@ -#[macro_use] -extern crate diesel; - -table! { - users { - id -> Integer, - name -> Text, - } -} - -#[derive(AsChangeset)] -#[table_name = "users"] -#[changeset_options(treat_none_as_null("true"))] -struct UserForm1 { - id: i32, - name: String, -} - -#[derive(AsChangeset)] -#[table_name = "users"] -#[changeset_options(treat_none_as_null)] -struct UserForm2 { - id: i32, - name: String, -} - -#[derive(AsChangeset)] -#[table_name = "users"] -#[changeset_options(treat_none_as_null = "foo")] -struct UserForm3 { - id: i32, - name: String, -} - -#[derive(AsChangeset)] -#[table_name = "users"] -#[changeset_options()] -struct UserForm4 { - id: i32, - name: String, -} - -#[derive(AsChangeset)] -#[table_name = "users"] -#[changeset_options = "treat_none_as_null"] -struct UserForm5 { - id: i32, - name: String, -} - -#[derive(AsChangeset)] -#[table_name = "users"] -#[changeset_options] -struct UserForm6 { - id: i32, - name: String, -} - -fn main() {} diff --git a/diesel_compile_tests/tests/fail/as_changeset_bad_options.stderr b/diesel_compile_tests/tests/fail/as_changeset_bad_options.stderr deleted file mode 100644 index 1d25bc3545b3..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_bad_options.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error: `treat_none_as_null` must be in the form `treat_none_as_null = "true"` - --> $DIR/as_changeset_bad_options.rs:13:21 - | -13 | #[changeset_options(treat_none_as_null("true"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `treat_none_as_null` must be in the form `treat_none_as_null = "true"` - --> $DIR/as_changeset_bad_options.rs:21:21 - | -21 | #[changeset_options(treat_none_as_null)] - | ^^^^^^^^^^^^^^^^^^ - -error: `treat_none_as_null` must be in the form `treat_none_as_null = "true"` - --> $DIR/as_changeset_bad_options.rs:29:21 - | -29 | #[changeset_options(treat_none_as_null = "foo")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: Missing required option `treat_none_as_null` - --> $DIR/as_changeset_bad_options.rs:37:3 - | -37 | #[changeset_options()] - | ^^^^^^^^^^^^^^^^^^^ - -error: `changeset_options` must be in the form `changeset_options(...)` - --> $DIR/as_changeset_bad_options.rs:45:3 - | -45 | #[changeset_options = "treat_none_as_null"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `changeset_options` must be in the form `changeset_options(...)` - --> $DIR/as_changeset_bad_options.rs:53:3 - | -53 | #[changeset_options] - | ^^^^^^^^^^^^^^^^^ diff --git a/diesel_compile_tests/tests/fail/as_changeset_bad_primary_key_syntax.rs b/diesel_compile_tests/tests/fail/as_changeset_bad_primary_key_syntax.rs deleted file mode 100644 index 2b4f38e3b0c5..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_bad_primary_key_syntax.rs +++ /dev/null @@ -1,18 +0,0 @@ -#[macro_use] -extern crate diesel; - -table! { - users { - id -> Integer, - name -> Text, - } -} - -#[derive(AsChangeset)] -#[primary_key(id, bar = "baz", qux(id))] -struct UserForm { - id: i32, - name: String, -} - -fn main() {} diff --git a/diesel_compile_tests/tests/fail/as_changeset_bad_primary_key_syntax.stderr b/diesel_compile_tests/tests/fail/as_changeset_bad_primary_key_syntax.stderr deleted file mode 100644 index ec2495eba4f0..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_bad_primary_key_syntax.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: Expected `bar` found `bar = "baz"` - --> $DIR/as_changeset_bad_primary_key_syntax.rs:12:19 - | -12 | #[primary_key(id, bar = "baz", qux(id))] - | ^^^^^^^^^^^ - -error: Expected `qux` found `qux(id)` - --> $DIR/as_changeset_bad_primary_key_syntax.rs:12:32 - | -12 | #[primary_key(id, bar = "baz", qux(id))] - | ^^^^^^^ - -error[E0433]: failed to resolve: use of undeclared crate or module `user_forms` - --> $DIR/as_changeset_bad_primary_key_syntax.rs:13:8 - | -13 | struct UserForm { - | ^^^^^^^^ use of undeclared crate or module `user_forms` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/as_changeset_deprecated_column_name.rs b/diesel_compile_tests/tests/fail/as_changeset_deprecated_column_name.rs deleted file mode 100644 index 3002378a9024..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_deprecated_column_name.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[macro_use] -extern crate diesel; - -table! { - users { - id -> Integer, - name -> Text, - } -} - -#[derive(AsChangeset)] -#[table_name(users)] -struct UserForm { - id: i32, - #[column_name(name)] - name: String, -} - -fn main() { - // Workaround for https://github.com/dtolnay/trybuild/issues/8 - compile_error!("warnings"); -} diff --git a/diesel_compile_tests/tests/fail/as_changeset_deprecated_column_name.stderr b/diesel_compile_tests/tests/fail/as_changeset_deprecated_column_name.stderr deleted file mode 100644 index f8e5f036125b..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_deprecated_column_name.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: The form `table_name(value)` is deprecated. Use `table_name = "value"` instead - --> $DIR/as_changeset_deprecated_column_name.rs:12:3 - | -12 | #[table_name(users)] - | ^^^^^^^^^^^^^^^^^ - -warning: The form `column_name(value)` is deprecated. Use `column_name = "value"` instead - --> $DIR/as_changeset_deprecated_column_name.rs:15:7 - | -15 | #[column_name(name)] - | ^^^^^^^^^^^^^^^^^ - -error: warnings - --> $DIR/as_changeset_deprecated_column_name.rs:21:5 - | -21 | compile_error!("warnings"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/diesel_compile_tests/tests/fail/as_changeset_missing_column_name_tuple_struct.stderr b/diesel_compile_tests/tests/fail/as_changeset_missing_column_name_tuple_struct.stderr deleted file mode 100644 index fed8bc12ebc2..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_missing_column_name_tuple_struct.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error: All fields of tuple structs must be annotated with `#[column_name]` - --> $DIR/as_changeset_missing_column_name_tuple_struct.rs:14:13 - | -14 | struct User(i32, #[column_name = "name"] String, String); - | ^^^ - -error: All fields of tuple structs must be annotated with `#[column_name]` - --> $DIR/as_changeset_missing_column_name_tuple_struct.rs:14:50 - | -14 | struct User(i32, #[column_name = "name"] String, String); - | ^^^^^^ - -error[E0412]: cannot find type `unknown_column` in module `users` - --> $DIR/as_changeset_missing_column_name_tuple_struct.rs:14:13 - | -14 | struct User(i32, #[column_name = "name"] String, String); - | ^^^ not found in `users` - -error[E0412]: cannot find type `unknown_column` in module `users` - --> $DIR/as_changeset_missing_column_name_tuple_struct.rs:14:50 - | -14 | struct User(i32, #[column_name = "name"] String, String); - | ^^^^^^ not found in `users` - -error[E0425]: cannot find value `unknown_column` in module `users` - --> $DIR/as_changeset_missing_column_name_tuple_struct.rs:14:13 - | -14 | struct User(i32, #[column_name = "name"] String, String); - | ^^^ not found in `users` - -error[E0425]: cannot find value `unknown_column` in module `users` - --> $DIR/as_changeset_missing_column_name_tuple_struct.rs:14:50 - | -14 | struct User(i32, #[column_name = "name"] String, String); - | ^^^^^^ not found in `users` diff --git a/diesel_compile_tests/tests/fail/as_changeset_missing_table_import.stderr b/diesel_compile_tests/tests/fail/as_changeset_missing_table_import.stderr deleted file mode 100644 index 3004ee63e08e..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_missing_table_import.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0433]: failed to resolve: use of undeclared crate or module `users` - --> $DIR/as_changeset_missing_table_import.rs:5:8 - | -5 | struct User { - | ^^^^ use of undeclared crate or module `users` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0433]: failed to resolve: use of undeclared crate or module `users` - --> $DIR/as_changeset_missing_table_import.rs:11:16 - | -11 | #[table_name = "users"] - | ^^^^^^^ use of undeclared crate or module `users` diff --git a/diesel_compile_tests/tests/fail/as_changeset_struct_with_only_primary_key.stderr b/diesel_compile_tests/tests/fail/as_changeset_struct_with_only_primary_key.stderr deleted file mode 100644 index 230cd12b1595..000000000000 --- a/diesel_compile_tests/tests/fail/as_changeset_struct_with_only_primary_key.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: Deriving `AsChangeset` on a structure that only contains the primary key isn't supported. - --> $DIR/as_changeset_struct_with_only_primary_key.rs:17:10 - | -17 | #[derive(AsChangeset)] - | ^^^^^^^^^^^ - | - = help: If you want to change the primary key of a row, you should do so with `.set(table::id.eq(new_id))`. - = note: `#[derive(AsChangeset)]` never changes the primary key of a row. - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the trait bound `(): AsChangeset` is not satisfied - --> $DIR/as_changeset_struct_with_only_primary_key.rs:17:10 - | -17 | #[derive(AsChangeset)] - | ^^^^^^^^^^^ the trait `AsChangeset` is not implemented for `()` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/as_expression_bad_sql_type.stderr b/diesel_compile_tests/tests/fail/as_expression_bad_sql_type.stderr deleted file mode 100644 index 45749c265d46..000000000000 --- a/diesel_compile_tests/tests/fail/as_expression_bad_sql_type.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: `sql_type` must be in the form `sql_type = "value"` - --> $DIR/as_expression_bad_sql_type.rs:5:3 - | -5 | #[sql_type(Foo)] - | ^^^^^^^^^^^^^ - -error: `sql_type` must be in the form `sql_type = "value"` - --> $DIR/as_expression_bad_sql_type.rs:6:3 - | -6 | #[sql_type] - | ^^^^^^^^ - -error: Invalid Rust type: `@%&&*` - --> $DIR/as_expression_bad_sql_type.rs:7:14 - | -7 | #[sql_type = "@%&&*"] - | ^^^^^^^ - -error: Invalid Rust type: `1omg` - --> $DIR/as_expression_bad_sql_type.rs:8:14 - | -8 | #[sql_type = "1omg"] - | ^^^^^^ diff --git a/diesel_compile_tests/tests/fail/belongs_to_incorrect_lifetime_syntax.stderr b/diesel_compile_tests/tests/fail/belongs_to_incorrect_lifetime_syntax.stderr deleted file mode 100644 index 2ac7bdff3184..000000000000 --- a/diesel_compile_tests/tests/fail/belongs_to_incorrect_lifetime_syntax.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/belongs_to_incorrect_lifetime_syntax.rs:25:23 - | -24 | #[derive(Associations)] - | - lifetime `'a` is missing in item created through this procedural macro -25 | #[belongs_to(parent = "Foo<'a>")] - | ^^^^^^^^^ undeclared lifetime diff --git a/diesel_compile_tests/tests/fail/belongs_to_invalid_option_syntax.rs b/diesel_compile_tests/tests/fail/belongs_to_invalid_option_syntax.rs deleted file mode 100644 index 0de1fa3e9cf3..000000000000 --- a/diesel_compile_tests/tests/fail/belongs_to_invalid_option_syntax.rs +++ /dev/null @@ -1,41 +0,0 @@ -#[macro_use] -extern crate diesel; - -table! { - bar (id) { - id -> Integer, - } -} - -table! { - foo (bar_id) { - bar_id -> Integer, - } -} - -#[derive(Identifiable)] -#[table_name = "bar"] -struct Bar { - id: i32, -} - -#[derive(Identifiable)] -#[table_name = "bar"] -struct Baz { - id: i32, -} - -#[derive(Associations)] -#[belongs_to] -#[belongs_to = "Bar"] -#[belongs_to()] -#[belongs_to(foreign_key = "bar_id")] -#[belongs_to(Bar, foreign_key)] -#[belongs_to(Bar, foreign_key(bar_id))] -#[belongs_to(Baz, foreign_key = "bar_id", random_option)] -#[table_name = "foo"] -struct Foo { - bar_id: i32, -} - -fn main() {} diff --git a/diesel_compile_tests/tests/fail/belongs_to_invalid_option_syntax.stderr b/diesel_compile_tests/tests/fail/belongs_to_invalid_option_syntax.stderr deleted file mode 100644 index ce2f5207f065..000000000000 --- a/diesel_compile_tests/tests/fail/belongs_to_invalid_option_syntax.stderr +++ /dev/null @@ -1,49 +0,0 @@ -error: `belongs_to` must be in the form `belongs_to(...)` - --> $DIR/belongs_to_invalid_option_syntax.rs:29:3 - | -29 | #[belongs_to] - | ^^^^^^^^^^ - -error: `belongs_to` must be in the form `belongs_to(...)` - --> $DIR/belongs_to_invalid_option_syntax.rs:30:3 - | -30 | #[belongs_to = "Bar"] - | ^^^^^^^^^^^^^^^^^^ - -error: Expected a struct name - --> $DIR/belongs_to_invalid_option_syntax.rs:31:3 - | -31 | #[belongs_to()] - | ^^^^^^^^^^^^ - | - = help: e.g. `#[belongs_to(User)]` or `#[belongs_to(parent = "User<'_>")] - -error: Expected a struct name - --> $DIR/belongs_to_invalid_option_syntax.rs:32:3 - | -32 | #[belongs_to(foreign_key = "bar_id")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: e.g. `#[belongs_to(User)]` or `#[belongs_to(parent = "User<'_>")] - -error: `foreign_key` must be in the form `foreign_key = "value"` - --> $DIR/belongs_to_invalid_option_syntax.rs:33:19 - | -33 | #[belongs_to(Bar, foreign_key)] - | ^^^^^^^^^^^ - -warning: The form `foreign_key(value)` is deprecated. Use `foreign_key = "value"` instead - --> $DIR/belongs_to_invalid_option_syntax.rs:34:19 - | -34 | #[belongs_to(Bar, foreign_key(bar_id))] - | ^^^^^^^^^^^^^^^^^^^ - -warning: belongs_to takes a single parent. Change - belongs_to(Baz, random_option) -to - belongs_to(Baz) - belongs_to(random_option) - --> $DIR/belongs_to_invalid_option_syntax.rs:35:3 - | -35 | #[belongs_to(Baz, foreign_key = "bar_id", random_option)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_column.stderr b/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_column.stderr deleted file mode 100644 index 846a5fda5088..000000000000 --- a/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_column.stderr +++ /dev/null @@ -1,55 +0,0 @@ -error[E0412]: cannot find type `bar_id` in module `foo` - --> $DIR/belongs_to_missing_foreign_key_column.rs:13:14 - | -13 | #[belongs_to(Bar)] - | ^^^ not found in `foo` - -error[E0425]: cannot find value `bar_id` in module `foo` - --> $DIR/belongs_to_missing_foreign_key_column.rs:13:14 - | -13 | #[belongs_to(Bar)] - | ^^^ not found in `foo` - -error[E0412]: cannot find type `bar_id` in module `foo` - --> $DIR/belongs_to_missing_foreign_key_column.rs:20:33 - | -20 | #[belongs_to(Bar, foreign_key = "bar_id")] - | ^^^^^^^^ not found in `foo` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0425]: cannot find value `bar_id` in module `foo` - --> $DIR/belongs_to_missing_foreign_key_column.rs:20:33 - | -20 | #[belongs_to(Bar, foreign_key = "bar_id")] - | ^^^^^^^^ not found in `foo` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0412]: cannot find type `bar_id` in module `foo` - --> $DIR/belongs_to_missing_foreign_key_column.rs:27:14 - | -27 | #[belongs_to(Bar)] - | ^^^ not found in `foo` - -error[E0425]: cannot find value `bar_id` in module `foo` - --> $DIR/belongs_to_missing_foreign_key_column.rs:27:14 - | -27 | #[belongs_to(Bar)] - | ^^^ not found in `foo` - -error[E0412]: cannot find type `bar_id` in module `foo` - --> $DIR/belongs_to_missing_foreign_key_column.rs:35:33 - | -35 | #[belongs_to(Bar, foreign_key = "bar_id")] - | ^^^^^^^^ not found in `foo` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0425]: cannot find value `bar_id` in module `foo` - --> $DIR/belongs_to_missing_foreign_key_column.rs:35:33 - | -35 | #[belongs_to(Bar, foreign_key = "bar_id")] - | ^^^^^^^^ not found in `foo` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_field.rs b/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_field.rs deleted file mode 100644 index 348199d388cc..000000000000 --- a/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_field.rs +++ /dev/null @@ -1,19 +0,0 @@ -#[macro_use] -extern crate diesel; - -struct Bar; - -#[derive(Associations)] -#[belongs_to(Bar)] -#[belongs_to(Bar, foreign_key = "bar_id")] -struct Foo {} - -#[derive(Associations)] -#[belongs_to(Bar)] -#[belongs_to(Bar, foreign_key = "bar_id")] -struct Baz { - #[column_name = "baz_id"] - bar_id: i32, -} - -fn main() {} diff --git a/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_field.stderr b/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_field.stderr deleted file mode 100644 index db866421c9f0..000000000000 --- a/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_field.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error: No field with column name bar_id - --> $DIR/belongs_to_missing_foreign_key_field.rs:7:14 - | -7 | #[belongs_to(Bar)] - | ^^^ - -error: No field with column name bar_id - --> $DIR/belongs_to_missing_foreign_key_field.rs:8:33 - | -8 | #[belongs_to(Bar, foreign_key = "bar_id")] - | ^^^^^^^^ - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: No field with column name bar_id - --> $DIR/belongs_to_missing_foreign_key_field.rs:12:14 - | -12 | #[belongs_to(Bar)] - | ^^^ - -error: No field with column name bar_id - --> $DIR/belongs_to_missing_foreign_key_field.rs:13:33 - | -13 | #[belongs_to(Bar, foreign_key = "bar_id")] - | ^^^^^^^^ - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/belongs_to_missing_parent_import.stderr b/diesel_compile_tests/tests/fail/belongs_to_missing_parent_import.stderr deleted file mode 100644 index 315d8e3ceb42..000000000000 --- a/diesel_compile_tests/tests/fail/belongs_to_missing_parent_import.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error[E0412]: cannot find type `Bar` in this scope - --> $DIR/belongs_to_missing_parent_import.rs:12:14 - | -12 | #[belongs_to(Bar)] - | ^^^ not found in this scope diff --git a/diesel_compile_tests/tests/fail/belongs_to_second_parent.stderr b/diesel_compile_tests/tests/fail/belongs_to_second_parent.stderr deleted file mode 100644 index 5c4e1f116521..000000000000 --- a/diesel_compile_tests/tests/fail/belongs_to_second_parent.stderr +++ /dev/null @@ -1,15 +0,0 @@ -warning: belongs_to takes a single parent. Change - belongs_to(Bar, Baz) -to - belongs_to(Bar) - belongs_to(Baz) - --> $DIR/belongs_to_second_parent.rs:29:3 - | -29 | #[belongs_to(Bar, Baz)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: warnings - --> $DIR/belongs_to_second_parent.rs:37:5 - | -37 | compile_error!("warnings"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr b/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr index 5cea87dbc641..9e3144a2b25d 100644 --- a/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr +++ b/diesel_compile_tests/tests/fail/boxed_queries_require_selectable_expression_for_order.stderr @@ -8,5 +8,5 @@ error[E0277]: the trait bound `users::table: AppearsInFromClause` > = note: required because of the requirements on the impl of `AppearsOnTable` for `posts::columns::title` = note: 1 redundant requirements hidden - = note: required because of the requirements on the impl of `AppearsOnTable` for `Desc` - = note: required because of the requirements on the impl of `OrderDsl>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), users::table, Pg>` + = note: required because of the requirements on the impl of `AppearsOnTable` for `diesel::expression::operators::Desc` + = note: required because of the requirements on the impl of `OrderDsl>` for `BoxedSelectStatement<'_, (diesel::sql_types::Integer, diesel::sql_types::Text), users::table, Pg>` diff --git a/diesel_compile_tests/tests/fail/cannot_pass_aggregate_to_where.stderr b/diesel_compile_tests/tests/fail/cannot_pass_aggregate_to_where.stderr index 21ccb4124955..0210abca6ac2 100644 --- a/diesel_compile_tests/tests/fail/cannot_pass_aggregate_to_where.stderr +++ b/diesel_compile_tests/tests/fail/cannot_pass_aggregate_to_where.stderr @@ -7,4 +7,5 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::Yes: MixedAggre = help: the following implementations were found: > > - = note: required because of the requirements on the impl of `FilterDsl, diesel::expression::bound::Bound>>>` for `SelectStatement` + = note: required because of the requirements on the impl of `NonAggregate` for `Grouped, diesel::expression::bound::Bound>>` + = note: required because of the requirements on the impl of `FilterDsl, diesel::expression::bound::Bound>>>` for `SelectStatement` diff --git a/diesel_compile_tests/tests/fail/cannot_use_expression_methods_on_tuples.stderr b/diesel_compile_tests/tests/fail/cannot_use_expression_methods_on_tuples.stderr index 6e3432b37ba9..4dee9119beac 100644 --- a/diesel_compile_tests/tests/fail/cannot_use_expression_methods_on_tuples.stderr +++ b/diesel_compile_tests/tests/fail/cannot_use_expression_methods_on_tuples.stderr @@ -5,9 +5,9 @@ error[E0599]: the method `is_not_null` exists for tuple `(columns::id, columns:: | ^^^^^^^^^^^ method cannot be called on `(columns::id, columns::name)` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: - `(diesel::sql_types::Integer, diesel::sql_types::Text): SingleValue` + `(diesel::sql_types::Integer, diesel::sql_types::Text): diesel::sql_types::SingleValue` which is required by `(columns::id, columns::name): diesel::ExpressionMethods` - `(diesel::sql_types::Integer, diesel::sql_types::Text): SingleValue` + `(diesel::sql_types::Integer, diesel::sql_types::Text): diesel::sql_types::SingleValue` which is required by `&(columns::id, columns::name): diesel::ExpressionMethods` `&mut (columns::id, columns::name): diesel::Expression` which is required by `&mut (columns::id, columns::name): diesel::ExpressionMethods` @@ -19,9 +19,9 @@ error[E0599]: the method `eq_any` exists for tuple `(columns::id, columns::name) | ^^^^^^ method cannot be called on `(columns::id, columns::name)` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: - `(diesel::sql_types::Integer, diesel::sql_types::Text): SingleValue` + `(diesel::sql_types::Integer, diesel::sql_types::Text): diesel::sql_types::SingleValue` which is required by `(columns::id, columns::name): diesel::ExpressionMethods` - `(diesel::sql_types::Integer, diesel::sql_types::Text): SingleValue` + `(diesel::sql_types::Integer, diesel::sql_types::Text): diesel::sql_types::SingleValue` which is required by `&(columns::id, columns::name): diesel::ExpressionMethods` `&mut (columns::id, columns::name): diesel::Expression` which is required by `&mut (columns::id, columns::name): diesel::ExpressionMethods` diff --git a/diesel_compile_tests/tests/fail/codegen_does_not_add_save_changes_method_on_structs_without_primary_key.rs b/diesel_compile_tests/tests/fail/codegen_does_not_add_save_changes_method_on_structs_without_primary_key.rs index e8f8b8329632..e45c9236eed7 100644 --- a/diesel_compile_tests/tests/fail/codegen_does_not_add_save_changes_method_on_structs_without_primary_key.rs +++ b/diesel_compile_tests/tests/fail/codegen_does_not_add_save_changes_method_on_structs_without_primary_key.rs @@ -11,7 +11,7 @@ table! { } #[derive(Queryable, AsChangeset)] -#[table_name = "users"] +#[diesel(table_name = users)] pub struct User { name: String, hair_color: String, diff --git a/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.rs b/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.rs index 9a13a88640aa..c4adf58a2fa6 100644 --- a/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.rs +++ b/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.rs @@ -1,7 +1,7 @@ extern crate diesel; -use diesel::*; use diesel::dsl::count; +use diesel::*; table! { users { @@ -11,7 +11,7 @@ table! { } #[derive(Insertable)] -#[table_name="users"] +#[diesel(table_name = users)] pub struct NewUser { name: String, } diff --git a/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.stderr b/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.stderr index 98fd853b35fa..bcebeeead5fe 100644 --- a/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.stderr +++ b/diesel_compile_tests/tests/fail/custom_returning_requires_nonaggregate.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::Yes: MixedAggregates` is not satisfied - --> $DIR/custom_returning_requires_nonaggregate.rs:22:68 + --> tests/fail/custom_returning_requires_nonaggregate.rs:22:68 | 22 | let stmt = update(users.filter(id.eq(1))).set(name.eq("Bill")).returning(count(id)); | ^^^^^^^^^ the trait `MixedAggregates` is not implemented for `diesel::expression::is_aggregate::Yes` @@ -7,10 +7,10 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::Yes: MixedAggre = help: the following implementations were found: > > - = note: required because of the requirements on the impl of `Query` for `UpdateStatement>>>, diesel::query_builder::update_statement::changeset::Assign>, ReturningClause>>` + = note: required because of the requirements on the impl of `Query` for `UpdateStatement>>>, diesel::query_builder::update_statement::changeset::Assign>, ReturningClause>>` error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggregates` is not satisfied - --> $DIR/custom_returning_requires_nonaggregate.rs:27:53 + --> tests/fail/custom_returning_requires_nonaggregate.rs:27:53 | 27 | let stmt = insert_into(users).values(&new_user).returning((name, count(name))); | ^^^^^^^^^ the trait `MixedAggregates` is not implemented for `diesel::expression::is_aggregate::No` @@ -18,5 +18,6 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggreg = help: the following implementations were found: > > - = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(columns::name, count::count::count)` - = note: required because of the requirements on the impl of `Query` for `InsertStatement>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<(columns::name, count::count::count)>>` + = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(columns::name, diesel::expression::count::count::count)` + = note: required because of the requirements on the impl of `NonAggregate` for `(columns::name, diesel::expression::count::count::count)` + = note: required because of the requirements on the impl of `Query` for `InsertStatement>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause<(columns::name, diesel::expression::count::count::count)>>` diff --git a/diesel_compile_tests/tests/fail/custom_returning_requires_selectable_expression.rs b/diesel_compile_tests/tests/fail/custom_returning_requires_selectable_expression.rs index 9cb14678914a..ec07312623a3 100644 --- a/diesel_compile_tests/tests/fail/custom_returning_requires_selectable_expression.rs +++ b/diesel_compile_tests/tests/fail/custom_returning_requires_selectable_expression.rs @@ -17,7 +17,7 @@ table! { } #[derive(Insertable)] -#[table_name="users"] +#[diesel(table_name = users)] pub struct NewUser { name: String, } diff --git a/diesel_compile_tests/tests/fail/as_changeset_struct_with_only_primary_key.rs b/diesel_compile_tests/tests/fail/derive/as_changeset_struct_with_only_primary_key.rs similarity index 50% rename from diesel_compile_tests/tests/fail/as_changeset_struct_with_only_primary_key.rs rename to diesel_compile_tests/tests/fail/derive/as_changeset_struct_with_only_primary_key.rs index 8e44f71ceed6..89dea061883c 100644 --- a/diesel_compile_tests/tests/fail/as_changeset_struct_with_only_primary_key.rs +++ b/diesel_compile_tests/tests/fail/derive/as_changeset_struct_with_only_primary_key.rs @@ -1,4 +1,5 @@ -#[macro_use] extern crate diesel; +#[macro_use] +extern crate diesel; table! { foo { @@ -8,16 +9,23 @@ table! { } #[derive(AsChangeset)] -#[table_name="foo"] +#[diesel(table_name = foo)] struct Foo1 { id: i32, bar: i32, } #[derive(AsChangeset)] -#[table_name="foo"] +#[diesel(table_name = foo)] struct Foo2 { id: i32, } +#[derive(AsChangeset)] +#[diesel(table_name = foo, primary_key(id, bar))] +struct Foo3 { + id: i32, + bar: i32, +} + fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/as_changeset_struct_with_only_primary_key.stderr b/diesel_compile_tests/tests/fail/derive/as_changeset_struct_with_only_primary_key.stderr new file mode 100644 index 000000000000..4992682acad6 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/as_changeset_struct_with_only_primary_key.stderr @@ -0,0 +1,23 @@ +error: Deriving `AsChangeset` on a structure that only contains primary keys isn't supported. + + = help: If you want to change the primary key of a row, you should do so with `.set(table::id.eq(new_id))`. + = note: `#[derive(AsChangeset)]` never changes the primary key of a row. + + --> $DIR/as_changeset_struct_with_only_primary_key.rs:18:10 + | +18 | #[derive(AsChangeset)] + | ^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: Deriving `AsChangeset` on a structure that only contains primary keys isn't supported. + + = help: If you want to change the primary key of a row, you should do so with `.set(table::id.eq(new_id))`. + = note: `#[derive(AsChangeset)]` never changes the primary key of a row. + + --> $DIR/as_changeset_struct_with_only_primary_key.rs:24:10 + | +24 | #[derive(AsChangeset)] + | ^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/as_expression_bad_sql_type.rs b/diesel_compile_tests/tests/fail/derive/as_expression_without_sql_type.rs similarity index 60% rename from diesel_compile_tests/tests/fail/as_expression_bad_sql_type.rs rename to diesel_compile_tests/tests/fail/derive/as_expression_without_sql_type.rs index a708307c0fc4..b3fcd6b2f42c 100644 --- a/diesel_compile_tests/tests/fail/as_expression_bad_sql_type.rs +++ b/diesel_compile_tests/tests/fail/derive/as_expression_without_sql_type.rs @@ -2,10 +2,6 @@ extern crate diesel; use diesel::expression::AsExpression; #[derive(AsExpression)] -#[sql_type(Foo)] -#[sql_type] -#[sql_type = "@%&&*"] -#[sql_type = "1omg"] struct Lol; fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/as_expression_without_sql_type.stderr b/diesel_compile_tests/tests/fail/derive/as_expression_without_sql_type.stderr new file mode 100644 index 000000000000..462d23412347 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/as_expression_without_sql_type.stderr @@ -0,0 +1,7 @@ +error: At least one `sql_type` is needed for deriving `AsExpression` on a structure. + --> $DIR/as_expression_without_sql_type.rs:4:10 + | +4 | #[derive(AsExpression)] + | ^^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/derive/associations_without_belongs_to.rs b/diesel_compile_tests/tests/fail/derive/associations_without_belongs_to.rs new file mode 100644 index 000000000000..43527c7ba47e --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/associations_without_belongs_to.rs @@ -0,0 +1,9 @@ +#[macro_use] +extern crate diesel; + +#[derive(Associations)] +struct User { + id: i32, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/associations_without_belongs_to.stderr b/diesel_compile_tests/tests/fail/derive/associations_without_belongs_to.stderr new file mode 100644 index 000000000000..a9710bc03ce2 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/associations_without_belongs_to.stderr @@ -0,0 +1,7 @@ +error: At least one `belongs_to` is needed for deriving `Associations` on a structure. + --> $DIR/associations_without_belongs_to.rs:4:10 + | +4 | #[derive(Associations)] + | ^^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/derive/bad_aggregate.rs b/diesel_compile_tests/tests/fail/derive/bad_aggregate.rs new file mode 100644 index 000000000000..26f334e85199 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_aggregate.rs @@ -0,0 +1,9 @@ +extern crate diesel; + +use diesel::expression::ValidGrouping; + +#[derive(ValidGrouping)] +#[diesel(aggregate = true)] +struct User; + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_aggregate.stderr b/diesel_compile_tests/tests/fail/derive/bad_aggregate.stderr new file mode 100644 index 000000000000..92f224d8262b --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_aggregate.stderr @@ -0,0 +1,5 @@ +error: expected `,` + --> $DIR/bad_aggregate.rs:6:20 + | +6 | #[diesel(aggregate = true)] + | ^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_belongs_to.rs b/diesel_compile_tests/tests/fail/derive/bad_belongs_to.rs new file mode 100644 index 000000000000..2f94d5215f24 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_belongs_to.rs @@ -0,0 +1,84 @@ +#[macro_use] +extern crate diesel; + +table! { + bar (id) { + id -> Integer, + } +} + +table! { + foo (bar_id) { + bar_id -> Integer, + } +} + +#[derive(Identifiable)] +#[diesel(table_name = bar)] +struct Bar { + id: i32, +} + +#[derive(Identifiable)] +#[diesel(table_name = bar)] +struct Baz { + id: i32, +} + +#[derive(Associations)] +#[diesel(belongs_to)] +#[diesel(table_name = foo)] +struct Foo1 { + bar_id: i32, +} + +#[derive(Associations)] +#[diesel(belongs_to = "Bar")] +#[diesel(table_name = foo)] +struct Foo2 { + bar_id: i32, +} + +#[derive(Associations)] +#[diesel(belongs_to())] +#[diesel(table_name = foo)] +struct Foo3 { + bar_id: i32, +} + +#[derive(Associations)] +#[diesel(belongs_to(foreign_key = bar_id))] +#[diesel(table_name = foo)] +struct Foo4 { + bar_id: i32, +} + +#[derive(Associations)] +#[diesel(belongs_to(Bar = "bar_id"))] +#[diesel(table_name = foo)] +struct Foo5 { + bar_id: i32, +} + +#[derive(Associations)] +#[diesel(belongs_to(Bar, foreign_key))] +#[diesel(table_name = foo)] +struct Foo6 { + bar_id: i32, +} + +#[derive(Associations)] +#[diesel(belongs_to(Bar, foreign_key(bar_id)))] +#[diesel(table_name = foo)] +struct Foo7 { + bar_id: i32, +} + +#[derive(Associations)] +#[diesel(belongs_to(Bar, what))] +#[diesel(table_name = foo)] +struct Foo8 { + bar_id: i32, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_belongs_to.stderr b/diesel_compile_tests/tests/fail/derive/bad_belongs_to.stderr new file mode 100644 index 000000000000..d6effd72f394 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_belongs_to.stderr @@ -0,0 +1,47 @@ +error: unexpected end of input, expected parentheses + --> $DIR/bad_belongs_to.rs:29:9 + | +29 | #[diesel(belongs_to)] + | ^^^^^^^^^^^^ + +error: expected parentheses + --> $DIR/bad_belongs_to.rs:36:21 + | +36 | #[diesel(belongs_to = "Bar")] + | ^ + +error: unexpected end of input, expected identifier + --> $DIR/bad_belongs_to.rs:43:20 + | +43 | #[diesel(belongs_to())] + | ^^ + +error: expected `,` + --> $DIR/bad_belongs_to.rs:50:33 + | +50 | #[diesel(belongs_to(foreign_key = bar_id))] + | ^ + +error: expected `,` + --> $DIR/bad_belongs_to.rs:57:25 + | +57 | #[diesel(belongs_to(Bar = "bar_id"))] + | ^ + +error: unexpected end of input, expected `=` + --> $DIR/bad_belongs_to.rs:64:20 + | +64 | #[diesel(belongs_to(Bar, foreign_key))] + | ^^^^^^^^^^^^^^^^^^ + +error: expected `=` + --> $DIR/bad_belongs_to.rs:71:37 + | +71 | #[diesel(belongs_to(Bar, foreign_key(bar_id)))] + | ^^^^^^^^ + +error: unknown attribute + --> $DIR/bad_belongs_to.rs:78:26 + | +78 | #[diesel(belongs_to(Bar, what))] + | ^^^^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_column_name.rs b/diesel_compile_tests/tests/fail/derive/bad_column_name.rs new file mode 100644 index 000000000000..09f327506b9b --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_column_name.rs @@ -0,0 +1,39 @@ +#[macro_use] +extern crate diesel; + +table! { + users { + id -> Integer, + name -> Text, + } +} + +#[derive(Queryable)] +#[diesel(table_name = users)] +struct User1 { + #[diesel(column_name)] + name: String, +} + +#[derive(Queryable)] +#[diesel(table_name = users)] +struct User2 { + #[diesel(column_name(another))] + name: String, +} + +#[derive(Queryable)] +#[diesel(table_name = users)] +struct User3 { + #[diesel(column_name = true)] + name: String, +} + +#[derive(Queryable)] +#[diesel(table_name = users)] +struct User4 { + #[diesel(column_name = "name")] + name: String, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_column_name.stderr b/diesel_compile_tests/tests/fail/derive/bad_column_name.stderr new file mode 100644 index 000000000000..941e09611a42 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_column_name.stderr @@ -0,0 +1,23 @@ +error: unexpected end of input, expected `=` + --> $DIR/bad_column_name.rs:14:13 + | +14 | #[diesel(column_name)] + | ^^^^^^^^^^^^^ + +error: expected `=` + --> $DIR/bad_column_name.rs:21:25 + | +21 | #[diesel(column_name(another))] + | ^^^^^^^^^ + +error: expected identifier + --> $DIR/bad_column_name.rs:28:28 + | +28 | #[diesel(column_name = true)] + | ^^^^ + +error: expected identifier + --> $DIR/bad_column_name.rs:35:28 + | +35 | #[diesel(column_name = "name")] + | ^^^^^^ diff --git a/diesel_compile_tests/tests/fail/as_changeset_missing_column_name_tuple_struct.rs b/diesel_compile_tests/tests/fail/derive/bad_derive_input.rs similarity index 60% rename from diesel_compile_tests/tests/fail/as_changeset_missing_column_name_tuple_struct.rs rename to diesel_compile_tests/tests/fail/derive/bad_derive_input.rs index b30fbb942960..20830f0c99d2 100644 --- a/diesel_compile_tests/tests/fail/as_changeset_missing_column_name_tuple_struct.rs +++ b/diesel_compile_tests/tests/fail/derive/bad_derive_input.rs @@ -10,7 +10,11 @@ table! { } #[derive(AsChangeset)] -#[table_name = "users"] -struct User(i32, #[column_name = "name"] String, String); +#[diesel(table_name = users)] +enum UserEnum {} + +#[derive(AsChangeset)] +#[diesel(table_name = users)] +struct UserStruct; fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_derive_input.stderr b/diesel_compile_tests/tests/fail/derive/bad_derive_input.stderr new file mode 100644 index 000000000000..2b5445435a0d --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_derive_input.stderr @@ -0,0 +1,15 @@ +error: This derive can only be used on non-unit structs + --> $DIR/bad_derive_input.rs:12:10 + | +12 | #[derive(AsChangeset)] + | ^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: This derive can only be used on non-unit structs + --> $DIR/bad_derive_input.rs:16:10 + | +16 | #[derive(AsChangeset)] + | ^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/derive/bad_deserialize_as.rs b/diesel_compile_tests/tests/fail/derive/bad_deserialize_as.rs new file mode 100644 index 000000000000..b5341de1e12b --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_deserialize_as.rs @@ -0,0 +1,32 @@ +#[macro_use] +extern crate diesel; + +#[derive(Queryable)] +struct User1 { + id: i32, + #[diesel(deserialize_as)] + name: String, +} + +#[derive(Queryable)] +struct User2 { + id: i32, + #[diesel(deserialize_as(Foo))] + name: String, +} + +#[derive(Queryable)] +struct User3 { + id: i32, + #[diesel(deserialize_as = "foo")] + name: String, +} + +#[derive(Queryable)] +struct User4 { + id: i32, + #[diesel(deserialize_as = 1omg)] + name: String, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_deserialize_as.stderr b/diesel_compile_tests/tests/fail/derive/bad_deserialize_as.stderr new file mode 100644 index 000000000000..d655f0aaf4a6 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_deserialize_as.stderr @@ -0,0 +1,23 @@ +error: unexpected end of input, expected `=` + --> $DIR/bad_deserialize_as.rs:7:13 + | +7 | #[diesel(deserialize_as)] + | ^^^^^^^^^^^^^^^^ + +error: expected `=` + --> $DIR/bad_deserialize_as.rs:14:28 + | +14 | #[diesel(deserialize_as(Foo))] + | ^^^^^ + +error: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime + --> $DIR/bad_deserialize_as.rs:21:31 + | +21 | #[diesel(deserialize_as = "foo")] + | ^^^^^ + +error: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime + --> $DIR/bad_deserialize_as.rs:28:31 + | +28 | #[diesel(deserialize_as = 1omg)] + | ^^^^ diff --git a/diesel_compile_tests/tests/fail/as_changeset_bad_column_name_syntax.rs b/diesel_compile_tests/tests/fail/derive/bad_embed.rs similarity index 64% rename from diesel_compile_tests/tests/fail/as_changeset_bad_column_name_syntax.rs rename to diesel_compile_tests/tests/fail/derive/bad_embed.rs index bfe6318819bf..5af6051f247d 100644 --- a/diesel_compile_tests/tests/fail/as_changeset_bad_column_name_syntax.rs +++ b/diesel_compile_tests/tests/fail/derive/bad_embed.rs @@ -2,16 +2,16 @@ extern crate diesel; table! { - users { + users (id) { id -> Integer, name -> Text, } } -#[derive(AsChangeset)] -#[table_name = "users"] +#[derive(Insertable)] struct User { - #[column_name] + id: i32, + #[diesel(embed = true)] name: String, } diff --git a/diesel_compile_tests/tests/fail/derive/bad_embed.stderr b/diesel_compile_tests/tests/fail/derive/bad_embed.stderr new file mode 100644 index 000000000000..9a83108d6eca --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_embed.stderr @@ -0,0 +1,5 @@ +error: expected `,` + --> $DIR/bad_embed.rs:14:20 + | +14 | #[diesel(embed = true)] + | ^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_foreign_derive.rs b/diesel_compile_tests/tests/fail/derive/bad_foreign_derive.rs new file mode 100644 index 000000000000..2c59d0d692d7 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_foreign_derive.rs @@ -0,0 +1,23 @@ +extern crate diesel; + +use diesel::deserialize::FromSqlRow; +use diesel::expression::{AsExpression, ValidGrouping}; + +#[derive(ValidGrouping)] +#[diesel(foreign_derive = true)] +struct User1; + +#[derive(ValidGrouping)] +#[diesel(foreign_derive)] +struct User2; + +#[derive(AsExpression)] +#[diesel(sql_type = bool)] +#[diesel(foreign_derive)] +struct User3; + +#[derive(FromSqlRow)] +#[diesel(foreign_derive)] +struct User4; + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_foreign_derive.stderr b/diesel_compile_tests/tests/fail/derive/bad_foreign_derive.stderr new file mode 100644 index 000000000000..5745d41c83b5 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_foreign_derive.stderr @@ -0,0 +1,29 @@ +error: expected `,` + --> $DIR/bad_foreign_derive.rs:7:25 + | +7 | #[diesel(foreign_derive = true)] + | ^ + +error: foreign_derive requires at least one field + --> $DIR/bad_foreign_derive.rs:10:10 + | +10 | #[derive(ValidGrouping)] + | ^^^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: foreign_derive requires at least one field + --> $DIR/bad_foreign_derive.rs:14:10 + | +14 | #[derive(AsExpression)] + | ^^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: foreign_derive requires at least one field + --> $DIR/bad_foreign_derive.rs:19:10 + | +19 | #[derive(FromSqlRow)] + | ^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/sql_type_bad_options.rs b/diesel_compile_tests/tests/fail/derive/bad_mysql_type.rs similarity index 54% rename from diesel_compile_tests/tests/fail/sql_type_bad_options.rs rename to diesel_compile_tests/tests/fail/derive/bad_mysql_type.rs index 6a1d4e3bc6dc..7393123a3d6f 100644 --- a/diesel_compile_tests/tests/fail/sql_type_bad_options.rs +++ b/diesel_compile_tests/tests/fail/derive/bad_mysql_type.rs @@ -3,27 +3,31 @@ extern crate diesel; use diesel::sql_types::SqlType; #[derive(SqlType)] -#[postgres] +#[diesel(mysql_type)] struct Type1; #[derive(SqlType)] -#[postgres(type_name = "foo", oid = "2", array_oid = "3")] +#[diesel(mysql_type())] struct Type2; #[derive(SqlType)] -#[postgres(oid = "2")] +#[diesel(mysql_type = "foo")] struct Type3; #[derive(SqlType)] -#[postgres(oid = "NaN", array_oid = "1")] +#[diesel(mysql_type(name))] struct Type4; #[derive(SqlType)] -#[postgres(oid = "NaN", ary_oid = "1")] +#[diesel(mysql_type(name()))] struct Type5; #[derive(SqlType)] -#[postgres = "foo"] +#[diesel(mysql_type(name = Foo))] struct Type6; +#[derive(SqlType)] +#[diesel(mysql_type(what))] +struct Type7; + fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_mysql_type.stderr b/diesel_compile_tests/tests/fail/derive/bad_mysql_type.stderr new file mode 100644 index 000000000000..7a15545d0523 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_mysql_type.stderr @@ -0,0 +1,41 @@ +error: unexpected end of input, expected parentheses + --> $DIR/bad_mysql_type.rs:6:9 + | +6 | #[diesel(mysql_type)] + | ^^^^^^^^^^^^ + +error: expected attribute `name` + --> $DIR/bad_mysql_type.rs:10:20 + | +10 | #[diesel(mysql_type())] + | ^^ + +error: expected parentheses + --> $DIR/bad_mysql_type.rs:14:21 + | +14 | #[diesel(mysql_type = "foo")] + | ^ + +error: unexpected end of input, expected `=` + --> $DIR/bad_mysql_type.rs:18:20 + | +18 | #[diesel(mysql_type(name))] + | ^^^^^^ + +error: expected `=` + --> $DIR/bad_mysql_type.rs:22:25 + | +22 | #[diesel(mysql_type(name()))] + | ^^ + +error: expected string literal + --> $DIR/bad_mysql_type.rs:26:28 + | +26 | #[diesel(mysql_type(name = Foo))] + | ^^^ + +error: unknown attribute + --> $DIR/bad_mysql_type.rs:30:21 + | +30 | #[diesel(mysql_type(what))] + | ^^^^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_not_sized.rs b/diesel_compile_tests/tests/fail/derive/bad_not_sized.rs new file mode 100644 index 000000000000..81acf584e912 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_not_sized.rs @@ -0,0 +1,9 @@ +extern crate diesel; +use diesel::expression::AsExpression; + +#[derive(AsExpression)] +#[diesel(sql_type = bool)] +#[diesel(not_sized = true)] +struct Lol; + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_not_sized.stderr b/diesel_compile_tests/tests/fail/derive/bad_not_sized.stderr new file mode 100644 index 000000000000..813d8a88eb66 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_not_sized.stderr @@ -0,0 +1,5 @@ +error: expected `,` + --> $DIR/bad_not_sized.rs:6:20 + | +6 | #[diesel(not_sized = true)] + | ^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_postgres_type.rs b/diesel_compile_tests/tests/fail/derive/bad_postgres_type.rs new file mode 100644 index 000000000000..62322367f5a9 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_postgres_type.rs @@ -0,0 +1,57 @@ +extern crate diesel; + +use diesel::sql_types::SqlType; + +#[derive(SqlType)] +#[diesel(postgres_type)] +struct Type1; + +#[derive(SqlType)] +#[diesel(postgres_type())] +struct Type2; + +#[derive(SqlType)] +#[diesel(postgres_type = "foo")] +struct Type3; + +#[derive(SqlType)] +#[diesel(postgres_type(name))] +struct Type4; + +#[derive(SqlType)] +#[diesel(postgres_type(name()))] +struct Type5; + +#[derive(SqlType)] +#[diesel(postgres_type(name = Foo))] +struct Type6; + +#[derive(SqlType)] +#[diesel(postgres_type(name = "foo", oid = 2, array_oid = 3))] +struct Type7; + +#[derive(SqlType)] +#[diesel(postgres_type(name = "foo", array_oid = 3))] +struct Type8; + +#[derive(SqlType)] +#[diesel(postgres_type(oid = 2))] +struct Type9; + +#[derive(SqlType)] +#[diesel(postgres_type(oid = 1, array_oid = "1"))] +struct Type10; + +#[derive(SqlType)] +#[diesel(postgres_type(oid = "1", array_oid = 1))] +struct Type11; + +#[derive(SqlType)] +#[diesel(postgres_type(schema = "foo"))] +struct Type12; + +#[derive(SqlType)] +#[diesel(postgres_type(what))] +struct Type13; + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_postgres_type.stderr b/diesel_compile_tests/tests/fail/derive/bad_postgres_type.stderr new file mode 100644 index 000000000000..0216b8c4f0f0 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_postgres_type.stderr @@ -0,0 +1,80 @@ +error: unexpected end of input, expected parentheses + --> $DIR/bad_postgres_type.rs:6:9 + | +6 | #[diesel(postgres_type)] + | ^^^^^^^^^^^^^^^ + +error: expected `oid` and `array_oid` attribute or `name` attribute + --> $DIR/bad_postgres_type.rs:10:23 + | +10 | #[diesel(postgres_type())] + | ^^ + +error: expected parentheses + --> $DIR/bad_postgres_type.rs:14:24 + | +14 | #[diesel(postgres_type = "foo")] + | ^ + +error: unexpected end of input, expected `=` + --> $DIR/bad_postgres_type.rs:18:23 + | +18 | #[diesel(postgres_type(name))] + | ^^^^^^ + +error: expected `=` + --> $DIR/bad_postgres_type.rs:22:28 + | +22 | #[diesel(postgres_type(name()))] + | ^^ + +error: expected string literal + --> $DIR/bad_postgres_type.rs:26:31 + | +26 | #[diesel(postgres_type(name = Foo))] + | ^^^ + +error: unexpected `oid` when `name` is present + --> $DIR/bad_postgres_type.rs:30:44 + | +30 | #[diesel(postgres_type(name = "foo", oid = 2, array_oid = 3))] + | ^ + +error: unexpected `array_oid` when `name` is present + --> $DIR/bad_postgres_type.rs:34:50 + | +34 | #[diesel(postgres_type(name = "foo", array_oid = 3))] + | ^ + +error: expected `oid` and `array_oid` attribute or `name` attribute + --> $DIR/bad_postgres_type.rs:38:23 + | +38 | #[diesel(postgres_type(oid = 2))] + | ^^^^^^^^^ + +error: expected integer literal + --> $DIR/bad_postgres_type.rs:42:45 + | +42 | #[diesel(postgres_type(oid = 1, array_oid = "1"))] + | ^^^ + +error: expected integer literal + --> $DIR/bad_postgres_type.rs:46:30 + | +46 | #[diesel(postgres_type(oid = "1", array_oid = 1))] + | ^^^ + +error: expected `name` to be also present + + = help: make sure `name` is present, `#[diesel(postgres_type(name = "...", schema = "foo"))]` + + --> $DIR/bad_postgres_type.rs:50:33 + | +50 | #[diesel(postgres_type(schema = "foo"))] + | ^^^^^ + +error: unknown attribute + --> $DIR/bad_postgres_type.rs:54:24 + | +54 | #[diesel(postgres_type(what))] + | ^^^^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_primary_key.rs b/diesel_compile_tests/tests/fail/derive/bad_primary_key.rs new file mode 100644 index 000000000000..fd9da07908f1 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_primary_key.rs @@ -0,0 +1,39 @@ +#[macro_use] +extern crate diesel; + +table! { + users { + id -> Integer, + name -> Text, + } +} + +#[derive(AsChangeset)] +#[diesel(primary_key(id, bar = "baz"))] +struct UserForm1 { + id: i32, + name: String, +} + +#[derive(AsChangeset)] +#[diesel(primary_key(id, qux(id)))] +struct UserForm2 { + id: i32, + name: String, +} + +#[derive(AsChangeset)] +#[diesel(primary_key)] +struct UserForm3 { + id: i32, + name: String, +} + +#[derive(AsChangeset)] +#[diesel(primary_key = id)] +struct UserForm4 { + id: i32, + name: String, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_primary_key.stderr b/diesel_compile_tests/tests/fail/derive/bad_primary_key.stderr new file mode 100644 index 000000000000..a0d0da4cc91d --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_primary_key.stderr @@ -0,0 +1,23 @@ +error: expected `,` + --> $DIR/bad_primary_key.rs:12:30 + | +12 | #[diesel(primary_key(id, bar = "baz"))] + | ^ + +error: expected `,` + --> $DIR/bad_primary_key.rs:19:29 + | +19 | #[diesel(primary_key(id, qux(id)))] + | ^^^^ + +error: unexpected end of input, expected parentheses + --> $DIR/bad_primary_key.rs:26:9 + | +26 | #[diesel(primary_key)] + | ^^^^^^^^^^^^^ + +error: expected parentheses + --> $DIR/bad_primary_key.rs:33:22 + | +33 | #[diesel(primary_key = id)] + | ^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_serialize_as.rs b/diesel_compile_tests/tests/fail/derive/bad_serialize_as.rs new file mode 100644 index 000000000000..2c7f4641d91f --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_serialize_as.rs @@ -0,0 +1,43 @@ +#[macro_use] +extern crate diesel; + +table! { + users (id) { + id -> Integer, + name -> Text, + } +} + +#[derive(Insertable)] +#[diesel(table_name = users)] +struct User1 { + id: i32, + #[diesel(serialize_as)] + name: String, +} + +#[derive(Insertable)] +#[diesel(table_name = users)] +struct User2 { + id: i32, + #[diesel(serialize_as(Foo))] + name: String, +} + +#[derive(Insertable)] +#[diesel(table_name = users)] +struct User3 { + id: i32, + #[diesel(serialize_as = "foo")] + name: String, +} + +#[derive(Insertable)] +#[diesel(table_name = users)] +struct User4 { + id: i32, + #[diesel(serialize_as = 1omg)] + name: String, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_serialize_as.stderr b/diesel_compile_tests/tests/fail/derive/bad_serialize_as.stderr new file mode 100644 index 000000000000..c1d82afac108 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_serialize_as.stderr @@ -0,0 +1,23 @@ +error: unexpected end of input, expected `=` + --> $DIR/bad_serialize_as.rs:15:13 + | +15 | #[diesel(serialize_as)] + | ^^^^^^^^^^^^^^ + +error: expected `=` + --> $DIR/bad_serialize_as.rs:23:26 + | +23 | #[diesel(serialize_as(Foo))] + | ^^^^^ + +error: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime + --> $DIR/bad_serialize_as.rs:31:29 + | +31 | #[diesel(serialize_as = "foo")] + | ^^^^^ + +error: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime + --> $DIR/bad_serialize_as.rs:39:29 + | +39 | #[diesel(serialize_as = 1omg)] + | ^^^^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_sql_type.rs b/diesel_compile_tests/tests/fail/derive/bad_sql_type.rs new file mode 100644 index 000000000000..2fb7c2c75c0d --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_sql_type.rs @@ -0,0 +1,20 @@ +extern crate diesel; +use diesel::expression::AsExpression; + +#[derive(AsExpression)] +#[diesel(sql_type)] +struct Lol; + +#[derive(AsExpression)] +#[diesel(sql_type(Foo))] +struct Lol2; + +#[derive(AsExpression)] +#[diesel(sql_type = "foo")] +struct Lol3; + +#[derive(AsExpression)] +#[diesel(sql_type = 1omg)] +struct Lol4; + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_sql_type.stderr b/diesel_compile_tests/tests/fail/derive/bad_sql_type.stderr new file mode 100644 index 000000000000..c572978d2d55 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_sql_type.stderr @@ -0,0 +1,23 @@ +error: unexpected end of input, expected `=` + --> $DIR/bad_sql_type.rs:5:9 + | +5 | #[diesel(sql_type)] + | ^^^^^^^^^^ + +error: expected `=` + --> $DIR/bad_sql_type.rs:9:18 + | +9 | #[diesel(sql_type(Foo))] + | ^^^^^ + +error: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime + --> $DIR/bad_sql_type.rs:13:21 + | +13 | #[diesel(sql_type = "foo")] + | ^^^^^ + +error: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime + --> $DIR/bad_sql_type.rs:17:21 + | +17 | #[diesel(sql_type = 1omg)] + | ^^^^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_sqlite_type.rs b/diesel_compile_tests/tests/fail/derive/bad_sqlite_type.rs new file mode 100644 index 000000000000..75924567cdfe --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_sqlite_type.rs @@ -0,0 +1,33 @@ +extern crate diesel; + +use diesel::sql_types::SqlType; + +#[derive(SqlType)] +#[diesel(sqlite_type)] +struct Type1; + +#[derive(SqlType)] +#[diesel(sqlite_type())] +struct Type2; + +#[derive(SqlType)] +#[diesel(sqlite_type = "foo")] +struct Type3; + +#[derive(SqlType)] +#[diesel(sqlite_type(name))] +struct Type4; + +#[derive(SqlType)] +#[diesel(sqlite_type(name()))] +struct Type5; + +#[derive(SqlType)] +#[diesel(sqlite_type(name = Foo))] +struct Type6; + +#[derive(SqlType)] +#[diesel(sqlite_type(what))] +struct Type7; + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_sqlite_type.stderr b/diesel_compile_tests/tests/fail/derive/bad_sqlite_type.stderr new file mode 100644 index 000000000000..6a72f2cbe679 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_sqlite_type.stderr @@ -0,0 +1,41 @@ +error: unexpected end of input, expected parentheses + --> $DIR/bad_sqlite_type.rs:6:9 + | +6 | #[diesel(sqlite_type)] + | ^^^^^^^^^^^^^ + +error: expected attribute `name` + --> $DIR/bad_sqlite_type.rs:10:21 + | +10 | #[diesel(sqlite_type())] + | ^^ + +error: expected parentheses + --> $DIR/bad_sqlite_type.rs:14:22 + | +14 | #[diesel(sqlite_type = "foo")] + | ^ + +error: unexpected end of input, expected `=` + --> $DIR/bad_sqlite_type.rs:18:21 + | +18 | #[diesel(sqlite_type(name))] + | ^^^^^^ + +error: expected `=` + --> $DIR/bad_sqlite_type.rs:22:26 + | +22 | #[diesel(sqlite_type(name()))] + | ^^ + +error: expected string literal + --> $DIR/bad_sqlite_type.rs:26:29 + | +26 | #[diesel(sqlite_type(name = Foo))] + | ^^^ + +error: unknown attribute + --> $DIR/bad_sqlite_type.rs:30:22 + | +30 | #[diesel(sqlite_type(what))] + | ^^^^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_table_name.rs b/diesel_compile_tests/tests/fail/derive/bad_table_name.rs new file mode 100644 index 000000000000..e24ad5fdbcac --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_table_name.rs @@ -0,0 +1,41 @@ +#[macro_use] +extern crate diesel; + +table! { + users { + id -> Integer, + name -> Text, + } +} + +#[derive(Queryable)] +#[diesel(table_name)] +struct User1 { + name: String, +} + +#[derive(Queryable)] +#[diesel(table_name(users))] +struct User2 { + name: String, +} + +#[derive(Insertable)] +#[diesel(table_name = true)] +struct User3 { + id: i32, +} + +#[derive(Insertable)] +#[diesel(table_name = "not a path")] +struct User4 { + id: i32, +} + +#[derive(Insertable)] +#[diesel(table_name = does::not::exist)] +struct User5 { + id: i32, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_table_name.stderr b/diesel_compile_tests/tests/fail/derive/bad_table_name.stderr new file mode 100644 index 000000000000..1c081eee8236 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_table_name.stderr @@ -0,0 +1,29 @@ +error: unexpected end of input, expected `=` + --> $DIR/bad_table_name.rs:12:9 + | +12 | #[diesel(table_name)] + | ^^^^^^^^^^^^ + +error: expected `=` + --> $DIR/bad_table_name.rs:18:20 + | +18 | #[diesel(table_name(users))] + | ^^^^^^^ + +error: expected identifier + --> $DIR/bad_table_name.rs:24:23 + | +24 | #[diesel(table_name = true)] + | ^^^^ + +error: expected identifier + --> $DIR/bad_table_name.rs:30:23 + | +30 | #[diesel(table_name = "not a path")] + | ^^^^^^^^^^^^ + +error[E0433]: failed to resolve: use of undeclared crate or module `does` + --> $DIR/bad_table_name.rs:36:23 + | +36 | #[diesel(table_name = does::not::exist)] + | ^^^^ use of undeclared crate or module `does` diff --git a/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_default_value.rs b/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_default_value.rs new file mode 100644 index 000000000000..ff2e0919cc58 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_default_value.rs @@ -0,0 +1,35 @@ +#[macro_use] +extern crate diesel; + +table! { + users { + id -> Integer, + name -> Text, + } +} + +#[derive(Insertable)] +#[diesel(table_name = users)] +#[diesel(treat_none_as_default_value())] +struct UserForm1 { + id: i32, + name: String, +} + +#[derive(Insertable)] +#[diesel(table_name = users)] +#[diesel(treat_none_as_default_value)] +struct UserForm2 { + id: i32, + name: String, +} + +#[derive(Insertable)] +#[diesel(table_name = users)] +#[diesel(treat_none_as_default_value = "foo")] +struct UserForm3 { + id: i32, + name: String, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_default_value.stderr b/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_default_value.stderr new file mode 100644 index 000000000000..e097688c4a29 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_default_value.stderr @@ -0,0 +1,17 @@ +error: expected `=` + --> $DIR/bad_treat_none_as_default_value.rs:13:37 + | +13 | #[diesel(treat_none_as_default_value())] + | ^^ + +error: unexpected end of input, expected `=` + --> $DIR/bad_treat_none_as_default_value.rs:21:9 + | +21 | #[diesel(treat_none_as_default_value)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected boolean literal + --> $DIR/bad_treat_none_as_default_value.rs:29:40 + | +29 | #[diesel(treat_none_as_default_value = "foo")] + | ^^^^^ diff --git a/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_null.rs b/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_null.rs new file mode 100644 index 000000000000..df493f01b350 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_null.rs @@ -0,0 +1,35 @@ +#[macro_use] +extern crate diesel; + +table! { + users { + id -> Integer, + name -> Text, + } +} + +#[derive(AsChangeset)] +#[diesel(table_name = users)] +#[diesel(treat_none_as_null("true"))] +struct UserForm1 { + id: i32, + name: String, +} + +#[derive(AsChangeset)] +#[diesel(table_name = users)] +#[diesel(treat_none_as_null)] +struct UserForm2 { + id: i32, + name: String, +} + +#[derive(AsChangeset)] +#[diesel(table_name = users)] +#[diesel(treat_none_as_null = "foo")] +struct UserForm3 { + id: i32, + name: String, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_null.stderr b/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_null.stderr new file mode 100644 index 000000000000..288ec8a14af5 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/bad_treat_none_as_null.stderr @@ -0,0 +1,17 @@ +error: expected `=` + --> $DIR/bad_treat_none_as_null.rs:13:28 + | +13 | #[diesel(treat_none_as_null("true"))] + | ^^^^^^^^ + +error: unexpected end of input, expected `=` + --> $DIR/bad_treat_none_as_null.rs:21:9 + | +21 | #[diesel(treat_none_as_null)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: expected boolean literal + --> $DIR/bad_treat_none_as_null.rs:29:31 + | +29 | #[diesel(treat_none_as_null = "foo")] + | ^^^^^ diff --git a/diesel_compile_tests/tests/fail/belongs_to_incorrect_lifetime_syntax.rs b/diesel_compile_tests/tests/fail/derive/belongs_to_incorrect_lifetime_syntax.rs similarity index 85% rename from diesel_compile_tests/tests/fail/belongs_to_incorrect_lifetime_syntax.rs rename to diesel_compile_tests/tests/fail/derive/belongs_to_incorrect_lifetime_syntax.rs index c2546e1706a3..b5bfbaae097e 100644 --- a/diesel_compile_tests/tests/fail/belongs_to_incorrect_lifetime_syntax.rs +++ b/diesel_compile_tests/tests/fail/derive/belongs_to_incorrect_lifetime_syntax.rs @@ -15,14 +15,14 @@ table! { } #[derive(Identifiable)] -#[table_name = "foo"] +#[diesel(table_name = foo)] struct Foo<'a> { id: i32, _marker: ::std::marker::PhantomData<&'a ()>, } #[derive(Associations)] -#[belongs_to(parent = "Foo<'a>")] +#[diesel(belongs_to(Foo<'a>))] struct Bar { foo_id: i32, } diff --git a/diesel_compile_tests/tests/fail/derive/belongs_to_incorrect_lifetime_syntax.stderr b/diesel_compile_tests/tests/fail/derive/belongs_to_incorrect_lifetime_syntax.stderr new file mode 100644 index 000000000000..2ce39d88b9fd --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/belongs_to_incorrect_lifetime_syntax.stderr @@ -0,0 +1,7 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/belongs_to_incorrect_lifetime_syntax.rs:25:25 + | +24 | #[derive(Associations)] + | - help: consider introducing lifetime `'a` here: `'a,` +25 | #[diesel(belongs_to(Foo<'a>))] + | ^^ undeclared lifetime diff --git a/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_column.rs b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_column.rs similarity index 50% rename from diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_column.rs rename to diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_column.rs index 55265dfbc03e..42f76b0e0d2c 100644 --- a/diesel_compile_tests/tests/fail/belongs_to_missing_foreign_key_column.rs +++ b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_column.rs @@ -10,32 +10,32 @@ table! { } #[derive(Associations)] -#[belongs_to(Bar)] -#[table_name = "foo"] +#[diesel(belongs_to(Bar))] +#[diesel(table_name = foo)] struct Foo1 { bar_id: i32, } #[derive(Associations)] -#[belongs_to(Bar, foreign_key = "bar_id")] -#[table_name = "foo"] +#[diesel(belongs_to(Bar, foreign_key = bar_id))] +#[diesel(table_name = foo)] struct Foo2 { bar_id: i32, } #[derive(Associations)] -#[belongs_to(Bar)] -#[table_name = "foo"] +#[diesel(belongs_to(Bar))] +#[diesel(table_name = foo)] struct Foo3 { - #[column_name = "bar_id"] + #[diesel(column_name = bar_id)] baz_id: i32, } #[derive(Associations)] -#[belongs_to(Bar, foreign_key = "bar_id")] -#[table_name = "foo"] +#[diesel(belongs_to(Bar, foreign_key = bar_id))] +#[diesel(table_name = foo)] struct Foo4 { - #[column_name = "bar_id"] + #[diesel(column_name = bar_id)] baz_id: i32, } diff --git a/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_column.stderr b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_column.stderr new file mode 100644 index 000000000000..749b6a75bad5 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_column.stderr @@ -0,0 +1,47 @@ +error[E0412]: cannot find type `bar_id` in module `foo` + --> $DIR/belongs_to_missing_foreign_key_column.rs:13:21 + | +13 | #[diesel(belongs_to(Bar))] + | ^^^ not found in `foo` + +error[E0425]: cannot find value `bar_id` in module `foo` + --> $DIR/belongs_to_missing_foreign_key_column.rs:13:21 + | +13 | #[diesel(belongs_to(Bar))] + | ^^^ not found in `foo` + +error[E0412]: cannot find type `bar_id` in module `foo` + --> $DIR/belongs_to_missing_foreign_key_column.rs:20:40 + | +20 | #[diesel(belongs_to(Bar, foreign_key = bar_id))] + | ^^^^^^ not found in `foo` + +error[E0425]: cannot find value `bar_id` in module `foo` + --> $DIR/belongs_to_missing_foreign_key_column.rs:20:40 + | +20 | #[diesel(belongs_to(Bar, foreign_key = bar_id))] + | ^^^^^^ not found in `foo` + +error[E0412]: cannot find type `bar_id` in module `foo` + --> $DIR/belongs_to_missing_foreign_key_column.rs:27:21 + | +27 | #[diesel(belongs_to(Bar))] + | ^^^ not found in `foo` + +error[E0425]: cannot find value `bar_id` in module `foo` + --> $DIR/belongs_to_missing_foreign_key_column.rs:27:21 + | +27 | #[diesel(belongs_to(Bar))] + | ^^^ not found in `foo` + +error[E0412]: cannot find type `bar_id` in module `foo` + --> $DIR/belongs_to_missing_foreign_key_column.rs:35:40 + | +35 | #[diesel(belongs_to(Bar, foreign_key = bar_id))] + | ^^^^^^ not found in `foo` + +error[E0425]: cannot find value `bar_id` in module `foo` + --> $DIR/belongs_to_missing_foreign_key_column.rs:35:40 + | +35 | #[diesel(belongs_to(Bar, foreign_key = bar_id))] + | ^^^^^^ not found in `foo` diff --git a/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_field.rs b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_field.rs new file mode 100644 index 000000000000..8318027b333b --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_field.rs @@ -0,0 +1,28 @@ +#[macro_use] +extern crate diesel; + +struct Bar; + +#[derive(Associations)] +#[diesel(belongs_to(Bar))] +struct Foo1 {} + +#[derive(Associations)] +#[diesel(belongs_to(Bar, foreign_key = bar_id))] +struct Foo2 {} + +#[derive(Associations)] +#[diesel(belongs_to(Bar))] +struct Baz1 { + #[diesel(column_name = baz_id)] + bar_id: i32, +} + +#[derive(Associations)] +#[diesel(belongs_to(Bar, foreign_key = bar_id))] +struct Baz2 { + #[diesel(column_name = baz_id)] + bar_id: i32, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_field.stderr b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_field.stderr new file mode 100644 index 000000000000..968fed0fab41 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_foreign_key_field.stderr @@ -0,0 +1,23 @@ +error: No field with column name bar_id + --> $DIR/belongs_to_missing_foreign_key_field.rs:7:21 + | +7 | #[diesel(belongs_to(Bar))] + | ^^^ + +error: No field with column name bar_id + --> $DIR/belongs_to_missing_foreign_key_field.rs:11:40 + | +11 | #[diesel(belongs_to(Bar, foreign_key = bar_id))] + | ^^^^^^ + +error: No field with column name bar_id + --> $DIR/belongs_to_missing_foreign_key_field.rs:15:21 + | +15 | #[diesel(belongs_to(Bar))] + | ^^^ + +error: No field with column name bar_id + --> $DIR/belongs_to_missing_foreign_key_field.rs:22:40 + | +22 | #[diesel(belongs_to(Bar, foreign_key = bar_id))] + | ^^^^^^ diff --git a/diesel_compile_tests/tests/fail/belongs_to_missing_parent_import.rs b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_parent_import.rs similarity index 87% rename from diesel_compile_tests/tests/fail/belongs_to_missing_parent_import.rs rename to diesel_compile_tests/tests/fail/derive/belongs_to_missing_parent_import.rs index cfb33f96018b..7574ae6f61cf 100644 --- a/diesel_compile_tests/tests/fail/belongs_to_missing_parent_import.rs +++ b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_parent_import.rs @@ -9,7 +9,7 @@ table! { } #[derive(Associations)] -#[belongs_to(Bar)] +#[diesel(belongs_to(Bar))] struct Foo { bar_id: i32, } diff --git a/diesel_compile_tests/tests/fail/derive/belongs_to_missing_parent_import.stderr b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_parent_import.stderr new file mode 100644 index 000000000000..0089b714ff0a --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/belongs_to_missing_parent_import.stderr @@ -0,0 +1,5 @@ +error[E0412]: cannot find type `Bar` in this scope + --> $DIR/belongs_to_missing_parent_import.rs:12:21 + | +12 | #[diesel(belongs_to(Bar))] + | ^^^ not found in this scope diff --git a/diesel_compile_tests/tests/fail/belongs_to_second_parent.rs b/diesel_compile_tests/tests/fail/derive/belongs_to_second_parent.rs similarity index 61% rename from diesel_compile_tests/tests/fail/belongs_to_second_parent.rs rename to diesel_compile_tests/tests/fail/derive/belongs_to_second_parent.rs index b3cb24f6afeb..eeda6280ffe8 100644 --- a/diesel_compile_tests/tests/fail/belongs_to_second_parent.rs +++ b/diesel_compile_tests/tests/fail/derive/belongs_to_second_parent.rs @@ -14,25 +14,22 @@ table! { } #[derive(Identifiable)] -#[table_name = "bar"] +#[diesel(table_name = bar)] struct Bar { id: i32, } #[derive(Identifiable)] -#[table_name = "bar"] +#[diesel(table_name = bar)] struct Baz { id: i32, } #[derive(Associations)] -#[belongs_to(Bar, Baz)] -#[table_name = "foo"] +#[diesel(belongs_to(Bar, Baz))] +#[diesel(table_name = foo)] struct Foo { bar_id: i32, } -fn main() { - // Workaround for https://github.com/dtolnay/trybuild/issues/8 - compile_error!("warnings"); -} +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/belongs_to_second_parent.stderr b/diesel_compile_tests/tests/fail/derive/belongs_to_second_parent.stderr new file mode 100644 index 000000000000..a33d542e22b5 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/belongs_to_second_parent.stderr @@ -0,0 +1,5 @@ +error: unknown attribute + --> $DIR/belongs_to_second_parent.rs:29:26 + | +29 | #[diesel(belongs_to(Bar, Baz))] + | ^^^ diff --git a/diesel_compile_tests/tests/fail/embed_and_serialize_as_cannot_be_mixed.rs b/diesel_compile_tests/tests/fail/derive/embed_and_serialize_as_cannot_be_mixed.rs similarity index 84% rename from diesel_compile_tests/tests/fail/embed_and_serialize_as_cannot_be_mixed.rs rename to diesel_compile_tests/tests/fail/derive/embed_and_serialize_as_cannot_be_mixed.rs index 7550c6ad2b66..20cdcba7a17e 100644 --- a/diesel_compile_tests/tests/fail/embed_and_serialize_as_cannot_be_mixed.rs +++ b/diesel_compile_tests/tests/fail/derive/embed_and_serialize_as_cannot_be_mixed.rs @@ -10,7 +10,7 @@ table! { } #[derive(Insertable)] -#[table_name = "users"] +#[diesel(table_name = users)] struct NameAndHairColor<'a> { name: &'a str, hair_color: &'a str, @@ -19,7 +19,7 @@ struct NameAndHairColor<'a> { #[derive(Insertable)] struct User<'a> { id: i32, - #[diesel(embed, serialize_as = "SomeType")] + #[diesel(embed, serialize_as = SomeType)] // to test the compile error, this type doesn't need to exist name_and_hair_color: NameAndHairColor<'a>, } diff --git a/diesel_compile_tests/tests/fail/derive/embed_and_serialize_as_cannot_be_mixed.stderr b/diesel_compile_tests/tests/fail/derive/embed_and_serialize_as_cannot_be_mixed.stderr new file mode 100644 index 000000000000..76a7e616691f --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/embed_and_serialize_as_cannot_be_mixed.stderr @@ -0,0 +1,5 @@ +error: `#[diesel(embed)]` cannot be combined with `#[diesel(serialize_as)]` + --> $DIR/embed_and_serialize_as_cannot_be_mixed.rs:22:36 + | +22 | #[diesel(embed, serialize_as = SomeType)] + | ^^^^^^^^ diff --git a/diesel_compile_tests/tests/fail/derive/empty_struct.rs b/diesel_compile_tests/tests/fail/derive/empty_struct.rs new file mode 100644 index 000000000000..5f168e43a6cb --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/empty_struct.rs @@ -0,0 +1,35 @@ +#[macro_use] +extern crate diesel; + +table! { + users { + id -> Integer, + } +} + +#[derive(AsChangeset)] +#[diesel(table_name = users)] +struct User1; + +#[derive(Identifiable)] +#[diesel(table_name = users)] +struct User2; + +#[derive(Insertable)] +#[diesel(table_name = users)] +struct User3; + +#[derive(Queryable)] +struct User4; + +#[derive(QueryableByName)] +struct User5; + +#[derive(Selectable)] +struct User6; + +#[derive(Associations)] +#[diesel(table_name = users)] +struct User7; + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/empty_struct.stderr b/diesel_compile_tests/tests/fail/derive/empty_struct.stderr new file mode 100644 index 000000000000..cfd9b20cf853 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/empty_struct.stderr @@ -0,0 +1,55 @@ +error: This derive can only be used on non-unit structs + --> $DIR/empty_struct.rs:10:10 + | +10 | #[derive(AsChangeset)] + | ^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: This derive can only be used on non-unit structs + --> $DIR/empty_struct.rs:14:10 + | +14 | #[derive(Identifiable)] + | ^^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: This derive can only be used on non-unit structs + --> $DIR/empty_struct.rs:18:10 + | +18 | #[derive(Insertable)] + | ^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: This derive can only be used on non-unit structs + --> $DIR/empty_struct.rs:22:10 + | +22 | #[derive(Queryable)] + | ^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: This derive can only be used on non-unit structs + --> $DIR/empty_struct.rs:25:10 + | +25 | #[derive(QueryableByName)] + | ^^^^^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: This derive can only be used on non-unit structs + --> $DIR/empty_struct.rs:28:10 + | +28 | #[derive(Selectable)] + | ^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: This derive can only be used on non-unit structs + --> $DIR/empty_struct.rs:31:10 + | +31 | #[derive(Associations)] + | ^^^^^^^^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/identifiable_missing_pk_field.rs b/diesel_compile_tests/tests/fail/derive/identifiable_missing_pk_field.rs similarity index 51% rename from diesel_compile_tests/tests/fail/identifiable_missing_pk_field.rs rename to diesel_compile_tests/tests/fail/derive/identifiable_missing_pk_field.rs index 01c4f0e2c45a..fd812380b4b0 100644 --- a/diesel_compile_tests/tests/fail/identifiable_missing_pk_field.rs +++ b/diesel_compile_tests/tests/fail/derive/identifiable_missing_pk_field.rs @@ -8,42 +8,42 @@ table! { } #[derive(Identifiable)] -#[table_name = "foo"] +#[diesel(table_name = foo)] struct Foo1 {} #[derive(Identifiable)] -#[table_name = "foo"] +#[diesel(table_name = foo)] struct Foo2 { - #[column_name = "foo"] + #[diesel(column_name = foo)] id: i32, } #[derive(Identifiable)] -#[primary_key(bar)] -#[table_name = "foo"] +#[diesel(primary_key(bar))] +#[diesel(table_name = foo)] struct Foo3 {} #[derive(Identifiable)] -#[primary_key(baz)] -#[table_name = "foo"] +#[diesel(primary_key(baz))] +#[diesel(table_name = foo)] struct Foo4 { - #[column_name = "bar"] + #[diesel(column_name = bar)] baz: i32, } #[derive(Identifiable)] -#[primary_key(foo, bar)] -#[table_name = "foo"] +#[diesel(primary_key(foo, bar))] +#[diesel(table_name = foo)] struct Foo5 { foo: i32, } #[derive(Identifiable)] -#[primary_key(foo, bar)] -#[table_name = "foo"] +#[diesel(primary_key(foo, bar))] +#[diesel(table_name = foo)] struct Foo6 { foo: i32, - #[column_name = "baz"] + #[diesel(column_name = baz)] bar: i32, } diff --git a/diesel_compile_tests/tests/fail/identifiable_missing_pk_field.stderr b/diesel_compile_tests/tests/fail/derive/identifiable_missing_pk_field.stderr similarity index 59% rename from diesel_compile_tests/tests/fail/identifiable_missing_pk_field.stderr rename to diesel_compile_tests/tests/fail/derive/identifiable_missing_pk_field.stderr index 1be731ef72ba..6ebb21a2d7c9 100644 --- a/diesel_compile_tests/tests/fail/identifiable_missing_pk_field.stderr +++ b/diesel_compile_tests/tests/fail/derive/identifiable_missing_pk_field.stderr @@ -15,25 +15,25 @@ error: No field with column name id = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: No field with column name bar - --> $DIR/identifiable_missing_pk_field.rs:22:15 + --> $DIR/identifiable_missing_pk_field.rs:22:22 | -22 | #[primary_key(bar)] - | ^^^ +22 | #[diesel(primary_key(bar))] + | ^^^ error: No field with column name baz - --> $DIR/identifiable_missing_pk_field.rs:27:15 + --> $DIR/identifiable_missing_pk_field.rs:27:22 | -27 | #[primary_key(baz)] - | ^^^ +27 | #[diesel(primary_key(baz))] + | ^^^ error: No field with column name bar - --> $DIR/identifiable_missing_pk_field.rs:35:20 + --> $DIR/identifiable_missing_pk_field.rs:35:27 | -35 | #[primary_key(foo, bar)] - | ^^^ +35 | #[diesel(primary_key(foo, bar))] + | ^^^ error: No field with column name bar - --> $DIR/identifiable_missing_pk_field.rs:42:20 + --> $DIR/identifiable_missing_pk_field.rs:42:27 | -42 | #[primary_key(foo, bar)] - | ^^^ +42 | #[diesel(primary_key(foo, bar))] + | ^^^ diff --git a/diesel_compile_tests/tests/fail/derive/no_column.rs b/diesel_compile_tests/tests/fail/derive/no_column.rs new file mode 100644 index 000000000000..4a49f5ccaa9d --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/no_column.rs @@ -0,0 +1,27 @@ +#[macro_use] +extern crate diesel; + +table! { + users { + id -> Integer, + } +} + +#[derive(AsChangeset)] +#[diesel(table_name = users)] +struct UserStruct1 { + name: String, +} + +#[derive(AsChangeset)] +#[diesel(table_name = users)] +struct UserStruct2 { + #[diesel(column_name = name)] + full_name: String, +} + +#[derive(AsChangeset)] +#[diesel(table_name = users)] +struct UserTuple(#[diesel(column_name = name)] String); + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/no_column.stderr b/diesel_compile_tests/tests/fail/derive/no_column.stderr new file mode 100644 index 000000000000..93c530fcc10c --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/no_column.stderr @@ -0,0 +1,35 @@ +error[E0412]: cannot find type `name` in module `users` + --> $DIR/no_column.rs:13:5 + | +13 | name: String, + | ^^^^ not found in `users` + +error[E0425]: cannot find value `name` in module `users` + --> $DIR/no_column.rs:13:5 + | +13 | name: String, + | ^^^^ not found in `users` + +error[E0412]: cannot find type `name` in module `users` + --> $DIR/no_column.rs:19:28 + | +19 | #[diesel(column_name = name)] + | ^^^^ not found in `users` + +error[E0425]: cannot find value `name` in module `users` + --> $DIR/no_column.rs:19:28 + | +19 | #[diesel(column_name = name)] + | ^^^^ not found in `users` + +error[E0412]: cannot find type `name` in module `users` + --> $DIR/no_column.rs:25:41 + | +25 | struct UserTuple(#[diesel(column_name = name)] String); + | ^^^^ not found in `users` + +error[E0425]: cannot find value `name` in module `users` + --> $DIR/no_column.rs:25:41 + | +25 | struct UserTuple(#[diesel(column_name = name)] String); + | ^^^^ not found in `users` diff --git a/diesel_compile_tests/tests/fail/as_changeset_missing_table_import.rs b/diesel_compile_tests/tests/fail/derive/no_table.rs similarity index 86% rename from diesel_compile_tests/tests/fail/as_changeset_missing_table_import.rs rename to diesel_compile_tests/tests/fail/derive/no_table.rs index 9dc67bc944b7..6899fb7231b4 100644 --- a/diesel_compile_tests/tests/fail/as_changeset_missing_table_import.rs +++ b/diesel_compile_tests/tests/fail/derive/no_table.rs @@ -8,7 +8,7 @@ struct User { } #[derive(AsChangeset)] -#[table_name = "users"] +#[diesel(table_name = users)] struct UserForm { id: i32, name: String, diff --git a/diesel_compile_tests/tests/fail/derive/no_table.stderr b/diesel_compile_tests/tests/fail/derive/no_table.stderr new file mode 100644 index 000000000000..2c3d9b5c9422 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/no_table.stderr @@ -0,0 +1,11 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `users` + --> $DIR/no_table.rs:5:8 + | +5 | struct User { + | ^^^^ use of undeclared crate or module `users` + +error[E0433]: failed to resolve: use of undeclared crate or module `users` + --> $DIR/no_table.rs:11:23 + | +11 | #[diesel(table_name = users)] + | ^^^^^ use of undeclared crate or module `users` diff --git a/diesel_compile_tests/tests/fail/queryable_by_name_requires_table_name_or_sql_type_annotation.rs b/diesel_compile_tests/tests/fail/derive/queryable_by_name_requires_table_name_or_sql_type_annotation.rs similarity index 100% rename from diesel_compile_tests/tests/fail/queryable_by_name_requires_table_name_or_sql_type_annotation.rs rename to diesel_compile_tests/tests/fail/derive/queryable_by_name_requires_table_name_or_sql_type_annotation.rs diff --git a/diesel_compile_tests/tests/fail/derive/queryable_by_name_requires_table_name_or_sql_type_annotation.stderr b/diesel_compile_tests/tests/fail/derive/queryable_by_name_requires_table_name_or_sql_type_annotation.stderr new file mode 100644 index 000000000000..295672ff0e18 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/queryable_by_name_requires_table_name_or_sql_type_annotation.stderr @@ -0,0 +1,17 @@ +error: Cannot determine the SQL type of foo + + = help: Your struct must either be annotated with `#[diesel(table_name = foo)]` or have this field annotated with `#[diesel(sql_type = ...)]` + + --> $DIR/queryable_by_name_requires_table_name_or_sql_type_annotation.rs:6:5 + | +6 | foo: i32, + | ^^^ + +error: Cannot determine the SQL type of field + + = help: Your struct must either be annotated with `#[diesel(table_name = foo)]` or have this field annotated with `#[diesel(sql_type = ...)]` + + --> $DIR/queryable_by_name_requires_table_name_or_sql_type_annotation.rs:11:12 + | +11 | struct Bar(i32, String); + | ^^^ diff --git a/diesel_compile_tests/tests/fail/queryable_type_missmatch.rs b/diesel_compile_tests/tests/fail/derive/queryable_type_missmatch.rs similarity index 100% rename from diesel_compile_tests/tests/fail/queryable_type_missmatch.rs rename to diesel_compile_tests/tests/fail/derive/queryable_type_missmatch.rs diff --git a/diesel_compile_tests/tests/fail/queryable_type_missmatch.stderr b/diesel_compile_tests/tests/fail/derive/queryable_type_missmatch.stderr similarity index 100% rename from diesel_compile_tests/tests/fail/queryable_type_missmatch.stderr rename to diesel_compile_tests/tests/fail/derive/queryable_type_missmatch.stderr diff --git a/diesel_compile_tests/tests/fail/as_changeset_on_non_struct.rs b/diesel_compile_tests/tests/fail/derive/tuple_struct.rs similarity index 66% rename from diesel_compile_tests/tests/fail/as_changeset_on_non_struct.rs rename to diesel_compile_tests/tests/fail/derive/tuple_struct.rs index 50150f44343d..c669997397f3 100644 --- a/diesel_compile_tests/tests/fail/as_changeset_on_non_struct.rs +++ b/diesel_compile_tests/tests/fail/derive/tuple_struct.rs @@ -10,7 +10,7 @@ table! { } #[derive(AsChangeset)] -#[table_name = "users"] -enum User {} +#[diesel(table_name = users)] +struct User(i32, #[diesel(column_name = name)] String, String); fn main() {} diff --git a/diesel_compile_tests/tests/fail/as_changeset_on_non_struct.stderr b/diesel_compile_tests/tests/fail/derive/tuple_struct.stderr similarity index 60% rename from diesel_compile_tests/tests/fail/as_changeset_on_non_struct.stderr rename to diesel_compile_tests/tests/fail/derive/tuple_struct.stderr index cb40883230f0..6f57bfa847f9 100644 --- a/diesel_compile_tests/tests/fail/as_changeset_on_non_struct.stderr +++ b/diesel_compile_tests/tests/fail/derive/tuple_struct.stderr @@ -1,5 +1,5 @@ -error: This derive can only be used on structs - --> $DIR/as_changeset_on_non_struct.rs:12:10 +error: All fields of tuple structs must be annotated with `#[diesel(column_name)]` + --> $DIR/tuple_struct.rs:12:10 | 12 | #[derive(AsChangeset)] | ^^^^^^^^^^^ diff --git a/diesel_compile_tests/tests/fail/derive/unknown_attribute.rs b/diesel_compile_tests/tests/fail/derive/unknown_attribute.rs new file mode 100644 index 000000000000..6073e6aeed5b --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/unknown_attribute.rs @@ -0,0 +1,16 @@ +#[macro_use] +extern crate diesel; + +#[derive(Queryable)] +#[diesel(what = true)] +struct User1 { + id: i32, +} + +#[derive(Queryable)] +struct User2 { + #[diesel(what = true)] + id: i32, +} + +fn main() {} diff --git a/diesel_compile_tests/tests/fail/derive/unknown_attribute.stderr b/diesel_compile_tests/tests/fail/derive/unknown_attribute.stderr new file mode 100644 index 000000000000..0453efc01e20 --- /dev/null +++ b/diesel_compile_tests/tests/fail/derive/unknown_attribute.stderr @@ -0,0 +1,11 @@ +error: unknown attribute + --> $DIR/unknown_attribute.rs:5:10 + | +5 | #[diesel(what = true)] + | ^^^^ + +error: unknown attribute + --> $DIR/unknown_attribute.rs:12:14 + | +12 | #[diesel(what = true)] + | ^^^^ diff --git a/diesel_compile_tests/tests/fail/distinct_on_allows_only_fields_of_table.stderr b/diesel_compile_tests/tests/fail/distinct_on_allows_only_fields_of_table.stderr index 84f5aa3e805c..ec857e88ea95 100644 --- a/diesel_compile_tests/tests/fail/distinct_on_allows_only_fields_of_table.stderr +++ b/diesel_compile_tests/tests/fail/distinct_on_allows_only_fields_of_table.stderr @@ -12,11 +12,11 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression` for `users::table` -error[E0277]: the trait bound `(diesel::sql_types::Text, diesel::sql_types::Text): SingleValue` is not satisfied +error[E0277]: the trait bound `(diesel::sql_types::Text, diesel::sql_types::Text): diesel::sql_types::SingleValue` is not satisfied --> tests/fail/distinct_on_allows_only_fields_of_table.rs:25:18 | 25 | posts::table.distinct_on((posts::name, users::name)).get_result(&mut connection); - | ^^^^^^^^^^^ the trait `SingleValue` is not implemented for `(diesel::sql_types::Text, diesel::sql_types::Text)` + | ^^^^^^^^^^^ the trait `diesel::sql_types::SingleValue` is not implemented for `(diesel::sql_types::Text, diesel::sql_types::Text)` | = note: required because of the requirements on the impl of `DistinctOnDsl<(posts::columns::name, users::columns::name)>` for `SelectStatement` diff --git a/diesel_compile_tests/tests/fail/embed_and_serialize_as_cannot_be_mixed.stderr b/diesel_compile_tests/tests/fail/embed_and_serialize_as_cannot_be_mixed.stderr deleted file mode 100644 index 4139cbb4ba67..000000000000 --- a/diesel_compile_tests/tests/fail/embed_and_serialize_as_cannot_be_mixed.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: `#[diesel(embed)]` cannot be combined with `#[diesel(serialize_as)]` - --> $DIR/embed_and_serialize_as_cannot_be_mixed.rs:22:7 - | -22 | #[diesel(embed, serialize_as = "SomeType")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/diesel_compile_tests/tests/fail/filter_requires_bool_nonaggregate_expression.stderr b/diesel_compile_tests/tests/fail/filter_requires_bool_nonaggregate_expression.stderr index af91df852740..e0adf9484f6d 100644 --- a/diesel_compile_tests/tests/fail/filter_requires_bool_nonaggregate_expression.stderr +++ b/diesel_compile_tests/tests/fail/filter_requires_bool_nonaggregate_expression.stderr @@ -15,4 +15,5 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::Yes: MixedAggre = help: the following implementations were found: > > + = note: required because of the requirements on the impl of `NonAggregate` for `Grouped, diesel::expression::bound::Bound, i64>>>` = note: required because of the requirements on the impl of `FilterDsl, diesel::expression::bound::Bound, i64>>>>` for `SelectStatement` diff --git a/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr b/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr index bbd61b0fcea7..e181d18a7e9a 100644 --- a/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr +++ b/diesel_compile_tests/tests/fail/find_requires_correct_type.stderr @@ -18,6 +18,7 @@ error[E0277]: the trait bound `str: ValidGrouping<()>` is not satisfied = note: required because of the requirements on the impl of `ValidGrouping<()>` for `&str` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::expression::operators::Eq` + = note: required because of the requirements on the impl of `NonAggregate` for `Grouped>` = note: required because of the requirements on the impl of `FilterDsl>>` for `SelectStatement` error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied @@ -48,4 +49,5 @@ error[E0277]: the trait bound `{integer}: ValidGrouping<()>` is not satisfied <(A, B, C, D) as ValidGrouping<__GroupByClause>> and 131 others = note: required because of the requirements on the impl of `ValidGrouping<()>` for `diesel::expression::operators::Eq` + = note: required because of the requirements on the impl of `NonAggregate` for `Grouped>` = note: required because of the requirements on the impl of `FilterDsl>>` for `SelectStatement` diff --git a/diesel_compile_tests/tests/fail/ilike_only_compiles_for_pg.rs b/diesel_compile_tests/tests/fail/ilike_only_compiles_for_pg.rs index 0d71dd7dc6e6..912bd9b9667f 100644 --- a/diesel_compile_tests/tests/fail/ilike_only_compiles_for_pg.rs +++ b/diesel_compile_tests/tests/fail/ilike_only_compiles_for_pg.rs @@ -10,7 +10,7 @@ table! { } #[derive(Insertable)] -#[table_name="users"] +#[diesel(table_name = users)] struct User { id: i32, name: String, diff --git a/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.rs b/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.rs index f8f0d5f80856..5383a3557df4 100644 --- a/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.rs +++ b/diesel_compile_tests/tests/fail/insert_statement_does_not_support_returning_methods_on_sqlite.rs @@ -18,8 +18,8 @@ pub struct User { } #[derive(Insertable)] -#[table_name = "users"] -pub struct NewUser(#[column_name = "name"] String); +#[diesel(table_name = users)] +pub struct NewUser(#[diesel(column_name = name)] String); fn main() { let mut connection = SqliteConnection::establish(":memory:").unwrap(); diff --git a/diesel_compile_tests/tests/fail/insertable_bad_table_name.rs b/diesel_compile_tests/tests/fail/insertable_bad_table_name.rs deleted file mode 100644 index b088c3abf02a..000000000000 --- a/diesel_compile_tests/tests/fail/insertable_bad_table_name.rs +++ /dev/null @@ -1,52 +0,0 @@ -#[macro_use] -extern crate diesel; - -table! { - users { - id -> Integer, - } -} - -#[derive(Insertable)] -#[table_name = "self::users"] -struct UserOk { - id: i32, -} - -#[derive(Insertable)] -#[table_name(self::users)] -struct UserWarn { - id: i32, -} - -#[derive(Insertable)] -#[table_name] -struct UserError1 { - id: i32, -} - -#[derive(Insertable)] -#[table_name = true] -struct UserError2 { - id: i32, -} - -#[derive(Insertable)] -#[table_name = ""] -struct UserError3 { - id: i32, -} - -#[derive(Insertable)] -#[table_name = "not a path"] -struct UserError4 { - id: i32, -} - -#[derive(Insertable)] -#[table_name = "does::not::exist"] -struct UserError5 { - id: i32, -} - -fn main() {} diff --git a/diesel_compile_tests/tests/fail/insertable_bad_table_name.stderr b/diesel_compile_tests/tests/fail/insertable_bad_table_name.stderr deleted file mode 100644 index 0a0ff9143bc7..000000000000 --- a/diesel_compile_tests/tests/fail/insertable_bad_table_name.stderr +++ /dev/null @@ -1,35 +0,0 @@ -warning: The form `table_name(value)` is deprecated. Use `table_name = "value"` instead - --> $DIR/insertable_bad_table_name.rs:17:3 - | -17 | #[table_name(self::users)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: `table_name` must be in the form `table_name = "value"` - --> $DIR/insertable_bad_table_name.rs:23:3 - | -23 | #[table_name] - | ^^^^^^^^^^ - -error: `table_name` must be in the form `table_name = "value"` - --> $DIR/insertable_bad_table_name.rs:29:3 - | -29 | #[table_name = true] - | ^^^^^^^^^^^^^^^^^ - -error: `` is not a valid path - --> $DIR/insertable_bad_table_name.rs:35:16 - | -35 | #[table_name = ""] - | ^^ - -error: `not a path` is not a valid path - --> $DIR/insertable_bad_table_name.rs:41:16 - | -41 | #[table_name = "not a path"] - | ^^^^^^^^^^^^ - -error[E0433]: failed to resolve: use of undeclared crate or module `does` - --> $DIR/insertable_bad_table_name.rs:47:16 - | -47 | #[table_name = "does::not::exist"] - | ^^^^^^^^^^^^^^^^^^ use of undeclared crate or module `does` diff --git a/diesel_compile_tests/tests/fail/insertable_empty_struct.rs b/diesel_compile_tests/tests/fail/insertable_empty_struct.rs deleted file mode 100644 index ca68827bc719..000000000000 --- a/diesel_compile_tests/tests/fail/insertable_empty_struct.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[macro_use] -extern crate diesel; - -table! { - users { - id -> Integer, - } -} - -#[derive(Insertable)] -struct User; - -fn main() {} diff --git a/diesel_compile_tests/tests/fail/insertable_empty_struct.stderr b/diesel_compile_tests/tests/fail/insertable_empty_struct.stderr deleted file mode 100644 index e20a19d15f8b..000000000000 --- a/diesel_compile_tests/tests/fail/insertable_empty_struct.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: Cannot derive Insertable for unit structs - --> $DIR/insertable_empty_struct.rs:10:10 - | -10 | #[derive(Insertable)] - | ^^^^^^^^^^ - | - = help: Use `insert_into(users::table).default_values()` if you want `DEFAULT VALUES` - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/insertable_missing_table_or_column.rs b/diesel_compile_tests/tests/fail/insertable_missing_table_or_column.rs deleted file mode 100644 index 22f0543a02c5..000000000000 --- a/diesel_compile_tests/tests/fail/insertable_missing_table_or_column.rs +++ /dev/null @@ -1,34 +0,0 @@ -#[macro_use] -extern crate diesel; - -table! { - users { - id -> Integer, - } -} - -#[derive(Insertable)] -struct Post { - id: i32, -} - -#[derive(Insertable)] -#[table_name = "posts"] -struct Post2 { - id: i32, -} - -#[derive(Insertable)] -#[table_name = "users"] -struct User1 { - name: String -} - -#[derive(Insertable)] -#[table_name = "users"] -struct User2 { - #[column_name = "name"] - name: String -} - -fn main() {} diff --git a/diesel_compile_tests/tests/fail/insertable_missing_table_or_column.stderr b/diesel_compile_tests/tests/fail/insertable_missing_table_or_column.stderr deleted file mode 100644 index 485d88e0c4df..000000000000 --- a/diesel_compile_tests/tests/fail/insertable_missing_table_or_column.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error[E0433]: failed to resolve: use of undeclared crate or module `posts` - --> $DIR/insertable_missing_table_or_column.rs:11:8 - | -11 | struct Post { - | ^^^^ use of undeclared crate or module `posts` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0433]: failed to resolve: use of undeclared crate or module `posts` - --> $DIR/insertable_missing_table_or_column.rs:16:16 - | -16 | #[table_name = "posts"] - | ^^^^^^^ use of undeclared crate or module `posts` - -error[E0412]: cannot find type `name` in module `users` - --> $DIR/insertable_missing_table_or_column.rs:24:5 - | -24 | name: String - | ^^^^ not found in `users` - -error[E0425]: cannot find value `name` in module `users` - --> $DIR/insertable_missing_table_or_column.rs:24:5 - | -24 | name: String - | ^^^^ not found in `users` - -error[E0412]: cannot find type `name` in module `users` - --> $DIR/insertable_missing_table_or_column.rs:30:21 - | -30 | #[column_name = "name"] - | ^^^^^^ not found in `users` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0425]: cannot find value `name` in module `users` - --> $DIR/insertable_missing_table_or_column.rs:30:21 - | -30 | #[column_name = "name"] - | ^^^^^^ not found in `users` - | - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/pg_on_conflict_requires_valid_conflict_target.rs b/diesel_compile_tests/tests/fail/pg_on_conflict_requires_valid_conflict_target.rs index 2b2b66556627..6f4816a2695b 100644 --- a/diesel_compile_tests/tests/fail/pg_on_conflict_requires_valid_conflict_target.rs +++ b/diesel_compile_tests/tests/fail/pg_on_conflict_requires_valid_conflict_target.rs @@ -17,8 +17,8 @@ table! { } #[derive(Insertable)] -#[table_name = "users"] -pub struct NewUser(#[column_name = "name"] &'static str); +#[diesel(table_name = users)] +pub struct NewUser(#[diesel(column_name = name)] &'static str); sql_function!(fn lower(x: diesel::sql_types::Text) -> diesel::sql_types::Text); @@ -26,7 +26,11 @@ fn main() { use self::users::dsl::*; let mut connection = PgConnection::establish("postgres://localhost").unwrap(); - let valid_insert = insert_into(users).values(&NewUser("Sean")).on_conflict(id).do_nothing().execute(&mut connection); + let valid_insert = insert_into(users) + .values(&NewUser("Sean")) + .on_conflict(id) + .do_nothing() + .execute(&mut connection); // Sanity check, no error let column_from_other_table = insert_into(users) diff --git a/diesel_compile_tests/tests/fail/pg_on_conflict_requires_valid_conflict_target.stderr b/diesel_compile_tests/tests/fail/pg_on_conflict_requires_valid_conflict_target.stderr index 464b7b88bef7..cf26e8fb8fe7 100644 --- a/diesel_compile_tests/tests/fail/pg_on_conflict_requires_valid_conflict_target.stderr +++ b/diesel_compile_tests/tests/fail/pg_on_conflict_requires_valid_conflict_target.stderr @@ -1,21 +1,21 @@ error[E0271]: type mismatch resolving `::Table == users::table` - --> $DIR/pg_on_conflict_requires_valid_conflict_target.rs:34:10 + --> $DIR/pg_on_conflict_requires_valid_conflict_target.rs:38:10 | -34 | .on_conflict(posts::id); +38 | .on_conflict(posts::id); | ^^^^^^^^^^^ expected struct `posts::table`, found struct `users::table` error[E0277]: the trait bound `lower::lower: Column` is not satisfied - --> $DIR/pg_on_conflict_requires_valid_conflict_target.rs:38:22 + --> $DIR/pg_on_conflict_requires_valid_conflict_target.rs:42:22 | -38 | .on_conflict(lower(posts::title)); +42 | .on_conflict(lower(posts::title)); | ^^^^^^^^^^^^^^^^^^^ the trait `Column` is not implemented for `lower::lower` | = note: required because of the requirements on the impl of `diesel::query_builder::upsert::on_conflict_target::OnConflictTarget` for `diesel::query_builder::upsert::on_conflict_target::ConflictTarget>` error[E0277]: the trait bound `&str: Column` is not satisfied - --> $DIR/pg_on_conflict_requires_valid_conflict_target.rs:42:22 + --> $DIR/pg_on_conflict_requires_valid_conflict_target.rs:46:22 | -42 | .on_conflict("id"); +46 | .on_conflict("id"); | ^^^^ the trait `Column` is not implemented for `&str` | = note: required because of the requirements on the impl of `diesel::query_builder::upsert::on_conflict_target::OnConflictTarget` for `diesel::query_builder::upsert::on_conflict_target::ConflictTarget<&str>` diff --git a/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.rs b/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.rs index 2b84b7b70216..1d7945e845f9 100644 --- a/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.rs +++ b/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.rs @@ -1,9 +1,9 @@ extern crate diesel; -use diesel::*; -use diesel::sql_types::*; use diesel::dsl::*; +use diesel::sql_types::*; use diesel::upsert::on_constraint; +use diesel::*; table! { users { @@ -15,8 +15,8 @@ table! { sql_function!(fn lower(x: VarChar) -> VarChar); #[derive(Insertable)] -#[table_name="users"] -struct NewUser(#[column_name = "name"] &'static str); +#[diesel(table_name = users)] +struct NewUser(#[diesel(column_name = name)] &'static str); // NOTE: This test is meant to be comprehensive, but not exhaustive. fn main() { diff --git a/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.stderr b/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.stderr index 1c450153e091..03363b734f64 100644 --- a/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.stderr +++ b/diesel_compile_tests/tests/fail/pg_specific_expressions_cant_be_used_in_a_sqlite_query.stderr @@ -20,7 +20,7 @@ error[E0271]: type mismatch resolving `(&mut connection); | ^^^^ expected struct `Sqlite`, found struct `Pg` | - = note: required because of the requirements on the impl of `LoadQuery` for `SelectStatement, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause>>>>` + = note: required because of the requirements on the impl of `LoadQuery` for `SelectStatement, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause>>>>` error[E0271]: type mismatch resolving `::Backend == Pg` --> $DIR/pg_specific_expressions_cant_be_used_in_a_sqlite_query.rs:31:10 diff --git a/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.rs b/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.rs index d2406e73b4db..bf0e81277093 100644 --- a/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.rs +++ b/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.rs @@ -1,7 +1,7 @@ extern crate diesel; -use diesel::*; use diesel::upsert::*; +use diesel::*; table! { users { @@ -18,8 +18,8 @@ table! { } #[derive(Insertable)] -#[table_name = "users"] -pub struct NewUser(#[column_name = "name"] &'static str); +#[diesel(table_name = users)] +pub struct NewUser(#[diesel(column_name = name)] &'static str); #[allow(deprecated)] fn main() { @@ -27,7 +27,12 @@ fn main() { let mut connection = PgConnection::establish("postgres://localhost").unwrap(); // Valid update as sanity check - insert_into(users).values(&NewUser("Sean")).on_conflict(id).do_update().set(name.eq("Sean")).execute(&mut connection); + insert_into(users) + .values(&NewUser("Sean")) + .on_conflict(id) + .do_update() + .set(name.eq("Sean")) + .execute(&mut connection); // No set clause insert_into(users) @@ -43,7 +48,6 @@ fn main() { .do_update() .set(posts::title.eq("Sean")); - // Update column with value that is not selectable insert_into(users) .values(&NewUser("Sean")) diff --git a/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.stderr b/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.stderr index df9ad789f4e6..c6833dec8f2c 100644 --- a/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.stderr +++ b/diesel_compile_tests/tests/fail/pg_upsert_do_update_requires_valid_update.stderr @@ -1,7 +1,7 @@ error[E0599]: the method `execute` exists for struct `IncompleteDoUpdate>>,), users::table>>, diesel::query_builder::upsert::on_conflict_target::ConflictTarget>`, but its trait bounds were not satisfied - --> $DIR/pg_upsert_do_update_requires_valid_update.rs:37:10 + --> $DIR/pg_upsert_do_update_requires_valid_update.rs:42:10 | -37 | .execute(&mut connection); +42 | .execute(&mut connection); | ^^^^^^^ method cannot be called on `IncompleteDoUpdate>>,), users::table>>, diesel::query_builder::upsert::on_conflict_target::ConflictTarget>` due to unsatisfied trait bounds | ::: $DIESEL/src/upsert/on_conflict_extension.rs @@ -21,15 +21,15 @@ error[E0599]: the method `execute` exists for struct `IncompleteDoUpdate>>,), users::table>>, diesel::query_builder::upsert::on_conflict_target::ConflictTarget>: diesel::RunQueryDsl<_>` error[E0271]: type mismatch resolving `>> as AsChangeset>::Target == users::table` - --> $DIR/pg_upsert_do_update_requires_valid_update.rs:44:10 + --> $DIR/pg_upsert_do_update_requires_valid_update.rs:49:10 | -44 | .set(posts::title.eq("Sean")); +49 | .set(posts::title.eq("Sean")); | ^^^ expected struct `posts::table`, found struct `users::table` error[E0277]: the trait bound `users::table: AppearsInFromClause` is not satisfied - --> $DIR/pg_upsert_do_update_requires_valid_update.rs:52:10 + --> $DIR/pg_upsert_do_update_requires_valid_update.rs:56:10 | -52 | .set(name.eq(posts::title)); +56 | .set(name.eq(posts::title)); | ^^^ the trait `AppearsInFromClause` is not implemented for `users::table` | = help: the following implementations were found: @@ -38,17 +38,17 @@ error[E0277]: the trait bound `users::table: AppearsInFromClause` = note: required because of the requirements on the impl of `AsChangeset` for `diesel::expression::operators::Eq` error[E0271]: type mismatch resolving `::Table == users::table` - --> $DIR/pg_upsert_do_update_requires_valid_update.rs:59:10 + --> $DIR/pg_upsert_do_update_requires_valid_update.rs:63:10 | -59 | .set(name.eq(excluded(posts::title))); +63 | .set(name.eq(excluded(posts::title))); | ^^^ expected struct `posts::table`, found struct `users::table` | = note: required because of the requirements on the impl of `AsChangeset` for `diesel::expression::operators::Eq>` error[E0271]: type mismatch resolving ` as diesel::Expression>::SqlType == diesel::sql_types::Text` - --> $DIR/pg_upsert_do_update_requires_valid_update.rs:66:19 + --> $DIR/pg_upsert_do_update_requires_valid_update.rs:70:19 | -66 | .set(name.eq(excluded(id))); +70 | .set(name.eq(excluded(id))); | ^^ expected struct `diesel::sql_types::Integer`, found struct `diesel::sql_types::Text` | = note: required because of the requirements on the impl of `AsExpression` for `diesel::query_builder::upsert::on_conflict_actions::Excluded` diff --git a/diesel_compile_tests/tests/fail/queryable_by_name_requires_table_name_or_sql_type_annotation.stderr b/diesel_compile_tests/tests/fail/queryable_by_name_requires_table_name_or_sql_type_annotation.stderr deleted file mode 100644 index 4269c2edf34a..000000000000 --- a/diesel_compile_tests/tests/fail/queryable_by_name_requires_table_name_or_sql_type_annotation.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error: Cannot determine the SQL type of foo - --> $DIR/queryable_by_name_requires_table_name_or_sql_type_annotation.rs:6:5 - | -6 | foo: i32, - | ^^^^^^^^ - | - = help: Your struct must either be annotated with `#[table_name = "foo"]` or have all of its fields annotated with `#[sql_type = "Integer"]` - -error: Cannot determine the SQL type of bar - --> $DIR/queryable_by_name_requires_table_name_or_sql_type_annotation.rs:7:5 - | -7 | bar: String, - | ^^^^^^^^^^^ - | - = help: Your struct must either be annotated with `#[table_name = "foo"]` or have all of its fields annotated with `#[sql_type = "Integer"]` - -error: All fields of tuple structs must be annotated with `#[column_name]` - --> $DIR/queryable_by_name_requires_table_name_or_sql_type_annotation.rs:11:12 - | -11 | struct Bar(i32, String); - | ^^^ - -error: All fields of tuple structs must be annotated with `#[column_name]` - --> $DIR/queryable_by_name_requires_table_name_or_sql_type_annotation.rs:11:17 - | -11 | struct Bar(i32, String); - | ^^^^^^ - -error: Cannot determine the SQL type of field - --> $DIR/queryable_by_name_requires_table_name_or_sql_type_annotation.rs:11:12 - | -11 | struct Bar(i32, String); - | ^^^ - | - = help: Your struct must either be annotated with `#[table_name = "foo"]` or have all of its fields annotated with `#[sql_type = "Integer"]` - -error: Cannot determine the SQL type of field - --> $DIR/queryable_by_name_requires_table_name_or_sql_type_annotation.rs:11:17 - | -11 | struct Bar(i32, String); - | ^^^^^^ - | - = help: Your struct must either be annotated with `#[table_name = "foo"]` or have all of its fields annotated with `#[sql_type = "Integer"]` diff --git a/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.rs b/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.rs index ebfdb57dcca2..ccff00c002dc 100644 --- a/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.rs +++ b/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.rs @@ -10,16 +10,15 @@ table! { } #[derive(Insertable)] -#[table_name = "users"] -pub struct NewUser(#[column_name = "name"] String); +#[diesel(table_name = users)] +pub struct NewUser(#[diesel(column_name = name)] String); fn main() { use self::users::dsl::*; let mut connection = PgConnection::establish("").unwrap(); - let query = delete(users.filter(name.eq("Bill"))) - .returning(id); + let query = delete(users.filter(name.eq("Bill"))).returning(id); query.returning(name); let query = insert_into(users) @@ -27,8 +26,6 @@ fn main() { .returning(id); query.returning(name); - let query = update(users) - .set(name.eq("Bill")) - .returning(id); + let query = update(users).set(name.eq("Bill")).returning(id); query.returning(name); } diff --git a/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.stderr b/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.stderr index 7c4b33dcd4a3..8d11c504ae3e 100644 --- a/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.stderr +++ b/diesel_compile_tests/tests/fail/returning_cannot_be_called_twice.stderr @@ -1,17 +1,17 @@ error[E0599]: no method named `returning` found for struct `DeleteStatement>>>, ReturningClause>` in the current scope - --> $DIR/returning_cannot_be_called_twice.rs:23:11 + --> tests/fail/returning_cannot_be_called_twice.rs:22:11 | -23 | query.returning(name); +22 | query.returning(name); | ^^^^^^^^^ private field, not a method error[E0599]: no method named `returning` found for struct `InsertStatement>>,), users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause>` in the current scope - --> $DIR/returning_cannot_be_called_twice.rs:28:11 + --> tests/fail/returning_cannot_be_called_twice.rs:27:11 | -28 | query.returning(name); +27 | query.returning(name); | ^^^^^^^^^ private field, not a method error[E0599]: no method named `returning` found for struct `UpdateStatement>, ReturningClause>` in the current scope - --> $DIR/returning_cannot_be_called_twice.rs:33:11 + --> tests/fail/returning_cannot_be_called_twice.rs:30:11 | -33 | query.returning(name); +30 | query.returning(name); | ^^^^^^^^^ private field, not a method diff --git a/diesel_compile_tests/tests/fail/returning_clause_requires_selectable_expression.rs b/diesel_compile_tests/tests/fail/returning_clause_requires_selectable_expression.rs index 36b5e9d4b965..3dac8a15aa03 100644 --- a/diesel_compile_tests/tests/fail/returning_clause_requires_selectable_expression.rs +++ b/diesel_compile_tests/tests/fail/returning_clause_requires_selectable_expression.rs @@ -10,8 +10,8 @@ table! { } #[derive(Insertable)] -#[table_name = "users"] -pub struct NewUser(#[column_name = "name"] String); +#[diesel(table_name = users)] +pub struct NewUser(#[diesel(column_name = name)] String); table! { non_users { diff --git a/diesel_compile_tests/tests/fail/select_for_update_cannot_be_mixed_with_some_clauses.stderr b/diesel_compile_tests/tests/fail/select_for_update_cannot_be_mixed_with_some_clauses.stderr index dc5442d75e0e..b35244293848 100644 --- a/diesel_compile_tests/tests/fail/select_for_update_cannot_be_mixed_with_some_clauses.stderr +++ b/diesel_compile_tests/tests/fail/select_for_update_cannot_be_mixed_with_some_clauses.stderr @@ -221,20 +221,20 @@ error[E0277]: the trait bound `SelectStatement as GroupByDsl> -error[E0271]: type mismatch resolving `, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>> as AsQuery>::Query == SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>>` +error[E0271]: type mismatch resolving `, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>> as AsQuery>::Query == SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>>` --> tests/fail/select_for_update_cannot_be_mixed_with_some_clauses.rs:26:41 | 26 | users.group_by(id).having(id.gt(1)).for_update(); | ^^^^^^^^^^ expected struct `users::table`, found struct `SelectStatement` | = note: expected type `SelectStatement` - found struct `SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>, _, _>` - = note: required because of the requirements on the impl of `LockingDsl` for `SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>` + found struct `SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>, _, _>` + = note: required because of the requirements on the impl of `LockingDsl` for `SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>` -error[E0277]: the trait bound `SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>: Table` is not satisfied +error[E0277]: the trait bound `SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>: Table` is not satisfied --> tests/fail/select_for_update_cannot_be_mixed_with_some_clauses.rs:26:41 | 26 | users.group_by(id).having(id.gt(1)).for_update(); - | ^^^^^^^^^^ the trait `Table` is not implemented for `SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>` + | ^^^^^^^^^^ the trait `Table` is not implemented for `SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>` | - = note: required because of the requirements on the impl of `LockingDsl` for `SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>` + = note: required because of the requirements on the impl of `LockingDsl` for `SelectStatement, diesel::query_builder::group_by_clause::GroupByClause, diesel::query_builder::having_clause::HavingClause>>>>` diff --git a/diesel_compile_tests/tests/fail/selectable.rs b/diesel_compile_tests/tests/fail/selectable.rs index 1c3c2c1484df..7d945633b6d8 100644 --- a/diesel_compile_tests/tests/fail/selectable.rs +++ b/diesel_compile_tests/tests/fail/selectable.rs @@ -21,7 +21,7 @@ joinable!(posts -> users(user_id)); allow_tables_to_appear_in_same_query!(users, posts); #[derive(Selectable, Queryable)] -#[table_name = "users"] +#[diesel(table_name = users)] struct UserWithEmbeddedPost { id: i32, name: String, @@ -30,7 +30,7 @@ struct UserWithEmbeddedPost { } #[derive(Selectable, Queryable)] -#[table_name = "users"] +#[diesel(table_name = users)] struct UserWithOptionalPost { id: i32, name: String, @@ -39,14 +39,14 @@ struct UserWithOptionalPost { } #[derive(Selectable, Queryable)] -#[table_name = "posts"] +#[diesel(table_name = posts)] struct Post { id: i32, title: String, } #[derive(Selectable)] -#[table_name = "posts"] +#[diesel(table_name = posts)] struct PostWithWrongField { id: i32, // There is a typo here: @@ -55,7 +55,7 @@ struct PostWithWrongField { #[derive(Selectable)] // wrong table name here -#[table_name = "post"] +#[diesel(table_name = post)] struct PostWithWrongTableName { id: i32, title: String, diff --git a/diesel_compile_tests/tests/fail/selectable.stderr b/diesel_compile_tests/tests/fail/selectable.stderr index 5e2ed2bcbfd3..a2d33cf84698 100644 --- a/diesel_compile_tests/tests/fail/selectable.stderr +++ b/diesel_compile_tests/tests/fail/selectable.stderr @@ -1,23 +1,23 @@ error[E0433]: failed to resolve: use of undeclared crate or module `post` - --> tests/fail/selectable.rs:58:16 + --> $DIR/selectable.rs:58:23 | -58 | #[table_name = "post"] - | ^^^^^^ use of undeclared crate or module `post` +58 | #[diesel(table_name = post)] + | ^^^^ use of undeclared crate or module `post` error[E0412]: cannot find type `titel` in module `posts` - --> tests/fail/selectable.rs:53:5 + --> $DIR/selectable.rs:53:5 | 53 | titel: String | ^^^^^ not found in `posts` error[E0425]: cannot find value `titel` in module `posts` - --> tests/fail/selectable.rs:53:5 + --> $DIR/selectable.rs:53:5 | 53 | titel: String | ^^^^^ not found in `posts` error[E0271]: type mismatch resolving `>::Count == diesel::query_source::Never` - --> tests/fail/selectable.rs:149:10 + --> $DIR/selectable.rs:149:10 | 149 | .select(UserWithEmbeddedPost::as_select()) | ^^^^^^ expected struct `diesel::query_source::Once`, found struct `diesel::query_source::Never` @@ -28,7 +28,7 @@ error[E0271]: type mismatch resolving `>` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>>` error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:149:10 + --> $DIR/selectable.rs:149:10 | 149 | .select(UserWithEmbeddedPost::as_select()) | ^^^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::id` @@ -45,7 +45,7 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression>` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>>` error[E0277]: the trait bound `posts::columns::title: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:149:10 + --> $DIR/selectable.rs:149:10 | 149 | .select(UserWithEmbeddedPost::as_select()) | ^^^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::title` @@ -62,7 +62,7 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression>` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>>` error[E0271]: type mismatch resolving `>::Count == diesel::query_source::Never` - --> tests/fail/selectable.rs:150:10 + --> $DIR/selectable.rs:150:10 | 150 | .load(&mut conn) | ^^^^ expected struct `diesel::query_source::Once`, found struct `diesel::query_source::Never` @@ -75,7 +75,7 @@ error[E0271]: type mismatch resolving `` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>, diesel::query_builder::select_clause::SelectClause>>` error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:150:10 + --> $DIR/selectable.rs:150:10 | 150 | .load(&mut conn) | ^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::id` @@ -94,7 +94,7 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>, diesel::query_builder::select_clause::SelectClause>>` error[E0277]: the trait bound `posts::columns::title: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:150:10 + --> $DIR/selectable.rs:150:10 | 150 | .load(&mut conn) | ^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::title` @@ -113,7 +113,7 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>, diesel::query_builder::select_clause::SelectClause>>` error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy` is not satisfied - --> tests/fail/selectable.rs:157:10 + --> $DIR/selectable.rs:157:10 | 157 | .select(UserWithEmbeddedPost::as_select()) | ^^^^^^ the trait `IsContainedInGroupBy` is not implemented for `posts::columns::id` @@ -128,7 +128,7 @@ error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy>` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, LimitOffsetClause, diesel::query_builder::group_by_clause::GroupByClause>` error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy` is not satisfied - --> tests/fail/selectable.rs:157:10 + --> $DIR/selectable.rs:157:10 | 157 | .select(UserWithEmbeddedPost::as_select()) | ^^^^^^ the trait `IsContainedInGroupBy` is not implemented for `posts::columns::id` @@ -143,7 +143,7 @@ error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy>` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, LimitOffsetClause, diesel::query_builder::group_by_clause::GroupByClause>` error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy` is not satisfied - --> tests/fail/selectable.rs:158:10 + --> $DIR/selectable.rs:158:10 | 158 | .load(&mut conn) | ^^^^ the trait `IsContainedInGroupBy` is not implemented for `posts::columns::id` @@ -159,7 +159,7 @@ error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>, diesel::query_builder::select_clause::SelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, LimitOffsetClause, diesel::query_builder::group_by_clause::GroupByClause>` error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy` is not satisfied - --> tests/fail/selectable.rs:158:10 + --> $DIR/selectable.rs:158:10 | 158 | .load(&mut conn) | ^^^^ the trait `IsContainedInGroupBy` is not implemented for `posts::columns::id` @@ -175,7 +175,7 @@ error[E0277]: the trait bound `posts::columns::id: IsContainedInGroupBy` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>, diesel::query_builder::select_clause::SelectClause>, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::NoWhereClause, diesel::query_builder::order_clause::NoOrderClause, LimitOffsetClause, diesel::query_builder::group_by_clause::GroupByClause>` error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggregates` is not satisfied - --> tests/fail/selectable.rs:164:10 + --> $DIR/selectable.rs:164:10 | 164 | .select(UserWithPostCount::as_select()) | ^^^^^^ the trait `MixedAggregates` is not implemented for `diesel::expression::is_aggregate::No` @@ -183,13 +183,13 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggreg = help: the following implementations were found: > > - = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::id, users::columns::name, count::count::count)` + = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::id, users::columns::name, diesel::expression::count::count::count)` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `SelectBy` = note: required because of the requirements on the impl of `SelectDsl>` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>>` error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggregates` is not satisfied - --> tests/fail/selectable.rs:165:10 + --> $DIR/selectable.rs:165:10 | 165 | .load(&mut conn) | ^^^^ the trait `MixedAggregates` is not implemented for `diesel::expression::is_aggregate::No` @@ -197,14 +197,14 @@ error[E0277]: the trait bound `diesel::expression::is_aggregate::No: MixedAggreg = help: the following implementations were found: > > - = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::id, users::columns::name, count::count::count)` + = note: required because of the requirements on the impl of `ValidGrouping<()>` for `(users::columns::id, users::columns::name, diesel::expression::count::count::count)` = note: 1 redundant requirements hidden = note: required because of the requirements on the impl of `ValidGrouping<()>` for `SelectBy` = note: required because of the requirements on the impl of `Query` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>, diesel::query_builder::select_clause::SelectClause>>` = note: required because of the requirements on the impl of `LoadQuery<_, UserWithPostCount>` for `SelectStatement, Grouped, diesel::expression::nullable::Nullable>>>, diesel::query_builder::select_clause::SelectClause>>` error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:172:10 + --> $DIR/selectable.rs:172:10 | 172 | .returning(UserWithEmbeddedPost::as_select()) | ^^^^^^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::id` @@ -221,7 +221,7 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause>>` error[E0277]: the trait bound `posts::columns::title: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:172:10 + --> $DIR/selectable.rs:172:10 | 172 | .returning(UserWithEmbeddedPost::as_select()) | ^^^^^^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::title` @@ -238,7 +238,7 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause>>` error[E0271]: type mismatch resolving `>::Count == diesel::query_source::Once` - --> tests/fail/selectable.rs:172:10 + --> $DIR/selectable.rs:172:10 | 172 | .returning(UserWithEmbeddedPost::as_select()) | ^^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once` @@ -252,7 +252,7 @@ error[E0271]: type mismatch resolving `>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause>>` error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:173:10 + --> $DIR/selectable.rs:173:10 | 173 | .load(&mut conn) | ^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::id` @@ -270,7 +270,7 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression` for `InsertStatement>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause>>` error[E0277]: the trait bound `posts::columns::title: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:173:10 + --> $DIR/selectable.rs:173:10 | 173 | .load(&mut conn) | ^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::title` @@ -288,7 +288,7 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression` for `InsertStatement>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause>>` error[E0271]: type mismatch resolving `>::Count == diesel::query_source::Once` - --> tests/fail/selectable.rs:173:10 + --> $DIR/selectable.rs:173:10 | 173 | .load(&mut conn) | ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once` @@ -303,7 +303,7 @@ error[E0271]: type mismatch resolving `` for `InsertStatement>, users::table>, diesel::query_builder::insert_statement::Insert, ReturningClause>>` error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:180:10 + --> $DIR/selectable.rs:180:10 | 180 | .returning(UserWithEmbeddedPost::as_select()) | ^^^^^^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::id` @@ -320,7 +320,7 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression>, ReturningClause>>` error[E0277]: the trait bound `posts::columns::title: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:180:10 + --> $DIR/selectable.rs:180:10 | 180 | .returning(UserWithEmbeddedPost::as_select()) | ^^^^^^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::title` @@ -337,7 +337,7 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression>, ReturningClause>>` error[E0271]: type mismatch resolving `>::Count == diesel::query_source::Once` - --> tests/fail/selectable.rs:180:10 + --> $DIR/selectable.rs:180:10 | 180 | .returning(UserWithEmbeddedPost::as_select()) | ^^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once` @@ -351,7 +351,7 @@ error[E0271]: type mismatch resolving `>, ReturningClause>>` error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:181:10 + --> $DIR/selectable.rs:181:10 | 181 | .load(&mut conn) | ^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::id` @@ -369,7 +369,7 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression` for `UpdateStatement>, ReturningClause>>` error[E0277]: the trait bound `posts::columns::title: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:181:10 + --> $DIR/selectable.rs:181:10 | 181 | .load(&mut conn) | ^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::title` @@ -387,7 +387,7 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression` for `UpdateStatement>, ReturningClause>>` error[E0271]: type mismatch resolving `>::Count == diesel::query_source::Once` - --> tests/fail/selectable.rs:181:10 + --> $DIR/selectable.rs:181:10 | 181 | .load(&mut conn) | ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once` @@ -402,7 +402,7 @@ error[E0271]: type mismatch resolving `` for `UpdateStatement>, ReturningClause>>` error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:187:10 + --> $DIR/selectable.rs:187:10 | 187 | .returning(UserWithEmbeddedPost::as_select()) | ^^^^^^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::id` @@ -418,7 +418,7 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression` for `SelectBy` error[E0277]: the trait bound `posts::columns::title: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:187:10 + --> $DIR/selectable.rs:187:10 | 187 | .returning(UserWithEmbeddedPost::as_select()) | ^^^^^^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::title` @@ -434,7 +434,7 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression` for `SelectBy` error[E0271]: type mismatch resolving `>::Count == diesel::query_source::Once` - --> tests/fail/selectable.rs:187:10 + --> $DIR/selectable.rs:187:10 | 187 | .returning(UserWithEmbeddedPost::as_select()) | ^^^^^^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once` @@ -447,7 +447,7 @@ error[E0271]: type mismatch resolving `` for `SelectBy` error[E0277]: the trait bound `posts::columns::id: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:188:10 + --> $DIR/selectable.rs:188:10 | 188 | .load(&mut conn) | ^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::id` @@ -465,7 +465,7 @@ error[E0277]: the trait bound `posts::columns::id: SelectableExpression` for `DeleteStatement>>` error[E0277]: the trait bound `posts::columns::title: SelectableExpression` is not satisfied - --> tests/fail/selectable.rs:188:10 + --> $DIR/selectable.rs:188:10 | 188 | .load(&mut conn) | ^^^^ the trait `SelectableExpression` is not implemented for `posts::columns::title` @@ -483,7 +483,7 @@ error[E0277]: the trait bound `posts::columns::title: SelectableExpression` for `DeleteStatement>>` error[E0271]: type mismatch resolving `>::Count == diesel::query_source::Once` - --> tests/fail/selectable.rs:188:10 + --> $DIR/selectable.rs:188:10 | 188 | .load(&mut conn) | ^^^^ expected struct `diesel::query_source::Never`, found struct `diesel::query_source::Once` @@ -498,7 +498,7 @@ error[E0271]: type mismatch resolving `` for `DeleteStatement>>` error[E0599]: the function or associated item `as_select` exists for struct `UserWithoutSelectable`, but its trait bounds were not satisfied - --> tests/fail/selectable.rs:192:56 + --> $DIR/selectable.rs:192:56 | 80 | struct UserWithoutSelectable { | ---------------------------- @@ -518,17 +518,17 @@ error[E0599]: the function or associated item `as_select` exists for struct `Use `&mut UserWithoutSelectable: diesel::Selectable<_>` which is required by `&mut UserWithoutSelectable: diesel::SelectableHelper<_>` -error[E0277]: the trait bound `SelectBy: SingleValue` is not satisfied - --> tests/fail/selectable.rs:195:52 +error[E0277]: the trait bound `SelectBy: diesel::sql_types::SingleValue` is not satisfied + --> $DIR/selectable.rs:195:52 | 195 | let _ = posts::table.select(Post::as_select()).load::<(i32, String)>(&mut conn).unwrap(); - | ^^^^ the trait `SingleValue` is not implemented for `SelectBy` + | ^^^^ the trait `diesel::sql_types::SingleValue` is not implemented for `SelectBy` | = note: required because of the requirements on the impl of `CompatibleType<(i32, std::string::String), _>` for `SelectBy` = note: required because of the requirements on the impl of `LoadQuery<_, (i32, std::string::String)>` for `SelectStatement>>` error[E0277]: the trait bound `(i32, std::string::String): diesel::Queryable, _>` is not satisfied - --> tests/fail/selectable.rs:195:52 + --> $DIR/selectable.rs:195:52 | 195 | let _ = posts::table.select(Post::as_select()).load::<(i32, String)>(&mut conn).unwrap(); | ^^^^ the trait `diesel::Queryable, _>` is not implemented for `(i32, std::string::String)` @@ -541,17 +541,17 @@ error[E0277]: the trait bound `(i32, std::string::String): diesel::Queryable` for `SelectBy` = note: required because of the requirements on the impl of `LoadQuery<_, (i32, std::string::String)>` for `SelectStatement>>` -error[E0277]: the trait bound `SelectBy: SingleValue` is not satisfied - --> tests/fail/selectable.rs:196:65 +error[E0277]: the trait bound `SelectBy: diesel::sql_types::SingleValue` is not satisfied + --> $DIR/selectable.rs:196:65 | 196 | let _ = posts::table.select(Post::as_select()).into_boxed().load::<(i32, String)>(&mut conn).unwrap(); - | ^^^^ the trait `SingleValue` is not implemented for `SelectBy` + | ^^^^ the trait `diesel::sql_types::SingleValue` is not implemented for `SelectBy` | = note: required because of the requirements on the impl of `CompatibleType<(i32, std::string::String), _>` for `SelectBy` = note: required because of the requirements on the impl of `LoadQuery<_, (i32, std::string::String)>` for `BoxedSelectStatement<'_, SelectBy, posts::table, _>` error[E0277]: the trait bound `(i32, std::string::String): diesel::Queryable, _>` is not satisfied - --> tests/fail/selectable.rs:196:65 + --> $DIR/selectable.rs:196:65 | 196 | let _ = posts::table.select(Post::as_select()).into_boxed().load::<(i32, String)>(&mut conn).unwrap(); | ^^^^ the trait `diesel::Queryable, _>` is not implemented for `(i32, std::string::String)` @@ -565,7 +565,7 @@ error[E0277]: the trait bound `(i32, std::string::String): diesel::Queryable` for `BoxedSelectStatement<'_, SelectBy, posts::table, _>` error[E0277]: the trait bound `(SelectBy, diesel::sql_types::Text): CompatibleType<((i32, std::string::String), std::string::String), _>` is not satisfied - --> tests/fail/selectable.rs:197:68 + --> $DIR/selectable.rs:197:68 | 197 | let _ = posts::table.select((Post::as_select(), posts::title)).load::<((i32, String), String)>(&mut conn).unwrap(); | ^^^^ the trait `CompatibleType<((i32, std::string::String), std::string::String), _>` is not implemented for `(SelectBy, diesel::sql_types::Text)` @@ -574,17 +574,17 @@ error[E0277]: the trait bound `(SelectBy, diesel::sql_types::Text): Com <(SA, SB) as CompatibleType<__T, __DB>> = note: required because of the requirements on the impl of `LoadQuery<_, ((i32, std::string::String), std::string::String)>` for `SelectStatement, posts::columns::title)>>` -error[E0277]: the trait bound `SelectBy: SingleValue` is not satisfied - --> tests/fail/selectable.rs:201:10 +error[E0277]: the trait bound `SelectBy: diesel::sql_types::SingleValue` is not satisfied + --> $DIR/selectable.rs:201:10 | 201 | .load::<(i32, String, i32)>(&mut conn) - | ^^^^ the trait `SingleValue` is not implemented for `SelectBy` + | ^^^^ the trait `diesel::sql_types::SingleValue` is not implemented for `SelectBy` | = note: required because of the requirements on the impl of `CompatibleType<(i32, std::string::String, i32), _>` for `SelectBy` = note: required because of the requirements on the impl of `LoadQuery<_, (i32, std::string::String, i32)>` for `InsertStatement>, posts::table>, diesel::query_builder::insert_statement::Insert, ReturningClause>>` error[E0277]: the trait bound `(i32, std::string::String, i32): diesel::Queryable, _>` is not satisfied - --> tests/fail/selectable.rs:201:10 + --> $DIR/selectable.rs:201:10 | 201 | .load::<(i32, String, i32)>(&mut conn) | ^^^^ the trait `diesel::Queryable, _>` is not implemented for `(i32, std::string::String, i32)` @@ -597,7 +597,7 @@ error[E0277]: the trait bound `(i32, std::string::String, i32): diesel::Queryabl = note: required because of the requirements on the impl of `LoadQuery<_, (i32, std::string::String, i32)>` for `InsertStatement>, posts::table>, diesel::query_builder::insert_statement::Insert, ReturningClause>>` error[E0271]: type mismatch resolving `::Backend == Pg` - --> tests/fail/selectable.rs:210:10 + --> $DIR/selectable.rs:210:10 | 210 | .load(&mut conn) | ^^^^ expected struct `Sqlite`, found struct `Pg` diff --git a/diesel_compile_tests/tests/fail/sql_type_bad_options.stderr b/diesel_compile_tests/tests/fail/sql_type_bad_options.stderr deleted file mode 100644 index dc8b52195422..000000000000 --- a/diesel_compile_tests/tests/fail/sql_type_bad_options.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error: `postgres` must be in the form `postgres(...)` - --> $DIR/sql_type_bad_options.rs:6:3 - | -6 | #[postgres] - | ^^^^^^^^ - -warning: Option oid has no effect - --> $DIR/sql_type_bad_options.rs:10:31 - | -10 | #[postgres(type_name = "foo", oid = "2", array_oid = "3")] - | ^^^^^^^^^ - -warning: Option array_oid has no effect - --> $DIR/sql_type_bad_options.rs:10:42 - | -10 | #[postgres(type_name = "foo", oid = "2", array_oid = "3")] - | ^^^^^^^^^^^^^^^ - -error: Missing required option `array_oid` - --> $DIR/sql_type_bad_options.rs:14:3 - | -14 | #[postgres(oid = "2")] - | ^^^^^^^^^^^^^^^^^^^ - -error: Expected a number - --> $DIR/sql_type_bad_options.rs:18:18 - | -18 | #[postgres(oid = "NaN", array_oid = "1")] - | ^^^^^ - -warning: Option ary_oid has no effect - --> $DIR/sql_type_bad_options.rs:22:25 - | -22 | #[postgres(oid = "NaN", ary_oid = "1")] - | ^^^^^^^^^^^^^ - -error: Missing required option `array_oid` - --> $DIR/sql_type_bad_options.rs:22:3 - | -22 | #[postgres(oid = "NaN", ary_oid = "1")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `postgres` must be in the form `postgres(...)` - --> $DIR/sql_type_bad_options.rs:26:3 - | -26 | #[postgres = "foo"] - | ^^^^^^^^^^^^^^^^ diff --git a/diesel_compile_tests/tests/fail/sqlite_insert_or_ignore_cannot_be_used_on_pg.rs b/diesel_compile_tests/tests/fail/sqlite_insert_or_ignore_cannot_be_used_on_pg.rs index a3df6eb3e89b..96e7cc5cd24c 100644 --- a/diesel_compile_tests/tests/fail/sqlite_insert_or_ignore_cannot_be_used_on_pg.rs +++ b/diesel_compile_tests/tests/fail/sqlite_insert_or_ignore_cannot_be_used_on_pg.rs @@ -9,7 +9,7 @@ table! { } #[derive(Insertable)] -#[table_name="users"] +#[diesel(table_name = users)] struct User { id: i32, } diff --git a/diesel_compile_tests/tests/fail/sqlite_upsert_cannot_be_used_on_pg.rs b/diesel_compile_tests/tests/fail/sqlite_upsert_cannot_be_used_on_pg.rs index a0253a2c7924..1260faccdd78 100644 --- a/diesel_compile_tests/tests/fail/sqlite_upsert_cannot_be_used_on_pg.rs +++ b/diesel_compile_tests/tests/fail/sqlite_upsert_cannot_be_used_on_pg.rs @@ -9,7 +9,7 @@ table! { } #[derive(Insertable)] -#[table_name="users"] +#[diesel(table_name = users)] struct User { id: i32, } diff --git a/diesel_compile_tests/tests/trybuild.rs b/diesel_compile_tests/tests/trybuild.rs index 82122d5b7abf..64bbe1c34432 100644 --- a/diesel_compile_tests/tests/trybuild.rs +++ b/diesel_compile_tests/tests/trybuild.rs @@ -4,4 +4,5 @@ extern crate trybuild; fn trybuild() { let t = trybuild::TestCases::new(); t.compile_fail("tests/fail/*.rs"); + t.compile_fail("tests/fail/derive/*.rs"); } diff --git a/diesel_derives/Cargo.toml b/diesel_derives/Cargo.toml index 7df9b103d8c8..ae8d6001a90f 100644 --- a/diesel_derives/Cargo.toml +++ b/diesel_derives/Cargo.toml @@ -11,9 +11,10 @@ autotests = false include = ["src/**/*", "LICENSE-*"] [dependencies] -syn = { version = "1.0.1", features = ["full", "fold"] } -quote = "1" -proc-macro2 = "1" +syn = { version = "1.0.73", features = ["full", "fold"] } +quote = "1.0.9" +proc-macro2 = "1.0.27" +proc-macro-error = "1.0.4" [dev-dependencies] cfg-if = "1" diff --git a/diesel_derives/src/as_changeset.rs b/diesel_derives/src/as_changeset.rs index 4ab695e8db3f..8206814c463a 100644 --- a/diesel_derives/src/as_changeset.rs +++ b/diesel_derives/src/as_changeset.rs @@ -1,35 +1,37 @@ -use proc_macro2; -use proc_macro2::Span; -use syn; - -use diagnostic_shim::*; -use field::*; -use meta::*; -use model::*; -use util::*; - -pub fn derive(item: syn::DeriveInput) -> Result { - let treat_none_as_null = MetaItem::with_name(&item.attrs, "changeset_options") - .map(|meta| { - meta.warn_if_other_options(&["treat_none_as_null"]); - meta.required_nested_item("treat_none_as_null") - .map(|m| m.expect_bool_value()) - }) - .unwrap_or(Ok(false))?; - let model = Model::from_item(&item)?; - let struct_name = &model.name; +use proc_macro2::TokenStream; +use syn::{DeriveInput, Path}; + +use field::Field; +use model::Model; +use util::{inner_of_option_ty, is_option_ty, wrap_in_dummy_mod}; + +pub fn derive(item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, false); + + let struct_name = &item.ident; let table_name = model.table_name(); + let fields_for_update = model + .fields() + .iter() + .filter(|f| !model.primary_key_names.contains(f.column_name())) + .collect::>(); + + if fields_for_update.is_empty() { + abort_call_site!( + "Deriving `AsChangeset` on a structure that only contains primary keys isn't supported."; + help = "If you want to change the primary key of a row, you should do so with `.set(table::id.eq(new_id))`."; + note = "`#[derive(AsChangeset)]` never changes the primary key of a row."; + ) + } + + let treat_none_as_null = model.treat_none_as_null(); + let (_, ty_generics, where_clause) = item.generics.split_for_impl(); let mut impl_generics = item.generics.clone(); impl_generics.params.push(parse_quote!('update)); let (impl_generics, _, _) = impl_generics.split_for_impl(); - let fields_for_update = model - .fields() - .iter() - .filter(|f| !model.primary_key_names.contains(&f.column_name_ident())) - .collect::>(); let ref_changeset_ty = fields_for_update.iter().map(|field| { field_changeset_ty( field, @@ -41,6 +43,7 @@ pub fn derive(item: syn::DeriveInput) -> Result Result Result, -) -> syn::Type { - let column_name = field.column_name_ident(); + lifetime: Option, +) -> TokenStream { + let column_name = field.column_name(); if !treat_none_as_null && is_option_ty(&field.ty) { let field_ty = inner_of_option_ty(&field.ty); - parse_quote!(std::option::Option>) + quote!(std::option::Option>) } else { let field_ty = &field.ty; - parse_quote!(diesel::dsl::Eq<#table_name::#column_name, #lifetime #field_ty>) + quote!(diesel::dsl::Eq<#table_name::#column_name, #lifetime #field_ty>) } } fn field_changeset_expr( field: &Field, - table_name: &syn::Path, + table_name: &Path, treat_none_as_null: bool, - lifetime: Option, -) -> syn::Expr { - let field_access = field.name.access(); - let column_name = field.column_name_ident(); + lifetime: Option, +) -> TokenStream { + let field_name = &field.name; + let column_name = field.column_name(); if !treat_none_as_null && is_option_ty(&field.ty) { if lifetime.is_some() { - parse_quote!(self#field_access.as_ref().map(|x| #table_name::#column_name.eq(x))) + quote!(self.#field_name.as_ref().map(|x| #table_name::#column_name.eq(x))) } else { - parse_quote!(self#field_access.map(|x| #table_name::#column_name.eq(x))) + quote!(self.#field_name.map(|x| #table_name::#column_name.eq(x))) } } else { - parse_quote!(#table_name::#column_name.eq(#lifetime self#field_access)) + quote!(#table_name::#column_name.eq(#lifetime self.#field_name)) } } diff --git a/diesel_derives/src/as_expression.rs b/diesel_derives/src/as_expression.rs index 695b9041ca28..72be1d1d695e 100644 --- a/diesel_derives/src/as_expression.rs +++ b/diesel_derives/src/as_expression.rs @@ -1,30 +1,30 @@ -use proc_macro2; -use syn; +use proc_macro2::TokenStream; +use syn::DeriveInput; -use meta::*; -use util::*; +use model::Model; +use util::{ty_for_foreign_derive, wrap_in_dummy_mod}; -pub fn derive(item: syn::DeriveInput) -> Result { - let flags = - MetaItem::with_name(&item.attrs, "diesel").unwrap_or_else(|| MetaItem::empty("diesel")); - let is_sized = !flags.has_flag("not_sized"); +pub fn derive(item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, true); - let sql_types = MetaItem::all_with_name(&item.attrs, "sql_type"); - let any_sql_types = !sql_types.is_empty(); - let sql_types = sql_types - .into_iter() - .filter_map(|attr| attr.ty_value().map_err(Diagnostic::emit).ok()); + if model.sql_types.is_empty() { + abort_call_site!( + "At least one `sql_type` is needed for deriving `AsExpression` on a structure." + ); + } + + let struct_ty = ty_for_foreign_derive(&item, &model); let (impl_generics, ..) = item.generics.split_for_impl(); let lifetimes = item.generics.lifetimes().collect::>(); let ty_params = item.generics.type_params().collect::>(); let const_params = item.generics.const_params().collect::>(); - let struct_ty = ty_for_foreign_derive(&item, &flags)?; - let tokens = sql_types.map(|sql_type| { + let tokens = model.sql_types.iter().map(|sql_type| { let lifetimes = &lifetimes; let ty_params = &ty_params; let const_params = &const_params; + let tokens = quote!( impl<'expr, #(#lifetimes,)* #(#ty_params,)* #(#const_params,)*> AsExpression<#sql_type> for &'expr #struct_ty @@ -77,7 +77,10 @@ pub fn derive(item: syn::DeriveInput) -> Result Result Result { - let model = Model::from_item(&item)?; - let tokens = MetaItem::all_with_name(&item.attrs, "belongs_to") - .into_iter() - .filter_map( - |attr| match derive_belongs_to(&model, &item.generics, attr) { - Ok(t) => Some(t), - Err(e) => { - e.emit(); - None - } - }, +use syn::{DeriveInput, Ident, Lifetime}; + +use model::Model; +use parsers::BelongsTo; +use util::{camel_to_snake, wrap_in_dummy_mod}; + +pub fn derive(item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, false); + + if model.belongs_to.is_empty() { + abort_call_site!( + "At least one `belongs_to` is needed for deriving `Associations` on a structure." ); + } + + let tokens = model + .belongs_to + .iter() + .map(|assoc| derive_belongs_to(&item, &model, assoc)); - Ok(wrap_in_dummy_mod(quote!(#(#tokens)*))) + wrap_in_dummy_mod(quote!(#(#tokens)*)) } -fn derive_belongs_to( - model: &Model, - generics: &syn::Generics, - meta: MetaItem, -) -> Result { - let AssociationOptions { - parent_struct, - foreign_key, - } = AssociationOptions::from_meta(meta)?; - let (_, ty_generics, _) = generics.split_for_impl(); - - let foreign_key_field = model.find_column(&foreign_key)?; - let struct_name = &model.name; - let foreign_key_access = foreign_key_field.name.access(); - let foreign_key_ty = &foreign_key_field.ty; +fn derive_belongs_to(item: &DeriveInput, model: &Model, assoc: &BelongsTo) -> TokenStream { + let (_, ty_generics, _) = item.generics.split_for_impl(); + + let struct_name = &item.ident; let table_name = model.table_name(); - let mut generics = generics.clone(); + let foreign_key = &foreign_key(assoc); + + let foreign_key_field = model.find_column(foreign_key); + let foreign_key_name = &foreign_key_field.name; + let foreign_key_ty = &foreign_key_field.ty; + + let mut generics = item.generics.clone(); let parent_struct = ReplacePathLifetimes::new(|i, span| { let letter = char::from(b'b' + i as u8); - let lifetime = syn::Lifetime::new(&format!("'__{}", letter), span); + let lifetime = Lifetime::new(&format!("'__{}", letter), span); generics.params.push(parse_quote!(#lifetime)); lifetime }) - .fold_type_path(parent_struct); + .fold_type_path(assoc.parent.clone()); generics.params.push(parse_quote!(__FK)); { @@ -67,12 +59,12 @@ fn derive_belongs_to( ); } - let foreign_key_expr = quote!(std::convert::Into::into(&self#foreign_key_access)); + let foreign_key_expr = quote!(std::convert::Into::into(&self.#foreign_key_name)); let foreign_key_ty = quote!(__FK); let (impl_generics, _, where_clause) = generics.split_for_impl(); - Ok(quote! { + quote! { impl #impl_generics diesel::associations::BelongsTo<#parent_struct> for #struct_name #ty_generics #where_clause @@ -88,97 +80,27 @@ fn derive_belongs_to( #table_name::#foreign_key } } - }) -} - -struct AssociationOptions { - parent_struct: syn::TypePath, - foreign_key: syn::Ident, + } } -impl AssociationOptions { - fn from_meta(meta: MetaItem) -> Result { - let parent_struct = meta - .nested()? - .find(|m| m.path().is_ok() || m.name().is_ident("parent")) - .ok_or_else(|| meta.span()) - .and_then(|m| { - m.path() - .map(|i| parse_quote!(#i)) - .or_else(|_| m.ty_value()) - .map_err(|_| m.span()) - }) - .and_then(|ty| match ty { - syn::Type::Path(ty_path) => Ok(ty_path), - _ => Err(ty.span()), - }) - .map_err(|span| { - span.error("Expected a struct name") - .help("e.g. `#[belongs_to(User)]` or `#[belongs_to(parent = \"User<'_>\")]") - })?; - let foreign_key = { - let parent_struct_name = parent_struct - .path - .segments - .last() - .expect("paths always have at least one segment"); - meta.nested_item("foreign_key")? - .map(|i| i.ident_value()) - .unwrap_or_else(|| Ok(infer_foreign_key(&parent_struct_name.ident)))? - }; - - let (unrecognized_paths, unrecognized_options): (Vec<_>, Vec<_>) = meta - .nested()? - .skip(1) - .filter(|n| !n.name().is_ident("foreign_key")) - .partition(|item| item.path().is_ok()); - - if !unrecognized_paths.is_empty() { - let parent_path_string = path_to_string(&parent_struct.path); - let unrecognized_path_strings: Vec<_> = unrecognized_paths - .iter() - .filter_map(|item| item.path().as_ref().map(path_to_string).ok()) - .collect(); - - meta.span() - .warning(format!( - "belongs_to takes a single parent. Change\n\ - \tbelongs_to({}, {})\n\ - to\n\ - \tbelongs_to({})\n\ - {}", - parent_path_string, - unrecognized_path_strings.join(","), - parent_path_string, - unrecognized_path_strings - .iter() - .map(|path| format!("\tbelongs_to({})", path)) - .collect::>() - .join("\n") - )) - .emit(); - } - - for ignored in unrecognized_options { - ignored - .span() - .warning(format!( - "Unrecognized option {}", - path_to_string(&ignored.name()) - )) - .emit(); - } - - Ok(Self { - parent_struct, - foreign_key, - }) - } +fn foreign_key(assoc: &BelongsTo) -> Ident { + let ident = &assoc + .parent + .path + .segments + .last() + .expect("paths always have at least one segment") + .ident; + + assoc + .foreign_key + .clone() + .unwrap_or_else(|| infer_foreign_key(ident)) } -fn infer_foreign_key(name: &syn::Ident) -> syn::Ident { +fn infer_foreign_key(name: &Ident) -> Ident { let snake_case = camel_to_snake(&name.to_string()); - syn::Ident::new(&format!("{}_id", snake_case), name.span()) + Ident::new(&format!("{}_id", snake_case), name.span()) } struct ReplacePathLifetimes { @@ -194,9 +116,9 @@ impl ReplacePathLifetimes { impl Fold for ReplacePathLifetimes where - F: FnMut(usize, Span) -> syn::Lifetime, + F: FnMut(usize, Span) -> Lifetime, { - fn fold_lifetime(&mut self, mut lt: syn::Lifetime) -> syn::Lifetime { + fn fold_lifetime(&mut self, mut lt: Lifetime) -> Lifetime { if lt.ident == "_" { lt = (self.f)(self.count, lt.span()); self.count += 1; diff --git a/diesel_derives/src/attrs.rs b/diesel_derives/src/attrs.rs new file mode 100644 index 000000000000..f37ac21d8d3e --- /dev/null +++ b/diesel_derives/src/attrs.rs @@ -0,0 +1,119 @@ +use proc_macro_error::{emit_warning, ResultExt}; +use syn::parse::{Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{parenthesized, parse, Attribute, Ident, LitBool, Path, Type}; + +use parsers::{BelongsTo, MysqlType, PostgresType, SqliteType}; +use util::{parse_eq, parse_paren, unknown_attribute}; + +pub enum FieldAttr { + Embed(Ident), + + ColumnName(Ident, Ident), + SqlType(Ident, Type), + SerializeAs(Ident, Type), + DeserializeAs(Ident, Type), +} + +impl Parse for FieldAttr { + fn parse(input: ParseStream) -> Result { + let name: Ident = input.parse()?; + let name_str = name.to_string(); + + match &*name_str { + "embed" => Ok(FieldAttr::Embed(name)), + + "column_name" => Ok(FieldAttr::ColumnName(name, parse_eq(input)?)), + "sql_type" => Ok(FieldAttr::SqlType(name, parse_eq(input)?)), + "serialize_as" => Ok(FieldAttr::SerializeAs(name, parse_eq(input)?)), + "deserialize_as" => Ok(FieldAttr::DeserializeAs(name, parse_eq(input)?)), + + _ => unknown_attribute(&name), + } + } +} + +#[allow(clippy::large_enum_variant)] +pub enum StructAttr { + Aggregate(Ident), + NotSized(Ident), + ForeignDerive(Ident), + + TableName(Ident, Path), + SqlType(Ident, Type), + TreatNoneAsDefaultValue(Ident, LitBool), + TreatNoneAsNull(Ident, LitBool), + + BelongsTo(Ident, BelongsTo), + MysqlType(Ident, MysqlType), + SqliteType(Ident, SqliteType), + PostgresType(Ident, PostgresType), + PrimaryKey(Ident, Punctuated), +} + +impl Parse for StructAttr { + fn parse(input: ParseStream) -> Result { + let name: Ident = input.parse()?; + let name_str = name.to_string(); + + match &*name_str { + "aggregate" => Ok(StructAttr::Aggregate(name)), + "not_sized" => Ok(StructAttr::NotSized(name)), + "foreign_derive" => Ok(StructAttr::ForeignDerive(name)), + + "table_name" => Ok(StructAttr::TableName(name, parse_eq(input)?)), + "sql_type" => Ok(StructAttr::SqlType(name, parse_eq(input)?)), + "treat_none_as_default_value" => { + Ok(StructAttr::TreatNoneAsDefaultValue(name, parse_eq(input)?)) + } + "treat_none_as_null" => Ok(StructAttr::TreatNoneAsNull(name, parse_eq(input)?)), + + "belongs_to" => Ok(StructAttr::BelongsTo(name, parse_paren(input)?)), + "mysql_type" => Ok(StructAttr::MysqlType(name, parse_paren(input)?)), + "sqlite_type" => Ok(StructAttr::SqliteType(name, parse_paren(input)?)), + "postgres_type" => Ok(StructAttr::PostgresType(name, parse_paren(input)?)), + "primary_key" => Ok(StructAttr::PrimaryKey(name, { + let content; + parenthesized!(content in input); + content.parse_terminated(Ident::parse)? + })), + + _ => unknown_attribute(&name), + } + } +} + +pub fn parse_attributes(attrs: &[Attribute]) -> Vec { + attrs + .iter() + .flat_map(|attr| { + if attr.path.is_ident("diesel") { + attr.parse_args_with(Punctuated::::parse_terminated) + .unwrap_or_abort() + } else { + parse_old_attribute(attr) + } + }) + .collect() +} + +fn parse_old_attribute(attr: &Attribute) -> Punctuated { + attr.path + .get_ident() + .and_then(|ident| match &*ident.to_string() { + "table_name" | "primary_key" | "column_name" | "sql_type" | "changeset_options" => { + emit_warning!(ident, "#[{}] attribute form is deprecated", ident); + + let Attribute { path, tokens, .. } = attr; + + Some(parse::(quote! { #path #tokens }.into()).unwrap_or_abort()) + } + _ => None, + }) + .map_or(Punctuated::new(), |attr| { + let mut p = Punctuated::new(); + p.push_value(attr); + p + }) +} diff --git a/diesel_derives/src/diagnostic_shim.rs b/diesel_derives/src/diagnostic_shim.rs deleted file mode 100644 index 8eea833902e1..000000000000 --- a/diesel_derives/src/diagnostic_shim.rs +++ /dev/null @@ -1,87 +0,0 @@ -use proc_macro2::Span; - -pub trait EmitErrorExt { - fn emit_error(self) -> Option; -} - -impl EmitErrorExt for Result { - fn emit_error(self) -> Option { - self.map_err(Diagnostic::emit).ok() - } -} - -pub trait DiagnosticShim { - fn error>(self, msg: T) -> Diagnostic; - fn warning>(self, msg: T) -> Diagnostic; -} - -#[cfg(feature = "nightly")] -impl DiagnosticShim for Span { - fn error>(self, msg: T) -> Diagnostic { - self.unstable().error(msg) - } - - fn warning>(self, msg: T) -> Diagnostic { - self.unstable().warning(msg) - } -} - -#[cfg(not(feature = "nightly"))] -impl DiagnosticShim for Span { - fn error>(self, msg: T) -> Diagnostic { - Diagnostic::error(msg) - } - - fn warning>(self, msg: T) -> Diagnostic { - Diagnostic::warning(msg) - } -} - -#[cfg(feature = "nightly")] -pub use proc_macro::Diagnostic; - -#[cfg(not(feature = "nightly"))] -pub struct Diagnostic { - message: String, - level: Level, -} - -#[cfg(not(feature = "nightly"))] -impl Diagnostic { - fn error>(msg: T) -> Self { - Diagnostic { - message: msg.into(), - level: Level::Error, - } - } - - fn warning>(msg: T) -> Self { - Diagnostic { - message: msg.into(), - level: Level::Warning, - } - } - - pub fn help>(mut self, msg: T) -> Self { - self.message.push('\n'); - self.message.push_str(&msg.into()); - self - } - - pub fn note(self, msg: &str) -> Self { - self.help(msg) - } - - pub fn emit(self) { - match self.level { - Level::Error => panic!("{}", self.message), - Level::Warning => println!("{}", self.message), - } - } -} - -#[cfg(not(feature = "nightly"))] -enum Level { - Warning, - Error, -} diff --git a/diesel_derives/src/diesel_numeric_ops.rs b/diesel_derives/src/diesel_numeric_ops.rs index b8e02199097c..4d39c4c6b2f6 100644 --- a/diesel_derives/src/diesel_numeric_ops.rs +++ b/diesel_derives/src/diesel_numeric_ops.rs @@ -1,9 +1,9 @@ -use proc_macro2; -use syn; +use proc_macro2::TokenStream; +use syn::DeriveInput; -use util::*; +use util::wrap_in_dummy_mod; -pub fn derive(mut item: syn::DeriveInput) -> Result { +pub fn derive(mut item: DeriveInput) -> TokenStream { let struct_name = &item.ident; { @@ -14,12 +14,13 @@ pub fn derive(mut item: syn::DeriveInput) -> Result Result, - pub flags: MetaItem, - column_name_from_attribute: Option, + pub name: FieldName, + column_name: Option, + pub sql_type: Option, + pub serialize_as: Option, + pub deserialize_as: Option, + pub embed: bool, } impl Field { - pub fn from_struct_field(field: &syn::Field, index: usize) -> Self { - let column_name_from_attribute = MetaItem::with_name(&field.attrs, "column_name"); - let name = match field.ident.clone() { - Some(mut x) => { - // https://github.com/rust-lang/rust/issues/47983#issuecomment-362817105 - let span = x.span(); - x.set_span(fix_span(span, Span::call_site())); - FieldName::Named(x) + pub fn from_struct_field(field: &SynField, index: usize) -> Self { + let SynField { + ident, attrs, ty, .. + } = field; + + let mut column_name = None; + let mut sql_type = None; + let mut serialize_as = None; + let mut deserialize_as = None; + let mut embed = false; + + for attr in parse_attributes(attrs) { + match attr { + FieldAttr::ColumnName(_, value) => column_name = Some(value), + FieldAttr::SqlType(_, value) => sql_type = Some(value), + FieldAttr::SerializeAs(_, value) => serialize_as = Some(value), + FieldAttr::DeserializeAs(_, value) => deserialize_as = Some(value), + FieldAttr::Embed(_) => embed = true, } - None => FieldName::Unnamed(syn::Index { - index: index as u32, - // https://github.com/rust-lang/rust/issues/47312 - span: Span::call_site(), - }), + } + + let name = match ident.clone() { + Some(x) => FieldName::Named(x), + None => FieldName::Unnamed(index.into()), + }; + + let span = match name { + FieldName::Named(ref ident) => ident.span(), + FieldName::Unnamed(_) => ty.span(), }; - let sql_type = MetaItem::with_name(&field.attrs, "sql_type") - .and_then(|m| m.ty_value().map_err(Diagnostic::emit).ok()); - let flags = MetaItem::with_name(&field.attrs, "diesel") - .unwrap_or_else(|| MetaItem::empty("diesel")); - let span = field.span(); Self { - ty: field.ty.clone(), - column_name_from_attribute, + ty: ty.clone(), + span, name, + column_name, sql_type, - flags, - span, + serialize_as, + deserialize_as, + embed, } } - pub fn column_name_ident(&self) -> syn::Ident { - self.column_name_from_attribute - .as_ref() - .map(|m| m.expect_ident_value()) - .unwrap_or_else(|| match self.name { - FieldName::Named(ref x) => x.clone(), - _ => { - self.span - .error( - "All fields of tuple structs must be annotated with `#[column_name]`", - ) - .emit(); - Ident::new("unknown_column", self.span) - } - }) - } - - pub fn column_name_str(&self) -> String { - self.column_name_from_attribute - .as_ref() - .map(|m| { - m.str_value().unwrap_or_else(|e| { - e.emit(); - m.name().segments.first().unwrap().ident.to_string() - }) - }) + pub fn column_name(&self) -> &Ident { + self.column_name.as_ref() .unwrap_or_else(|| match self.name { - FieldName::Named(ref x) => x.to_string(), - _ => { - self.span - .error( - "All fields of tuple structs must be annotated with `#[column_name]`", - ) - .emit(); - "unknown_column".to_string() + FieldName::Named(ref x) => x, + FieldName::Unnamed(ref x) => { + abort!(x, "All fields of tuple structs must be annotated with `#[diesel(column_name)]`"); } }) } - pub fn has_flag(&self, flag: &str) -> bool { - self.flags.has_flag(flag) - } - - pub fn ty_for_serialize(&self) -> Result, Diagnostic> { - if let Some(meta) = self.flags.nested_item("serialize_as")? { - let ty = meta.ty_value()?; - Ok(Some(ty)) - } else { - Ok(None) - } - } - - pub fn ty_for_deserialize(&self) -> Result, Diagnostic> { - if let Some(meta) = self.flags.nested_item("deserialize_as")? { - meta.ty_value().map(Cow::Owned) + pub fn ty_for_deserialize(&self) -> &Type { + if let Some(value) = &self.deserialize_as { + value } else { - Ok(Cow::Borrowed(&self.ty)) + &self.ty } } } pub enum FieldName { - Named(syn::Ident), - Unnamed(syn::Index), -} - -impl FieldName { - pub fn assign(&self, expr: syn::Expr) -> syn::FieldValue { - let span = self.span(); - // Parens are to work around https://github.com/rust-lang/rust/issues/47311 - let tokens = quote_spanned!(span=> #self: (#expr)); - parse_quote!(#tokens) - } - - pub fn access(&self) -> proc_macro2::TokenStream { - let span = self.span(); - // Span of the dot is important due to - // https://github.com/rust-lang/rust/issues/47312 - quote_spanned!(span=> .#self) - } - - pub fn span(&self) -> Span { - match *self { - FieldName::Named(ref x) => x.span(), - FieldName::Unnamed(ref x) => x.span, - } - } + Named(Ident), + Unnamed(Index), } impl ToTokens for FieldName { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + fn to_tokens(&self, tokens: &mut TokenStream) { match *self { FieldName::Named(ref x) => x.to_tokens(tokens), FieldName::Unnamed(ref x) => x.to_tokens(tokens), diff --git a/diesel_derives/src/from_sql_row.rs b/diesel_derives/src/from_sql_row.rs index eb8758db633d..2e5fc2e08e65 100644 --- a/diesel_derives/src/from_sql_row.rs +++ b/diesel_derives/src/from_sql_row.rs @@ -1,13 +1,12 @@ -use proc_macro2::*; -use syn; +use proc_macro2::TokenStream; +use syn::DeriveInput; -use meta::*; -use util::*; +use model::Model; +use util::{ty_for_foreign_derive, wrap_in_dummy_mod}; -pub fn derive(mut item: syn::DeriveInput) -> Result { - let flags = - MetaItem::with_name(&item.attrs, "diesel").unwrap_or_else(|| MetaItem::empty("diesel")); - let struct_ty = ty_for_foreign_derive(&item, &flags)?; +pub fn derive(mut item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, true); + let struct_ty = ty_for_foreign_derive(&item, &model); { let where_clause = item @@ -30,7 +29,7 @@ pub fn derive(mut item: syn::DeriveInput) -> Result { let ty_params = item.generics.type_params().collect::>(); let const_params = item.generics.const_params().collect::>(); - Ok(wrap_in_dummy_mod(quote! { + wrap_in_dummy_mod(quote! { use diesel::deserialize::{self, FromSql, Queryable}; // Need to put __ST and __DB after lifetimes but before const params @@ -43,5 +42,5 @@ pub fn derive(mut item: syn::DeriveInput) -> Result { Ok(row) } } - })) + }) } diff --git a/diesel_derives/src/identifiable.rs b/diesel_derives/src/identifiable.rs index eb43fa816ee4..a8faeeb6cb0b 100644 --- a/diesel_derives/src/identifiable.rs +++ b/diesel_derives/src/identifiable.rs @@ -1,12 +1,13 @@ -use proc_macro2; -use syn; +use proc_macro2::TokenStream; +use syn::DeriveInput; -use model::*; -use util::*; +use model::Model; +use util::wrap_in_dummy_mod; -pub fn derive(item: syn::DeriveInput) -> Result { - let model = Model::from_item(&item)?; - let struct_name = &model.name; +pub fn derive(item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, false); + + let struct_name = &item.ident; let table_name = model.table_name(); let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl(); @@ -14,14 +15,14 @@ pub fn derive(item: syn::DeriveInput) -> Result, Vec<_>) = model + let (field_ty, field_name): (Vec<_>, Vec<_>) = model .primary_key_names .iter() - .filter_map(|pk| model.find_column(pk).emit_error()) - .map(|f| (&f.ty, f.name.access())) + .map(|pk| model.find_column(pk)) + .map(|f| (&f.ty, &f.name)) .unzip(); - Ok(wrap_in_dummy_mod(quote! { + wrap_in_dummy_mod(quote! { use diesel::associations::{HasTable, Identifiable}; impl #impl_generics HasTable for #struct_name #ty_generics @@ -40,8 +41,8 @@ pub fn derive(item: syn::DeriveInput) -> Result Self::Id { - (#(&self#field_access),*) + (#(&self.#field_name),*) } } - })) + }) } diff --git a/diesel_derives/src/insertable.rs b/diesel_derives/src/insertable.rs index 99958bac30aa..0c51b83776df 100644 --- a/diesel_derives/src/insertable.rs +++ b/diesel_derives/src/insertable.rs @@ -1,34 +1,14 @@ -use proc_macro2; -use proc_macro2::Span; -use syn; +use proc_macro2::TokenStream; +use syn::{DeriveInput, Expr, Path, Type}; -use field::*; -use meta::path_to_string; -use model::*; -use util::*; +use field::Field; +use model::Model; +use util::{inner_of_option_ty, is_option_ty, wrap_in_dummy_mod}; -use crate::meta::MetaItem; - -pub fn derive(item: syn::DeriveInput) -> Result { - let treat_none_as_default_value = MetaItem::with_name(&item.attrs, "diesel") - .map(|meta| { - meta.warn_if_other_options(&["treat_none_as_default_value"]); - meta.required_nested_item("treat_none_as_default_value") - .map(|m| m.expect_bool_value()) - }) - .unwrap_or(Ok(true))?; - - let model = Model::from_item(&item)?; - - if model.fields().is_empty() { - return Err(Span::call_site() - .error("Cannot derive Insertable for unit structs") - .help(format!( - "Use `insert_into({}::table).default_values()` if you want `DEFAULT VALUES`", - path_to_string(&model.table_name()) - ))); - } +pub fn derive(item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, false); + let treat_none_as_default_value = model.treat_none_as_default_value(); let table_name = &model.table_name(); let struct_name = &item.ident; @@ -45,10 +25,7 @@ pub fn derive(item: syn::DeriveInput) -> Result { direct_field_ty.push(field_ty_embed(field, None)); direct_field_assign.push(field_expr_embed(field, None)); @@ -85,23 +62,23 @@ pub fn derive(item: syn::DeriveInput) -> Result { - return Err(field - .flags - .span() - .error("`#[diesel(embed)]` cannot be combined with `#[diesel(serialize_as)]`")) + (Some(ty), true) => { + abort!( + ty, + "`#[diesel(embed)]` cannot be combined with `#[diesel(serialize_as)]`" + ) } } } @@ -135,7 +112,7 @@ pub fn derive(item: syn::DeriveInput) -> Result Result) -> syn::Type { +fn field_ty_embed(field: &Field, lifetime: Option) -> TokenStream { let field_ty = &field.ty; - parse_quote!(#lifetime #field_ty) + quote!(#lifetime #field_ty) } -fn field_expr_embed(field: &Field, lifetime: Option) -> syn::Expr { - let field_access = field.name.access(); +fn field_expr_embed(field: &Field, lifetime: Option) -> TokenStream { + let field_name = &field.name; - parse_quote!(#lifetime self#field_access) + quote!(#lifetime self.#field_name) } fn field_ty_serialize_as( field: &Field, - table_name: &syn::Path, - ty: &syn::Type, + table_name: &Path, + ty: &Type, treat_none_as_default_value: bool, -) -> syn::Type { - let column_name = field.column_name_ident(); +) -> TokenStream { + let column_name = field.column_name(); if treat_none_as_default_value { let inner_ty = inner_of_option_ty(&ty); - parse_quote!( + + quote!( std::option::Option> ) } else { - parse_quote!( + quote!( diesel::dsl::Eq< #table_name::#column_name, #ty, @@ -192,47 +170,49 @@ fn field_ty_serialize_as( fn field_expr_serialize_as( field: &Field, - table_name: &syn::Path, - ty: &syn::Type, + table_name: &Path, + ty: &Type, treat_none_as_default_value: bool, -) -> syn::Expr { - let field_access = field.name.access(); - let column_name = field.column_name_ident(); - let column: syn::Expr = parse_quote!(#table_name::#column_name); +) -> TokenStream { + let field_name = &field.name; + let column_name = field.column_name(); + let column = quote!(#table_name::#column_name); if treat_none_as_default_value { if is_option_ty(&ty) { - parse_quote!(self#field_access.map(|x| #column.eq(::std::convert::Into::<#ty>::into(x)))) + quote!(self.#field_name.map(|x| #column.eq(::std::convert::Into::<#ty>::into(x)))) } else { - parse_quote!(std::option::Option::Some(#column.eq(::std::convert::Into::<#ty>::into(self#field_access)))) + quote!(std::option::Option::Some(#column.eq(::std::convert::Into::<#ty>::into(self.#field_name)))) } } else { - parse_quote!(#column.eq(::std::convert::Into::<#ty>::into(self#field_access))) + quote!(#column.eq(::std::convert::Into::<#ty>::into(self.#field_name))) } } fn field_ty( field: &Field, - table_name: &syn::Path, - lifetime: Option, + table_name: &Path, + lifetime: Option, treat_none_as_default_value: bool, -) -> syn::Type { - let column_name = field.column_name_ident(); +) -> TokenStream { + let column_name = field.column_name(); if treat_none_as_default_value { let inner_ty = inner_of_option_ty(&field.ty); - parse_quote!( + + quote!( std::option::Option> ) } else { let inner_ty = &field.ty; - parse_quote!( + + quote!( diesel::dsl::Eq< #table_name::#column_name, - #lifetime #inner_ty, + #lifetime #inner_ty, > ) } @@ -240,25 +220,25 @@ fn field_ty( fn field_expr( field: &Field, - table_name: &syn::Path, - lifetime: Option, + table_name: &Path, + lifetime: Option, treat_none_as_default_value: bool, -) -> syn::Expr { - let field_access = field.name.access(); - let column_name = field.column_name_ident(); - let column: syn::Expr = parse_quote!(#table_name::#column_name); +) -> TokenStream { + let field_name = &field.name; + let column_name = field.column_name(); + let column: Expr = parse_quote!(#table_name::#column_name); if treat_none_as_default_value { if is_option_ty(&field.ty) { if lifetime.is_some() { - parse_quote!(self#field_access.as_ref().map(|x| #column.eq(x))) + quote!(self.#field_name.as_ref().map(|x| #column.eq(x))) } else { - parse_quote!(self#field_access.map(|x| #column.eq(x))) + quote!(self.#field_name.map(|x| #column.eq(x))) } } else { - parse_quote!(std::option::Option::Some(#column.eq(#lifetime self#field_access))) + quote!(std::option::Option::Some(#column.eq(#lifetime self.#field_name))) } } else { - parse_quote!(#column.eq(#lifetime self#field_access)) + quote!(#column.eq(#lifetime self.#field_name)) } } diff --git a/diesel_derives/src/lib.rs b/diesel_derives/src/lib.rs index 0fabb10a5f05..7c9bf5ee2f21 100644 --- a/diesel_derives/src/lib.rs +++ b/diesel_derives/src/lib.rs @@ -17,22 +17,21 @@ clippy::items_after_statements, clippy::used_underscore_binding )] -#![cfg_attr(feature = "nightly", feature(proc_macro_diagnostic, proc_macro_span))] extern crate proc_macro; extern crate proc_macro2; -#[macro_use] extern crate quote; #[macro_use] extern crate syn; +#[macro_use] +extern crate proc_macro_error; use proc_macro::TokenStream; -mod diagnostic_shim; +mod attrs; mod field; -mod meta; mod model; -mod resolved_at_shim; +mod parsers; mod util; mod as_changeset; @@ -50,48 +49,49 @@ mod sql_function; mod sql_type; mod valid_grouping; -use diagnostic_shim::*; - /// Implements `AsChangeset` /// /// To implement `AsChangeset` this derive needs to know the corresponding table /// type. By default it uses the `snake_case` type name with an added `s` from /// the current scope. -/// It is possible to change this default by using `#[table_name = "something"]`. +/// It is possible to change this default by using `#[diesel(table_name = something)]`. /// /// If a field name of your struct differs /// from the name of the corresponding column, you can annotate the field with -/// `#[column_name = "some_column_name"]`. +/// `#[diesel(column_name = some_column_name)]`. /// /// By default, any `Option` fields on the struct are skipped if their value is /// `None`. If you would like to assign `NULL` to the field instead, you can -/// annotate your struct with `#[changeset_options(treat_none_as_null = -/// "true")]`. +/// annotate your struct with `#[diesel(treat_none_as_null = true)]`. /// /// # Attributes /// /// ## Optional container attributes /// -/// * `#[changeset_options(treat_none_as_null = "true")]`, specifies that -/// the derive should threat `None` values as `NULL`. By default -/// `Option::::None` is just skipped. To insert a `NULL` using default -/// behavior use `Option::>::Some(None)` -/// * `#[table_name = "path::to::table"]`, specifies a path to the table for which the -/// current type is a changeset. The path is relative to the current module. -/// If this attribute is not used, the type name converted to -/// `snake_case` with an added `s` is used as table name. +/// * `#[diesel(treat_none_as_null = true)]`, specifies that +/// the derive should threat `None` values as `NULL`. By default +/// `Option::::None` is just skipped. To insert a `NULL` using default +/// behavior use `Option::>::Some(None)` +/// * `#[diesel(table_name = path::to::table)]`, specifies a path to the table for which the +/// current type is a changeset. The path is relative to the current module. +/// If this attribute is not used, the type name converted to +/// `snake_case` with an added `s` is used as table name. +/// * `#[diesel(primary_key(id1, id2))]` to specify the struct field that +/// that corresponds to the primary key. If not used, `id` will be +/// assumed as primary key field /// /// ## Optional field attributes /// -/// * `#[column_name = "some_column_name"]`, overrides the column name -/// of the current field to `some_column_name`. By default the field -/// name is used as column name. +/// * `#[diesel(column_name = some_column_name)]`, overrides the column name +/// of the current field to `some_column_name`. By default the field +/// name is used as column name. +#[proc_macro_error] #[proc_macro_derive( AsChangeset, - attributes(table_name, primary_key, column_name, changeset_options) + attributes(diesel, table_name, column_name, primary_key, changeset_options) )] pub fn derive_as_changeset(input: TokenStream) -> TokenStream { - expand_proc_macro(input, as_changeset::derive) + as_changeset::derive(parse_macro_input!(input)).into() } /// Implements all required variants of `AsExpression` @@ -113,60 +113,60 @@ pub fn derive_as_changeset(input: TokenStream) -> TokenStream { /// /// ## Required container attributes /// -/// * `#[sql_type = "SqlType"]`, to specify the sql type of the -/// generated implementations. If the attribute exists multiple times -/// impls for each sql type are generated. +/// * `#[diesel(sql_type = SqlType)]`, to specify the sql type of the +/// generated implementations. If the attribute exists multiple times +/// impls for each sql type are generated. /// /// ## Optional container attributes /// /// * `#[diesel(not_sized)]`, to skip generating impls that require -/// that the type is `Sized` +/// that the type is `Sized` +#[proc_macro_error] #[proc_macro_derive(AsExpression, attributes(diesel, sql_type))] pub fn derive_as_expression(input: TokenStream) -> TokenStream { - expand_proc_macro(input, as_expression::derive) + as_expression::derive(parse_macro_input!(input)).into() } /// Implement required traits for the associations API /// -/// This derive implement support for diesels associations api. Check the +/// This derive implement support for diesel's associations api. Check the /// module level documentation of the `diesel::associations` module for details. /// /// # Attributes /// /// # Required container attributes /// -/// * `#[belongs_to(User)]`, to specify a child-to-parent relation ship -/// between the current type and the specified parent type (`User`). -/// If this attribute is given multiple times, multiple relation ships -/// are generated. -/// * `#[belongs_to(User, foreign_key = "mykey")]`, variant of the attribute -/// above. Allows to specify the name of the foreign key. If the foreign key -/// is not specified explicitly, the remote lower case type name with an -/// appended `_id` is used as foreign key name. (`user_id` in this example -/// case) +/// * `#[diesel(belongs_to(User))]`, to specify a child-to-parent relation ship +/// between the current type and the specified parent type (`User`). +/// If this attribute is given multiple times, multiple relation ships +/// are generated. `#[diesel(belongs_to(User, foreign_key = mykey))]` variant +/// allows to specify the name of the foreign key. If the foreign key +/// is not specified explicitly, the remote lower case type name with an +/// appended `_id` is used as foreign key name. (`user_id` in this example +/// case) /// /// # Optional container attributes /// -/// * `#[table_name = "path::to::table"]` specifies a path to the table this +/// * `#[diesel(table_name = path::to::table)]` specifies a path to the table this /// type belongs to. The path is relative to the current module. /// If this attribute is not used, the type name converted to /// `snake_case` with an added `s` is used as table name. /// /// # Optional field attributes /// -/// * `#[column_name = "some_column_name"]`, overrides the column the current -/// field maps to to `some_column_name`. By default the field name is used -/// as column name. Only useful for the foreign key field. -/// -#[proc_macro_derive(Associations, attributes(belongs_to, column_name, table_name))] +/// * `#[diesel(column_name = some_column_name)]`, overrides the column the current +/// field maps to to `some_column_name`. By default the field name is used +/// as column name. +#[proc_macro_error] +#[proc_macro_derive(Associations, attributes(diesel, belongs_to, column_name, table_name))] pub fn derive_associations(input: TokenStream) -> TokenStream { - expand_proc_macro(input, associations::derive) + associations::derive(parse_macro_input!(input)).into() } /// Implement numeric operators for the current query node #[proc_macro_derive(DieselNumericOps)] pub fn derive_diesel_numeric_ops(input: TokenStream) -> TokenStream { - expand_proc_macro(input, diesel_numeric_ops::derive) + diesel_numeric_ops::derive(parse_macro_input!(input)).into() } /// Implements `Queryable` for primitive types @@ -175,23 +175,24 @@ pub fn derive_diesel_numeric_ops(input: TokenStream) -> TokenStream { /// into rust types not supported by diesel itself. /// /// There are no options or special considerations needed for this derive. +#[proc_macro_error] #[proc_macro_derive(FromSqlRow, attributes(diesel))] pub fn derive_from_sql_row(input: TokenStream) -> TokenStream { - expand_proc_macro(input, from_sql_row::derive) + from_sql_row::derive(parse_macro_input!(input)).into() } /// Implements `Identifiable` for references of the current type /// /// By default, the primary key field is assumed to be a single field called `id`. -/// If it's not, you can put `#[primary_key(your_id)]` on your struct. -/// If you have a composite primary key, the syntax is `#[primary_key(id1, id2)]`. +/// If it's not, you can put `#[diesel(primary_key(your_id))]` on your struct. +/// If you have a composite primary key, the syntax is `#[diesel(primary_key(id1, id2))]`. /// /// By default, `#[derive(Identifiable)]` will assume that your table is /// in scope and its name is the plural form of your struct name. /// Diesel uses very simple pluralization rules. /// It only adds an `s` to the end, and converts `CamelCase` to `snake_case`. /// If your table name does not follow this convention or is not in scope, -/// you can specify a path to the table with `#[table_name = "path::to::table"]`. +/// you can specify a path to the table with `#[diesel(table_name = path::to::table)]`. /// Our rules for inferring table names is considered public API. /// It will never change without a major version bump. /// @@ -199,16 +200,23 @@ pub fn derive_from_sql_row(input: TokenStream) -> TokenStream { /// /// ## Optional container attributes /// -/// * `#[table_name = "path::to::table"]` specifies a path to the table this +/// * `#[diesel(table_name = path::to::table)]` specifies a path to the table this /// type belongs to. The path is relative to the current module. /// If this attribute is not used, the type name converted to /// `snake_case` with an added `s` is used as table name -/// * `#[primary_key(id1, id2)]` to specify the struct field that +/// * `#[diesel(primary_key(id1, id2))]` to specify the struct field that /// that corresponds to the primary key. If not used, `id` will be /// assumed as primary key field -#[proc_macro_derive(Identifiable, attributes(table_name, primary_key, column_name))] +/// +/// # Optional field attributes +/// +/// * `#[diesel(column_name = some_column_name)]`, overrides the column the current +/// field maps to to `some_column_name`. By default the field name is used +/// as column name. +#[proc_macro_error] +#[proc_macro_derive(Identifiable, attributes(diesel, table_name, column_name, primary_key))] pub fn derive_identifiable(input: TokenStream) -> TokenStream { - expand_proc_macro(input, identifiable::derive) + identifiable::derive(parse_macro_input!(input)).into() } /// Implements `Insertable` @@ -216,11 +224,11 @@ pub fn derive_identifiable(input: TokenStream) -> TokenStream { /// To implement `Insertable` this derive needs to know the corresponding table /// type. By default it uses the `snake_case` type name with an added `s` /// from the current scope. -/// It is possible to change this default by using `#[table_name = "something"]`. +/// It is possible to change this default by using `#[diesel(table_name = something)]`. /// /// If a field name of your /// struct differs from the name of the corresponding column, -/// you can annotate the field with `#[column_name = "some_column_name"]`. +/// you can annotate the field with `#[diesel(column_name = some_column_name)]`. /// /// Your struct can also contain fields which implement `Insertable`. This is /// useful when you want to have one field map to more than one column (for @@ -228,7 +236,7 @@ pub fn derive_identifiable(input: TokenStream) -> TokenStream { /// `#[diesel(embed)]` to any such fields. /// /// To provide custom serialization behavior for a field, you can use -/// `#[diesel(serialize_as = "SomeType")]`. If this attribute is present, Diesel +/// `#[diesel(serialize_as = SomeType)]`. If this attribute is present, Diesel /// will call `.into` on the corresponding field and serialize the instance of `SomeType`, /// rather than the actual field on your struct. This can be used to add custom behavior for a /// single field, or use types that are otherwise unsupported by Diesel. @@ -243,26 +251,26 @@ pub fn derive_identifiable(input: TokenStream) -> TokenStream { /// /// ## Optional container attributes /// -/// * `#[table_name = "path::to::table"]`, specifies a path to the table this type -/// is insertable into. The path is relative to the current module. -/// If this attribute is not used, the type name converted to -/// `snake_case` with an added `s` is used as table name -/// * `#[diesel(treat_none_as_default_value = "true/false")], specifies if `None` values -/// should be converted to `NULL` values on SQL side or treated as `DEFAULT` value primitive -/// *Note: This option may control if your query is stored in the -/// prepared statement cache or not* +/// * `#[diesel(table_name = path::to::table)]`, specifies a path to the table this type +/// is insertable into. The path is relative to the current module. +/// If this attribute is not used, the type name converted to +/// `snake_case` with an added `s` is used as table name +/// * `#[diesel(treat_none_as_default_value = false)], specifies that `None` values +/// should be converted to `NULL` values on SQL side instead of being treated as `DEFAULT` +/// value primitive. *Note*: This option may control if your query is stored in the +/// prepared statement cache or not* /// /// ## Optional field attributes /// -/// * `#[column_name = "some_column_name"]`, overrides the column the current -/// field maps to `some_column_name`. By default the field name is used -/// as column name +/// * `#[diesel(column_name = some_column_name)]`, overrides the column the current +/// field maps to `some_column_name`. By default the field name is used +/// as column name /// * `#[diesel(embed)]`, specifies that the current field maps not only -/// to single database field, but is a struct that implements `Insertable` -/// * `#[diesel(serialize_as = "SomeType")]`, instead of serializing the actual -/// field type, Diesel will convert the field into `SomeType` using `.into` and -/// serialize that instead. By default this derive will serialize directly using -/// the actual field type. +/// to single database field, but is a struct that implements `Insertable` +/// * `#[diesel(serialize_as = SomeType)]`, instead of serializing the actual +/// field type, Diesel will convert the field into `SomeType` using `.into` and +/// serialize that instead. By default this derive will serialize directly using +/// the actual field type. /// /// # Examples /// @@ -277,7 +285,7 @@ pub fn derive_identifiable(input: TokenStream) -> TokenStream { /// # use std::io::Write; /// # /// #[derive(Debug, FromSqlRow, AsExpression)] -/// #[sql_type = "sql_types::Text"] +/// #[diesel(sql_type = sql_types::Text)] /// struct UppercaseString(pub String); /// /// impl Into for String { @@ -297,10 +305,10 @@ pub fn derive_identifiable(input: TokenStream) -> TokenStream { /// } /// /// #[derive(Insertable, PartialEq, Debug)] -/// #[table_name = "users"] +/// #[diesel(table_name = users)] /// struct InsertableUser { /// id: i32, -/// #[diesel(serialize_as = "UppercaseString")] +/// #[diesel(serialize_as = UppercaseString)] /// name: String, /// } /// @@ -329,20 +337,10 @@ pub fn derive_identifiable(input: TokenStream) -> TokenStream { /// # Ok(()) /// # } /// ``` - -#[proc_macro_derive(Insertable, attributes(table_name, column_name, diesel))] +#[proc_macro_error] +#[proc_macro_derive(Insertable, attributes(diesel, table_name, column_name))] pub fn derive_insertable(input: TokenStream) -> TokenStream { - expand_proc_macro(input, insertable::derive) -} - -#[doc(hidden)] -#[proc_macro_derive(NonAggregate)] -pub fn derive_non_aggregate(input: TokenStream) -> TokenStream { - eprintln!( - "#[derive(NonAggregate)] is deprecated. Please use \ - `#[derive(ValidGrouping)]` instead.)" - ); - expand_proc_macro(input, valid_grouping::derive) + insertable::derive(parse_macro_input!(input)).into() } /// Implements `QueryId` @@ -379,9 +377,10 @@ pub fn derive_non_aggregate(input: TokenStream) -> TokenStream { /// meaning that `HAS_STATIC_QUERY_ID` should always be false, /// you should not derive this trait. /// In that case you should implement it manually instead. +#[proc_macro_error] #[proc_macro_derive(QueryId)] pub fn derive_query_id(input: TokenStream) -> TokenStream { - expand_proc_macro(input, query_id::derive) + query_id::derive(parse_macro_input!(input)).into() } /// Implements `Queryable` to load the result of statically typed queries @@ -394,7 +393,7 @@ pub fn derive_query_id(input: TokenStream) -> TokenStream { /// `#[derive(Queryable)]`. __Field name has no effect__. /// /// To provide custom deserialization behavior for a field, you can use -/// `#[diesel(deserialize_as = "SomeType")]`. If this attribute is present, Diesel +/// `#[diesel(deserialize_as = SomeType)]`. If this attribute is present, Diesel /// will deserialize the corresponding field into `SomeType`, rather than the /// actual field type on your struct and then call /// [`.try_into`](https://doc.rust-lang.org/stable/std/convert/trait.TryInto.html#tymethod.try_into) @@ -405,14 +404,13 @@ pub fn derive_query_id(input: TokenStream) -> TokenStream { /// /// # Attributes /// -/// /// ## Optional field attributes /// -/// * `#[diesel(deserialize_as = "Type")]`, instead of deserializing directly -/// into the field type, the implementation will deserialize into `Type`. -/// Then `Type` is converted via -/// [`.try_into`](https://doc.rust-lang.org/stable/std/convert/trait.TryInto.html#tymethod.try_into) -/// into the field type. By default this derive will deserialize directly into the field type +/// * `#[diesel(deserialize_as = Type)]`, instead of deserializing directly +/// into the field type, the implementation will deserialize into `Type`. +/// Then `Type` is converted via +/// [`.try_into`](https://doc.rust-lang.org/stable/std/convert/trait.TryInto.html#tymethod.try_into) +/// into the field type. By default this derive will deserialize directly into the field type /// /// # Examples /// @@ -480,7 +478,7 @@ pub fn derive_query_id(input: TokenStream) -> TokenStream { /// #[derive(Queryable, PartialEq, Debug)] /// struct User { /// id: i32, -/// #[diesel(deserialize_as = "LowercaseString")] +/// #[diesel(deserialize_as = LowercaseString)] /// name: String, /// } /// @@ -543,23 +541,24 @@ pub fn derive_query_id(input: TokenStream) -> TokenStream { /// # Ok(()) /// # } /// ``` -#[proc_macro_derive(Queryable, attributes(column_name, diesel))] +#[proc_macro_error] +#[proc_macro_derive(Queryable, attributes(diesel, column_name))] pub fn derive_queryable(input: TokenStream) -> TokenStream { - expand_proc_macro(input, queryable::derive) + queryable::derive(parse_macro_input!(input)).into() } /// Implements `QueryableByName` for untyped sql queries, such as that one generated /// by `sql_query` /// /// To derive this trait, Diesel needs to know the SQL type of each field. You -/// can do this by either annotating your struct with `#[table_name = -/// "some_table"]` (in which case the SQL type will be +/// can do this by either annotating your struct with `#[diesel(table_name = +/// some_table)]` (in which case the SQL type will be /// `diesel::dsl::SqlTypeOf`), or by annotating each -/// field with `#[sql_type = "SomeType"]`. +/// field with `#[diesel(sql_type = SomeType)]`. /// /// If the name of a field on your struct is different than the column in your /// `table!` declaration, or if you are deriving this trait on a tuple struct, -/// you can annotate the field with `#[column_name = "some_column"]`. For tuple +/// you can annotate the field with `#[diesel(column_name = some_column)]`. For tuple /// structs, all fields must have this annotation. /// /// If a field is another struct which implements `QueryableByName`, @@ -568,7 +567,7 @@ pub fn derive_queryable(input: TokenStream) -> TokenStream { /// the embedded struct. /// /// To provide custom deserialization behavior for a field, you can use -/// `#[diesel(deserialize_as = "SomeType")]`. If this attribute is present, Diesel +/// `#[diesel(deserialize_as = SomeType)]`. If this attribute is present, Diesel /// will deserialize the corresponding field into `SomeType`, rather than the /// actual field type on your struct and then call `.into` to convert it to the /// actual field type. This can be used to add custom behavior for a @@ -576,29 +575,29 @@ pub fn derive_queryable(input: TokenStream) -> TokenStream { /// /// # Attributes /// -/// ## Type attributes +/// ## Optional container attributes /// -/// * `#[table_name = "path::to::table"]`, to specify that this type contains -/// columns for the specified table. The path is relative to the current module. -/// If no field attributes are specified the derive will use the sql type of -/// the corresponding column. +/// * `#[diesel(table_name = path::to::table)]`, to specify that this type contains +/// columns for the specified table. The path is relative to the current module. +/// If no field attributes are specified the derive will use the sql type of +/// the corresponding column. /// -/// ## Field attributes +/// ## Optional field attributes /// -/// * `#[column_name = "some_column"]`, overrides the column name for +/// * `#[diesel(column_name = some_column)]`, overrides the column name for /// a given field. If not set, the name of the field is used as column /// name. This attribute is required on tuple structs, if -/// `#[table_name = "some_table"]` is used, otherwise it's optional. -/// * `#[sql_type = "SomeType"]`, assumes `SomeType` as sql type of the +/// `#[diesel(table_name = some_table)]` is used, otherwise it's optional. +/// * `#[diesel(sql_type = SomeType)]`, assumes `SomeType` as sql type of the /// corresponding field. This attributes has precedence over all other /// variants to specify the sql type. -/// * `#[diesel(deserialize_as = "Type")]`, instead of deserializing directly -/// into the field type, the implementation will deserialize into `Type`. -/// Then `Type` is converted via `.into()` into the field type. By default -/// this derive will deserialize directly into the field type +/// * `#[diesel(deserialize_as = Type)]`, instead of deserializing directly +/// into the field type, the implementation will deserialize into `Type`. +/// Then `Type` is converted via `.into()` into the field type. By default +/// this derive will deserialize directly into the field type /// * `#[diesel(embed)]`, specifies that the current field maps not only -/// single database column, but is a type that implements -/// `QueryableByName` on it's own +/// single database column, but is a type that implements +/// `QueryableByName` on it's own /// /// # Examples /// @@ -612,7 +611,7 @@ pub fn derive_queryable(input: TokenStream) -> TokenStream { /// # use diesel::sql_query; /// # /// #[derive(QueryableByName, PartialEq, Debug)] -/// #[table_name = "users"] +/// #[diesel(table_name = users)] /// struct User { /// id: i32, /// name: String, @@ -664,10 +663,10 @@ pub fn derive_queryable(input: TokenStream) -> TokenStream { /// } /// /// #[derive(QueryableByName, PartialEq, Debug)] -/// #[table_name = "users"] +/// #[diesel(table_name = users)] /// struct User { /// id: i32, -/// #[diesel(deserialize_as = "LowercaseString")] +/// #[diesel(deserialize_as = LowercaseString)] /// name: String, /// } /// @@ -730,20 +729,21 @@ pub fn derive_queryable(input: TokenStream) -> TokenStream { /// # Ok(()) /// # } /// ``` -#[proc_macro_derive(QueryableByName, attributes(table_name, column_name, sql_type, diesel))] +#[proc_macro_error] +#[proc_macro_derive(QueryableByName, attributes(diesel, table_name, column_name, sql_type))] pub fn derive_queryable_by_name(input: TokenStream) -> TokenStream { - expand_proc_macro(input, queryable_by_name::derive) + queryable_by_name::derive(parse_macro_input!(input)).into() } /// Implements `Selectable` /// /// To implement `Selectable` this derive needs to know the corresponding table /// type. By default it uses the `snake_case` type name with an added `s`. -/// It is possible to change this default by using `#[table_name = "something"]`. +/// It is possible to change this default by using `#[diesel(table_name = something)]`. /// /// If the name of a field on your struct is different than the column in your /// `table!` declaration, or if you are deriving this trait on a tuple struct, -/// you can annotate the field with `#[column_name = "some_column"]`. For tuple +/// you can annotate the field with `#[diesel(column_name = some_column)]`. For tuple /// structs, all fields must have this annotation. /// /// If a field is another struct which implements `Selectable`, @@ -760,21 +760,23 @@ pub fn derive_queryable_by_name(input: TokenStream) -> TokenStream { /// /// ## Type attributes /// -/// * `#[table_name = "path::to::table"]`, specifies a path to the table for which the -/// current type is selectable. The path is relative to the current module. -/// If this attribute is not used, the type name converted to -/// `snake_case` with an added `s` is used as table name. +/// * `#[diesel(table_name = path::to::table)]`, specifies a path to the table for which the +/// current type is selectable. The path is relative to the current module. +/// If this attribute is not used, the type name converted to +/// `snake_case` with an added `s` is used as table name. /// /// ## Field attributes -/// * `#[column_name = "some_column"]`, overrides the column name for +/// +/// * `#[diesel(column_name = some_column)]`, overrides the column name for /// a given field. If not set, the name of the field is used as column /// name. /// * `#[diesel(embed)]`, specifies that the current field maps not only /// single database column, but is a type that implements /// `Selectable` on it's own -#[proc_macro_derive(Selectable, attributes(table_name, column_name, sql_type, diesel))] +#[proc_macro_error] +#[proc_macro_derive(Selectable, attributes(diesel))] pub fn derive_selectable(input: TokenStream) -> TokenStream { - expand_proc_macro(input, selectable::derive) + selectable::derive(parse_macro_input!(input)).into() } /// Implement necessary traits for adding a new sql type @@ -785,39 +787,40 @@ pub fn derive_selectable(input: TokenStream) -> TokenStream { /// all backends you specified via the attributes listed below. /// /// This derive will implement `NotNull`, `HasSqlType` and `SingleValue`. -/// When using this deriving, +/// When using this derive macro, /// you need to specify how the type is represented on various backends. /// You don't need to specify every backend, /// only the ones supported by your type. /// -/// For PostgreSQL, add `#[postgres(type_name = "pg_type_name", type_schema = "pg_schema_name")]` -/// or `#[postgres(oid = "some_oid", array_oid = "some_oid")]` for +/// For PostgreSQL, add `#[diesel(postgres_type(name = "pg_type_name", schema = "pg_schema_name"))]` +/// or `#[diesel(postgres_type(oid = "some_oid", array_oid = "some_oid"))]` for /// builtin types. /// For MySQL, specify which variant of `MysqlType` should be used -/// by adding `#[mysql_type = "Variant"]`. +/// by adding `#[diesel(mysql_type(name = "Variant"))]`. /// For SQLite, specify which variant of `SqliteType` should be used -/// by adding `#[sqlite_type = "Variant"]`. +/// by adding `#[diesel(sqlite_type(name = "Variant"))]`. /// /// # Attributes /// /// ## Type attributes /// -/// * `#[postgres(type_name = "TypeName", type_schema = "public")]` specifies support for -/// a postgresql type with the name `TypeName` in the schema `public`. Prefer this variant -/// for types with no stable OID (== everything but the builtin types). It's possible to leaf -/// of the `type_schema` part. In that case diesel defaults to the default postgres search path. -/// * `#[postgres(oid = 42, array_oid = 142)]`, specifies support for a -/// postgresql type with the given `oid` and `array_oid`. This variant -/// should only be used with types that have a stable OID. -/// * `#[sqlite_type = "TypeName"]`, specifies support for a sqlite type -/// with the given name. `TypeName` needs to be one of the possible values -/// in `SqliteType` -/// * `#[mysql_type = "TypeName"]`, specifies support for a mysql type -/// with the given name. `TypeName` needs to be one of the possible values -/// in `MysqlType` -#[proc_macro_derive(SqlType, attributes(postgres, sqlite_type, mysql_type))] +/// * `#[diesel(postgres_type(name = "TypeName", schema = "public"))]` specifies support for +/// a postgresql type with the name `TypeName` in the schema `public`. Prefer this variant +/// for types with no stable OID (== everything but the builtin types). It's possible to leaf +/// of the `schema` part. In that case diesel defaults to the default postgres search path. +/// * `#[diesel(postgres_type(oid = 42, array_oid = 142))]`, specifies support for a +/// postgresql type with the given `oid` and `array_oid`. This variant +/// should only be used with types that have a stable OID. +/// * `#[diesel(sqlite_type(name = "TypeName"))]`, specifies support for a sqlite type +/// with the given name. `TypeName` needs to be one of the possible values +/// in `SqliteType` +/// * `#[diesel(mysql_type(name = "TypeName"))]`, specifies support for a mysql type +/// with the given name. `TypeName` needs to be one of the possible values +/// in `MysqlType` +#[proc_macro_error] +#[proc_macro_derive(SqlType, attributes(diesel, postgres, sqlite_type, mysql_type))] pub fn derive_sql_type(input: TokenStream) -> TokenStream { - expand_proc_macro(input, sql_type::derive) + sql_type::derive(parse_macro_input!(input)).into() } /// Implements `ValidGrouping` @@ -858,10 +861,11 @@ pub fn derive_sql_type(input: TokenStream) -> TokenStream { /// ## Optional container attributes /// /// * `#[diesel(aggregate)]` for cases where the type represents an aggregating -/// SQL expression +/// SQL expression +#[proc_macro_error] #[proc_macro_derive(ValidGrouping, attributes(diesel))] pub fn derive_valid_grouping(input: TokenStream) -> TokenStream { - expand_proc_macro(input, valid_grouping::derive) + valid_grouping::derive(parse_macro_input!(input)).into() } /// Declare a sql function for use in your code. @@ -957,7 +961,7 @@ pub fn derive_valid_grouping(input: TokenStream) -> TokenStream { /// - `#[aggregate]` /// - Indicates that this is an aggregate function, and that `NonAggregate` /// should not be implemented. -/// - `#[sql_name="name"]` +/// - `#[sql_name = "name"]` /// - The SQL to be generated is different than the Rust name of the function. /// This can be used to represent functions which can take many argument /// types, or to capitalize function names. @@ -1204,19 +1208,5 @@ pub fn derive_valid_grouping(input: TokenStream) -> TokenStream { /// ``` #[proc_macro] pub fn sql_function_proc(input: TokenStream) -> TokenStream { - expand_proc_macro(input, sql_function::expand) -} - -fn expand_proc_macro( - input: TokenStream, - f: fn(T) -> Result, -) -> TokenStream { - let item = syn::parse(input).unwrap(); - match f(item) { - Ok(x) => x.into(), - Err(e) => { - e.emit(); - "".parse().unwrap() - } - } + sql_function::expand(parse_macro_input!(input)).into() } diff --git a/diesel_derives/src/meta.rs b/diesel_derives/src/meta.rs deleted file mode 100644 index 976c44d337a4..000000000000 --- a/diesel_derives/src/meta.rs +++ /dev/null @@ -1,299 +0,0 @@ -use proc_macro2::{Ident, Span}; -use syn; -use syn::fold::Fold; -use syn::spanned::Spanned; - -use resolved_at_shim::*; -use util::*; - -pub struct MetaItem { - meta: syn::Meta, -} - -pub(crate) fn path_to_string(path: &syn::Path) -> String { - path.segments - .iter() - .map(|s| s.ident.to_string()) - .collect::>() - .join("::") -} - -impl MetaItem { - pub fn all_with_name(attrs: &[syn::Attribute], name: &str) -> Vec { - attrs - .iter() - .filter_map(|attr| { - attr.parse_meta() - .ok() - .map(|m| FixSpan(attr.pound_token.spans[0]).fold_meta(m)) - }) - .filter(|m| m.path().is_ident(name)) - .map(|meta| Self { meta }) - .collect() - } - - pub fn with_name(attrs: &[syn::Attribute], name: &str) -> Option { - Self::all_with_name(attrs, name).pop() - } - - pub fn empty(name: &str) -> Self { - Self { - meta: syn::Meta::List(syn::MetaList { - path: syn::Path::from(Ident::new(name, Span::call_site())), - paren_token: Default::default(), - nested: Default::default(), - }), - } - } - - pub fn nested_item(&self, name: &str) -> Result, Diagnostic> { - self.nested() - .map(|mut i| i.find(|n| n.name().is_ident(name))) - } - - pub fn required_nested_item(&self, name: &str) -> Result { - self.nested_item(name)?.ok_or_else(|| { - self.span() - .error(format!("Missing required option `{}`", name)) - }) - } - - pub fn expect_bool_value(&self) -> bool { - match self.str_value().as_ref().map(String::as_str) { - Ok("true") => true, - Ok("false") => false, - _ => { - self.span() - .error(format!( - "`{0}` must be in the form `{0} = \"true\"`", - path_to_string(&self.name()) - )) - .emit(); - false - } - } - } - - pub fn expect_ident_value(&self) -> syn::Ident { - self.ident_value().unwrap_or_else(|e| { - e.emit(); - self.name().segments.first().unwrap().ident.clone() - }) - } - - pub fn ident_value(&self) -> Result { - let maybe_attr = self.nested().ok().and_then(|mut n| n.next()); - let maybe_path = maybe_attr.as_ref().and_then(|m| m.path().ok()); - match maybe_path { - Some(x) => { - self.span() - .warning(format!( - "The form `{0}(value)` is deprecated. Use `{0} = \"value\"` instead", - path_to_string(&self.name()), - )) - .emit(); - Ok(x.segments.first().unwrap().ident.clone()) - } - _ => Ok(syn::Ident::new( - &self.str_value()?, - self.value_span().resolved_at(Span::call_site()), - )), - } - } - - pub fn path_value(&self) -> Result { - let maybe_attr = self.nested().ok().and_then(|mut n| n.next()); - let maybe_path = maybe_attr.as_ref().and_then(|m| m.path().ok()); - match maybe_path { - Some(path) => { - self.span() - .warning(format!( - "The form `{0}(value)` is deprecated. Use `{0} = \"value\"` instead", - path_to_string(&self.name()), - )) - .emit(); - Ok(path) - } - None => { - let lit = self.lit_str_value()?; - match lit.parse() { - Ok(path) => Ok(path), - _ => Err(lit - .span() - .error(format!("`{}` is not a valid path", lit.value()))), - } - } - } - } - - pub fn expect_path(&self) -> syn::Path { - self.path().unwrap_or_else(|e| { - e.emit(); - self.name() - }) - } - - pub fn path(&self) -> Result { - use syn::Meta::*; - - match self.meta { - Path(ref x) => Ok(x.clone()), - _ => { - let meta = &self.meta; - Err(self.span().error(format!( - "Expected `{}` found `{}`", - path_to_string(&self.name()), - quote!(#meta) - ))) - } - } - } - - pub fn nested(&self) -> Result { - use syn::Meta::*; - - match self.meta { - List(ref list) => Ok(Nested(list.nested.iter())), - _ => Err(self.span().error(format!( - "`{0}` must be in the form `{0}(...)`", - path_to_string(&self.name()) - ))), - } - } - - pub fn name(&self) -> syn::Path { - self.meta.path().clone() - } - - pub fn has_flag(&self, flag: &str) -> bool { - self.nested() - .map(|mut n| { - n.any(|m| match m.path() { - Ok(word) => word.is_ident(flag), - Err(_) => false, - }) - }) - .unwrap_or_else(|e| { - e.emit(); - false - }) - } - - pub fn ty_value(&self) -> Result { - let str = self.lit_str_value()?; - str.parse().map_err(|_| { - str.span() - .error(format!("Invalid Rust type: `{}`", str.value())) - }) - } - - pub fn expect_str_value(&self) -> String { - self.str_value().unwrap_or_else(|e| { - e.emit(); - path_to_string(&self.name()) - }) - } - - pub fn str_value(&self) -> Result { - self.lit_str_value().map(syn::LitStr::value) - } - - fn lit_str_value(&self) -> Result<&syn::LitStr, Diagnostic> { - use syn::Lit::*; - - match *self.lit_value()? { - Str(ref s) => Ok(s), - _ => Err(self.span().error(format!( - "`{0}` must be in the form `{0} = \"value\"`", - path_to_string(&self.name()) - ))), - } - } - - pub fn expect_int_value(&self) -> u64 { - self.int_value().emit_error().unwrap_or(0) - } - - pub fn int_value(&self) -> Result { - use syn::Lit::*; - - let error = self.value_span().error("Expected a number"); - - match *self.lit_value()? { - Str(ref s) => s.value().parse().map_err(|_| error), - Int(ref i) => i.base10_parse().map_err(|_| error), - _ => Err(error), - } - } - - fn lit_value(&self) -> Result<&syn::Lit, Diagnostic> { - use syn::Meta::*; - - match self.meta { - NameValue(ref name_value) => Ok(&name_value.lit), - _ => Err(self.span().error(format!( - "`{0}` must be in the form `{0} = \"value\"`", - path_to_string(&self.name()) - ))), - } - } - - pub fn warn_if_other_options(&self, options: &[&str]) { - let nested = match self.nested() { - Ok(x) => x, - Err(_) => return, - }; - let unrecognized_options = - nested.filter(|n| !options.iter().any(|&o| n.name().is_ident(o))); - for ignored in unrecognized_options { - ignored - .span() - .warning(format!( - "Option {} has no effect", - path_to_string(&ignored.name()) - )) - .emit(); - } - } - - fn value_span(&self) -> Span { - use syn::Meta::*; - - match self.meta { - Path(ref path) => path.span(), - List(ref meta) => meta.nested.span(), - NameValue(ref meta) => meta.lit.span(), - } - } - - pub fn span(&self) -> Span { - self.meta.span() - } -} - -pub struct Nested<'a>(syn::punctuated::Iter<'a, syn::NestedMeta>); - -impl<'a> Iterator for Nested<'a> { - type Item = MetaItem; - - fn next(&mut self) -> Option { - use syn::NestedMeta::*; - - match self.0.next() { - Some(&Meta(ref item)) => Some(MetaItem { meta: item.clone() }), - Some(_) => self.next(), - None => None, - } - } -} - -/// If the given span is affected by -/// , -/// returns the span of the pound token -struct FixSpan(Span); - -impl Fold for FixSpan { - fn fold_span(&mut self, span: Span) -> Span { - fix_span(span, self.0) - } -} diff --git a/diesel_derives/src/model.rs b/diesel_derives/src/model.rs index 2d083544ea0e..07238db536de 100644 --- a/diesel_derives/src/model.rs +++ b/diesel_derives/src/model.rs @@ -1,106 +1,160 @@ -use proc_macro2::{Ident, Span}; -use syn; +use proc_macro2::Span; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{ + Data, DataStruct, DeriveInput, Field as SynField, Fields, FieldsNamed, FieldsUnnamed, Ident, + LitBool, Path, Type, +}; -use diagnostic_shim::*; -use field::*; -use meta::*; -use resolved_at_shim::*; +use attrs::{parse_attributes, StructAttr}; +use field::Field; +use parsers::{BelongsTo, MysqlType, PostgresType, SqliteType}; +use util::camel_to_snake; pub struct Model { - pub name: syn::Ident, - pub primary_key_names: Vec, - table_name_from_attribute: Option, + name: Path, + table_name: Option, + pub primary_key_names: Vec, + treat_none_as_default_value: Option, + treat_none_as_null: Option, + pub belongs_to: Vec, + pub sql_types: Vec, + pub aggregate: bool, + pub not_sized: bool, + pub foreign_derive: bool, + pub mysql_type: Option, + pub sqlite_type: Option, + pub postgres_type: Option, fields: Vec, } impl Model { - pub fn from_item(item: &syn::DeriveInput) -> Result { - let table_name_from_attribute = MetaItem::with_name(&item.attrs, "table_name") - .map(|m| m.path_value()) - .transpose()?; - let primary_key_names = MetaItem::with_name(&item.attrs, "primary_key") - .map(|m| { - Ok(m.nested()? - .map(|m| m.expect_path().segments.first().unwrap().ident.clone()) - .collect()) - }) - .unwrap_or_else(|| Ok(vec![Ident::new("id", Span::call_site())]))?; - let fields = fields_from_item_data(&item.data)?; - Ok(Self { - name: item.ident.clone(), - table_name_from_attribute, + pub fn from_item(item: &DeriveInput, allow_unit_structs: bool) -> Self { + let DeriveInput { + data, ident, attrs, .. + } = item; + + let fields = match *data { + Data::Struct(DataStruct { + fields: Fields::Named(FieldsNamed { ref named, .. }), + .. + }) => Some(named), + Data::Struct(DataStruct { + fields: Fields::Unnamed(FieldsUnnamed { ref unnamed, .. }), + .. + }) => Some(unnamed), + _ if !allow_unit_structs => { + abort_call_site!("This derive can only be used on non-unit structs") + } + _ => None, + }; + + let mut table_name = None; + let mut primary_key_names = vec![Ident::new("id", Span::call_site())]; + let mut treat_none_as_default_value = None; + let mut treat_none_as_null = None; + let mut belongs_to = vec![]; + let mut sql_types = vec![]; + let mut aggregate = false; + let mut not_sized = false; + let mut foreign_derive = false; + let mut mysql_type = None; + let mut sqlite_type = None; + let mut postgres_type = None; + + for attr in parse_attributes(attrs) { + match attr { + StructAttr::SqlType(_, value) => sql_types.push(value), + StructAttr::TableName(_, value) => table_name = Some(value), + StructAttr::PrimaryKey(_, keys) => { + primary_key_names = keys.into_iter().collect(); + } + StructAttr::TreatNoneAsDefaultValue(_, val) => { + treat_none_as_default_value = Some(val) + } + StructAttr::TreatNoneAsNull(_, val) => treat_none_as_null = Some(val), + StructAttr::BelongsTo(_, val) => belongs_to.push(val), + StructAttr::Aggregate(_) => aggregate = true, + StructAttr::NotSized(_) => not_sized = true, + StructAttr::ForeignDerive(_) => foreign_derive = true, + StructAttr::MysqlType(_, val) => mysql_type = Some(val), + StructAttr::SqliteType(_, val) => sqlite_type = Some(val), + StructAttr::PostgresType(_, val) => postgres_type = Some(val), + } + } + + let name = Ident::new(&infer_table_name(&ident.to_string()), ident.span()).into(); + + Self { + name, + table_name, primary_key_names, - fields, - }) + treat_none_as_default_value, + treat_none_as_null, + belongs_to, + sql_types, + aggregate, + not_sized, + foreign_derive, + mysql_type, + sqlite_type, + postgres_type, + fields: fields_from_item_data(fields), + } } - pub fn table_name(&self) -> syn::Path { - self.table_name_from_attribute.clone().unwrap_or_else(|| { - syn::Ident::new( - &infer_table_name(&self.name.to_string()), - self.name.span().resolved_at(Span::call_site()), - ) - .into() - }) + pub fn table_name(&self) -> &Path { + self.table_name.as_ref().unwrap_or(&self.name) } pub fn fields(&self) -> &[Field] { &self.fields } - pub fn find_column(&self, column_name: &syn::Ident) -> Result<&Field, Diagnostic> { + pub fn find_column(&self, column_name: &Ident) -> &Field { self.fields() .iter() - .find(|f| &f.column_name_ident() == column_name) - .ok_or_else(|| { - column_name - .span() - .error(format!("No field with column name {}", column_name)) - }) + .find(|f| f.column_name() == column_name) + .unwrap_or_else(|| abort!(column_name, "No field with column name {}", column_name)) } pub fn has_table_name_attribute(&self) -> bool { - self.table_name_from_attribute.is_some() + self.table_name.is_some() } -} -pub fn camel_to_snake(name: &str) -> String { - let mut result = String::with_capacity(name.len()); - result.push_str(&name[..1].to_lowercase()); - for character in name[1..].chars() { - if character.is_uppercase() { - result.push('_'); - for lowercase in character.to_lowercase() { - result.push(lowercase); - } - } else { - result.push(character); - } + pub fn treat_none_as_default_value(&self) -> bool { + self.treat_none_as_default_value + .as_ref() + .map(|v| v.value()) + .unwrap_or(true) + } + + pub fn treat_none_as_null(&self) -> bool { + self.treat_none_as_null + .as_ref() + .map(|v| v.value()) + .unwrap_or(false) } - result } -fn infer_table_name(name: &str) -> String { +fn fields_from_item_data(fields: Option<&Punctuated>) -> Vec { + fields + .map(|fields| { + fields + .iter() + .enumerate() + .map(|(i, f)| Field::from_struct_field(f, i)) + .collect::>() + }) + .unwrap_or_default() +} + +pub fn infer_table_name(name: &str) -> String { let mut result = camel_to_snake(name); result.push('s'); result } -fn fields_from_item_data(data: &syn::Data) -> Result, Diagnostic> { - use syn::Data::*; - - let struct_data = match *data { - Struct(ref d) => d, - _ => return Err(Span::call_site().error("This derive can only be used on structs")), - }; - Ok(struct_data - .fields - .iter() - .enumerate() - .map(|(i, f)| Field::from_struct_field(f, i)) - .collect()) -} - #[test] fn infer_table_name_pluralizes_and_downcases() { assert_eq!("foos", &infer_table_name("Foo")); diff --git a/diesel_derives/src/parsers/belongs_to.rs b/diesel_derives/src/parsers/belongs_to.rs new file mode 100644 index 000000000000..69d33dc442d7 --- /dev/null +++ b/diesel_derives/src/parsers/belongs_to.rs @@ -0,0 +1,51 @@ +use syn::parse::{Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{Ident, TypePath}; + +use util::{parse_eq, unknown_attribute}; + +enum Attr { + ForeignKey(Ident, Ident), +} + +impl Parse for Attr { + fn parse(input: ParseStream) -> Result { + let name: Ident = input.parse()?; + let name_str = name.to_string(); + + match &*name_str { + "foreign_key" => Ok(Attr::ForeignKey(name, parse_eq(input)?)), + + _ => unknown_attribute(&name), + } + } +} + +pub struct BelongsTo { + pub parent: TypePath, + pub foreign_key: Option, +} + +impl Parse for BelongsTo { + fn parse(input: ParseStream) -> Result { + let parent = input.parse()?; + + if !input.is_empty() { + input.parse::()?; + } + + let mut foreign_key = None; + + for attr in Punctuated::::parse_terminated(input)? { + match attr { + Attr::ForeignKey(_, value) => foreign_key = Some(value), + } + } + + Ok(BelongsTo { + parent, + foreign_key, + }) + } +} diff --git a/diesel_derives/src/parsers/mod.rs b/diesel_derives/src/parsers/mod.rs new file mode 100644 index 000000000000..f351d516526d --- /dev/null +++ b/diesel_derives/src/parsers/mod.rs @@ -0,0 +1,9 @@ +mod belongs_to; +mod mysql_type; +mod postgres_type; +mod sqlite_type; + +pub use self::belongs_to::BelongsTo; +pub use self::mysql_type::MysqlType; +pub use self::postgres_type::PostgresType; +pub use self::sqlite_type::SqliteType; diff --git a/diesel_derives/src/parsers/mysql_type.rs b/diesel_derives/src/parsers/mysql_type.rs new file mode 100644 index 000000000000..8e1b8cf1b93a --- /dev/null +++ b/diesel_derives/src/parsers/mysql_type.rs @@ -0,0 +1,45 @@ +use syn::parse::{Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{Ident, LitStr}; + +use util::{parse_eq, unknown_attribute}; + +enum Attr { + Name(Ident, LitStr), +} + +impl Parse for Attr { + fn parse(input: ParseStream) -> Result { + let name: Ident = input.parse()?; + let name_str = name.to_string(); + + match &*name_str { + "name" => Ok(Attr::Name(name, parse_eq(input)?)), + + _ => unknown_attribute(&name), + } + } +} + +pub struct MysqlType { + pub name: LitStr, +} + +impl Parse for MysqlType { + fn parse(input: ParseStream) -> Result { + let mut name = None; + + for attr in Punctuated::::parse_terminated(input)? { + match attr { + Attr::Name(_, value) => name = Some(value), + } + } + + if let Some(name) = name { + Ok(MysqlType { name }) + } else { + abort!(input.span(), "expected attribute `name`"); + } + } +} diff --git a/diesel_derives/src/parsers/postgres_type.rs b/diesel_derives/src/parsers/postgres_type.rs new file mode 100644 index 000000000000..be43764bcfad --- /dev/null +++ b/diesel_derives/src/parsers/postgres_type.rs @@ -0,0 +1,75 @@ +use proc_macro_error::abort; +use syn::parse::{Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{Ident, LitInt, LitStr}; + +use util::{parse_eq, unknown_attribute}; + +enum Attr { + Oid(Ident, LitInt), + ArrayOid(Ident, LitInt), + Name(Ident, LitStr), + Schema(Ident, LitStr), +} + +impl Parse for Attr { + fn parse(input: ParseStream) -> Result { + let name: Ident = input.parse()?; + let name_str = name.to_string(); + + match &*name_str { + "oid" => Ok(Attr::Oid(name, parse_eq(input)?)), + "array_oid" => Ok(Attr::ArrayOid(name, parse_eq(input)?)), + "name" => Ok(Attr::Name(name, parse_eq(input)?)), + "schema" => Ok(Attr::Schema(name, parse_eq(input)?)), + + _ => unknown_attribute(&name), + } + } +} + +pub enum PostgresType { + Fixed(LitInt, LitInt), + Lookup(LitStr, Option), +} + +impl Parse for PostgresType { + fn parse(input: ParseStream) -> Result { + let mut oid = None; + let mut array_oid = None; + let mut name = None; + let mut schema = None; + + for attr in Punctuated::::parse_terminated(input)? { + match attr { + Attr::Oid(_, value) => oid = Some(value), + Attr::ArrayOid(_, value) => array_oid = Some(value), + Attr::Name(_, value) => name = Some(value), + Attr::Schema(_, value) => schema = Some(value), + } + } + + if let Some(name) = name { + if oid.is_some() { + abort!(oid, "unexpected `oid` when `name` is present"); + } else if array_oid.is_some() { + abort!(array_oid, "unexpected `array_oid` when `name` is present"); + } + + Ok(PostgresType::Lookup(name, schema)) + } else if let Some(schema) = schema { + abort!( + schema, "expected `name` to be also present"; + help = "make sure `name` is present, `#[diesel(postgres_type(name = \"...\", schema = \"{}\"))]`", schema.value() + ); + } else if let (Some(oid), Some(array_oid)) = (oid, array_oid) { + Ok(PostgresType::Fixed(oid, array_oid)) + } else { + abort!( + input.span(), + "expected `oid` and `array_oid` attribute or `name` attribute" + ); + } + } +} diff --git a/diesel_derives/src/parsers/sqlite_type.rs b/diesel_derives/src/parsers/sqlite_type.rs new file mode 100644 index 000000000000..dadb48f3895d --- /dev/null +++ b/diesel_derives/src/parsers/sqlite_type.rs @@ -0,0 +1,45 @@ +use syn::parse::{Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{Ident, LitStr}; + +use util::{parse_eq, unknown_attribute}; + +enum Attr { + Name(Ident, LitStr), +} + +impl Parse for Attr { + fn parse(input: ParseStream) -> Result { + let name: Ident = input.parse()?; + let name_str = name.to_string(); + + match &*name_str { + "name" => Ok(Attr::Name(name, parse_eq(input)?)), + + _ => unknown_attribute(&name), + } + } +} + +pub struct SqliteType { + pub name: LitStr, +} + +impl Parse for SqliteType { + fn parse(input: ParseStream) -> Result { + let mut name = None; + + for attr in Punctuated::::parse_terminated(input)? { + match attr { + Attr::Name(_, value) => name = Some(value), + } + } + + if let Some(name) = name { + Ok(SqliteType { name }) + } else { + abort!(input.span(), "expected attribute `name`"); + } + } +} diff --git a/diesel_derives/src/query_id.rs b/diesel_derives/src/query_id.rs index bfa561ca0d1b..2c681d523a42 100644 --- a/diesel_derives/src/query_id.rs +++ b/diesel_derives/src/query_id.rs @@ -1,9 +1,9 @@ -use proc_macro2; -use syn; +use proc_macro2::TokenStream; +use syn::DeriveInput; -use util::*; +use util::wrap_in_dummy_mod; -pub fn derive(mut item: syn::DeriveInput) -> Result { +pub fn derive(mut item: DeriveInput) -> TokenStream { for ty_param in item.generics.type_params_mut() { ty_param.bounds.push(parse_quote!(QueryId)); } @@ -11,18 +11,21 @@ pub fn derive(mut item: syn::DeriveInput) -> Result>(); + + let query_id_ty_params = ty_params + .iter() .map(|ty_param| quote!(<#ty_param as QueryId>::QueryId)); - let has_static_query_id = item - .generics - .type_params() - .map(|ty_param| &ty_param.ident) + let has_static_query_id = ty_params + .iter() .map(|ty_param| quote!(<#ty_param as QueryId>::HAS_STATIC_QUERY_ID)); - Ok(wrap_in_dummy_mod(quote! { + wrap_in_dummy_mod(quote! { use diesel::query_builder::QueryId; #[allow(non_camel_case_types)] @@ -33,5 +36,5 @@ pub fn derive(mut item: syn::DeriveInput) -> Result Result { - let model = Model::from_item(&item)?; +pub fn derive(item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, false); let struct_name = &item.ident; - let field_ty = model + let field_ty = &model .fields() .iter() .map(Field::ty_for_deserialize) - .collect::, _>>()?; - let field_ty = &field_ty; + .collect::>(); let build_expr = model.fields().iter().enumerate().map(|(i, f)| { - let i = syn::Index::from(i); - f.name.assign(parse_quote!(row.#i.try_into()?)) + let field_name = &f.name; + let i = Index::from(i); + quote!(#field_name: row.#i.try_into()?) }); - let sql_type = (0..model.fields().len()) + let sql_type = &(0..model.fields().len()) .map(|i| { - let i = syn::Ident::new(&format!("__ST{}", i), proc_macro2::Span::call_site()); + let i = Ident::new(&format!("__ST{}", i), Span::call_site()); quote!(#i) }) .collect::>(); - let sql_type = &sql_type; let (_, ty_generics, _) = item.generics.split_for_impl(); let mut generics = item.generics.clone(); @@ -33,7 +32,7 @@ pub fn derive(item: syn::DeriveInput) -> Result Result Result Result { - let model = Model::from_item(&item)?; +pub fn derive(item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, false); let struct_name = &item.ident; - let fields = model.fields().iter().map(get_ident).collect::>(); - let field_names = model.fields().iter().map(|f| &f.name).collect::>(); + let fields = &model.fields().iter().map(get_ident).collect::>(); + let field_names = model.fields().iter().map(|f| &f.name); - let initial_field_expr = model - .fields() - .iter() - .map(|f| { - let field_ty = &f.ty; + let initial_field_expr = model.fields().iter().map(|f| { + let field_ty = &f.ty; - if f.has_flag("embed") { - Ok(quote!(<#field_ty as QueryableByName<__DB>>::build( - row, - )?)) - } else { - let deserialize_ty = f.ty_for_deserialize()?; - let name = f.column_name_str(); - Ok(quote!( - { - let field = diesel::row::NamedRow::get(row, #name)?; - <#deserialize_ty as Into<#field_ty>>::into(field) - } - )) - } - }) - .collect::, Diagnostic>>()?; + if f.embed { + quote!(<#field_ty as QueryableByName<__DB>>::build(row)?) + } else { + let deserialize_ty = f.ty_for_deserialize(); + let name = f.column_name(); + let name = LitStr::new(&name.to_string(), name.span()); + quote!( + { + let field = diesel::row::NamedRow::get(row, #name)?; + <#deserialize_ty as Into<#field_ty>>::into(field) + } + ) + } + }); let (_, ty_generics, ..) = item.generics.split_for_impl(); let mut generics = item.generics.clone(); @@ -43,8 +38,8 @@ pub fn derive(item: syn::DeriveInput) -> Result)); @@ -58,7 +53,7 @@ pub fn derive(item: syn::DeriveInput) -> Result Result(row: &impl NamedRow<'__a, __DB>) -> deserialize::Result { - - #( let mut #fields = #initial_field_expr; )* @@ -81,39 +74,34 @@ pub fn derive(item: syn::DeriveInput) -> Result Ident { match &field.name { FieldName::Named(n) => n.clone(), - FieldName::Unnamed(i) => Ident::new(&format!("field_{}", i.index), Span::call_site()), + FieldName::Unnamed(i) => Ident::new(&format!("field_{}", i.index), i.span), } } -fn sql_type(field: &Field, model: &Model) -> syn::Type { +fn sql_type(field: &Field, model: &Model) -> Type { let table_name = model.table_name(); match field.sql_type { Some(ref st) => st.clone(), None => { if model.has_table_name_attribute() { - let column_name = field.column_name_ident(); + let column_name = field.column_name(); parse_quote!(diesel::dsl::SqlTypeOf<#table_name::#column_name>) } else { let field_name = match field.name { FieldName::Named(ref x) => x.clone(), _ => Ident::new("field", Span::call_site()), }; - field - .span - .error(format!("Cannot determine the SQL type of {}", field_name)) - .help( - "Your struct must either be annotated with `#[table_name = \"foo\"]` \ - or have all of its fields annotated with `#[sql_type = \"Integer\"]`", - ) - .emit(); - parse_quote!(()) + abort!( + field.span, "Cannot determine the SQL type of {}", field_name; + help = "Your struct must either be annotated with `#[diesel(table_name = foo)]` or have this field annotated with `#[diesel(sql_type = ...)]`"; + ); } } } diff --git a/diesel_derives/src/resolved_at_shim.rs b/diesel_derives/src/resolved_at_shim.rs deleted file mode 100644 index 280873344a66..000000000000 --- a/diesel_derives/src/resolved_at_shim.rs +++ /dev/null @@ -1,19 +0,0 @@ -use proc_macro2::Span; - -pub trait ResolvedAtExt { - fn resolved_at(self, span: Span) -> Span; -} - -#[cfg(feature = "nightly")] -impl ResolvedAtExt for Span { - fn resolved_at(self, span: Span) -> Span { - self.unstable().resolved_at(span.unstable()).into() - } -} - -#[cfg(not(feature = "nightly"))] -impl ResolvedAtExt for Span { - fn resolved_at(self, _: Span) -> Span { - self - } -} diff --git a/diesel_derives/src/selectable.rs b/diesel_derives/src/selectable.rs index 4417ab88c7de..549e89f99aa8 100644 --- a/diesel_derives/src/selectable.rs +++ b/diesel_derives/src/selectable.rs @@ -1,12 +1,12 @@ -use proc_macro2; -use syn; +use proc_macro2::TokenStream; +use syn::DeriveInput; -use field::*; -use model::*; -use util::*; +use field::Field; +use model::Model; +use util::wrap_in_dummy_mod; -pub fn derive(item: syn::DeriveInput) -> Result { - let model = Model::from_item(&item)?; +pub fn derive(item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, false); let (_, ty_generics, _) = item.generics.split_for_impl(); @@ -14,7 +14,8 @@ pub fn derive(item: syn::DeriveInput) -> Result Result)); } + let (impl_generics, _, where_clause) = generics.split_for_impl(); let struct_name = &item.ident; let field_columns_ty = model.fields().iter().map(|f| field_column_ty(f, &model)); - let field_columns_inst = model.fields().iter().map(|f| field_column_inst(f, &model)); - Ok(wrap_in_dummy_mod(quote! { + wrap_in_dummy_mod(quote! { use diesel::expression::Selectable; impl #impl_generics Selectable<__DB> @@ -43,27 +44,27 @@ pub fn derive(item: syn::DeriveInput) -> Result syn::Type { - if field.has_flag("embed") { +fn field_column_ty(field: &Field, model: &Model) -> TokenStream { + if field.embed { let embed_ty = &field.ty; - parse_quote!(<#embed_ty as Selectable<__DB>>::SelectExpression) + quote!(<#embed_ty as Selectable<__DB>>::SelectExpression) } else { let table_name = model.table_name(); - let column_name = field.column_name_ident(); - parse_quote!(#table_name::#column_name) + let column_name = field.column_name(); + quote!(#table_name::#column_name) } } -fn field_column_inst(field: &Field, model: &Model) -> syn::Expr { - if field.has_flag("embed") { +fn field_column_inst(field: &Field, model: &Model) -> TokenStream { + if field.embed { let embed_ty = &field.ty; - parse_quote!(<#embed_ty as Selectable<__DB>>::construct_selection()) + quote!(<#embed_ty as Selectable<__DB>>::construct_selection()) } else { let table_name = model.table_name(); - let column_name = field.column_name_ident(); - parse_quote!(#table_name::#column_name) + let column_name = field.column_name(); + quote!(#table_name::#column_name) } } diff --git a/diesel_derives/src/sql_function.rs b/diesel_derives/src/sql_function.rs index dda7ff01f5ea..1843db4b55d0 100644 --- a/diesel_derives/src/sql_function.rs +++ b/diesel_derives/src/sql_function.rs @@ -1,18 +1,12 @@ -use proc_macro2::*; +use proc_macro2::TokenStream; use quote::ToTokens; -use syn::parse::{self, Parse, ParseStream}; +use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; +use syn::{ + Attribute, GenericArgument, Generics, Ident, Lit, Meta, MetaNameValue, PathArguments, Type, +}; -use meta::*; -use util::*; - -// Extremely curious why this triggers on a nearly branchless function -#[allow(clippy::cognitive_complexity)] -// for loop comes from `quote!` -#[allow(clippy::for_loops_over_fallibles)] -// https://github.com/rust-lang/rust-clippy/issues/3768 -#[allow(clippy::useless_let_if_seq)] -pub(crate) fn expand(input: SqlFunctionDecl) -> Result { +pub(crate) fn expand(input: SqlFunctionDecl) -> TokenStream { let SqlFunctionDecl { mut attributes, fn_token, @@ -22,10 +16,30 @@ pub(crate) fn expand(input: SqlFunctionDecl) -> Result return_type, } = input; - let sql_name = MetaItem::with_name(&attributes, "sql_name") - .map(|m| m.str_value()) - .unwrap_or_else(|| Ok(fn_name.to_string()))?; - let is_aggregate = MetaItem::with_name(&attributes, "aggregate").is_some(); + let sql_name = attributes + .iter() + .find(|attr| { + attr.parse_meta() + .map(|m| m.path().is_ident("sql_name")) + .unwrap_or(false) + }) + .and_then(|attr| { + if let Ok(Meta::NameValue(MetaNameValue { + lit: Lit::Str(lit), .. + })) = attr.parse_meta() + { + Some(lit.value()) + } else { + None + } + }) + .unwrap_or_else(|| fn_name.to_string()); + + let is_aggregate = attributes.iter().any(|attr| { + attr.parse_meta() + .map(|m| m.path().is_ident("aggregate")) + .unwrap_or(false) + }); attributes.retain(|attr| { attr.parse_meta() @@ -366,7 +380,8 @@ pub(crate) fn expand(input: SqlFunctionDecl) -> Result } let args_iter = args.iter(); - tokens = quote! { + + quote! { #(#attributes)* #[allow(non_camel_case_types)] pub #fn_token #fn_name #impl_generics (#(#args_iter,)*) @@ -385,31 +400,29 @@ pub(crate) fn expand(input: SqlFunctionDecl) -> Result pub(crate) mod #fn_name { #tokens } - }; - - Ok(tokens) + } } pub(crate) struct SqlFunctionDecl { - attributes: Vec, + attributes: Vec, fn_token: Token![fn], - fn_name: syn::Ident, - generics: syn::Generics, + fn_name: Ident, + generics: Generics, args: Punctuated, - return_type: syn::Type, + return_type: Type, } impl Parse for SqlFunctionDecl { - fn parse(input: ParseStream) -> parse::Result { - let attributes = syn::Attribute::parse_outer(input)?; + fn parse(input: ParseStream) -> Result { + let attributes = Attribute::parse_outer(input)?; let fn_token: Token![fn] = input.parse()?; - let fn_name = syn::Ident::parse(input)?; - let generics = syn::Generics::parse(input)?; + let fn_name = Ident::parse(input)?; + let generics = Generics::parse(input)?; let args; let _paren = parenthesized!(args in input); let args = args.parse_terminated::<_, Token![,]>(StrictFnArg::parse)?; let return_type = if Option::]>::parse(input)?.is_some() { - syn::Type::parse(input)? + Type::parse(input)? } else { parse_quote!(diesel::expression::expression_types::NotSelectable) }; @@ -426,15 +439,15 @@ impl Parse for SqlFunctionDecl { } } -/// Essentially the same as syn::ArgCaptured, but only allowing ident patterns +/// Essentially the same as ArgCaptured, but only allowing ident patterns struct StrictFnArg { - name: syn::Ident, + name: Ident, colon_token: Token![:], - ty: syn::Type, + ty: Type, } impl Parse for StrictFnArg { - fn parse(input: ParseStream) -> parse::Result { + fn parse(input: ParseStream) -> Result { let name = input.parse()?; let colon_token = input.parse()?; let ty = input.parse()?; @@ -454,8 +467,8 @@ impl ToTokens for StrictFnArg { } } -fn is_sqlite_type(ty: &syn::Type) -> bool { - let last_segment = if let syn::Type::Path(tp) = ty { +fn is_sqlite_type(ty: &Type) -> bool { + let last_segment = if let Type::Path(tp) = ty { if let Some(segment) = tp.path.segments.last() { segment } else { @@ -467,8 +480,8 @@ fn is_sqlite_type(ty: &syn::Type) -> bool { let ident = last_segment.ident.to_string(); if ident == "Nullable" { - if let syn::PathArguments::AngleBracketed(ref ab) = last_segment.arguments { - if let Some(syn::GenericArgument::Type(ty)) = ab.args.first() { + if let PathArguments::AngleBracketed(ref ab) = last_segment.arguments { + if let Some(GenericArgument::Type(ty)) = ab.args.first() { return is_sqlite_type(&ty); } } diff --git a/diesel_derives/src/sql_type.rs b/diesel_derives/src/sql_type.rs index 541705267942..d51e60fa58f9 100644 --- a/diesel_derives/src/sql_type.rs +++ b/diesel_derives/src/sql_type.rs @@ -1,18 +1,21 @@ -use proc_macro2; -use syn; +use proc_macro2::{Span, TokenStream}; +use syn::{DeriveInput, Ident}; -use meta::*; -use util::*; +use model::Model; +use parsers::PostgresType; +use util::wrap_in_dummy_mod; + +pub fn derive(item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, true); -pub fn derive(item: syn::DeriveInput) -> Result { let struct_name = &item.ident; let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl(); - let sqlite_tokens = sqlite_tokens(&item); - let mysql_tokens = mysql_tokens(&item); - let pg_tokens = pg_tokens(&item); + let sqlite_tokens = sqlite_tokens(&item, &model); + let mysql_tokens = mysql_tokens(&item, &model); + let pg_tokens = pg_tokens(&item, &model); - Ok(wrap_in_dummy_mod(quote! { + wrap_in_dummy_mod(quote! { impl #impl_generics diesel::sql_types::SqlType for #struct_name #ty_generics #where_clause @@ -29,12 +32,14 @@ pub fn derive(item: syn::DeriveInput) -> Result Option { - MetaItem::with_name(&item.attrs, "sqlite_type") - .map(|attr| attr.expect_ident_value()) +fn sqlite_tokens(item: &DeriveInput, model: &Model) -> Option { + model + .sqlite_type + .as_ref() + .map(|sqlite_type| Ident::new(&sqlite_type.name.value(), Span::call_site())) .and_then(|ty| { if cfg!(not(feature = "sqlite")) { return None; @@ -56,9 +61,11 @@ fn sqlite_tokens(item: &syn::DeriveInput) -> Option { }) } -fn mysql_tokens(item: &syn::DeriveInput) -> Option { - MetaItem::with_name(&item.attrs, "mysql_type") - .map(|attr| attr.expect_ident_value()) +fn mysql_tokens(item: &DeriveInput, model: &Model) -> Option { + model + .mysql_type + .as_ref() + .map(|mysql_type| Ident::new(&mysql_type.name.value(), Span::call_site())) .and_then(|ty| { if cfg!(not(feature = "mysql")) { return None; @@ -80,86 +87,42 @@ fn mysql_tokens(item: &syn::DeriveInput) -> Option { }) } -fn pg_tokens(item: &syn::DeriveInput) -> Option { - MetaItem::with_name(&item.attrs, "postgres") - .map(|attr| { - if let Some(x) = get_type_name(&attr)? { - Ok(x) - } else if let Some(x) = get_oids(&attr)? { - Ok(x) - } else { - Err(attr - .span() - .error("Missing required options") - .help("Valid options are `type_name` or `oid` and `array_oid`")) - } - }) - .and_then(|res| res.map_err(Diagnostic::emit).ok()) - .and_then(|ty| { - if cfg!(not(feature = "postgres")) { - return None; - } - - let struct_name = &item.ident; - let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl(); - - let metadata_fn = match ty { - PgType::Fixed { oid, array_oid } => quote!( - fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata { - PgTypeMetadata::new(#oid, #array_oid) - } - ), - PgType::Lookup(type_name, Some(type_schema)) => quote!( - fn metadata(lookup: &mut Self::MetadataLookup) -> PgTypeMetadata { - lookup.lookup_type(#type_name, Some(#type_schema)) - } - ), - PgType::Lookup(type_name, None) => quote!( - fn metadata(lookup: &mut Self::MetadataLookup) -> PgTypeMetadata { - lookup.lookup_type(#type_name, None) - } - ), - }; +fn pg_tokens(item: &DeriveInput, model: &Model) -> Option { + model.postgres_type.as_ref().and_then(|ty| { + if cfg!(not(feature = "postgres")) { + return None; + } - Some(quote! { - use diesel::pg::{PgMetadataLookup, PgTypeMetadata}; + let struct_name = &item.ident; + let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl(); - impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics> - for diesel::pg::Pg - #where_clause - { - #metadata_fn + let metadata_fn = match ty { + PostgresType::Fixed(oid, array_oid) => quote!( + fn metadata(_: &mut Self::MetadataLookup) -> PgTypeMetadata { + PgTypeMetadata::new(#oid, #array_oid) } - }) - }) -} + ), + PostgresType::Lookup(type_name, Some(type_schema)) => quote!( + fn metadata(lookup: &mut Self::MetadataLookup) -> PgTypeMetadata { + lookup.lookup_type(#type_name, Some(#type_schema)) + } + ), + PostgresType::Lookup(type_name, None) => quote!( + fn metadata(lookup: &mut Self::MetadataLookup) -> PgTypeMetadata { + lookup.lookup_type(#type_name, None) + } + ), + }; -fn get_type_name(attr: &MetaItem) -> Result, Diagnostic> { - let schema = attr.nested_item("type_schema")?; - Ok(attr.nested_item("type_name")?.map(|ty| { - attr.warn_if_other_options(&["type_name", "type_schema"]); - PgType::Lookup( - ty.expect_str_value(), - schema.map(|schema| schema.expect_str_value()), - ) - })) -} + Some(quote! { + use diesel::pg::{PgMetadataLookup, PgTypeMetadata}; -fn get_oids(attr: &MetaItem) -> Result, Diagnostic> { - if let Some(oid) = attr.nested_item("oid")? { - attr.warn_if_other_options(&["oid", "array_oid"]); - let array_oid = attr.required_nested_item("array_oid")?.expect_int_value(); - let oid = oid.expect_int_value(); - Ok(Some(PgType::Fixed { - oid: oid as u32, - array_oid: array_oid as u32, - })) - } else { - Ok(None) - } -} - -enum PgType { - Fixed { oid: u32, array_oid: u32 }, - Lookup(String, Option), + impl #impl_generics diesel::sql_types::HasSqlType<#struct_name #ty_generics> + for diesel::pg::Pg + #where_clause + { + #metadata_fn + } + }) + }) } diff --git a/diesel_derives/src/util.rs b/diesel_derives/src/util.rs index 057a03bec707..fe36fb1111fe 100644 --- a/diesel_derives/src/util.rs +++ b/diesel_derives/src/util.rs @@ -1,8 +1,28 @@ -pub use diagnostic_shim::{Diagnostic, DiagnosticShim, EmitErrorExt}; +use proc_macro2::TokenStream; +use syn::parse::{Parse, ParseStream, Result}; +use syn::token::Eq; +use syn::{parenthesized, Data, DeriveInput, GenericArgument, Ident, Type}; -use meta::MetaItem; -use proc_macro2::{Span, TokenStream}; -use syn::{Data, DeriveInput, GenericArgument, Type}; +use model::Model; + +pub fn unknown_attribute(name: &Ident) -> ! { + abort!(name, "unknown attribute") +} + +pub fn parse_eq(input: ParseStream) -> Result { + if input.is_empty() { + abort!(input.span(), "unexpected end of input, expected `=`"); + } + + input.parse::()?; + input.parse() +} + +pub fn parse_paren(input: ParseStream) -> Result { + let content; + parenthesized!(content in input); + content.parse() +} pub fn wrap_in_dummy_mod(item: TokenStream) -> TokenStream { quote! { @@ -49,37 +69,34 @@ fn option_ty_arg(ty: &Type) -> Option<&Type> { } } -pub fn ty_for_foreign_derive(item: &DeriveInput, flags: &MetaItem) -> Result { - if flags.has_flag("foreign_derive") { +pub fn ty_for_foreign_derive(item: &DeriveInput, model: &Model) -> Type { + if model.foreign_derive { match item.data { Data::Struct(ref body) => match body.fields.iter().next() { - Some(field) => Ok(field.ty.clone()), - None => Err(flags - .span() - .error("foreign_derive requires at least one field")), + Some(field) => field.ty.clone(), + None => abort_call_site!("foreign_derive requires at least one field"), }, - _ => Err(flags - .span() - .error("foreign_derive can only be used with structs")), + _ => abort_call_site!("foreign_derive can only be used with structs"), } } else { let ident = &item.ident; let (_, ty_generics, ..) = item.generics.split_for_impl(); - Ok(parse_quote!(#ident #ty_generics)) + parse_quote!(#ident #ty_generics) } } -pub fn fix_span(maybe_bad_span: Span, mut fallback: Span) -> Span { - let bad_span_debug = "#0 bytes(0..0)"; - - if format!("{:?}", fallback) == bad_span_debug { - // On recent rust nightlies, even our fallback span is bad. - fallback = Span::call_site(); - } - - if format!("{:?}", maybe_bad_span) == bad_span_debug { - fallback - } else { - maybe_bad_span +pub fn camel_to_snake(name: &str) -> String { + let mut result = String::with_capacity(name.len()); + result.push_str(&name[..1].to_lowercase()); + for character in name[1..].chars() { + if character.is_uppercase() { + result.push('_'); + for lowercase in character.to_lowercase() { + result.push(lowercase); + } + } else { + result.push(character); + } } + result } diff --git a/diesel_derives/src/valid_grouping.rs b/diesel_derives/src/valid_grouping.rs index 45ec153d048a..7705a7095a01 100644 --- a/diesel_derives/src/valid_grouping.rs +++ b/diesel_derives/src/valid_grouping.rs @@ -1,18 +1,19 @@ -use proc_macro2::*; -use syn; +use proc_macro2::TokenStream; +use syn::DeriveInput; -use meta::*; -use util::*; +use model::Model; +use util::{ty_for_foreign_derive, wrap_in_dummy_mod}; + +pub fn derive(mut item: DeriveInput) -> TokenStream { + let model = Model::from_item(&item, true); + let struct_ty = ty_for_foreign_derive(&item, &model); -pub fn derive(mut item: syn::DeriveInput) -> Result { - let flags = - MetaItem::with_name(&item.attrs, "diesel").unwrap_or_else(|| MetaItem::empty("diesel")); - let struct_ty = ty_for_foreign_derive(&item, &flags)?; let type_params = item .generics .type_params() .map(|param| param.ident.clone()) .collect::>(); + for type_param in type_params { let where_clause = item.generics.make_where_clause(); where_clause @@ -20,12 +21,11 @@ pub fn derive(mut item: syn::DeriveInput) -> Result { .push(parse_quote!(#type_param: ValidGrouping<__GroupByClause>)); } - let is_aggregate = flags.has_flag("aggregate"); - - if is_aggregate { + if model.aggregate { item.generics.params.push(parse_quote!(__GroupByClause)); let (impl_generics, _, where_clause) = item.generics.split_for_impl(); - Ok(wrap_in_dummy_mod(quote! { + + wrap_in_dummy_mod(quote! { use diesel::expression::{ValidGrouping, MixedAggregates, is_aggregate}; impl #impl_generics ValidGrouping<__GroupByClause> for #struct_ty @@ -33,14 +33,15 @@ pub fn derive(mut item: syn::DeriveInput) -> Result { { type IsAggregate = is_aggregate::Yes; } - })) + }) } else { let mut aggregates = item .generics .type_params() - .map(|t| parse_quote!(#t::IsAggregate)) - .collect::>() + .map(|t| quote!(#t::IsAggregate)) + .collect::>() .into_iter(); + let is_aggregate = aggregates .next() .map(|first| { @@ -49,14 +50,15 @@ pub fn derive(mut item: syn::DeriveInput) -> Result { where_clause.predicates.push(parse_quote!( #left: MixedAggregates<#right> )); - parse_quote!(<#left as MixedAggregates<#right>>::Output) + quote!(<#left as MixedAggregates<#right>>::Output) }) }) - .unwrap_or_else(|| parse_quote!(is_aggregate::Never)); + .unwrap_or_else(|| quote!(is_aggregate::Never)); + item.generics.params.push(parse_quote!(__GroupByClause)); let (impl_generics, _, where_clause) = item.generics.split_for_impl(); - Ok(wrap_in_dummy_mod(quote! { + wrap_in_dummy_mod(quote! { use diesel::expression::{ValidGrouping, MixedAggregates, is_aggregate}; impl #impl_generics ValidGrouping<__GroupByClause> for #struct_ty @@ -64,6 +66,6 @@ pub fn derive(mut item: syn::DeriveInput) -> Result { { type IsAggregate = #is_aggregate; } - })) + }) } } diff --git a/diesel_derives/tests/as_changeset.rs b/diesel_derives/tests/as_changeset.rs index 97c7fc2fe8ac..be225f1ef48c 100644 --- a/diesel_derives/tests/as_changeset.rs +++ b/diesel_derives/tests/as_changeset.rs @@ -57,7 +57,7 @@ fn named_struct() { #[test] fn with_explicit_table_name() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct UserForm { name: String, hair_color: String, @@ -84,7 +84,7 @@ fn with_explicit_table_name() { #[test] fn with_path_in_table_name() { #[derive(AsChangeset)] - #[table_name = "crate::schema::users"] + #[diesel(table_name = crate::schema::users)] struct UserForm { name: String, hair_color: String, @@ -111,7 +111,7 @@ fn with_path_in_table_name() { #[test] fn with_lifetime() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct UserForm<'a> { name: &'a str, hair_color: &'a str, @@ -138,7 +138,7 @@ fn with_lifetime() { #[test] fn with_multiple_lifetimes() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct UserForm<'a, 'b> { name: &'a str, hair_color: &'b str, @@ -165,7 +165,7 @@ fn with_multiple_lifetimes() { #[test] fn with_lifetime_constraints() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct UserForm<'a, 'b: 'a> { name: &'a str, hair_color: &'b str, @@ -192,11 +192,11 @@ fn with_lifetime_constraints() { #[test] fn with_explicit_column_names() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct UserForm<'a> { - #[column_name = "name"] + #[diesel(column_name = name)] nombre: &'a str, - #[column_name = "hair_color"] + #[diesel(column_name = hair_color)] color_de_pelo: &'a str, } @@ -221,10 +221,10 @@ fn with_explicit_column_names() { #[test] fn tuple_struct() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct UserForm<'a>( - #[column_name = "name"] &'a str, - #[column_name = "hair_color"] &'a str, + #[diesel(column_name = name)] &'a str, + #[diesel(column_name = hair_color)] &'a str, ); let connection = &mut connection_with_sean_and_tess_in_users_table(); @@ -245,7 +245,7 @@ fn tuple_struct() { #[test] fn struct_containing_single_field() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct UserForm<'a> { name: &'a str, } @@ -268,8 +268,8 @@ fn struct_containing_single_field() { #[test] fn tuple_struct_containing_single_field() { #[derive(AsChangeset)] - #[table_name = "users"] - struct UserForm<'a>(#[column_name = "name"] &'a str); + #[diesel(table_name = users)] + struct UserForm<'a>(#[diesel(column_name = name)] &'a str); let connection = &mut connection_with_sean_and_tess_in_users_table(); @@ -289,7 +289,7 @@ fn tuple_struct_containing_single_field() { #[test] fn primary_key_is_not_updated() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct UserForm<'a> { #[allow(dead_code)] id: i32, @@ -319,9 +319,9 @@ fn primary_key_is_not_updated() { #[test] fn primary_key_is_based_on_column_name() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct UserForm<'a> { - #[column_name = "id"] + #[diesel(column_name = id)] _id: i32, name: &'a str, hair_color: &'a str, @@ -349,8 +349,8 @@ fn primary_key_is_based_on_column_name() { #[test] fn primary_key_is_not_updated_with_custom_pk() { #[derive(AsChangeset)] - #[table_name = "users"] - #[primary_key(name)] + #[diesel(table_name = users)] + #[diesel(primary_key(name))] struct UserForm<'a> { #[allow(dead_code)] name: &'a str, @@ -378,8 +378,8 @@ fn primary_key_is_not_updated_with_custom_pk() { #[test] fn primary_key_is_not_updated_with_custom_composite_pk() { #[derive(AsChangeset)] - #[table_name = "users"] - #[primary_key(id, name)] + #[diesel(table_name = users)] + #[diesel(primary_key(id, name))] #[allow(dead_code)] struct UserForm<'a> { id: i32, @@ -409,7 +409,7 @@ fn primary_key_is_not_updated_with_custom_composite_pk() { #[test] fn option_fields_are_skipped() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct UserForm<'a> { name: &'a str, hair_color: Option<&'a str>, @@ -443,8 +443,8 @@ fn option_fields_are_skipped() { #[test] fn option_fields_are_assigned_null_when_specified() { #[derive(AsChangeset)] - #[table_name = "users"] - #[changeset_options(treat_none_as_null = "true")] + #[diesel(table_name = users)] + #[diesel(treat_none_as_null = true)] struct UserForm<'a> { name: &'a str, hair_color: Option<&'a str>, diff --git a/diesel_derives/tests/as_expression.rs b/diesel_derives/tests/as_expression.rs index ff55dd37b93b..a154408df319 100644 --- a/diesel_derives/tests/as_expression.rs +++ b/diesel_derives/tests/as_expression.rs @@ -17,7 +17,7 @@ table! { } #[derive(Debug, AsExpression, FromSqlRow, Clone, Copy, PartialEq)] -#[sql_type = "Text"] +#[diesel(sql_type = Text)] struct StringArray(pub [u8; N]); impl FromSql for StringArray @@ -47,7 +47,7 @@ where #[test] fn struct_with_sql_type() { #[derive(Debug, Clone, PartialEq, Queryable, Selectable)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct MyStruct { foo: i32, bar: StringArray<4>, diff --git a/diesel_derives/tests/associations.rs b/diesel_derives/tests/associations.rs index 29cfcd843b18..ea043826b2ba 100644 --- a/diesel_derives/tests/associations.rs +++ b/diesel_derives/tests/associations.rs @@ -28,7 +28,7 @@ fn simple_belongs_to() { } #[derive(Associations, Identifiable)] - #[belongs_to(User)] + #[diesel(belongs_to(User))] pub struct Post { id: i32, user_id: i32, @@ -86,14 +86,14 @@ fn table_in_different_module() { } #[derive(Identifiable)] - #[table_name = "schema::users"] + #[diesel(table_name = schema::users)] pub struct User { id: i32, } #[derive(Associations, Identifiable)] - #[table_name = "schema::posts"] - #[belongs_to(User)] + #[diesel(table_name = schema::posts)] + #[diesel(belongs_to(User))] pub struct Post { id: i32, user_id: i32, @@ -154,7 +154,7 @@ fn custom_foreign_key() { } #[derive(Associations, Identifiable)] - #[belongs_to(User, foreign_key = "belongs_to_user")] + #[diesel(belongs_to(User, foreign_key = belongs_to_user))] pub struct Post { id: i32, belongs_to_user: i32, @@ -198,7 +198,7 @@ fn self_referential() { } #[derive(Associations, Identifiable)] - #[belongs_to(Tree, foreign_key = "parent_id")] + #[diesel(belongs_to(Tree, foreign_key = parent_id))] pub struct Tree { id: i32, parent_id: Option, @@ -249,8 +249,8 @@ fn multiple_associations() { } #[derive(Identifiable, Associations)] - #[belongs_to(User)] - #[belongs_to(Post)] + #[diesel(belongs_to(User))] + #[diesel(belongs_to(Post))] struct Comment { id: i32, user_id: i32, @@ -295,10 +295,10 @@ fn foreign_key_field_with_column_rename() { } #[derive(Associations, Identifiable, Clone, Copy, PartialEq, Debug)] - #[belongs_to(User)] + #[diesel(belongs_to(User))] pub struct Post { id: i32, - #[column_name = "user_id"] + #[diesel(column_name = user_id)] author_id: i32, } @@ -346,8 +346,11 @@ fn tuple_struct() { } #[derive(Associations, Identifiable)] - #[belongs_to(User)] - pub struct Post(#[column_name = "id"] i32, #[column_name = "user_id"] i32); + #[diesel(belongs_to(User))] + pub struct Post( + #[diesel(column_name = id)] i32, + #[diesel(column_name = user_id)] i32, + ); let user = User { id: 1 }; diff --git a/diesel_derives/tests/identifiable.rs b/diesel_derives/tests/identifiable.rs index ea912f951976..e081884dbac0 100644 --- a/diesel_derives/tests/identifiable.rs +++ b/diesel_derives/tests/identifiable.rs @@ -31,9 +31,9 @@ fn derive_identifiable_on_simple_struct() { fn derive_identifiable_on_tuple_struct() { #[derive(Identifiable)] struct Foo( - #[column_name = "id"] i32, + #[diesel(column_name = id)] i32, #[allow(dead_code)] - #[column_name = "lol"] + #[diesel(column_name = lol)] i32, ); @@ -61,7 +61,7 @@ fn derive_identifiable_when_id_is_not_first_field() { #[test] fn derive_identifiable_on_struct_with_non_integer_pk() { #[derive(Identifiable)] - #[table_name = "bars"] + #[diesel(table_name = bars)] struct Foo { id: &'static str, #[allow(dead_code)] @@ -80,7 +80,7 @@ fn derive_identifiable_on_struct_with_non_integer_pk() { #[test] fn derive_identifiable_on_struct_with_lifetime() { #[derive(Identifiable)] - #[table_name = "bars"] + #[diesel(table_name = bars)] struct Foo<'a> { id: &'a str, #[allow(dead_code)] @@ -100,8 +100,8 @@ fn derive_identifiable_on_struct_with_lifetime() { fn derive_identifiable_with_non_standard_pk() { #[allow(dead_code)] #[derive(Identifiable)] - #[table_name = "bars"] - #[primary_key(foo_id)] + #[diesel(table_name = bars)] + #[diesel(primary_key(foo_id))] struct Foo<'a> { id: i32, foo_id: &'a str, @@ -126,8 +126,8 @@ fn derive_identifiable_with_non_standard_pk() { fn derive_identifiable_with_composite_pk() { #[allow(dead_code)] #[derive(Identifiable)] - #[table_name = "bars"] - #[primary_key(foo_id, bar_id)] + #[diesel(table_name = bars)] + #[diesel(primary_key(foo_id, bar_id))] struct Foo { id: i32, foo_id: i32, diff --git a/diesel_derives/tests/insertable.rs b/diesel_derives/tests/insertable.rs index dd18eb0e3cb7..5f6a98f39823 100644 --- a/diesel_derives/tests/insertable.rs +++ b/diesel_derives/tests/insertable.rs @@ -5,7 +5,7 @@ use schema::*; #[test] fn simple_struct_definition() { #[derive(Insertable)] - #[table_name = "users"] + #[diesel(table_name = users)] struct NewUser { name: String, hair_color: String, @@ -56,7 +56,7 @@ fn with_implicit_table_name() { #[test] fn with_path_in_table_name() { #[derive(Insertable)] - #[table_name = "crate::schema::users"] + #[diesel(table_name = crate::schema::users)] struct NewUser { name: String, hair_color: String, @@ -82,7 +82,7 @@ fn with_path_in_table_name() { #[test] fn simple_reference_definition() { #[derive(Insertable)] - #[table_name = "users"] + #[diesel(table_name = users)] struct NewUser { name: String, hair_color: String, @@ -110,7 +110,7 @@ macro_rules! test_struct_definition { #[test] fn $test_name() { #[derive(Insertable)] - #[table_name = "users"] + #[diesel(table_name = users)] $struct_def let conn = &mut connection(); @@ -168,9 +168,9 @@ test_struct_definition! { #[test] fn named_struct_with_renamed_field() { #[derive(Insertable)] - #[table_name = "users"] + #[diesel(table_name = users)] struct NewUser { - #[column_name = "name"] + #[diesel(column_name = name)] my_name: String, hair_color: String, } @@ -195,11 +195,11 @@ fn named_struct_with_renamed_field() { #[test] fn named_struct_with_renamed_option_field() { #[derive(Insertable)] - #[table_name = "users"] + #[diesel(table_name = users)] struct NewUser { - #[column_name = "name"] + #[diesel(column_name = name)] my_name: String, - #[column_name = "hair_color"] + #[diesel(column_name = hair_color)] my_hair_color: Option, } @@ -223,10 +223,10 @@ fn named_struct_with_renamed_option_field() { #[test] fn tuple_struct() { #[derive(Insertable)] - #[table_name = "users"] + #[diesel(table_name = users)] struct NewUser<'a>( - #[column_name = "name"] &'a str, - #[column_name = "hair_color"] Option<&'a str>, + #[diesel(column_name = name)] &'a str, + #[diesel(column_name = hair_color)] Option<&'a str>, ); let conn = &mut connection(); @@ -246,7 +246,7 @@ fn tuple_struct() { #[test] fn named_struct_with_unusual_reference_type() { #[derive(Insertable)] - #[table_name = "users"] + #[diesel(table_name = users)] struct NewUser<'a> { name: &'a String, hair_color: Option<&'a String>, @@ -282,7 +282,7 @@ fn insertable_with_slice_of_borrowed() { } #[derive(Insertable)] - #[table_name = "posts"] + #[diesel(table_name = posts)] struct NewPost<'a> { tags: &'a [&'a str], } @@ -310,7 +310,7 @@ fn insertable_with_slice_of_borrowed() { #[test] fn embedded_struct() { #[derive(Insertable)] - #[table_name = "users"] + #[diesel(table_name = users)] struct NameAndHairColor<'a> { name: &'a str, hair_color: &'a str, diff --git a/diesel_derives/tests/queryable.rs b/diesel_derives/tests/queryable.rs index 993fda3a5e0e..ef52da75b224 100644 --- a/diesel_derives/tests/queryable.rs +++ b/diesel_derives/tests/queryable.rs @@ -20,7 +20,10 @@ fn named_struct_definition() { #[test] fn tuple_struct() { #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable)] - struct MyStruct(#[column_name = "foo"] i32, #[column_name = "bar"] i32); + struct MyStruct( + #[diesel(column_name = foo)] i32, + #[diesel(column_name = bar)] i32, + ); let conn = &mut connection(); let data = select(sql::<(Integer, Integer)>("1, 2")).get_result(conn); diff --git a/diesel_derives/tests/queryable_by_name.rs b/diesel_derives/tests/queryable_by_name.rs index bbfe7be7ea24..7fe4106e5045 100644 --- a/diesel_derives/tests/queryable_by_name.rs +++ b/diesel_derives/tests/queryable_by_name.rs @@ -13,7 +13,7 @@ table! { #[test] fn named_struct_definition() { #[derive(Debug, Clone, Copy, PartialEq, Eq, QueryableByName)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct MyStruct { foo: i32, bar: i32, @@ -27,8 +27,11 @@ fn named_struct_definition() { #[test] fn tuple_struct() { #[derive(Debug, Clone, Copy, PartialEq, Eq, QueryableByName)] - #[table_name = "my_structs"] - struct MyStruct(#[column_name = "foo"] i32, #[column_name = "bar"] i32); + #[diesel(table_name = my_structs)] + struct MyStruct( + #[diesel(column_name = foo)] i32, + #[diesel(column_name = bar)] i32, + ); let conn = &mut connection(); let data = sql_query("SELECT 1 AS foo, 2 AS bar").get_result(conn); @@ -38,7 +41,7 @@ fn tuple_struct() { #[test] fn struct_with_path_in_name() { #[derive(Debug, Clone, Copy, PartialEq, Eq, QueryableByName)] - #[table_name = "self::my_structs"] + #[diesel(table_name = self::my_structs)] struct MyStruct { foo: i32, bar: i32, @@ -55,9 +58,9 @@ fn struct_with_path_in_name() { fn struct_with_no_table() { #[derive(Debug, Clone, Copy, PartialEq, Eq, QueryableByName)] struct MyStructNamedSoYouCantInferIt { - #[sql_type = "Integer"] + #[diesel(sql_type = Integer)] foo: i32, - #[sql_type = "Integer"] + #[diesel(sql_type = Integer)] bar: i32, } @@ -66,29 +69,29 @@ fn struct_with_no_table() { assert_eq!(Ok(MyStructNamedSoYouCantInferIt { foo: 1, bar: 2 }), data); } -#[test] -fn struct_with_non_ident_column_name() { - #[derive(Debug, Clone, PartialEq, Eq, QueryableByName)] - struct QueryPlan { - #[sql_type = "diesel::sql_types::Text"] - #[column_name = "QUERY PLAN"] - qp: String, - } - - let conn = &mut connection(); - let data = sql_query("SELECT 'some plan' AS \"QUERY PLAN\"").get_result(conn); - assert_eq!( - Ok(QueryPlan { - qp: "some plan".to_string() - }), - data - ); -} +// #[test] +// fn struct_with_non_ident_column_name() { +// #[derive(Debug, Clone, PartialEq, Eq, QueryableByName)] +// struct QueryPlan { +// #[diesel(sql_type = diesel::sql_types::Text)] +// #[diesel(column_name = "QUERY PLAN")] +// qp: String, +// } + +// let conn = &mut connection(); +// let data = sql_query("SELECT 'some plan' AS \"QUERY PLAN\"").get_result(conn); +// assert_eq!( +// Ok(QueryPlan { +// qp: "some plan".to_string() +// }), +// data +// ); +// } #[test] fn embedded_struct() { #[derive(Debug, Clone, Copy, PartialEq, Eq, QueryableByName)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct A { foo: i32, #[diesel(embed)] @@ -96,7 +99,7 @@ fn embedded_struct() { } #[derive(Debug, Clone, Copy, PartialEq, Eq, QueryableByName)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct B { bar: i32, } @@ -115,7 +118,7 @@ fn embedded_struct() { #[test] fn embedded_option() { #[derive(Debug, Clone, Copy, PartialEq, Eq, QueryableByName)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct A { foo: i32, #[diesel(embed)] @@ -123,7 +126,7 @@ fn embedded_option() { } #[derive(Debug, Clone, Copy, PartialEq, Eq, QueryableByName)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct B { bar: i32, } diff --git a/diesel_derives/tests/selectable.rs b/diesel_derives/tests/selectable.rs index 45729b5e119f..5174b5e5ca7f 100644 --- a/diesel_derives/tests/selectable.rs +++ b/diesel_derives/tests/selectable.rs @@ -12,7 +12,7 @@ table! { #[test] fn named_struct_definition() { #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Selectable)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct MyStruct { foo: i32, bar: i32, @@ -28,8 +28,11 @@ fn named_struct_definition() { #[test] fn tuple_struct() { #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Selectable)] - #[table_name = "my_structs"] - struct MyStruct(#[column_name = "foo"] i32, #[column_name = "bar"] i32); + #[diesel(table_name = my_structs)] + struct MyStruct( + #[diesel(column_name = foo)] i32, + #[diesel(column_name = bar)] i32, + ); let conn = &mut connection(); let data = my_structs::table @@ -43,7 +46,7 @@ fn tuple_struct() { #[test] fn embedded_struct() { #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Selectable)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct A { foo: i32, #[diesel(embed)] @@ -51,7 +54,7 @@ fn embedded_struct() { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Selectable)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct C { bar: i32, } @@ -66,7 +69,7 @@ fn embedded_struct() { #[test] fn embedded_option() { #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Selectable)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct A { foo: i32, #[diesel(embed)] @@ -74,7 +77,7 @@ fn embedded_option() { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Selectable)] - #[table_name = "my_structs"] + #[diesel(table_name = my_structs)] struct B { bar: i32, } diff --git a/diesel_tests/tests/annotations.rs b/diesel_tests/tests/annotations.rs index fc3be663ad78..d614af850d2e 100644 --- a/diesel_tests/tests/annotations.rs +++ b/diesel_tests/tests/annotations.rs @@ -5,8 +5,8 @@ use diesel::*; #[test] fn association_where_struct_name_doesnt_match_table_name() { #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)] - #[belongs_to(Post)] - #[table_name = "comments"] + #[diesel(belongs_to(Post))] + #[diesel(table_name = comments)] struct OtherComment { id: i32, post_id: i32, @@ -35,7 +35,7 @@ fn association_where_struct_name_doesnt_match_table_name() { #[cfg(not(any(feature = "sqlite", feature = "mysql")))] fn association_where_parent_and_child_have_underscores() { #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)] - #[belongs_to(User)] + #[diesel(belongs_to(User))] pub struct SpecialPost { id: i32, user_id: i32, @@ -43,7 +43,7 @@ fn association_where_parent_and_child_have_underscores() { } #[derive(Insertable)] - #[table_name = "special_posts"] + #[diesel(table_name = special_posts)] struct NewSpecialPost { user_id: i32, title: String, @@ -59,7 +59,7 @@ fn association_where_parent_and_child_have_underscores() { } #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)] - #[belongs_to(SpecialPost)] + #[diesel(belongs_to(SpecialPost))] struct SpecialComment { id: i32, special_post_id: i32, @@ -74,7 +74,7 @@ fn association_where_parent_and_child_have_underscores() { } #[derive(Insertable)] - #[table_name = "special_comments"] + #[diesel(table_name = special_comments)] struct NewSpecialComment { special_post_id: i32, } @@ -123,7 +123,7 @@ mod associations_can_have_nullable_foreign_keys { } #[derive(Identifiable, Associations)] - #[belongs_to(Foo)] + #[diesel(belongs_to(Foo))] pub struct Bar { id: i32, foo_id: Option, @@ -136,7 +136,7 @@ mod multiple_lifetimes_in_insertable_struct_definition { use crate::schema::posts; #[derive(Insertable)] - #[table_name = "posts"] + #[diesel(table_name = posts)] pub struct MyPost<'a> { title: &'a str, body: &'a str, @@ -148,7 +148,7 @@ mod lifetimes_with_names_other_than_a { use crate::schema::posts; #[derive(Insertable)] - #[table_name = "posts"] + #[diesel(table_name = posts)] pub struct MyPost<'a, 'b> { id: i32, title: &'b str, @@ -162,7 +162,7 @@ mod insertable_with_cow { use std::borrow::Cow; #[derive(Insertable)] - #[table_name = "posts"] + #[diesel(table_name = posts)] pub struct MyPost<'a> { id: i32, title: Cow<'a, str>, @@ -178,7 +178,7 @@ mod custom_foreign_keys_are_respected_on_belongs_to { table! { special_posts { id -> Integer, author_id -> Integer, } } #[derive(Identifiable, Associations)] - #[belongs_to(User, foreign_key = "author_id")] + #[diesel(belongs_to(User, foreign_key = author_id))] pub struct SpecialPost { id: i32, author_id: i32, @@ -200,8 +200,8 @@ fn derive_identifiable_with_non_standard_pk() { use diesel::associations::*; #[derive(Identifiable)] - #[table_name = "posts"] - #[primary_key(foo_id)] + #[diesel(table_name = posts)] + #[diesel(primary_key(foo_id))] #[allow(dead_code)] struct Foo<'a> { id: i32, @@ -230,8 +230,8 @@ fn derive_identifiable_with_composite_pk() { use diesel::associations::Identifiable; #[derive(Identifiable)] - #[primary_key(foo_id, bar_id)] - #[table_name = "posts"] + #[diesel(primary_key(foo_id, bar_id))] + #[diesel(table_name = posts)] #[allow(dead_code)] struct Foo { id: i32, @@ -259,7 +259,7 @@ fn derive_identifiable_with_composite_pk() { #[test] fn derive_insertable_with_option_for_not_null_field_with_default() { #[derive(Insertable)] - #[table_name = "users"] + #[diesel(table_name = users)] struct NewUser { id: Option, name: &'static str, @@ -292,7 +292,7 @@ sql_function!(fn nextval(a: Text) -> Integer); #[cfg(feature = "postgres")] fn derive_insertable_with_field_that_cannot_convert_expression_to_nullable() { #[derive(Insertable)] - #[table_name = "users"] + #[diesel(table_name = users)] struct NewUser { id: nextval::HelperType<&'static str>, name: &'static str, diff --git a/diesel_tests/tests/associations.rs b/diesel_tests/tests/associations.rs index c02f3cbbddcb..8f792b191538 100644 --- a/diesel_tests/tests/associations.rs +++ b/diesel_tests/tests/associations.rs @@ -54,7 +54,7 @@ mod eager_loading_with_string_keys { } #[derive(Queryable, Identifiable, Debug, PartialEq, Clone, Associations)] - #[belongs_to(User)] + #[diesel(belongs_to(User))] pub struct Post { id: String, user_id: String, @@ -178,8 +178,8 @@ fn associations_can_be_grouped_multiple_levels_deep() { #[test] fn self_referencing_associations() { #[derive(Insertable, Queryable, Associations, Identifiable, Debug, Clone, Copy, PartialEq)] - #[table_name = "trees"] - #[belongs_to(Tree, foreign_key = "parent_id")] + #[diesel(table_name = trees)] + #[diesel(belongs_to(Tree, foreign_key = parent_id))] struct Tree { id: i32, parent_id: Option, @@ -284,15 +284,15 @@ fn custom_foreign_key() { allow_tables_to_appear_in_same_query!(users1, posts1); #[derive(Clone, Debug, PartialEq, Identifiable, Queryable)] - #[table_name = "users1"] + #[diesel(table_name = users1)] pub struct User { id: i32, name: String, } #[derive(Clone, Debug, PartialEq, Associations, Identifiable, Queryable)] - #[belongs_to(User, foreign_key = "belongs_to_user")] - #[table_name = "posts1"] + #[diesel(belongs_to(User, foreign_key = belongs_to_user))] + #[diesel(table_name = posts1)] pub struct Post { id: i32, belongs_to_user: i32, diff --git a/diesel_tests/tests/custom_types.rs b/diesel_tests/tests/custom_types.rs index cf838d56c638..b3160ddbc07c 100644 --- a/diesel_tests/tests/custom_types.rs +++ b/diesel_tests/tests/custom_types.rs @@ -16,11 +16,11 @@ table! { } #[derive(SqlType)] -#[postgres(type_name = "my_type")] +#[diesel(postgres_type(name = "my_type"))] pub struct MyType; #[derive(Debug, PartialEq, FromSqlRow, AsExpression)] -#[sql_type = "MyType"] +#[diesel(sql_type = MyType)] pub enum MyEnum { Foo, Bar, @@ -47,7 +47,7 @@ impl FromSql for MyEnum { } #[derive(Insertable, Queryable, Identifiable, Debug, PartialEq)] -#[table_name = "custom_types"] +#[diesel(table_name = custom_types)] struct HasCustomTypes { id: i32, custom_enum: MyEnum, @@ -95,11 +95,11 @@ table! { } #[derive(SqlType)] -#[postgres(type_name = "my_type", type_schema = "custom_schema")] +#[diesel(postgres_type(name = "my_type", schema = "custom_schema"))] pub struct MyTypeInCustomSchema; #[derive(Debug, PartialEq, FromSqlRow, AsExpression)] -#[sql_type = "MyTypeInCustomSchema"] +#[diesel(sql_type = MyTypeInCustomSchema)] pub enum MyEnumInCustomSchema { Foo, Bar, @@ -126,7 +126,7 @@ impl FromSql for MyEnumInCustomSchema { } #[derive(Insertable, Queryable, Identifiable, Debug, PartialEq)] -#[table_name = "custom_types_with_custom_schema"] +#[diesel(table_name = custom_types_with_custom_schema)] struct HasCustomTypesInCustomSchema { id: i32, custom_enum: MyEnumInCustomSchema, @@ -166,15 +166,15 @@ fn custom_types_in_custom_schema_round_trip() { } #[derive(SqlType)] -#[postgres(type_name = "ty", type_schema = "other")] +#[diesel(postgres_type(name = "ty", schema = "other"))] struct OtherTy; #[derive(SqlType)] -#[postgres(type_name = "ty", type_schema = "public")] +#[diesel(postgres_type(name = "ty", schema = "public"))] struct PublicTy; #[derive(SqlType)] -#[postgres(type_name = "ty")] +#[diesel(postgres_type(name = "ty"))] struct InferedTy; #[test] diff --git a/diesel_tests/tests/deserialization.rs b/diesel_tests/tests/deserialization.rs index ecc630de3948..54a5c867aab6 100644 --- a/diesel_tests/tests/deserialization.rs +++ b/diesel_tests/tests/deserialization.rs @@ -3,7 +3,7 @@ use diesel::prelude::*; use std::borrow::Cow; #[derive(Queryable, PartialEq, Debug, Selectable)] -#[table_name = "users"] +#[diesel(table_name = users)] struct CowUser<'a> { id: i32, name: Cow<'a, str>, diff --git a/diesel_tests/tests/insert.rs b/diesel_tests/tests/insert.rs index 0d1796c2ac28..14ea6ac0bd10 100644 --- a/diesel_tests/tests/insert.rs +++ b/diesel_tests/tests/insert.rs @@ -368,13 +368,13 @@ fn insert_returning_count_returns_number_of_rows_inserted() { } #[derive(Insertable)] -#[table_name = "users"] +#[diesel(table_name = users)] struct BaldUser { name: String, } #[derive(Insertable)] -#[table_name = "users"] +#[diesel(table_name = users)] struct BorrowedUser<'a> { name: &'a str, } diff --git a/diesel_tests/tests/schema/backend_specifics.rs b/diesel_tests/tests/schema/backend_specifics.rs index 053eec58eff9..91055d246fae 100644 --- a/diesel_tests/tests/schema/backend_specifics.rs +++ b/diesel_tests/tests/schema/backend_specifics.rs @@ -1,8 +1,8 @@ use super::*; #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName)] -#[belongs_to(User)] -#[table_name = "posts"] +#[diesel(belongs_to(User))] +#[diesel(table_name = posts)] pub struct Post { pub id: i32, pub user_id: i32, diff --git a/diesel_tests/tests/schema/custom_schemas.rs b/diesel_tests/tests/schema/custom_schemas.rs index bc35b72389c2..5d861f256c2c 100644 --- a/diesel_tests/tests/schema/custom_schemas.rs +++ b/diesel_tests/tests/schema/custom_schemas.rs @@ -5,7 +5,7 @@ include!("pg_custom_schema.rs"); use self::custom_schema::users; #[derive(Insertable)] -#[table_name = "users"] +#[diesel(table_name = users)] struct NewUser { id: i32, } diff --git a/diesel_tests/tests/schema/mod.rs b/diesel_tests/tests/schema/mod.rs index a9ee11bd4da4..8f15b65ddf8a 100644 --- a/diesel_tests/tests/schema/mod.rs +++ b/diesel_tests/tests/schema/mod.rs @@ -22,7 +22,7 @@ include!("mysql_schema.rs"); QueryableByName, Selectable, )] -#[table_name = "users"] +#[diesel(table_name = users)] pub struct User { pub id: i32, pub name: String, @@ -52,8 +52,8 @@ impl User { } #[derive(PartialEq, Eq, Debug, Clone, Queryable, Selectable)] -#[table_name = "users"] -pub struct UserName(#[column_name = "name"] pub String); +#[diesel(table_name = users)] +pub struct UserName(#[diesel(column_name = name)] pub String); impl UserName { pub fn new(name: &str) -> Self { @@ -62,7 +62,7 @@ impl UserName { } #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations)] -#[belongs_to(Post)] +#[diesel(belongs_to(Post))] pub struct Comment { id: i32, post_id: i32, @@ -80,10 +80,10 @@ impl Comment { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Associations, Identifiable)] -#[belongs_to(User)] -#[belongs_to(Post)] -#[table_name = "followings"] -#[primary_key(user_id, post_id)] +#[diesel(belongs_to(User))] +#[diesel(belongs_to(Post))] +#[diesel(table_name = followings)] +#[diesel(primary_key(user_id, post_id))] pub struct Following { pub user_id: i32, pub post_id: i32, @@ -98,7 +98,7 @@ mod backend_specifics; pub use self::backend_specifics::*; #[derive(Debug, PartialEq, Eq, Queryable, Clone, Insertable, AsChangeset, Selectable)] -#[table_name = "users"] +#[diesel(table_name = users)] pub struct NewUser { pub name: String, pub hair_color: Option, @@ -114,7 +114,7 @@ impl NewUser { } #[derive(Debug, PartialEq, Eq, Insertable)] -#[table_name = "users"] +#[diesel(table_name = users)] pub struct DefaultColorUser { pub name: String, pub hair_color: Option>, @@ -130,7 +130,7 @@ impl DefaultColorUser { } #[derive(Insertable)] -#[table_name = "posts"] +#[diesel(table_name = posts)] pub struct NewPost { user_id: i32, title: String, @@ -148,14 +148,14 @@ impl NewPost { } #[derive(Debug, Clone, Copy, Insertable)] -#[table_name = "comments"] +#[diesel(table_name = comments)] pub struct NewComment<'a>( - #[column_name = "post_id"] pub i32, - #[column_name = "text"] pub &'a str, + #[diesel(column_name = post_id)] pub i32, + #[diesel(column_name = text)] pub &'a str, ); #[derive(PartialEq, Eq, Debug, Clone, Insertable)] -#[table_name = "fk_tests"] +#[diesel(table_name = fk_tests)] pub struct FkTest { id: i32, fk_id: i32, @@ -171,17 +171,17 @@ impl FkTest { } #[derive(Queryable, Insertable)] -#[table_name = "nullable_table"] +#[diesel(table_name = nullable_table)] pub struct NullableColumn { id: i32, value: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Queryable, Insertable, Identifiable, Associations)] -#[table_name = "likes"] -#[primary_key(user_id, comment_id)] -#[belongs_to(User)] -#[belongs_to(Comment)] +#[diesel(table_name = likes)] +#[diesel(primary_key(user_id, comment_id))] +#[diesel(belongs_to(User))] +#[diesel(belongs_to(Comment))] pub struct Like { pub user_id: i32, pub comment_id: i32, diff --git a/diesel_tests/tests/schema/postgres_specific_schema.rs b/diesel_tests/tests/schema/postgres_specific_schema.rs index 1113558fab38..d1a48bc0651f 100644 --- a/diesel_tests/tests/schema/postgres_specific_schema.rs +++ b/diesel_tests/tests/schema/postgres_specific_schema.rs @@ -1,8 +1,8 @@ use super::{posts, User}; #[derive(PartialEq, Eq, Debug, Clone, Queryable, Identifiable, Associations, QueryableByName)] -#[table_name = "posts"] -#[belongs_to(User)] +#[diesel(table_name = posts)] +#[diesel(belongs_to(User))] pub struct Post { pub id: i32, pub user_id: i32, diff --git a/diesel_tests/tests/schema_inference.rs b/diesel_tests/tests/schema_inference.rs index 686c3184cf17..151ccd6eca02 100644 --- a/diesel_tests/tests/schema_inference.rs +++ b/diesel_tests/tests/schema_inference.rs @@ -7,7 +7,7 @@ mod sqlite { use diesel::*; #[derive(Queryable, PartialEq, Debug, Insertable)] - #[table_name = "infer_all_the_ints"] + #[diesel(table_name = infer_all_the_ints)] struct InferredInts { col1: i32, col2: i32, @@ -54,7 +54,7 @@ mod sqlite { } #[derive(Queryable, PartialEq, Debug, Insertable)] - #[table_name = "infer_all_the_bools"] + #[diesel(table_name = infer_all_the_bools)] struct InferredBools { col1: bool, col2: bool, @@ -83,7 +83,7 @@ mod sqlite { } #[derive(Queryable, PartialEq, Debug, Insertable)] - #[table_name = "infer_all_the_strings"] + #[diesel(table_name = infer_all_the_strings)] struct InferredStrings { col1: String, col2: String, @@ -124,7 +124,7 @@ mod sqlite { } #[derive(Queryable, PartialEq, Debug, Insertable)] - #[table_name = "infer_all_the_floats"] + #[diesel(table_name = infer_all_the_floats)] struct InferredFloats { col1: f32, col2: f32, @@ -157,7 +157,7 @@ mod sqlite { } #[derive(Queryable, PartialEq, Debug, Insertable)] - #[table_name = "infer_all_the_datetime_types"] + #[diesel(table_name = infer_all_the_datetime_types)] struct InferredDatetimeTypes { dt: NaiveDateTime, date: NaiveDate, @@ -198,7 +198,7 @@ mod postgres { use std::collections::Bound; #[derive(Queryable, PartialEq, Debug, Insertable)] - #[table_name = "all_the_ranges"] + #[diesel(table_name = all_the_ranges)] struct InferredRanges { int4: (Bound, Bound), int8: (Bound, Bound), @@ -245,7 +245,7 @@ mod mysql { use diesel::*; #[derive(Insertable)] - #[table_name = "all_the_blobs"] + #[diesel(table_name = all_the_blobs)] struct InferredBlobs<'a> { id: i32, tiny: &'a [u8], @@ -296,7 +296,7 @@ fn columns_named_as_reserved_keywords_are_renamed() { use diesel::*; #[derive(Queryable, Insertable, Debug, PartialEq)] - #[table_name = "with_keywords"] + #[diesel(table_name = with_keywords)] struct WithKeywords { fn_: i32, let_: i32, diff --git a/diesel_tests/tests/select_by.rs b/diesel_tests/tests/select_by.rs index 5e864501b49b..731905c48802 100644 --- a/diesel_tests/tests/select_by.rs +++ b/diesel_tests/tests/select_by.rs @@ -64,7 +64,7 @@ fn selecting_columns_and_tables_with_reserved_names() { .unwrap(); #[derive(Debug, PartialEq, Queryable, Selectable)] - #[table_name = "select"] + #[diesel(table_name = select)] struct Select { join: i32, } @@ -117,7 +117,7 @@ fn selection_using_subselect() { connection.execute(&query).unwrap(); #[derive(Debug, PartialEq, Queryable, Selectable)] - struct Post(#[column_name = "title"] String); + struct Post(#[diesel(column_name = title)] String); let users = users::table .filter(users::name.eq("Sean")) diff --git a/diesel_tests/tests/serialize_as.rs b/diesel_tests/tests/serialize_as.rs index 93ae5048b168..b45106f96e33 100644 --- a/diesel_tests/tests/serialize_as.rs +++ b/diesel_tests/tests/serialize_as.rs @@ -5,7 +5,7 @@ use diesel::*; use std::io::Write; #[derive(Debug, FromSqlRow, AsExpression)] -#[sql_type = "sql_types::Text"] +#[diesel(sql_type = sql_types::Text)] struct UppercaseString(pub String); impl From for UppercaseString { @@ -25,9 +25,9 @@ where } #[derive(Insertable, PartialEq, Debug)] -#[table_name = "users"] +#[diesel(table_name = users)] struct InsertableUser { - #[diesel(serialize_as = "UppercaseString")] + #[diesel(serialize_as = UppercaseString)] name: String, } diff --git a/diesel_tests/tests/types.rs b/diesel_tests/tests/types.rs index 60c229165c07..9fa4a552499e 100644 --- a/diesel_tests/tests/types.rs +++ b/diesel_tests/tests/types.rs @@ -99,7 +99,7 @@ fn test_chrono_types_sqlite() { use self::has_time_types; #[derive(Queryable, Insertable)] - #[table_name = "has_time_types"] + #[diesel(table_name = has_time_types)] struct NewTimeTypes { datetime: NaiveDateTime, date: NaiveDate, diff --git a/diesel_tests/tests/update.rs b/diesel_tests/tests/update.rs index ad8ca5858c6a..ca180572cc4f 100644 --- a/diesel_tests/tests/update.rs +++ b/diesel_tests/tests/update.rs @@ -146,7 +146,7 @@ fn save_on_struct_with_primary_key_changes_that_struct() { #[test] fn sql_syntax_is_correct_when_option_field_comes_before_non_option() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct Changes { hair_color: Option, name: String, @@ -171,7 +171,7 @@ fn sql_syntax_is_correct_when_option_field_comes_before_non_option() { #[test] fn sql_syntax_is_correct_when_option_field_comes_mixed_with_non_option() { #[derive(AsChangeset)] - #[table_name = "posts"] + #[diesel(table_name = posts)] struct Changes { user_id: i32, title: Option, @@ -208,7 +208,7 @@ fn sql_syntax_is_correct_when_option_field_comes_mixed_with_non_option() { #[should_panic(expected = "There are no changes to save.")] fn update_with_no_changes() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct Changes { name: Option, hair_color: Option, @@ -229,7 +229,7 @@ fn update_with_no_changes() { #[cfg(any(feature = "postgres", feature = "sqlite"))] fn upsert_with_no_changes_executes_do_nothing() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct Changes { hair_color: Option, } @@ -249,7 +249,7 @@ fn upsert_with_no_changes_executes_do_nothing() { #[cfg(any(feature = "postgres", feature = "sqlite"))] fn upsert_with_no_changes_executes_do_nothing_owned() { #[derive(AsChangeset)] - #[table_name = "users"] + #[diesel(table_name = users)] struct Changes { hair_color: Option, } diff --git a/examples/mysql/all_about_inserts/Cargo.toml b/examples/mysql/all_about_inserts/Cargo.toml index 75fd88b76fea..ace5005b8f1b 100644 --- a/examples/mysql/all_about_inserts/Cargo.toml +++ b/examples/mysql/all_about_inserts/Cargo.toml @@ -6,10 +6,9 @@ edition = "2018" [dependencies] diesel = { version = "2.0.0", path = "../../../diesel", features = ["mysql", "chrono"] } -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" +serde = { version = "1.0.130", features = ["derive"] } +serde_json = "1.0.68" chrono = { version = "0.4.19", default-features = false, features = ["clock", "std"] } [lib] -doc = false \ No newline at end of file +doc = false diff --git a/examples/mysql/all_about_inserts/src/lib.rs b/examples/mysql/all_about_inserts/src/lib.rs index 57725f974704..f00d6d11a7b7 100644 --- a/examples/mysql/all_about_inserts/src/lib.rs +++ b/examples/mysql/all_about_inserts/src/lib.rs @@ -5,7 +5,7 @@ use diesel::insert_into; #[cfg(test)] use diesel::mysql::Mysql; use diesel::prelude::*; -use serde_derive::Deserialize; +use serde::Deserialize; use std::error::Error; mod schema { @@ -23,7 +23,7 @@ mod schema { use schema::users; #[derive(Deserialize, Insertable)] -#[table_name = "users"] +#[diesel(table_name = users)] pub struct UserForm<'a> { name: &'a str, hair_color: Option<&'a str>, diff --git a/examples/mysql/getting_started_step_2/src/models.rs b/examples/mysql/getting_started_step_2/src/models.rs index 5398224f2b28..48f17b23fe81 100644 --- a/examples/mysql/getting_started_step_2/src/models.rs +++ b/examples/mysql/getting_started_step_2/src/models.rs @@ -10,7 +10,7 @@ pub struct Post { } #[derive(Insertable)] -#[table_name = "posts"] +#[diesel(table_name = posts)] pub struct NewPost<'a> { pub title: &'a str, pub body: &'a str, diff --git a/examples/mysql/getting_started_step_3/src/models.rs b/examples/mysql/getting_started_step_3/src/models.rs index 5398224f2b28..48f17b23fe81 100644 --- a/examples/mysql/getting_started_step_3/src/models.rs +++ b/examples/mysql/getting_started_step_3/src/models.rs @@ -10,7 +10,7 @@ pub struct Post { } #[derive(Insertable)] -#[table_name = "posts"] +#[diesel(table_name = posts)] pub struct NewPost<'a> { pub title: &'a str, pub body: &'a str, diff --git a/examples/postgres/advanced-blog-cli/src/comment.rs b/examples/postgres/advanced-blog-cli/src/comment.rs index e6eb20d29cb0..369a6cd684cf 100644 --- a/examples/postgres/advanced-blog-cli/src/comment.rs +++ b/examples/postgres/advanced-blog-cli/src/comment.rs @@ -6,8 +6,8 @@ use crate::post::Post; use crate::schema::comments; #[derive(Queryable, Identifiable, Associations)] -#[belongs_to(User)] -#[belongs_to(Post)] +#[diesel(belongs_to(User))] +#[diesel(belongs_to(Post))] pub struct Comment { pub id: i32, pub user_id: i32, diff --git a/examples/postgres/advanced-blog-cli/src/post.rs b/examples/postgres/advanced-blog-cli/src/post.rs index 6d990c10e158..261043b1d6dd 100644 --- a/examples/postgres/advanced-blog-cli/src/post.rs +++ b/examples/postgres/advanced-blog-cli/src/post.rs @@ -6,7 +6,7 @@ use crate::comment::Comment; use crate::schema::posts; #[derive(Queryable, Associations, Identifiable)] -#[belongs_to(User)] +#[diesel(belongs_to(User))] pub struct Post { pub id: i32, pub user_id: i32, @@ -14,7 +14,7 @@ pub struct Post { pub body: String, pub created_at: NaiveDateTime, pub updated_at: NaiveDateTime, - #[diesel(deserialize_as = "Option")] + #[diesel(deserialize_as = Option)] pub status: Status, } diff --git a/examples/postgres/all_about_inserts/Cargo.toml b/examples/postgres/all_about_inserts/Cargo.toml index e3b7d6d96f65..cef89870e533 100644 --- a/examples/postgres/all_about_inserts/Cargo.toml +++ b/examples/postgres/all_about_inserts/Cargo.toml @@ -6,9 +6,8 @@ edition = "2018" [dependencies] diesel = { version = "2.0.0", path = "../../../diesel", features = ["postgres"] } -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" +serde = { version = "1.0.130", features = ["derive"] } +serde_json = "1.0.68" [lib] -doc = false \ No newline at end of file +doc = false diff --git a/examples/postgres/all_about_inserts/src/lib.rs b/examples/postgres/all_about_inserts/src/lib.rs index 0d4540a75cb1..23eb4e201ecf 100644 --- a/examples/postgres/all_about_inserts/src/lib.rs +++ b/examples/postgres/all_about_inserts/src/lib.rs @@ -1,11 +1,10 @@ -use serde_derive::Deserialize; - #[cfg(test)] use diesel::debug_query; use diesel::insert_into; #[cfg(test)] use diesel::pg::Pg; use diesel::prelude::*; +use serde::Deserialize; use std::error::Error; use std::time::SystemTime; @@ -24,7 +23,7 @@ mod schema { use schema::users; #[derive(Deserialize, Insertable)] -#[table_name = "users"] +#[diesel(table_name = users)] pub struct UserForm<'a> { name: &'a str, hair_color: Option<&'a str>, diff --git a/examples/postgres/all_about_updates/src/lib.rs b/examples/postgres/all_about_updates/src/lib.rs index 527cbc389da6..65775ba58039 100644 --- a/examples/postgres/all_about_updates/src/lib.rs +++ b/examples/postgres/all_about_updates/src/lib.rs @@ -177,7 +177,7 @@ fn examine_sql_from_update_post_fields() { pub fn update_with_option(conn: &mut PgConnection) -> QueryResult { #[derive(AsChangeset)] - #[table_name = "posts"] + #[diesel(table_name = posts)] struct PostForm<'a> { title: Option<&'a str>, body: Option<&'a str>, @@ -194,7 +194,7 @@ pub fn update_with_option(conn: &mut PgConnection) -> QueryResult { #[test] fn examine_sql_from_update_with_option() { #[derive(AsChangeset)] - #[table_name = "posts"] + #[diesel(table_name = posts)] struct PostForm<'a> { title: Option<&'a str>, body: Option<&'a str>, diff --git a/examples/postgres/custom_types/src/main.rs b/examples/postgres/custom_types/src/main.rs index a04a03403188..5e604e3a787e 100644 --- a/examples/postgres/custom_types/src/main.rs +++ b/examples/postgres/custom_types/src/main.rs @@ -5,7 +5,7 @@ mod model; mod schema; #[derive(Debug, Queryable, Insertable)] -#[table_name = "translations"] +#[diesel(table_name = translations)] pub struct Translation { word_id: i32, translation_id: i32, diff --git a/examples/postgres/custom_types/src/model.rs b/examples/postgres/custom_types/src/model.rs index 3648b3bc8d94..0f31ab6bbb65 100644 --- a/examples/postgres/custom_types/src/model.rs +++ b/examples/postgres/custom_types/src/model.rs @@ -5,7 +5,7 @@ use diesel::serialize::{self, IsNull, Output, ToSql}; use std::io::Write; #[derive(Debug, AsExpression, FromSqlRow)] -#[sql_type = "crate::schema::sql_types::Language"] +#[diesel(sql_type = crate::schema::sql_types::Language)] pub enum Language { En, Ru, diff --git a/examples/postgres/custom_types/src/schema.rs b/examples/postgres/custom_types/src/schema.rs index 0592a0aa13f1..69b72bdc0d36 100644 --- a/examples/postgres/custom_types/src/schema.rs +++ b/examples/postgres/custom_types/src/schema.rs @@ -2,7 +2,7 @@ pub mod sql_types { #[derive(diesel::sql_types::SqlType)] - #[postgres(type_name = "language")] + #[diesel(postgres_type(name = "language"))] pub struct Language; } diff --git a/examples/postgres/getting_started_step_2/src/models.rs b/examples/postgres/getting_started_step_2/src/models.rs index 5398224f2b28..48f17b23fe81 100644 --- a/examples/postgres/getting_started_step_2/src/models.rs +++ b/examples/postgres/getting_started_step_2/src/models.rs @@ -10,7 +10,7 @@ pub struct Post { } #[derive(Insertable)] -#[table_name = "posts"] +#[diesel(table_name = posts)] pub struct NewPost<'a> { pub title: &'a str, pub body: &'a str, diff --git a/examples/postgres/getting_started_step_3/src/models.rs b/examples/postgres/getting_started_step_3/src/models.rs index 5398224f2b28..48f17b23fe81 100644 --- a/examples/postgres/getting_started_step_3/src/models.rs +++ b/examples/postgres/getting_started_step_3/src/models.rs @@ -10,7 +10,7 @@ pub struct Post { } #[derive(Insertable)] -#[table_name = "posts"] +#[diesel(table_name = posts)] pub struct NewPost<'a> { pub title: &'a str, pub body: &'a str, diff --git a/examples/sqlite/all_about_inserts/Cargo.toml b/examples/sqlite/all_about_inserts/Cargo.toml index 647ae26a9d55..a8e63445a046 100644 --- a/examples/sqlite/all_about_inserts/Cargo.toml +++ b/examples/sqlite/all_about_inserts/Cargo.toml @@ -6,10 +6,9 @@ edition = "2018" [dependencies] diesel = { version = "2.0.0", path = "../../../diesel", features = ["sqlite", "chrono"] } -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" +serde = { version = "1.0.130", features = ["derive"] } +serde_json = "1.0.68" chrono = { version = "0.4.19", default-features = false, features = ["clock", "std"] } [lib] -doc = false \ No newline at end of file +doc = false diff --git a/examples/sqlite/all_about_inserts/src/lib.rs b/examples/sqlite/all_about_inserts/src/lib.rs index 3eb3acf1d2bc..78b23447cc6d 100644 --- a/examples/sqlite/all_about_inserts/src/lib.rs +++ b/examples/sqlite/all_about_inserts/src/lib.rs @@ -5,7 +5,7 @@ use diesel::insert_into; use diesel::prelude::*; #[cfg(test)] use diesel::sqlite::Sqlite; -use serde_derive::Deserialize; +use serde::Deserialize; use std::error::Error; mod schema { @@ -23,7 +23,7 @@ mod schema { use schema::users; #[derive(Deserialize, Insertable)] -#[table_name = "users"] +#[diesel(table_name = users)] pub struct UserForm<'a> { name: &'a str, hair_color: Option<&'a str>, diff --git a/examples/sqlite/getting_started_step_2/src/models.rs b/examples/sqlite/getting_started_step_2/src/models.rs index 4243db8b446e..7025caabc37d 100644 --- a/examples/sqlite/getting_started_step_2/src/models.rs +++ b/examples/sqlite/getting_started_step_2/src/models.rs @@ -10,7 +10,7 @@ pub struct Post { } #[derive(Insertable)] -#[table_name = "posts"] +#[diesel(table_name = posts)] pub struct NewPost<'a> { pub title: &'a str, pub body: &'a str, diff --git a/examples/sqlite/getting_started_step_3/src/models.rs b/examples/sqlite/getting_started_step_3/src/models.rs index 4243db8b446e..7025caabc37d 100644 --- a/examples/sqlite/getting_started_step_3/src/models.rs +++ b/examples/sqlite/getting_started_step_3/src/models.rs @@ -10,7 +10,7 @@ pub struct Post { } #[derive(Insertable)] -#[table_name = "posts"] +#[diesel(table_name = posts)] pub struct NewPost<'a> { pub title: &'a str, pub body: &'a str, diff --git a/guide_drafts/custom_types.md b/guide_drafts/custom_types.md index 8de260981ea8..87ae59bc79d2 100644 --- a/guide_drafts/custom_types.md +++ b/guide_drafts/custom_types.md @@ -81,11 +81,11 @@ Thus, we need to create a separate type `LanguageType` and use it in a generated ```rust #[derive(SqlType)] -#[postgres(type_name = "Language")] +#[diesel(postgres_type(name = "Language"))] pub struct LanguageType; #[derive(Debug, FromSqlRow, AsExpression)] -#[sql_type = "LanguageType"] +#[diesel(sql_type = LanguageType)] pub enum Language { En, Ru, @@ -97,7 +97,7 @@ pub mod exports { } ``` -`#[postgres(type_name = "..")]` provides a name of the type as declared in our SQL, similarly `#[mysql_type = ".."]` can be used for MySql and `#[sqlite_type = ".."]` for sqlite. `FromSqlRow` derives internal types that are necessary for querying and `AsExpression` for querying. `#[sql_type = "LanguageType"]` creates a relation between a type marker and a "high-level" type for insertions as well. +`#[diesel(postgres_type(name = ".."))]` provides a name of the type as declared in our SQL, similarly `#[diesel(mysql_type(name = ".."))]` can be used for MySql and `#[diesel(sqlite_type(name = ".."))]` for sqlite. `FromSqlRow` derives internal types that are necessary for querying and `AsExpression` for querying. `#[diesel(sql_type = LanguageType)]` creates a relation between a type marker and a "high-level" type for insertions as well. We are ready to implement real conversions. The first one is `ToSql`, that performs conversion to the bytes. Since it can convert our type to SQL, it allows to only make queries. diff --git a/guide_drafts/trait_derives.md b/guide_drafts/trait_derives.md index c9836f47238f..395aa453805e 100644 --- a/guide_drafts/trait_derives.md +++ b/guide_drafts/trait_derives.md @@ -3,13 +3,13 @@ Deriving Traits in Depth Part of what makes Diesel's query builder so powerful is its ability to assist writing safe SQL queries in Rust. -It enables this level of safety through implementing +It enables this level of safety through implementing a series of traits on your structs. Writing these implementations by hand can be very laborious, so Diesel offers custom derives. In this guide, -we will cover each trait in detail in terms of its use cases +we will cover each trait in detail in terms of its use cases and usage considerations. To be able to use these derives, make sure you have `#[macro_use] extern crate diesel;` at the root of your project. @@ -35,11 +35,11 @@ Diesel's code generation derives are for safely building SQL queries. - [Associations](#associations) ## Queryable -A `Queryable` struct is one that represents the +A `Queryable` struct is one that represents the data returned from a database query. In many cases this may map exactly to the column structure of a single table, however there may be cases where you need to make a query that spans several tables and/or only uses -a subset of columns. +a subset of columns. For this reason, it may be helpful to view `Queryable` structs as the *result* of your query. It is acceptable and often desirable to have multiple `Queryable` structs for the same database table. @@ -131,7 +131,7 @@ When reading, take note of the values in the tuple(s). `Queryable` is trying to convert those four types into the types on our `User` struct. Our struct has the three String fields commented out, so it doesn't know what those `Text` columns are supposed to be converted to. -Remember, `Queryable` structs represent the exact columns, value, +Remember, `Queryable` structs represent the exact columns, value, and ordering of your query's returned result, which we are violating here. `Queryable` is expecting a tuple that looks like `(i32, String, String, String)`, @@ -147,7 +147,7 @@ Diesel provides some escape hatches to execute raw SQL queries. The problem with this is that Diesel can't ensure type safety and it's accessing fields by name instead of by index. This means that you can't deserialize the raw query result into a tuple or a regular struct. -Adding [`#[derive(QueryableByName)]`][queryable_by_name_doc] to your struct means +Adding [`#[derive(QueryableByName)]`][queryable_by_name_doc] to your struct means that it will be able to be built from the result of a raw SQL query using the [`sql_query`] function. [`sql_query`]: https://docs.diesel.rs/diesel/fn.sql_query.html @@ -157,11 +157,11 @@ The implementation of `QueryableByName` assumes that each field on your struct has a certain SQL type. It makes these assumptions based on the annotations you add to your struct. If your `QueryableByName` struct references a single table, -you may annotate that struct with `#[table_name="my_table"]`. +you may annotate that struct with `#[diesel(table_name = my_table)]`. `QueryableByName` will bind the struct fields to the SQL types it finds in your table's schema. You may also individually annotate each field on your struct -with `#[sql_type="ColumnTypeHere"]`. +with `#[diesel(sql_type = ColumnTypeHere)]`. If you're not using the `table_name` annotation, every field in your struct needs to have this annotation. When combining both `table_name` and `sql_type` annotations, @@ -171,7 +171,7 @@ Diesel will override any fields using `sql_type` and pick the rest from the tabl If you have any fields whose type is a struct that also implements `QueryableByName`, you may add the `#[diesel(embed)]` annotation. -### Example +### Example ```rust // File: src/models.rs @@ -214,9 +214,9 @@ use diesel::sql_types::{Integer, Text}; #[derive(Debug, QueryableByName)] pub struct UserEmail { - #[sql_type="Integer"] + #[diesel(sql_type = Integer)] pub id: i32, - #[sql_type="Text"] + #[diesel(sql_type = Text)] pub email: String, } @@ -226,11 +226,11 @@ pub struct UserEmail { // `QueryableByName` will use the users table for // all other column types. #[derive(Debug, QueryableByName)] -#[table_name="users"] +#[diesel(table_name = users)] pub struct UserName { pub first_name: String, pub last_name: String, - #[sql_type="Text"] + #[diesel(sql_type = Text)] pub full_name: String, } @@ -238,7 +238,7 @@ pub struct UserName { // `QueryableByName` struct and all other fields // reference the posts table. #[derive(Debug, QueryableByName)] -#[table_name="posts"] +#[diesel(table_name = posts)] pub struct PostsWithUserName { #[diesel(embed)] pub user_name: UserName, @@ -285,26 +285,26 @@ fn main() { let users_emails = sql_query("SELECT users.id, users.email FROM users ORDER BY id") .load::(&connection); - println!("{:?}", users_emails); + println!("{:?}", users_emails); //=> User { id: 1, email: "gordon.freeman@blackmesa.co" } - + let joined = sql_query(" - SELECT users.first_name, + SELECT users.first_name, users.last_name, CONCAT(users.first_name, users.last_name) as full_name, posts.body, - posts.title - FROM users + posts.title + FROM users INNER JOIN posts ON users.id = posts.user_id ") .load::(&connection); - println!("{:?}", joined); + println!("{:?}", joined); /* Output => [ - PostsWithUserName { - user_name: UserName { first_name: "Gordon", last_name: "Freeman", full_name: "GordonFreeman" }, + PostsWithUserName { + user_name: UserName { first_name: "Gordon", last_name: "Freeman", full_name: "GordonFreeman" }, title: "Thoughts on Tomorrow's Experiment", - body: "What could possibly go wrong? + body: "What could possibly go wrong? } ] */ @@ -315,7 +315,7 @@ If we were to forget one of `QueryableByName`'s required struct annotations, we would see the following error. ```rust -error: Your struct must either be annotated with `#[table_name = "foo"]` or have all of its fields annotated with `#[sql_type = "Integer"]` +error: Your struct must either be annotated with `#[diesel(table_name = foo)]` or have all of its fields annotated with `#[diesel(sql_type = Integer)]` --> src/models.rs:4:17 | 4 | #[derive(Debug, QueryableByName)] @@ -343,7 +343,7 @@ whose data you want to easily insert into your database. To implement `Insertable` on your struct, add the [`#[derive(Insertable)]`][insertable_doc] annotation. -As with usual Diesel inserts, +As with usual Diesel inserts, you will still be using the [`.insert_into()`] method to generate a SQL `INSERT` statement for that table. You may chain [`.values()`] or [`.default_values()`] @@ -362,9 +362,9 @@ On SQLite, one query will be performed per row. [insertable_doc]: https://docs.diesel.rs/diesel/prelude/trait.Insertable.html For `Insertable` structs, Diesel needs to know the corresponding table name. -You must add the `#[table_name="some_table_name"]` attribute to your `Insertable` struct. +You must add the `#[diesel(table_name = some_table_name)]` attribute to your `Insertable` struct. If your struct has different field names than the columns they reference, -they may be annotated with `#[column_name = "some_column_name"]`. +they may be annotated with `#[diesel(column_name = some_column_name)]`. Typically, you will not use `Queryable` and `Insertable` together. Thinking of web forms again, a new record wouldn't have such fields as @@ -375,7 +375,7 @@ Thinking of web forms again, a new record wouldn't have such fields as ```rust // File: src/models.rs -// Add serde, serde_derive, and serde_json to simulate +// Add serde, serde_derive, and serde_json to simulate // deserializing a web form. extern crate serde; extern crate serde_derive; @@ -393,11 +393,11 @@ pub struct User { } #[derive(Deserialize, Insertable)] -#[table_name="users"] +#[diesel(table_name = users)] pub struct NewUser<'a> { pub first_name: &'a str, pub last_name: &'a str, - #[column_name = "email"] + #[diesel(column_name = email)] pub electronic_mail: &'a str, } ``` @@ -446,11 +446,11 @@ The compiler reports that `Insertable` isn't implemented for our `NewUser` struc ## Identifiable Certain database operations, -such as table [associations](#associations) and updates, +such as table [associations](#associations) and updates, require that rows be uniquely identifiable. Implementing the `Identifiable` trait on your struct will define which columns (primary keys) make your struct uniquely identifiable. -To implement `Identifiable`, +To implement `Identifiable`, annotate your struct with [`#[derive(Identifiable)]`][identifiable_doc]. [identifiable_doc]: https://docs.diesel.rs/diesel/associations/trait.Identifiable.html @@ -459,7 +459,7 @@ By default, `Identifiable` will assume the primary key is a column named `id`. If your table's primary key is named differently, you can annotate the table with the attribute `#[primary_key(some_field_name)` or `#[primary_key(some_field_name, another_field_name)`. The `Identifiable` trait will assume that the annotated struct will be named in the singular form of the table it corresponds to. -If the table name differs you may use the `#[table_name="some_table_name"]` attribute annotation. +If the table name differs you may use the `#[diesel(table_name = some_table_name)]` attribute annotation. The `Identifiable` trait gives us the `id()` method on our models, which returns the value of our record's primary key. @@ -484,7 +484,7 @@ pub struct User { } #[derive(Insertable)] -#[table_name="users"] +#[diesel(table_name = users)] pub struct NewUser<'a> { pub first_name: &'a str, pub last_name: &'a str, @@ -499,9 +499,9 @@ pub struct NewUser<'a> { use diesel::prelude::*; fn main() { - let new_user = NewUser { - first_name: "Gordon", - last_name: "Freeman", + let new_user = NewUser { + first_name: "Gordon", + last_name: "Freeman", electronic_mail: "gordon.freeman@blackmesa.co", }; @@ -526,10 +526,10 @@ fn main() { first_name.eq("Alyx"), last_name.eq("Vance"), )).execute(&db_connection); - + let updated_hero = users.first::(&db_connection) .expect("Error loading first user"); - + println!("Our Hero's updated name: {} {}", updated_hero.first_name, updated_hero.last_name); //=> Our Hero's updated name: Alyx Vance } @@ -612,12 +612,12 @@ table! { `AsChangeset` will automatically assume you don't want to change your record's primary key, so it will ignore that column. If your primary key field name is different than `id`, -you must annotate your struct with the `#[primary_key(your_key)]` attribute. +you must annotate your struct with the `#[diesel(primary_key(your_key))]` attribute. By default, `AsChangeset` will assume that anytime a field has the value `None`, we do not want to assign any values to it (ignore). If we truly want to assign a `NULL` value, -we can use the annotation `#[changeset_options(treat_none_as_null="true")]`. +we can use the annotation `#[diesel(treat_none_as_null = true)]`. Be careful, as when you are setting your `Option` fields to `None`, they will be `NULL` in the database instead of ignored. @@ -648,7 +648,7 @@ pub struct User { } #[derive(Insertable)] -#[table_name="users"] +#[diesel(table_name = users)] pub struct NewUser<'a> { pub first_name: &'a str, pub last_name: &'a str, @@ -658,7 +658,7 @@ pub struct NewUser<'a> { // This struct will ignore any fields with the value None // and NULL any fields with the value Some(None) - all the behaviors we need. #[derive(AsChangeset)] -#[table_name="users"] +#[diesel(table_name = users)] pub struct IgnoreNoneFieldsUpdateUser<'a> { pub first_name: &'a str, pub last_name: &'a str, @@ -668,8 +668,8 @@ pub struct IgnoreNoneFieldsUpdateUser<'a> { // This struct will set the column to NULL if its value is None // Notice the treat_none_as_null option. #[derive(AsChangeset)] -#[changeset_options(treat_none_as_null="true")] -#[table_name="users"] +#[diesel(treat_none_as_null = true)] +#[diesel(table_name = users)] pub struct NullNoneFieldsUpdateUser<'a> { pub first_name: &'a str, pub last_name: &'a str, @@ -684,9 +684,9 @@ pub struct NullNoneFieldsUpdateUser<'a> { use diesel::prelude::*; fn main() { - let new_user = NewUser { - first_name: "Gordon", - last_name: "Freeman", + let new_user = NewUser { + first_name: "Gordon", + last_name: "Freeman", email: "gordon.freeman@blackmesa.co", }; @@ -714,19 +714,19 @@ fn main() { diesel::update(&hero).set(&ignore_fields_update) .execute(&db_connection); - + let updated_hero = users.first(&db_connection):: .expect("Error loading first user"); - println!("Name: {} {} Email: {}", updated_hero.first_name, - updated_hero.last_name, + println!("Name: {} {} Email: {}", updated_hero.first_name, + updated_hero.last_name, updated_hero.email.unwrap(), ); // Output - //=> Name: Issac Kleiner Email: gordon.freeman@blackmesa.ca - - // Update scenario 2 + //=> Name: Issac Kleiner Email: gordon.freeman@blackmesa.ca + + // Update scenario 2 let null_a_field_update = IgnoreNoneFieldsUpdateUser { first_name: "Issac", last_name: "Kleiner", @@ -735,12 +735,12 @@ fn main() { diesel::update(&hero).set(&null_a_field_update) .execute(&db_connection); - + let updated_hero = users.first::(&db_connection) .expect("Error loading first user"); - println!("Name: {} {} Email: {}", updated_hero.first_name, - updated_hero.last_name, + println!("Name: {} {} Email: {}", updated_hero.first_name, + updated_hero.last_name, updated_hero.email.unwrap_or("This field is now Nulled".to_string()), ); @@ -756,12 +756,12 @@ fn main() { diesel::update(&hero).set(&null_fields_update) .execute(&db_connection); - + let updated_hero = users.first::(&db_connection) .expect("Error loading first user"); - println!("Name: {} {} Email: {:?}", updated_hero.first_name, - updated_hero.last_name, + println!("Name: {} {} Email: {:?}", updated_hero.first_name, + updated_hero.last_name, updated_hero.email.unwrap_or("This is a Null value".to_string()), ); @@ -780,7 +780,7 @@ error[E0277]: the trait bound `&diesel_demo_cli::models::IgnoreFieldsUpdateUser< | ^^^ the trait `diesel::query_builder::AsChangeset` is not implemented for `&diesel_demo_cli::models::IgnoreFieldsUpdateUser<'_>` ``` -Here we get a clear message from Rust indicating that we're trying to use this +Here we get a clear message from Rust indicating that we're trying to use this struct without an implementation of `AsChangeset`. ## Associations @@ -793,19 +793,19 @@ In this case, the parent is `User` and the child is `Posts`. To implement `Associations`, on the child struct use the [`#[derive(Associations)]`][associations_doc] annotation. -You will also need the `#[belongs_to(ParentStruct)]` annotation to reference its parent. +You will also need the `#[diesel(belongs_to(ParentStruct))]` annotation to reference its parent. [associations_doc]: https://docs.diesel.rs/diesel/associations/index.html Both parent and child structs must have the [Identifiable](#identifiable) trait implemented. By default, the foreign key column on the child should take the form of `parent_id`. If there is a custom foreign key, -the `belongs_to` attribute must be written as -`#[belongs_to(ParentStruct, foreign_key="my_custom_key")]`. +the `belongs_to` attribute must be written as +`#[diesel(belongs_to(ParentStruct, foreign_key = my_custom_key))]`. Let's take a look at how we would set up the relation between a User and their Posts. -### Example +### Example ```rust // Output of "diesel print-schema" @@ -843,7 +843,7 @@ pub struct User { } #[derive(Insertable)] -#[table_name="users"] +#[diesel(table_name = users)] pub struct NewUser<'a> { pub first_name: &'a str, pub last_name: &'a str, @@ -851,7 +851,7 @@ pub struct NewUser<'a> { } #[derive(AsChangeset)] -#[table_name="users"] +#[diesel(table_name = users)] pub struct UpdateUser<'a> { pub first_name: &'a str, pub last_name: &'a str, @@ -860,7 +860,7 @@ pub struct UpdateUser<'a> { // Setting up the association to users #[derive(Identifiable, Associations, Queryable)] -#[belongs_to(User)] +#[diesel(belongs_to(User))] pub struct Post { pub id: i32, pub user_id: i32, @@ -870,7 +870,7 @@ pub struct Post { // Lets us insert new posts #[derive(Insertable)] -#[table_name="posts"] +#[diesel(table_name = posts)] pub struct NewPost<'a> { pub user_id: i32, pub title: &'a str, @@ -885,9 +885,9 @@ pub struct NewPost<'a> { use diesel::prelude::*; fn main() { - let new_user = NewUser { - first_name: "Issac", - last_name: "Kleiner", + let new_user = NewUser { + first_name: "Issac", + last_name: "Kleiner", email: Some("issac.kleiner@blackmesa.co"), }; @@ -896,7 +896,7 @@ fn main() { .get_result::(&db_connection) .expect("Error inserting row into database"); - // Setting up our posts vec and pointing each post to the + // Setting up our posts vec and pointing each post to the // most recently inserted user let post_list = vec![ NewPost {