From 246e55d9c495df09b28c774b5644ba4f79d950e4 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 24 Mar 2023 07:39:30 +0100 Subject: [PATCH] Update to syn 2.0 --- diesel_cli/Cargo.toml | 2 +- diesel_compile_tests/Cargo.lock | 70 +++++------ ...ngeset_struct_with_only_primary_key.stderr | 8 +- .../tests/fail/derive/bad_belongs_to.stderr | 6 +- .../tests/fail/derive/bad_column_name.stderr | 3 +- .../fail/derive/bad_deserialize_as.stderr | 3 +- .../tests/fail/derive/bad_mysql_type.stderr | 9 +- .../fail/derive/bad_postgres_type.stderr | 30 ++--- .../tests/fail/derive/bad_primary_key.stderr | 3 +- .../tests/fail/derive/bad_serialize_as.stderr | 3 +- .../tests/fail/derive/bad_sql_type.stderr | 3 +- .../tests/fail/derive/bad_sqlite_type.stderr | 9 +- .../tests/fail/derive/bad_table_name.stderr | 5 +- .../bad_treat_none_as_default_value.stderr | 3 +- .../fail/derive/bad_treat_none_as_null.stderr | 3 +- ...ed_and_serialize_as_cannot_be_mixed.stderr | 4 +- .../fail/derive/multiple_table_names.stderr | 15 +-- .../deprecated_belongs_to.stderr | 13 +- .../deprecated_changeset_options.stderr | 7 +- .../deprecated_column_name.stderr | 5 +- .../deprecated_mysql_type.stderr | 5 +- .../deprecated_postgres_type.stderr | 26 ++-- .../deprecated_primary_key.stderr | 4 +- .../deprecated_sql_type.stderr | 10 +- .../deprecated_sqlite_type.stderr | 5 +- .../deprecated_table_name.stderr | 5 +- diesel_derives/Cargo.toml | 3 +- diesel_derives/src/as_changeset.rs | 80 ++++++------ diesel_derives/src/as_expression.rs | 19 +-- diesel_derives/src/associations.rs | 28 +++-- diesel_derives/src/attrs.rs | 117 +++++++++--------- diesel_derives/src/deprecated/belongs_to.rs | 13 +- .../src/deprecated/changeset_options.rs | 13 +- diesel_derives/src/deprecated/mod.rs | 17 +-- .../src/deprecated/postgres_type.rs | 13 +- diesel_derives/src/deprecated/primary_key.rs | 7 +- diesel_derives/src/deprecated/utils.rs | 10 +- diesel_derives/src/diesel_for_each_tuple.rs | 1 + diesel_derives/src/diesel_numeric_ops.rs | 2 + diesel_derives/src/diesel_public_if.rs | 23 ++-- diesel_derives/src/field.rs | 36 +++--- diesel_derives/src/from_sql_row.rs | 13 +- diesel_derives/src/identifiable.rs | 24 ++-- diesel_derives/src/insertable.rs | 101 ++++++++------- diesel_derives/src/lib.rs | 62 ++++++---- diesel_derives/src/model.rs | 46 ++++--- diesel_derives/src/parsers/belongs_to.rs | 2 +- diesel_derives/src/parsers/mysql_type.rs | 14 ++- diesel_derives/src/parsers/postgres_type.rs | 46 ++++--- diesel_derives/src/parsers/sqlite_type.rs | 14 ++- diesel_derives/src/query_id.rs | 2 + diesel_derives/src/queryable.rs | 11 +- diesel_derives/src/queryable_by_name.rs | 57 +++++---- diesel_derives/src/selectable.rs | 38 +++--- diesel_derives/src/sql_function.rs | 35 +++--- diesel_derives/src/sql_type.rs | 10 +- diesel_derives/src/table.rs | 1 + diesel_derives/src/util.rs | 76 +++++++----- diesel_derives/src/valid_grouping.rs | 17 +-- diesel_table_macro_syntax/Cargo.toml | 2 +- diesel_table_macro_syntax/src/lib.rs | 37 +++++- 61 files changed, 660 insertions(+), 589 deletions(-) diff --git a/diesel_cli/Cargo.toml b/diesel_cli/Cargo.toml index 102d2d5427d4..7f252456002d 100644 --- a/diesel_cli/Cargo.toml +++ b/diesel_cli/Cargo.toml @@ -32,7 +32,7 @@ diffy = "0.3.0" regex = "1.0.6" serde_regex = "1.1" diesel_table_macro_syntax = {version = "0.1", path = "../diesel_table_macro_syntax"} -syn = { version = "1", features = ["visit"] } +syn = { version = "2", features = ["visit"] } [dependencies.diesel] version = "~2.0.0" diff --git a/diesel_compile_tests/Cargo.lock b/diesel_compile_tests/Cargo.lock index f15efab591c3..853e57a994b9 100644 --- a/diesel_compile_tests/Cargo.lock +++ b/diesel_compile_tests/Cargo.lock @@ -92,20 +92,19 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.0.1" +version = "2.0.2" dependencies = [ "diesel_table_macro_syntax", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.8", ] [[package]] name = "diesel_table_macro_syntax" version = "0.1.0" dependencies = [ - "syn", + "syn 2.0.8", ] [[package]] @@ -315,44 +314,20 @@ 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" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.10" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -412,7 +387,7 @@ checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.94", ] [[package]] @@ -443,6 +418,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "syn" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "termcolor" version = "1.1.2" @@ -515,6 +501,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -554,12 +546,6 @@ 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 = "wasm-bindgen" version = "0.2.82" @@ -581,7 +567,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.94", "wasm-bindgen-shared", ] @@ -603,7 +589,7 @@ checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.94", "wasm-bindgen-backend", "wasm-bindgen-shared", ] 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 index f4827808f85c..71bb02767fe8 100644 --- 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 @@ -1,19 +1,19 @@ 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. --> tests/fail/derive/as_changeset_struct_with_only_primary_key.rs:18:10 | 18 | #[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 the derive macro `AsChangeset` (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. --> tests/fail/derive/as_changeset_struct_with_only_primary_key.rs:24:10 | 24 | #[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 the derive macro `AsChangeset` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/diesel_compile_tests/tests/fail/derive/bad_belongs_to.stderr b/diesel_compile_tests/tests/fail/derive/bad_belongs_to.stderr index 4058f7561a5e..6c444a5329c4 100644 --- a/diesel_compile_tests/tests/fail/derive/bad_belongs_to.stderr +++ b/diesel_compile_tests/tests/fail/derive/bad_belongs_to.stderr @@ -1,10 +1,9 @@ error: unexpected end of input, expected parentheses + help: The correct format looks like `#[diesel(belongs_to(Foo, foreign_key = foo_id))]` --> tests/fail/derive/bad_belongs_to.rs:29:20 | 29 | #[diesel(belongs_to)] | ^ - | - = help: The correct format looks like `#[diesel(belongs_to(Foo, foreign_key = foo_id))]` error: expected parentheses --> tests/fail/derive/bad_belongs_to.rs:36:21 @@ -31,12 +30,11 @@ error: expected `,` | ^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(belongs_to(Foo, foreign_key = foo_id))]` --> tests/fail/derive/bad_belongs_to.rs:64:37 | 64 | #[diesel(belongs_to(Bar, foreign_key))] | ^ - | - = help: The correct format looks like `#[diesel(belongs_to(Foo, foreign_key = foo_id))]` error: expected `=` --> tests/fail/derive/bad_belongs_to.rs:71:37 diff --git a/diesel_compile_tests/tests/fail/derive/bad_column_name.stderr b/diesel_compile_tests/tests/fail/derive/bad_column_name.stderr index 6c004664dc39..47e7baef6d0a 100644 --- a/diesel_compile_tests/tests/fail/derive/bad_column_name.stderr +++ b/diesel_compile_tests/tests/fail/derive/bad_column_name.stderr @@ -1,10 +1,9 @@ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(column_name = foo)]` --> tests/fail/derive/bad_column_name.rs:16:25 | 16 | #[diesel(column_name)] | ^ - | - = help: The correct format looks like `#[diesel(column_name = foo)]` error: expected `=` --> tests/fail/derive/bad_column_name.rs:23:25 diff --git a/diesel_compile_tests/tests/fail/derive/bad_deserialize_as.stderr b/diesel_compile_tests/tests/fail/derive/bad_deserialize_as.stderr index 8b7ded22ce6f..787b6e7412c4 100644 --- a/diesel_compile_tests/tests/fail/derive/bad_deserialize_as.stderr +++ b/diesel_compile_tests/tests/fail/derive/bad_deserialize_as.stderr @@ -1,10 +1,9 @@ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(deserialize_as = Foo)]` --> tests/fail/derive/bad_deserialize_as.rs:7:28 | 7 | #[diesel(deserialize_as)] | ^ - | - = help: The correct format looks like `#[diesel(deserialize_as = Foo)]` error: expected `=` --> tests/fail/derive/bad_deserialize_as.rs:14:28 diff --git a/diesel_compile_tests/tests/fail/derive/bad_mysql_type.stderr b/diesel_compile_tests/tests/fail/derive/bad_mysql_type.stderr index 575df6a81526..83a0b5494316 100644 --- a/diesel_compile_tests/tests/fail/derive/bad_mysql_type.stderr +++ b/diesel_compile_tests/tests/fail/derive/bad_mysql_type.stderr @@ -1,18 +1,16 @@ error: unexpected end of input, expected parentheses + help: The correct format looks like `#[diesel(mysql_type(name = "foo"))]` --> tests/fail/derive/bad_mysql_type.rs:6:20 | 6 | #[diesel(mysql_type)] | ^ - | - = help: The correct format looks like `#[diesel(mysql_type(name = "foo"))]` error: expected attribute `name` + help: The correct format looks like #[diesel(mysql_type(name = "foo"))] --> tests/fail/derive/bad_mysql_type.rs:10:21 | 10 | #[diesel(mysql_type())] | ^ - | - = help: The correct format looks like #[diesel(mysql_type(name = "foo"))] error: expected parentheses --> tests/fail/derive/bad_mysql_type.rs:14:21 @@ -21,12 +19,11 @@ error: expected parentheses | ^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(mysql_type(name = "foo"))]` --> tests/fail/derive/bad_mysql_type.rs:18:25 | 18 | #[diesel(mysql_type(name))] | ^ - | - = help: The correct format looks like `#[diesel(mysql_type(name = "foo"))]` error: expected `=` --> tests/fail/derive/bad_mysql_type.rs:22:25 diff --git a/diesel_compile_tests/tests/fail/derive/bad_postgres_type.stderr b/diesel_compile_tests/tests/fail/derive/bad_postgres_type.stderr index 7e52c61ceeaa..f78b2135c217 100644 --- a/diesel_compile_tests/tests/fail/derive/bad_postgres_type.stderr +++ b/diesel_compile_tests/tests/fail/derive/bad_postgres_type.stderr @@ -1,18 +1,16 @@ error: unexpected end of input, expected parentheses + help: The correct format looks like `#[diesel(postgres_type(name = "foo", schema = "public"))]` --> tests/fail/derive/bad_postgres_type.rs:6:23 | 6 | #[diesel(postgres_type)] | ^ - | - = help: The correct format looks like `#[diesel(postgres_type(name = "foo", schema = "public"))]` error: expected `oid` and `array_oid` attribute or `name` attribute + help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` --> tests/fail/derive/bad_postgres_type.rs:10:24 | 10 | #[diesel(postgres_type())] | ^ - | - = help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` error: expected parentheses --> tests/fail/derive/bad_postgres_type.rs:14:24 @@ -21,12 +19,11 @@ error: expected parentheses | ^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(postgres_type(name = "foo", schema = "public"))]` --> tests/fail/derive/bad_postgres_type.rs:18:28 | 18 | #[diesel(postgres_type(name))] | ^ - | - = help: The correct format looks like `#[diesel(postgres_type(name = "foo", schema = "public"))]` error: expected `=` --> tests/fail/derive/bad_postgres_type.rs:22:28 @@ -41,28 +38,25 @@ error: expected string literal | ^^^ error: unexpected `oid` when `name` is present + help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` --> tests/fail/derive/bad_postgres_type.rs:30:38 | 30 | #[diesel(postgres_type(name = "foo", oid = 2, array_oid = 3))] | ^^^ - | - = help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` error: unexpected `array_oid` when `name` is present + help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` --> tests/fail/derive/bad_postgres_type.rs:34:38 | 34 | #[diesel(postgres_type(name = "foo", array_oid = 3))] | ^^^^^^^^^ - | - = help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` error: expected `oid` and `array_oid` attribute or `name` attribute + help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` --> tests/fail/derive/bad_postgres_type.rs:38:31 | 38 | #[diesel(postgres_type(oid = 2))] | ^ - | - = help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` error: expected integer literal --> tests/fail/derive/bad_postgres_type.rs:42:45 @@ -77,12 +71,11 @@ error: expected integer literal | ^^^ error: expected `name` to be also present + help: make sure `name` is present, `#[diesel(postgres_type(name = "...", schema = "foo"))]` --> tests/fail/derive/bad_postgres_type.rs:50:24 | 50 | #[diesel(postgres_type(schema = "foo"))] | ^^^^^^ - | - = help: make sure `name` is present, `#[diesel(postgres_type(name = "...", schema = "foo"))]` error: unknown attribute, expected one of `oid`, `array_oid`, `name`, `schema` --> tests/fail/derive/bad_postgres_type.rs:54:24 @@ -91,25 +84,22 @@ error: unknown attribute, expected one of `oid`, `array_oid`, `name`, `schema` | ^^^^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(postgres_type(name = "foo", schema = "public"))]` --> tests/fail/derive/bad_postgres_type.rs:58:30 | 58 | #[diesel(postgres_type(schema))] | ^ - | - = help: The correct format looks like `#[diesel(postgres_type(name = "foo", schema = "public"))]` error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(postgres_type(oid = 37, array_oid = 54))]` --> tests/fail/derive/bad_postgres_type.rs:62:27 | 62 | #[diesel(postgres_type(oid))] | ^ - | - = help: The correct format looks like `#[diesel(postgres_type(oid = 37, array_oid = 54))]` error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(postgres_type(oid = 37, array_oid = 54))]` --> tests/fail/derive/bad_postgres_type.rs:66:33 | 66 | #[diesel(postgres_type(array_oid))] | ^ - | - = help: The correct format looks like `#[diesel(postgres_type(oid = 37, array_oid = 54))]` diff --git a/diesel_compile_tests/tests/fail/derive/bad_primary_key.stderr b/diesel_compile_tests/tests/fail/derive/bad_primary_key.stderr index 47086bf33846..8e9d6286e516 100644 --- a/diesel_compile_tests/tests/fail/derive/bad_primary_key.stderr +++ b/diesel_compile_tests/tests/fail/derive/bad_primary_key.stderr @@ -11,12 +11,11 @@ error: expected `,` | ^ error: unexpected end of input, expected parentheses + help: The correct format looks like `#[diesel(key1, key2)]` --> tests/fail/derive/bad_primary_key.rs:26:21 | 26 | #[diesel(primary_key)] | ^ - | - = help: The correct format looks like `#[diesel(key1, key2)]` error: expected parentheses --> tests/fail/derive/bad_primary_key.rs:33:22 diff --git a/diesel_compile_tests/tests/fail/derive/bad_serialize_as.stderr b/diesel_compile_tests/tests/fail/derive/bad_serialize_as.stderr index 8bc2d02809f4..b38cd3de8bc7 100644 --- a/diesel_compile_tests/tests/fail/derive/bad_serialize_as.stderr +++ b/diesel_compile_tests/tests/fail/derive/bad_serialize_as.stderr @@ -1,10 +1,9 @@ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(serialize_as = Foo)]` --> tests/fail/derive/bad_serialize_as.rs:15:26 | 15 | #[diesel(serialize_as)] | ^ - | - = help: The correct format looks like `#[diesel(serialize_as = Foo)]` error: expected `=` --> tests/fail/derive/bad_serialize_as.rs:23:26 diff --git a/diesel_compile_tests/tests/fail/derive/bad_sql_type.stderr b/diesel_compile_tests/tests/fail/derive/bad_sql_type.stderr index 8bbfbf08b852..5632750b1bc0 100644 --- a/diesel_compile_tests/tests/fail/derive/bad_sql_type.stderr +++ b/diesel_compile_tests/tests/fail/derive/bad_sql_type.stderr @@ -1,10 +1,9 @@ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(sql_type = Foo)]` --> tests/fail/derive/bad_sql_type.rs:5:18 | 5 | #[diesel(sql_type)] | ^ - | - = help: The correct format looks like `#[diesel(sql_type = Foo)]` error: expected `=` --> tests/fail/derive/bad_sql_type.rs:9:18 diff --git a/diesel_compile_tests/tests/fail/derive/bad_sqlite_type.stderr b/diesel_compile_tests/tests/fail/derive/bad_sqlite_type.stderr index 6bf4959ce57a..89dcca63ccb1 100644 --- a/diesel_compile_tests/tests/fail/derive/bad_sqlite_type.stderr +++ b/diesel_compile_tests/tests/fail/derive/bad_sqlite_type.stderr @@ -1,18 +1,16 @@ error: unexpected end of input, expected parentheses + help: The correct format looks like `#[diesel(sqlite_type(name = "foo"))]` --> tests/fail/derive/bad_sqlite_type.rs:6:21 | 6 | #[diesel(sqlite_type)] | ^ - | - = help: The correct format looks like `#[diesel(sqlite_type(name = "foo"))]` error: expected attribute `name` + help: The correct format looks like #[diesel(sqlite_type(name = "foo"))] --> tests/fail/derive/bad_sqlite_type.rs:10:22 | 10 | #[diesel(sqlite_type())] | ^ - | - = help: The correct format looks like #[diesel(sqlite_type(name = "foo"))] error: expected parentheses --> tests/fail/derive/bad_sqlite_type.rs:14:22 @@ -21,12 +19,11 @@ error: expected parentheses | ^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(sqlite_type(name = "foo"))]` --> tests/fail/derive/bad_sqlite_type.rs:18:26 | 18 | #[diesel(sqlite_type(name))] | ^ - | - = help: The correct format looks like `#[diesel(sqlite_type(name = "foo"))]` error: expected `=` --> tests/fail/derive/bad_sqlite_type.rs:22:26 diff --git a/diesel_compile_tests/tests/fail/derive/bad_table_name.stderr b/diesel_compile_tests/tests/fail/derive/bad_table_name.stderr index 96092f80dd77..330580575e86 100644 --- a/diesel_compile_tests/tests/fail/derive/bad_table_name.stderr +++ b/diesel_compile_tests/tests/fail/derive/bad_table_name.stderr @@ -1,10 +1,9 @@ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(table_name = foo)]` --> tests/fail/derive/bad_table_name.rs:12:20 | 12 | #[diesel(table_name)] | ^ - | - = help: The correct format looks like `#[diesel(table_name = foo)]` error: expected `=` --> tests/fail/derive/bad_table_name.rs:18:20 @@ -12,7 +11,7 @@ error: expected `=` 18 | #[diesel(table_name(users))] | ^ -error: expected identifier +error: expected identifier, found keyword `true` --> tests/fail/derive/bad_table_name.rs:24:23 | 24 | #[diesel(table_name = true)] 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 index 1553c222a3c0..6caaa3cbe1ba 100644 --- 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 @@ -5,12 +5,11 @@ error: expected `=` | ^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(treat_none_as_default_value = true)]` --> tests/fail/derive/bad_treat_none_as_default_value.rs:21:37 | 21 | #[diesel(treat_none_as_default_value)] | ^ - | - = help: The correct format looks like `#[diesel(treat_none_as_default_value = true)]` error: expected boolean literal --> tests/fail/derive/bad_treat_none_as_default_value.rs:29:40 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 index a5512d469cdc..84a0a94bb63e 100644 --- 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 @@ -5,12 +5,11 @@ error: expected `=` | ^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(treat_none_as_null = true)]` --> tests/fail/derive/bad_treat_none_as_null.rs:21:28 | 21 | #[diesel(treat_none_as_null)] | ^ - | - = help: The correct format looks like `#[diesel(treat_none_as_null = true)]` error: expected boolean literal --> tests/fail/derive/bad_treat_none_as_null.rs:29:31 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 index 9c5b8749d6bc..e9b6f799bac6 100644 --- 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 @@ -1,5 +1,5 @@ error: `#[diesel(embed)]` cannot be combined with `#[diesel(serialize_as)]` - --> $DIR/embed_and_serialize_as_cannot_be_mixed.rs:22:13 + --> tests/fail/derive/embed_and_serialize_as_cannot_be_mixed.rs:22:7 | 22 | #[diesel(embed, serialize_as = SomeType)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/diesel_compile_tests/tests/fail/derive/multiple_table_names.stderr b/diesel_compile_tests/tests/fail/derive/multiple_table_names.stderr index 0eef5f7d6906..fbfa5def4a13 100644 --- a/diesel_compile_tests/tests/fail/derive/multiple_table_names.stderr +++ b/diesel_compile_tests/tests/fail/derive/multiple_table_names.stderr @@ -1,39 +1,34 @@ error: expected a single table name attribute + note: remove this attribute --> tests/fail/derive/multiple_table_names.rs:29:30 | 29 | #[diesel(table_name = users, table_name = users_)] | ^^^^^^^^^^ - | - = note: remove this attribute error: expected a single table name attribute + note: remove this attribute --> tests/fail/derive/multiple_table_names.rs:37:30 | 37 | #[diesel(table_name = users, table_name = users_)] | ^^^^^^^^^^ - | - = note: remove this attribute error: expected a single table name attribute + note: remove this attribute --> tests/fail/derive/multiple_table_names.rs:44:30 | 44 | #[diesel(table_name = users, table_name = users_)] | ^^^^^^^^^^ - | - = note: remove this attribute error: expected a single table name attribute + note: remove this attribute --> tests/fail/derive/multiple_table_names.rs:52:10 | 52 | #[diesel(table_name = users_)] | ^^^^^^^^^^ - | - = note: remove this attribute error: expected a single table name attribute + note: remove this attribute --> tests/fail/derive/multiple_table_names.rs:59:30 | 59 | #[diesel(table_name = users, table_name = users_)] | ^^^^^^^^^^ - | - = note: remove this attribute diff --git a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_belongs_to.stderr b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_belongs_to.stderr index 448dcae6b52d..8e72f2c2179d 100644 --- a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_belongs_to.stderr +++ b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_belongs_to.stderr @@ -1,10 +1,9 @@ error: unexpected end of input, expected parentheses + help: The correct format looks like `#[diesel(belongs_to(Foo, foreign_key = foo_id))]` --> tests/fail/derive_deprecated/deprecated_belongs_to.rs:29:3 | 29 | #[belongs_to] | ^^^^^^^^^^ - | - = help: The correct format looks like `#[diesel(belongs_to(Foo, foreign_key = foo_id))]` error: expected parentheses --> tests/fail/derive_deprecated/deprecated_belongs_to.rs:36:14 @@ -13,10 +12,10 @@ error: expected parentheses | ^ error: unexpected end of input, expected identifier - --> tests/fail/derive_deprecated/deprecated_belongs_to.rs:43:14 + --> tests/fail/derive_deprecated/deprecated_belongs_to.rs:43:13 | 43 | #[belongs_to()] - | ^ + | ^^ error: expected identifier --> tests/fail/derive_deprecated/deprecated_belongs_to.rs:50:14 @@ -25,12 +24,11 @@ error: expected identifier | ^^^^^^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(belongs_to(Foo, foreign_key = foo_id))]` --> tests/fail/derive_deprecated/deprecated_belongs_to.rs:57:14 | 57 | #[belongs_to(parent)] | ^^^^^^ - | - = help: The correct format looks like `#[diesel(belongs_to(Foo, foreign_key = foo_id))]` error: expected `=` --> tests/fail/derive_deprecated/deprecated_belongs_to.rs:64:20 @@ -57,12 +55,11 @@ error: expected `foreign_key` | ^^^^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(belongs_to(Foo, foreign_key = foo_id))]` --> tests/fail/derive_deprecated/deprecated_belongs_to.rs:99:19 | 99 | #[belongs_to(Bar, foreign_key)] | ^^^^^^^^^^^ - | - = help: The correct format looks like `#[diesel(belongs_to(Foo, foreign_key = foo_id))]` error: expected string literal --> tests/fail/derive_deprecated/deprecated_belongs_to.rs:106:33 diff --git a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_changeset_options.stderr b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_changeset_options.stderr index b0f8e38f9e53..3ca8692bf691 100644 --- a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_changeset_options.stderr +++ b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_changeset_options.stderr @@ -5,10 +5,10 @@ error: unexpected end of input, expected parentheses | ^^^^^^^^^^^^^^^^^ error: unexpected end of input, expected identifier - --> tests/fail/derive_deprecated/deprecated_changeset_options.rs:29:21 + --> tests/fail/derive_deprecated/deprecated_changeset_options.rs:29:20 | 29 | #[changeset_options()] - | ^ + | ^^ error: expected `treat_none_as_null` --> tests/fail/derive_deprecated/deprecated_changeset_options.rs:37:21 @@ -17,12 +17,11 @@ error: expected `treat_none_as_null` | ^^^^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(treat_none_as_null = true)]` --> tests/fail/derive_deprecated/deprecated_changeset_options.rs:45:21 | 45 | #[changeset_options(treat_none_as_null)] | ^^^^^^^^^^^^^^^^^^ - | - = help: The correct format looks like `#[diesel(treat_none_as_null = true)]` error: expected boolean literal --> tests/fail/derive_deprecated/deprecated_changeset_options.rs:53:42 diff --git a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_column_name.stderr b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_column_name.stderr index 220a178a0101..327719a674e2 100644 --- a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_column_name.stderr +++ b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_column_name.stderr @@ -1,16 +1,15 @@ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(column_name = foo)]` --> tests/fail/derive_deprecated/deprecated_column_name.rs:24:7 | 24 | #[column_name] | ^^^^^^^^^^^ - | - = help: The correct format looks like `#[diesel(column_name = foo)]` error: expected `=` --> tests/fail/derive_deprecated/deprecated_column_name.rs:31:18 | 31 | #[column_name()] - | ^ + | ^^ error: expected string literal --> tests/fail/derive_deprecated/deprecated_column_name.rs:38:21 diff --git a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_mysql_type.stderr b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_mysql_type.stderr index 568183b4c363..29ec838978ea 100644 --- a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_mysql_type.stderr +++ b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_mysql_type.stderr @@ -1,16 +1,15 @@ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(mysql_type(name = "foo"))]` --> tests/fail/derive_deprecated/deprecated_mysql_type.rs:6:3 | 6 | #[mysql_type] | ^^^^^^^^^^ - | - = help: The correct format looks like `#[diesel(mysql_type(name = "foo"))]` error: expected `=` --> tests/fail/derive_deprecated/deprecated_mysql_type.rs:10:13 | 10 | #[mysql_type()] - | ^ + | ^^ error: expected string literal --> tests/fail/derive_deprecated/deprecated_mysql_type.rs:14:16 diff --git a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_postgres_type.stderr b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_postgres_type.stderr index 30f26e0f7d81..a56b2f9b728d 100644 --- a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_postgres_type.stderr +++ b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_postgres_type.stderr @@ -1,18 +1,16 @@ error: unexpected end of input, expected parentheses + help: The correct format looks like `#[diesel(postgres_type(name = "foo", schema = "public"))]` --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:6:3 | 6 | #[postgres] | ^^^^^^^^ - | - = help: The correct format looks like `#[diesel(postgres_type(name = "foo", schema = "public"))]` error: expected `oid` and `array_oid` attribute or `name` attribute - --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:10:12 + help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` + --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:10:11 | 10 | #[postgres()] - | ^ - | - = help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` + | ^^ error: expected parentheses --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:14:12 @@ -21,12 +19,11 @@ error: expected parentheses | ^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(postgres_type(name = "foo", schema = "public"))]` --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:18:12 | 18 | #[postgres(type_name)] | ^^^^^^^^^ - | - = help: The correct format looks like `#[diesel(postgres_type(name = "foo", schema = "public"))]` error: expected `=` --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:22:21 @@ -41,28 +38,25 @@ error: expected string literal | ^ error: unexpected `oid` when `name` is present + help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:30:31 | 30 | #[postgres(type_name = "foo", oid = "2", array_oid = "3")] | ^^^ - | - = help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` error: unexpected `array_oid` when `name` is present + help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:34:31 | 34 | #[postgres(type_name = "foo", array_oid = "3")] | ^^^^^^^^^ - | - = help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` error: expected `oid` and `array_oid` attribute or `name` attribute - --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:38:21 + help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` + --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:38:11 | 38 | #[postgres(oid = "2")] - | ^ - | - = help: The correct format looks like either `#[diesel(postgres_type(name = "foo", schema = "public"))]` or `#[diesel(postgres_type(oid = 37, array_oid = 54))]` + | ^^^^^^^^^^^ error: expected string literal --> tests/fail/derive_deprecated/deprecated_postgres_type.rs:42:18 diff --git a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_primary_key.stderr b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_primary_key.stderr index af60626df63a..e2b42ca2d656 100644 --- a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_primary_key.stderr +++ b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_primary_key.stderr @@ -23,13 +23,13 @@ error: expected parentheses | ^ 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. --> tests/fail/derive_deprecated/deprecated_primary_key.rs:39:10 | 39 | #[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 the derive macro `AsChangeset` (in Nightly builds, run with -Z macro-backtrace for more info) error: unexpected expression: `id` diff --git a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_sql_type.stderr b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_sql_type.stderr index 6db0b7842625..4636f06ec8c8 100644 --- a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_sql_type.stderr +++ b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_sql_type.stderr @@ -1,16 +1,15 @@ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(sql_type = Foo)]` --> tests/fail/derive_deprecated/deprecated_sql_type.rs:10:3 | 10 | #[sql_type] | ^^^^^^^^ - | - = help: The correct format looks like `#[diesel(sql_type = Foo)]` error: expected `=` --> tests/fail/derive_deprecated/deprecated_sql_type.rs:14:11 | 14 | #[sql_type()] - | ^ + | ^^ error: expected string literal --> tests/fail/derive_deprecated/deprecated_sql_type.rs:18:14 @@ -25,18 +24,17 @@ error: expected identifier | ^^^ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(sql_type = Foo)]` --> tests/fail/derive_deprecated/deprecated_sql_type.rs:33:7 | 33 | #[sql_type] | ^^^^^^^^ - | - = help: The correct format looks like `#[diesel(sql_type = Foo)]` error: expected `=` --> tests/fail/derive_deprecated/deprecated_sql_type.rs:39:15 | 39 | #[sql_type()] - | ^ + | ^^ error: expected string literal --> tests/fail/derive_deprecated/deprecated_sql_type.rs:45:18 diff --git a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_sqlite_type.stderr b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_sqlite_type.stderr index abc9a84e5e21..3de203b4ac87 100644 --- a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_sqlite_type.stderr +++ b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_sqlite_type.stderr @@ -1,16 +1,15 @@ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(sqlite_type(name = "foo"))]` --> tests/fail/derive_deprecated/deprecated_sqlite_type.rs:6:3 | 6 | #[sqlite_type] | ^^^^^^^^^^^ - | - = help: The correct format looks like `#[diesel(sqlite_type(name = "foo"))]` error: expected `=` --> tests/fail/derive_deprecated/deprecated_sqlite_type.rs:10:14 | 10 | #[sqlite_type()] - | ^ + | ^^ error: expected string literal --> tests/fail/derive_deprecated/deprecated_sqlite_type.rs:14:17 diff --git a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_table_name.stderr b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_table_name.stderr index 3c1dec205d2c..d57f04413823 100644 --- a/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_table_name.stderr +++ b/diesel_compile_tests/tests/fail/derive_deprecated/deprecated_table_name.stderr @@ -1,16 +1,15 @@ error: unexpected end of input, expected `=` + help: The correct format looks like `#[diesel(table_name = foo)]` --> tests/fail/derive_deprecated/deprecated_table_name.rs:12:3 | 12 | #[table_name] | ^^^^^^^^^^ - | - = help: The correct format looks like `#[diesel(table_name = foo)]` error: expected `=` --> tests/fail/derive_deprecated/deprecated_table_name.rs:19:13 | 19 | #[table_name()] - | ^ + | ^^ error: expected string literal --> tests/fail/derive_deprecated/deprecated_table_name.rs:25:16 diff --git a/diesel_derives/Cargo.toml b/diesel_derives/Cargo.toml index 4408693e2516..f71921332d05 100644 --- a/diesel_derives/Cargo.toml +++ b/diesel_derives/Cargo.toml @@ -11,10 +11,9 @@ include = ["src/**/*", "LICENSE-*"] rust-version = "1.65.0" [dependencies] -syn = { version = "1.0.73", features = ["derive", "fold", "full"] } +syn = { version = "2.0", features = ["derive", "fold", "full"] } quote = "1.0.9" proc-macro2 = "1.0.27" -proc-macro-error = "1.0.4" diesel_table_macro_syntax = {version = "0.1", path = "../diesel_table_macro_syntax"} [dev-dependencies] diff --git a/diesel_derives/src/as_changeset.rs b/diesel_derives/src/as_changeset.rs index c6ad20ce9e0c..c71240847707 100644 --- a/diesel_derives/src/as_changeset.rs +++ b/diesel_derives/src/as_changeset.rs @@ -1,13 +1,14 @@ use proc_macro2::TokenStream; -use syn::{DeriveInput, Expr, Path, Type}; +use quote::quote; +use syn::{parse_quote, DeriveInput, Expr, Path, Result, Type}; use attrs::AttributeSpanWrapper; 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, false); +pub fn derive(item: DeriveInput) -> Result { + let model = Model::from_item(&item, false, false)?; let struct_name = &item.ident; let table_name = &model.table_names()[0]; @@ -19,16 +20,17 @@ pub fn derive(item: DeriveInput) -> TokenStream { !model .primary_key_names .iter() - .any(|p| f.column_name() == *p) + .any(|p| f.column_name().map(|f| f == *p).unwrap_or_default()) }) .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."; - ) + return Err(syn::Error::new( + proc_macro2::Span::call_site(), + "Deriving `AsChangeset` on a structure that only contains primary keys isn't supported.\n\ + help: If you want to change the primary key of a row, you should do so with `.set(table::id.eq(new_id))`.\n\ + note: `#[derive(AsChangeset)]` never changes the primary key of a row." + )); } let treat_none_as_null = model.treat_none_as_null(); @@ -50,13 +52,13 @@ pub fn derive(item: DeriveInput) -> TokenStream { table_name, ty, treat_none_as_null, - )); + )?); direct_field_assign.push(field_changeset_expr_serialize_as( field, table_name, ty, treat_none_as_null, - )); + )?); generate_borrowed_changeset = false; // as soon as we hit one field with #[diesel(serialize_as)] there is no point in generating the impl of AsChangeset for borrowed structs } @@ -66,25 +68,25 @@ pub fn derive(item: DeriveInput) -> TokenStream { table_name, None, treat_none_as_null, - )); + )?); direct_field_assign.push(field_changeset_expr( field, table_name, None, treat_none_as_null, - )); + )?); ref_field_ty.push(field_changeset_ty( field, table_name, Some(quote!(&'update)), treat_none_as_null, - )); + )?); ref_field_assign.push(field_changeset_expr( field, table_name, Some(quote!(&)), treat_none_as_null, - )); + )?); } } } @@ -123,14 +125,14 @@ pub fn derive(item: DeriveInput) -> TokenStream { quote! {} }; - wrap_in_dummy_mod(quote!( + Ok(wrap_in_dummy_mod(quote!( use diesel::query_builder::AsChangeset; use diesel::prelude::*; #changeset_owned #changeset_borrowed - )) + ))) } fn field_changeset_ty( @@ -138,15 +140,17 @@ fn field_changeset_ty( table_name: &Path, lifetime: Option, treat_none_as_null: bool, -) -> TokenStream { - let column_name = field.column_name(); - column_name.valid_ident(); +) -> Result { + let column_name = field.column_name()?; + column_name.valid_ident()?; if !treat_none_as_null && is_option_ty(&field.ty) { let field_ty = inner_of_option_ty(&field.ty); - quote!(std::option::Option>) + Ok( + quote!(std::option::Option>), + ) } else { let field_ty = &field.ty; - quote!(diesel::dsl::Eq<#table_name::#column_name, #lifetime #field_ty>) + Ok(quote!(diesel::dsl::Eq<#table_name::#column_name, #lifetime #field_ty>)) } } @@ -155,18 +159,18 @@ fn field_changeset_expr( table_name: &Path, lifetime: Option, treat_none_as_null: bool, -) -> TokenStream { +) -> Result { let field_name = &field.name; - let column_name = field.column_name(); - column_name.valid_ident(); + let column_name = field.column_name()?; + column_name.valid_ident()?; if !treat_none_as_null && is_option_ty(&field.ty) { if lifetime.is_some() { - quote!(self.#field_name.as_ref().map(|x| #table_name::#column_name.eq(x))) + Ok(quote!(self.#field_name.as_ref().map(|x| #table_name::#column_name.eq(x)))) } else { - quote!(self.#field_name.map(|x| #table_name::#column_name.eq(x))) + Ok(quote!(self.#field_name.map(|x| #table_name::#column_name.eq(x)))) } } else { - quote!(#table_name::#column_name.eq(#lifetime self.#field_name)) + Ok(quote!(#table_name::#column_name.eq(#lifetime self.#field_name))) } } @@ -175,14 +179,14 @@ fn field_changeset_ty_serialize_as( table_name: &Path, ty: &Type, treat_none_as_null: bool, -) -> TokenStream { - let column_name = field.column_name(); - column_name.valid_ident(); +) -> Result { + let column_name = field.column_name()?; + column_name.valid_ident()?; if !treat_none_as_null && is_option_ty(&field.ty) { let inner_ty = inner_of_option_ty(ty); - quote!(std::option::Option>) + Ok(quote!(std::option::Option>)) } else { - quote!(diesel::dsl::Eq<#table_name::#column_name, #ty>) + Ok(quote!(diesel::dsl::Eq<#table_name::#column_name, #ty>)) } } @@ -191,14 +195,14 @@ fn field_changeset_expr_serialize_as( table_name: &Path, ty: &Type, treat_none_as_null: bool, -) -> TokenStream { +) -> Result { let field_name = &field.name; - let column_name = field.column_name(); - column_name.valid_ident(); + let column_name = field.column_name()?; + column_name.valid_ident()?; let column: Expr = parse_quote!(#table_name::#column_name); if !treat_none_as_null && is_option_ty(&field.ty) { - quote!(self.#field_name.map(|x| #column.eq(::std::convert::Into::<#ty>::into(x)))) + Ok(quote!(self.#field_name.map(|x| #column.eq(::std::convert::Into::<#ty>::into(x))))) } else { - quote!(#column.eq(::std::convert::Into::<#ty>::into(self.#field_name))) + Ok(quote!(#column.eq(::std::convert::Into::<#ty>::into(self.#field_name)))) } } diff --git a/diesel_derives/src/as_expression.rs b/diesel_derives/src/as_expression.rs index b87933e1e3b9..dd5cd26f3244 100644 --- a/diesel_derives/src/as_expression.rs +++ b/diesel_derives/src/as_expression.rs @@ -1,19 +1,22 @@ use proc_macro2::TokenStream; +use quote::quote; use syn::DeriveInput; +use syn::Result; use model::Model; use util::{ty_for_foreign_derive, wrap_in_dummy_mod}; -pub fn derive(item: DeriveInput) -> TokenStream { - let model = Model::from_item(&item, true, false); +pub fn derive(item: DeriveInput) -> Result { + let model = Model::from_item(&item, true, false)?; if model.sql_types.is_empty() { - abort_call_site!( - "At least one `sql_type` is needed for deriving `AsExpression` on a structure." - ); + return Err(syn::Error::new( + proc_macro2::Span::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 struct_ty = ty_for_foreign_derive(&item, &model)?; let (impl_generics, ..) = item.generics.split_for_impl(); let lifetimes = item.generics.lifetimes().collect::>(); @@ -104,12 +107,12 @@ pub fn derive(item: DeriveInput) -> TokenStream { } }); - wrap_in_dummy_mod(quote! { + Ok(wrap_in_dummy_mod(quote! { use diesel::expression::AsExpression; use diesel::internal::derives::as_expression::Bound; use diesel::sql_types::Nullable; use diesel::serialize::{self, ToSql, Output}; #(#tokens)* - }) + })) } diff --git a/diesel_derives/src/associations.rs b/diesel_derives/src/associations.rs index 873eda6fb297..8a7a528419b5 100644 --- a/diesel_derives/src/associations.rs +++ b/diesel_derives/src/associations.rs @@ -1,29 +1,33 @@ use proc_macro2::{Span, TokenStream}; +use quote::quote; use syn::fold::Fold; -use syn::{DeriveInput, Ident, Lifetime}; +use syn::parse_quote; +use syn::{DeriveInput, Ident, Lifetime, Result}; 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, false); +pub fn derive(item: DeriveInput) -> Result { + let model = Model::from_item(&item, false, false)?; if model.belongs_to.is_empty() { - abort_call_site!( - "At least one `belongs_to` is needed for deriving `Associations` on a structure." - ); + return Err(syn::Error::new( + proc_macro2::Span::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)); + .map(|assoc| derive_belongs_to(&item, &model, assoc)) + .collect::>>()?; - wrap_in_dummy_mod(quote!(#(#tokens)*)) + Ok(wrap_in_dummy_mod(quote!(#(#tokens)*))) } -fn derive_belongs_to(item: &DeriveInput, model: &Model, assoc: &BelongsTo) -> TokenStream { +fn derive_belongs_to(item: &DeriveInput, model: &Model, assoc: &BelongsTo) -> Result { let (_, ty_generics, _) = item.generics.split_for_impl(); let struct_name = &item.ident; @@ -31,7 +35,7 @@ fn derive_belongs_to(item: &DeriveInput, model: &Model, assoc: &BelongsTo) -> To let foreign_key = &foreign_key(assoc); - let foreign_key_field = model.find_column(foreign_key); + 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; @@ -64,7 +68,7 @@ fn derive_belongs_to(item: &DeriveInput, model: &Model, assoc: &BelongsTo) -> To let (impl_generics, _, where_clause) = generics.split_for_impl(); - quote! { + Ok(quote! { impl #impl_generics diesel::associations::BelongsTo<#parent_struct> for #struct_name #ty_generics #where_clause @@ -96,7 +100,7 @@ fn derive_belongs_to(item: &DeriveInput, model: &Model, assoc: &BelongsTo) -> To #table_name::#foreign_key } } - } + }) } fn foreign_key(assoc: &BelongsTo) -> Ident { diff --git a/diesel_derives/src/attrs.rs b/diesel_derives/src/attrs.rs index 8dc5d88567b7..af928422ee49 100644 --- a/diesel_derives/src/attrs.rs +++ b/diesel_derives/src/attrs.rs @@ -1,10 +1,9 @@ use std::fmt::{Display, Formatter}; use proc_macro2::{Span, TokenStream}; -use proc_macro_error::ResultExt; use quote::ToTokens; use syn::parse::discouraged::Speculative; -use syn::parse::{Parse, ParseStream, Parser, Result}; +use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::Comma; @@ -22,6 +21,10 @@ use util::{ use crate::field::SelectExpr; use crate::util::{parse_paren_list, CHECK_FOR_BACKEND_NOTE}; +pub trait MySpanned { + fn span(&self) -> Span; +} + pub struct AttributeSpanWrapper { pub item: T, pub attribute_span: Span, @@ -50,15 +53,19 @@ impl SqlIdentifier { self.span } - pub fn valid_ident(&self) { + pub fn valid_ident(&self) -> Result<()> { if syn::parse_str::(&self.field_name).is_err() { - abort!( + Err(syn::Error::new( self.span(), - "Expected valid identifier, found `{0}`. \ + format!( + "Expected valid identifier, found `{0}`. \ Diesel automatically renames invalid identifiers, \ perhaps you meant to write `{0}_`?", - self.field_name - ) + self.field_name + ), + )) + } else { + Ok(()) } } } @@ -136,7 +143,7 @@ impl Parse for FieldAttr { name, parse_eq(input, SELECT_EXPRESSION_TYPE_NOTE)?, )), - _ => unknown_attribute( + _ => Err(unknown_attribute( &name, &[ "embed", @@ -147,12 +154,12 @@ impl Parse for FieldAttr { "select_expression", "select_expression_type", ], - ), + )), } } } -impl Spanned for FieldAttr { +impl MySpanned for FieldAttr { fn span(&self) -> Span { match self { FieldAttr::Embed(ident) @@ -227,14 +234,14 @@ impl Parse for StructAttr { )), "primary_key" => Ok(StructAttr::PrimaryKey( name, - parse_paren_list(input, "key1, key2")?, + parse_paren_list(input, "key1, key2", syn::Token![,])?, )), "check_for_backend" => Ok(StructAttr::CheckForBackend( name, - parse_paren_list(input, CHECK_FOR_BACKEND_NOTE)?, + parse_paren_list(input, CHECK_FOR_BACKEND_NOTE, syn::Token![,])?, )), - _ => unknown_attribute( + _ => Err(unknown_attribute( &name, &[ "aggregate", @@ -251,12 +258,12 @@ impl Parse for StructAttr { "primary_key", "check_for_backend", ], - ), + )), } } } -impl Spanned for StructAttr { +impl MySpanned for StructAttr { fn span(&self) -> Span { match self { StructAttr::Aggregate(ident) @@ -276,50 +283,46 @@ impl Spanned for StructAttr { } } -pub fn parse_attributes(attrs: &[Attribute]) -> Vec> +pub fn parse_attributes(attrs: &[Attribute]) -> Result>> where - T: Parse + ParseDeprecated + Spanned, + T: Parse + ParseDeprecated + MySpanned, { - attrs - .iter() - .flat_map(|attr| { - if attr.path.is_ident("diesel") { - attr.parse_args_with(Punctuated::::parse_terminated) - .unwrap_or_abort() - .into_iter() - .map(|a| AttributeSpanWrapper { - ident_span: a.span(), - item: a, - attribute_span: attr.tokens.span(), - }) - .collect::>() - } else if cfg!(all( - not(feature = "without-deprecated"), - feature = "with-deprecated" - )) { - let mut p = Vec::new(); - let Attribute { path, tokens, .. } = attr; - let ident = path.get_ident().map(|f| f.to_string()); - - if let "sql_type" | "column_name" | "table_name" | "changeset_options" - | "primary_key" | "belongs_to" | "sqlite_type" | "mysql_type" | "postgres" = - ident.as_deref().unwrap_or_default() - { - let ts = quote!(#path #tokens).into(); - let value = Parser::parse(T::parse_deprecated, ts).unwrap_or_abort(); - - if let Some(value) = value { - p.push(AttributeSpanWrapper { - ident_span: value.span(), - item: value, - attribute_span: attr.tokens.span(), - }); - } + let mut out = Vec::new(); + for attr in attrs { + if attr.meta.path().is_ident("diesel") { + let map = attr + .parse_args_with(Punctuated::::parse_terminated)? + .into_iter() + .map(|a| AttributeSpanWrapper { + ident_span: a.span(), + item: a, + attribute_span: attr.meta.span(), + }); + out.extend(map); + } else if cfg!(all( + not(feature = "without-deprecated"), + feature = "with-deprecated" + )) { + let path = attr.meta.path(); + let ident = path.get_ident().map(|f| f.to_string()); + + if let "sql_type" | "column_name" | "table_name" | "changeset_options" | "primary_key" + | "belongs_to" | "sqlite_type" | "mysql_type" | "postgres" = + ident.as_deref().unwrap_or_default() + { + let m = &attr.meta; + let ts = quote::quote!(#m).into(); + let value = syn::parse::Parser::parse(T::parse_deprecated, ts)?; + + if let Some(value) = value { + out.push(AttributeSpanWrapper { + ident_span: value.span(), + item: value, + attribute_span: attr.meta.span(), + }); } - p - } else { - Vec::new() } - }) - .collect() + } + } + Ok(out) } diff --git a/diesel_derives/src/deprecated/belongs_to.rs b/diesel_derives/src/deprecated/belongs_to.rs index e0adfd53047e..16b167c673b3 100644 --- a/diesel_derives/src/deprecated/belongs_to.rs +++ b/diesel_derives/src/deprecated/belongs_to.rs @@ -8,11 +8,14 @@ use util::BELONGS_TO_NOTE; pub fn parse_belongs_to(name: Ident, input: ParseStream) -> Result { if input.is_empty() { - abort!( + return Err(syn::Error::new( name.span(), - "unexpected end of input, expected parentheses"; - help = "The correct format looks like `#[diesel({})]`", BELONGS_TO_NOTE - ); + format!( + "unexpected end of input, expected parentheses\n\ + help: The correct format looks like `#[diesel({})]`", + BELONGS_TO_NOTE + ), + )); } let content; @@ -39,7 +42,7 @@ pub fn parse_belongs_to(name: Ident, input: ParseStream) -> Result { let name: Ident = content.parse()?; if name != "foreign_key" { - abort!(name, "expected `foreign_key`"); + return Err(syn::Error::new(name.span(), "expected `foreign_key`")); } let lit_str = parse_eq_and_lit_str(name, &content, BELONGS_TO_NOTE)?; diff --git a/diesel_derives/src/deprecated/changeset_options.rs b/diesel_derives/src/deprecated/changeset_options.rs index 0212b526d1ac..23c8b2493d4e 100644 --- a/diesel_derives/src/deprecated/changeset_options.rs +++ b/diesel_derives/src/deprecated/changeset_options.rs @@ -1,4 +1,3 @@ -use proc_macro_error::ResultExt; use syn::parse::{ParseStream, Result}; use syn::{parenthesized, Ident, LitBool}; @@ -7,7 +6,10 @@ use util::TREAT_NONE_AS_NULL_NOTE; pub fn parse_changeset_options(name: Ident, input: ParseStream) -> Result<(Ident, LitBool)> { if input.is_empty() { - abort!(name.span(), "unexpected end of input, expected parentheses"); + return Err(syn::Error::new( + name.span(), + "unexpected end of input, expected parentheses", + )); } let content; @@ -17,11 +19,14 @@ pub fn parse_changeset_options(name: Ident, input: ParseStream) -> Result<(Ident let name_str = name.to_string(); if name_str != "treat_none_as_null" { - abort!(name.span(), "expected `treat_none_as_null`"); + return Err(syn::Error::new( + name.span(), + "expected `treat_none_as_null`", + )); } Ok((name.clone(), { let lit_str = parse_eq_and_lit_str(name, &content, TREAT_NONE_AS_NULL_NOTE)?; - lit_str.parse().unwrap_or_abort() + lit_str.parse()? })) } diff --git a/diesel_derives/src/deprecated/mod.rs b/diesel_derives/src/deprecated/mod.rs index 647582a5d93b..7c68774aec08 100644 --- a/diesel_derives/src/deprecated/mod.rs +++ b/diesel_derives/src/deprecated/mod.rs @@ -44,7 +44,6 @@ mod impl_deprecated { use deprecated::utils::parse_eq_and_lit_str; use parsers::{MysqlType, PostgresType, SqliteType}; use proc_macro2::Span; - use proc_macro_error::ResultExt; use syn::Ident; use util::{ COLUMN_NAME_NOTE, MYSQL_TYPE_NOTE, SQLITE_TYPE_NOTE, SQL_TYPE_NOTE, TABLE_NAME_NOTE, @@ -72,9 +71,7 @@ mod impl_deprecated { name, &format!("use `#[diesel(table_name = {})]` instead", lit_str.value()) ); - Ok(Some(StructAttr::TableName(name, { - lit_str.parse().unwrap_or_abort() - }))) + Ok(Some(StructAttr::TableName(name, lit_str.parse()?))) } "changeset_options" => { let (ident, value) = parse_changeset_options(name.clone(), input)?; @@ -93,9 +90,7 @@ mod impl_deprecated { name, &format!("use `#[diesel(sql_type = {})]` instead", lit_str.value()) ); - Ok(Some(StructAttr::SqlType(name, { - lit_str.parse().unwrap_or_abort() - }))) + Ok(Some(StructAttr::SqlType(name, lit_str.parse()?))) } "primary_key" => { let keys = parse_primary_key(name.clone(), input)?; @@ -203,9 +198,7 @@ mod impl_deprecated { name, &format!("use `#[diesel(column_name = {})]` instead", lit_str.value()) ); - Ok(Some(FieldAttr::ColumnName(name, { - lit_str.parse().unwrap_or_abort() - }))) + Ok(Some(FieldAttr::ColumnName(name, lit_str.parse()?))) } "sql_type" => { let lit_str = parse_eq_and_lit_str(name.clone(), input, SQL_TYPE_NOTE)?; @@ -213,9 +206,7 @@ mod impl_deprecated { name, &format!("use `#[diesel(sql_type = {})]` instead", lit_str.value()) ); - Ok(Some(FieldAttr::SqlType(name, { - lit_str.parse().unwrap_or_abort() - }))) + Ok(Some(FieldAttr::SqlType(name, lit_str.parse()?))) } _ => Ok(None), diff --git a/diesel_derives/src/deprecated/postgres_type.rs b/diesel_derives/src/deprecated/postgres_type.rs index 6354d068cebd..ddefabd3e42b 100644 --- a/diesel_derives/src/deprecated/postgres_type.rs +++ b/diesel_derives/src/deprecated/postgres_type.rs @@ -32,18 +32,21 @@ impl Parse for Attr { parse_eq_and_lit_str(name, input, POSTGRES_TYPE_NOTE)?, )), - _ => unknown_attribute(&name, &["oid", "array_oid", "type_name"]), + _ => Err(unknown_attribute(&name, &["oid", "array_oid", "type_name"])), } } } pub fn parse_postgres_type(name: Ident, input: ParseStream) -> Result { if input.is_empty() { - abort!( + return Err(syn::Error::new( name.span(), - "unexpected end of input, expected parentheses"; - help = "The correct format looks like `#[diesel({})]`", POSTGRES_TYPE_NOTE - ); + format!( + "unexpected end of input, expected parentheses\n\ + help: The correct format looks like `#[diesel({})]`", + POSTGRES_TYPE_NOTE + ), + )); } let content; diff --git a/diesel_derives/src/deprecated/primary_key.rs b/diesel_derives/src/deprecated/primary_key.rs index d4a1d0b70420..3fdbe07401d7 100644 --- a/diesel_derives/src/deprecated/primary_key.rs +++ b/diesel_derives/src/deprecated/primary_key.rs @@ -5,11 +5,14 @@ use syn::{parenthesized, Ident}; pub fn parse_primary_key(name: Ident, input: ParseStream) -> Result> { if input.is_empty() { - abort!(name.span(), "unexpected end of input, expected parentheses"); + return Err(syn::Error::new( + name.span(), + "unexpected end of input, expected parentheses", + )); } let content; parenthesized!(content in input); - content.parse_terminated(Ident::parse) + content.parse_terminated(Ident::parse, syn::Token![,]) } diff --git a/diesel_derives/src/deprecated/utils.rs b/diesel_derives/src/deprecated/utils.rs index 4524bf880875..165854666d5a 100644 --- a/diesel_derives/src/deprecated/utils.rs +++ b/diesel_derives/src/deprecated/utils.rs @@ -4,11 +4,13 @@ use syn::{Ident, LitStr}; pub fn parse_eq_and_lit_str(name: Ident, input: ParseStream, help: &str) -> Result { if input.is_empty() { - abort!( + return Err(syn::Error::new( name.span(), - "unexpected end of input, expected `=`"; - help = "The correct format looks like `#[diesel({})]`", help - ); + format!( + "unexpected end of input, expected `=`\n\ + help: The correct format looks like `#[diesel({help})]`" + ), + )); } input.parse::()?; diff --git a/diesel_derives/src/diesel_for_each_tuple.rs b/diesel_derives/src/diesel_for_each_tuple.rs index da0253dbf736..948ddfb8f22a 100644 --- a/diesel_derives/src/diesel_for_each_tuple.rs +++ b/diesel_derives/src/diesel_for_each_tuple.rs @@ -1,4 +1,5 @@ use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; #[cfg(not(feature = "32-column-tables"))] pub const MAX_TUPLE_SIZE: i32 = 16; diff --git a/diesel_derives/src/diesel_numeric_ops.rs b/diesel_derives/src/diesel_numeric_ops.rs index 87fd88e6cf13..6e9d21e160b7 100644 --- a/diesel_derives/src/diesel_numeric_ops.rs +++ b/diesel_derives/src/diesel_numeric_ops.rs @@ -1,4 +1,6 @@ use proc_macro2::TokenStream; +use quote::quote; +use syn::parse_quote; use syn::DeriveInput; use util::wrap_in_dummy_mod; diff --git a/diesel_derives/src/diesel_public_if.rs b/diesel_derives/src/diesel_public_if.rs index 53eaefe00918..54b4c6431817 100644 --- a/diesel_derives/src/diesel_public_if.rs +++ b/diesel_derives/src/diesel_public_if.rs @@ -1,3 +1,5 @@ +use quote::quote; +use syn::Token; use syn::{punctuated::Punctuated, DeriveInput}; pub(crate) fn expand(cfg: CfgInput, item: EntryWithVisibility) -> proc_macro2::TokenStream { @@ -41,18 +43,11 @@ impl syn::parse::Parse for CfgInput { ) }; let field_list = if let syn::Meta::List(v) = fields { - v.nested - .into_iter() - .map(|v| { - if let syn::NestedMeta::Meta(syn::Meta::Path(p)) = v { - p.get_ident() - .expect("Field names need to be idents") - .clone() - } else { - panic!("The field name key requires a list of field names as argument") - } - }) - .collect() + use syn::parse::Parser; + let parser = + syn::punctuated::Punctuated::::parse_terminated; + let idents = parser.parse2(v.tokens)?; + idents.into_iter().collect() } else { unreachable!() }; @@ -155,9 +150,7 @@ impl EntryWithVisibility { .map(|i| field_list.contains(i)) .unwrap_or(false) { - ret.vis = syn::Visibility::Public(syn::VisPublic { - pub_token: Default::default(), - }); + ret.vis = syn::Visibility::Public(Default::default()); } ret }); diff --git a/diesel_derives/src/field.rs b/diesel_derives/src/field.rs index 29ebee65c861..48de67c3c2e4 100644 --- a/diesel_derives/src/field.rs +++ b/diesel_derives/src/field.rs @@ -1,6 +1,6 @@ use proc_macro2::{Span, TokenStream}; use syn::spanned::Spanned; -use syn::{Field as SynField, Ident, Index, Type}; +use syn::{Field as SynField, Ident, Index, Result, Type}; use attrs::{parse_attributes, AttributeSpanWrapper, FieldAttr, SqlIdentifier}; @@ -18,7 +18,7 @@ pub struct Field { } impl Field { - pub fn from_struct_field(field: &SynField, index: usize) -> Self { + pub fn from_struct_field(field: &SynField, index: usize) -> Result { let SynField { ident, attrs, ty, .. } = field; @@ -31,7 +31,7 @@ impl Field { let mut select_expression = None; let mut select_expression_type = None; - for attr in parse_attributes(attrs) { + for attr in parse_attributes(attrs)? { let attribute_span = attr.attribute_span; let ident_span = attr.ident_span; match attr.item { @@ -97,7 +97,7 @@ impl Field { FieldName::Unnamed(_) => ty.span(), }; - Self { + Ok(Self { ty: ty.clone(), span, name, @@ -108,22 +108,22 @@ impl Field { select_expression, select_expression_type, embed, - } + }) } - pub fn column_name(&self) -> SqlIdentifier { - self.column_name - .as_ref() - .map(|a| a.item.clone()) - .unwrap_or_else(|| match self.name { - FieldName::Named(ref x) => x.into(), - FieldName::Unnamed(ref x) => { - abort!( - x, - "All fields of tuple structs must be annotated with `#[diesel(column_name)]`" - ); - } - }) + pub fn column_name(&self) -> Result { + let identifier = self.column_name.as_ref().map(|a| a.item.clone()); + if let Some(identifier) = identifier { + Ok(identifier) + } else { + match self.name { + FieldName::Named(ref x) => Ok(x.into()), + FieldName::Unnamed(ref x) => Err(syn::Error::new( + x.span(), + "All fields of tuple structs must be annotated with `#[diesel(column_name)]`", + )), + } + } } pub fn ty_for_deserialize(&self) -> &Type { diff --git a/diesel_derives/src/from_sql_row.rs b/diesel_derives/src/from_sql_row.rs index abe7c0d6c9a7..024463586d9e 100644 --- a/diesel_derives/src/from_sql_row.rs +++ b/diesel_derives/src/from_sql_row.rs @@ -1,12 +1,15 @@ use proc_macro2::TokenStream; +use quote::quote; +use syn::parse_quote; use syn::DeriveInput; +use syn::Result; 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, false); - let struct_ty = ty_for_foreign_derive(&item, &model); +pub fn derive(mut item: DeriveInput) -> Result { + let model = Model::from_item(&item, true, false)?; + let struct_ty = ty_for_foreign_derive(&item, &model)?; { let where_clause = item @@ -29,7 +32,7 @@ pub fn derive(mut item: DeriveInput) -> TokenStream { let ty_params = item.generics.type_params().collect::>(); let const_params = item.generics.const_params().collect::>(); - wrap_in_dummy_mod(quote! { + Ok(wrap_in_dummy_mod(quote! { use diesel::deserialize::{self, FromSql, Queryable}; // Need to put __ST and __DB after lifetimes but before const params @@ -42,5 +45,5 @@ pub fn derive(mut item: DeriveInput) -> TokenStream { Ok(row) } } - }) + })) } diff --git a/diesel_derives/src/identifiable.rs b/diesel_derives/src/identifiable.rs index 1ab526324e31..bbbca2016266 100644 --- a/diesel_derives/src/identifiable.rs +++ b/diesel_derives/src/identifiable.rs @@ -1,11 +1,14 @@ use proc_macro2::TokenStream; +use quote::quote; +use syn::parse_quote; use syn::DeriveInput; +use syn::Result; use model::Model; use util::wrap_in_dummy_mod; -pub fn derive(item: DeriveInput) -> TokenStream { - let model = Model::from_item(&item, false, false); +pub fn derive(item: DeriveInput) -> Result { + let model = Model::from_item(&item, false, false)?; let struct_name = &item.ident; let table_name = &model.table_names()[0]; @@ -15,14 +18,15 @@ pub fn derive(item: DeriveInput) -> TokenStream { ref_generics.params.push(parse_quote!('ident)); let (ref_generics, ..) = ref_generics.split_for_impl(); - let (field_ty, field_name): (Vec<_>, Vec<_>) = model - .primary_key_names - .iter() - .map(|pk| model.find_column(pk)) - .map(|f| (&f.ty, &f.name)) - .unzip(); + let mut field_ty = Vec::new(); + let mut field_name = Vec::new(); + for pk in model.primary_key_names.iter() { + let f = model.find_column(pk)?; + field_ty.push(&f.ty); + field_name.push(&f.name); + } - wrap_in_dummy_mod(quote! { + Ok(wrap_in_dummy_mod(quote! { use diesel::associations::{HasTable, Identifiable}; impl #impl_generics HasTable for #struct_name #ty_generics @@ -54,5 +58,5 @@ pub fn derive(item: DeriveInput) -> TokenStream { (#(&self.#field_name),*) } } - }) + })) } diff --git a/diesel_derives/src/insertable.rs b/diesel_derives/src/insertable.rs index 7566e2314029..eb5cdeee7ca0 100644 --- a/diesel_derives/src/insertable.rs +++ b/diesel_derives/src/insertable.rs @@ -2,28 +2,35 @@ use attrs::AttributeSpanWrapper; use field::Field; use model::Model; use proc_macro2::TokenStream; +use quote::quote; use quote::quote_spanned; -use syn::{DeriveInput, Expr, Path, Type}; +use syn::parse_quote; +use syn::{DeriveInput, Expr, Path, Result, Type}; 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, true); +pub fn derive(item: DeriveInput) -> Result { + let model = Model::from_item(&item, false, true)?; let tokens = model .table_names() .iter() - .map(|table_name| derive_into_single_table(&item, &model, table_name)); + .map(|table_name| derive_into_single_table(&item, &model, table_name)) + .collect::>>()?; - wrap_in_dummy_mod(quote! { + Ok(wrap_in_dummy_mod(quote! { use diesel::insertable::Insertable; use diesel::internal::derives::insertable::UndecoratedInsertRecord; use diesel::prelude::*; #(#tokens)* - }) + })) } -fn derive_into_single_table(item: &DeriveInput, model: &Model, table_name: &Path) -> TokenStream { +fn derive_into_single_table( + item: &DeriveInput, + model: &Model, + table_name: &Path, +) -> Result { let treat_none_as_default_value = model.treat_none_as_default_value(); let struct_name = &item.ident; @@ -50,25 +57,25 @@ fn derive_into_single_table(item: &DeriveInput, model: &Model, table_name: &Path table_name, None, treat_none_as_default_value, - )); + )?); direct_field_assign.push(field_expr( field, table_name, None, treat_none_as_default_value, - )); + )?); ref_field_ty.push(field_ty( field, table_name, Some(quote!(&'insert)), treat_none_as_default_value, - )); + )?); ref_field_assign.push(field_expr( field, table_name, Some(quote!(&)), treat_none_as_default_value, - )); + )?); } (Some(AttributeSpanWrapper { item: ty, .. }), false) => { direct_field_ty.push(field_ty_serialize_as( @@ -76,21 +83,21 @@ fn derive_into_single_table(item: &DeriveInput, model: &Model, table_name: &Path table_name, ty, treat_none_as_default_value, - )); + )?); direct_field_assign.push(field_expr_serialize_as( field, table_name, ty, treat_none_as_default_value, - )); + )?); generate_borrowed_insert = false; // as soon as we hit one field with #[diesel(serialize_as)] there is no point in generating the impl of Insertable for borrowed structs } (Some(AttributeSpanWrapper { attribute_span, .. }), true) => { - abort!( - attribute_span, - "`#[diesel(embed)]` cannot be combined with `#[diesel(serialize_as)]`" - ) + return Err(syn::Error::new( + *attribute_span, + "`#[diesel(embed)]` cannot be combined with `#[diesel(serialize_as)]`", + )); } } } @@ -128,7 +135,7 @@ fn derive_into_single_table(item: &DeriveInput, model: &Model, table_name: &Path quote! {} }; - quote! { + Ok(quote! { #[allow(unused_qualifications)] #insert_owned @@ -140,7 +147,7 @@ fn derive_into_single_table(item: &DeriveInput, model: &Model, table_name: &Path #where_clause { } - } + }) } fn field_ty_embed(field: &Field, lifetime: Option) -> TokenStream { @@ -159,26 +166,26 @@ fn field_ty_serialize_as( table_name: &Path, ty: &Type, treat_none_as_default_value: bool, -) -> TokenStream { - let column_name = field.column_name(); - column_name.valid_ident(); +) -> Result { + let column_name = field.column_name()?; + column_name.valid_ident()?; let span = field.span; if treat_none_as_default_value { let inner_ty = inner_of_option_ty(ty); - quote_spanned! {span=> + Ok(quote_spanned! {span=> std::option::Option> - } + }) } else { - quote_spanned! {span=> + Ok(quote_spanned! {span=> diesel::dsl::Eq< #table_name::#column_name, #ty, > - } + }) } } @@ -187,19 +194,21 @@ fn field_expr_serialize_as( table_name: &Path, ty: &Type, treat_none_as_default_value: bool, -) -> TokenStream { +) -> Result { let field_name = &field.name; - let column_name = field.column_name(); - column_name.valid_ident(); + let column_name = field.column_name()?; + column_name.valid_ident()?; let column = quote!(#table_name::#column_name); if treat_none_as_default_value { if is_option_ty(ty) { - quote!(self.#field_name.map(|x| #column.eq(::std::convert::Into::<#ty>::into(x)))) + Ok(quote!(self.#field_name.map(|x| #column.eq(::std::convert::Into::<#ty>::into(x))))) } else { - quote!(std::option::Option::Some(#column.eq(::std::convert::Into::<#ty>::into(self.#field_name)))) + Ok( + quote!(std::option::Option::Some(#column.eq(::std::convert::Into::<#ty>::into(self.#field_name)))), + ) } } else { - quote!(#column.eq(::std::convert::Into::<#ty>::into(self.#field_name))) + Ok(quote!(#column.eq(::std::convert::Into::<#ty>::into(self.#field_name)))) } } @@ -208,28 +217,28 @@ fn field_ty( table_name: &Path, lifetime: Option, treat_none_as_default_value: bool, -) -> TokenStream { - let column_name = field.column_name(); - column_name.valid_ident(); +) -> Result { + let column_name = field.column_name()?; + column_name.valid_ident()?; let span = field.span; if treat_none_as_default_value { let inner_ty = inner_of_option_ty(&field.ty); - quote_spanned! {span=> + Ok(quote_spanned! {span=> std::option::Option> - } + }) } else { let inner_ty = &field.ty; - quote_spanned! {span=> + Ok(quote_spanned! {span=> diesel::dsl::Eq< #table_name::#column_name, #lifetime #inner_ty, > - } + }) } } @@ -238,23 +247,23 @@ fn field_expr( table_name: &Path, lifetime: Option, treat_none_as_default_value: bool, -) -> TokenStream { +) -> Result { let field_name = &field.name; - let column_name = field.column_name(); - column_name.valid_ident(); + let column_name = field.column_name()?; + column_name.valid_ident()?; 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() { - quote!(self.#field_name.as_ref().map(|x| #column.eq(x))) + Ok(quote!(self.#field_name.as_ref().map(|x| #column.eq(x)))) } else { - quote!(self.#field_name.map(|x| #column.eq(x))) + Ok(quote!(self.#field_name.map(|x| #column.eq(x)))) } } else { - quote!(std::option::Option::Some(#column.eq(#lifetime self.#field_name))) + Ok(quote!(std::option::Option::Some(#column.eq(#lifetime self.#field_name)))) } } else { - quote!(#column.eq(#lifetime self.#field_name)) + Ok(quote!(#column.eq(#lifetime self.#field_name))) } } diff --git a/diesel_derives/src/lib.rs b/diesel_derives/src/lib.rs index 1e599046470c..f6a4ea9bf52e 100644 --- a/diesel_derives/src/lib.rs +++ b/diesel_derives/src/lib.rs @@ -15,16 +15,14 @@ missing_copy_implementations )] +extern crate diesel_table_macro_syntax; extern crate proc_macro; extern crate proc_macro2; extern crate quote; -#[macro_use] extern crate syn; -#[macro_use] -extern crate proc_macro_error; -extern crate diesel_table_macro_syntax; use proc_macro::TokenStream; +use syn::parse_macro_input; mod attrs; mod deprecated; @@ -103,7 +101,6 @@ mod valid_grouping; /// 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. -#[proc_macro_error] #[cfg_attr( all(not(feature = "without-deprecated"), feature = "with-deprecated"), proc_macro_derive( @@ -116,7 +113,9 @@ mod valid_grouping; proc_macro_derive(AsChangeset, attributes(diesel)) )] pub fn derive_as_changeset(input: TokenStream) -> TokenStream { - as_changeset::derive(parse_macro_input!(input)).into() + as_changeset::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Implements all required variants of `AsExpression` @@ -146,7 +145,6 @@ pub fn derive_as_changeset(input: TokenStream) -> TokenStream { /// /// * `#[diesel(not_sized)]`, to skip generating impls that require /// that the type is `Sized` -#[proc_macro_error] #[cfg_attr( all(not(feature = "without-deprecated"), feature = "with-deprecated"), proc_macro_derive(AsExpression, attributes(diesel, sql_type)) @@ -156,7 +154,9 @@ pub fn derive_as_changeset(input: TokenStream) -> TokenStream { proc_macro_derive(AsExpression, attributes(diesel)) )] pub fn derive_as_expression(input: TokenStream) -> TokenStream { - as_expression::derive(parse_macro_input!(input)).into() + as_expression::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Implement required traits for the associations API @@ -193,7 +193,6 @@ pub fn derive_as_expression(input: TokenStream) -> TokenStream { /// * `#[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 a column name. -#[proc_macro_error] #[cfg_attr( all(not(feature = "without-deprecated"), feature = "with-deprecated"), proc_macro_derive(Associations, attributes(diesel, belongs_to, column_name, table_name)) @@ -203,7 +202,9 @@ pub fn derive_as_expression(input: TokenStream) -> TokenStream { proc_macro_derive(Associations, attributes(diesel, belongs_to, column_name, table_name)) )] pub fn derive_associations(input: TokenStream) -> TokenStream { - associations::derive(parse_macro_input!(input)).into() + associations::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Implement numeric operators for the current query node @@ -218,10 +219,11 @@ 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 { - from_sql_row::derive(parse_macro_input!(input)).into() + from_sql_row::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Implements `Identifiable` for references of the current type @@ -260,7 +262,6 @@ pub fn derive_from_sql_row(input: TokenStream) -> TokenStream { /// * `#[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 a column name. -#[proc_macro_error] #[cfg_attr( all(not(feature = "without-deprecated"), feature = "with-deprecated"), proc_macro_derive(Identifiable, attributes(diesel, table_name, column_name, primary_key)) @@ -270,7 +271,9 @@ pub fn derive_from_sql_row(input: TokenStream) -> TokenStream { proc_macro_derive(Identifiable, attributes(diesel)) )] pub fn derive_identifiable(input: TokenStream) -> TokenStream { - identifiable::derive(parse_macro_input!(input)).into() + identifiable::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Implements `Insertable` @@ -394,7 +397,6 @@ pub fn derive_identifiable(input: TokenStream) -> TokenStream { /// # Ok(()) /// # } /// ``` -#[proc_macro_error] #[cfg_attr( all(not(feature = "without-deprecated"), feature = "with-deprecated"), proc_macro_derive(Insertable, attributes(diesel, table_name, column_name)) @@ -404,7 +406,9 @@ pub fn derive_identifiable(input: TokenStream) -> TokenStream { proc_macro_derive(Insertable, attributes(diesel)) )] pub fn derive_insertable(input: TokenStream) -> TokenStream { - insertable::derive(parse_macro_input!(input)).into() + insertable::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Implements `QueryId` @@ -441,7 +445,6 @@ pub fn derive_insertable(input: TokenStream) -> TokenStream { /// meaning that `HAS_STATIC_QUERY_ID` should always be false, /// you shouldn't 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 { query_id::derive(parse_macro_input!(input)).into() @@ -608,7 +611,6 @@ pub fn derive_query_id(input: TokenStream) -> TokenStream { /// # Ok(()) /// # } /// ``` -#[proc_macro_error] #[cfg_attr( all(not(feature = "without-deprecated"), feature = "with-deprecated"), proc_macro_derive(Queryable, attributes(diesel, column_name)) @@ -618,7 +620,9 @@ pub fn derive_query_id(input: TokenStream) -> TokenStream { proc_macro_derive(Queryable, attributes(diesel)) )] pub fn derive_queryable(input: TokenStream) -> TokenStream { - queryable::derive(parse_macro_input!(input)).into() + queryable::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Implements `QueryableByName` for untyped sql queries, such as that one generated @@ -802,7 +806,6 @@ pub fn derive_queryable(input: TokenStream) -> TokenStream { /// # Ok(()) /// # } /// ``` -#[proc_macro_error] #[cfg_attr( all(not(feature = "without-deprecated"), feature = "with-deprecated"), proc_macro_derive(QueryableByName, attributes(diesel, table_name, column_name, sql_type)) @@ -812,7 +815,9 @@ pub fn derive_queryable(input: TokenStream) -> TokenStream { proc_macro_derive(QueryableByName, attributes(diesel)) )] pub fn derive_queryable_by_name(input: TokenStream) -> TokenStream { - queryable_by_name::derive(parse_macro_input!(input)).into() + queryable_by_name::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Implements `Selectable` @@ -871,10 +876,11 @@ pub fn derive_queryable_by_name(input: TokenStream) -> TokenStream { /// * `#[diesel(select_expression_type = the_custom_select_expression_type]`, to be used /// in conjunction with `select_expression` (described above). /// For example: `#[diesel(select_expression_type = dsl::IsNotNull)]` -#[proc_macro_error] #[proc_macro_derive(Selectable, attributes(diesel))] pub fn derive_selectable(input: TokenStream) -> TokenStream { - selectable::derive(parse_macro_input!(input)).into() + selectable::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Implement necessary traits for adding a new sql type @@ -915,7 +921,6 @@ pub fn derive_selectable(input: TokenStream) -> TokenStream { /// * `#[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] #[cfg_attr( all(not(feature = "without-deprecated"), feature = "with-deprecated"), proc_macro_derive(SqlType, attributes(diesel, postgres, sqlite_type, mysql_type)) @@ -925,7 +930,9 @@ pub fn derive_selectable(input: TokenStream) -> TokenStream { proc_macro_derive(SqlType, attributes(diesel)) )] pub fn derive_sql_type(input: TokenStream) -> TokenStream { - sql_type::derive(parse_macro_input!(input)).into() + sql_type::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Implements `ValidGrouping` @@ -967,10 +974,11 @@ pub fn derive_sql_type(input: TokenStream) -> TokenStream { /// /// * `#[diesel(aggregate)]` for cases where the type represents an aggregating /// SQL expression -#[proc_macro_error] #[proc_macro_derive(ValidGrouping, attributes(diesel))] pub fn derive_valid_grouping(input: TokenStream) -> TokenStream { - valid_grouping::derive(parse_macro_input!(input)).into() + valid_grouping::derive(parse_macro_input!(input)) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /// Declare a sql function for use in your code. diff --git a/diesel_derives/src/model.rs b/diesel_derives/src/model.rs index e2041d78471e..8b4a870b6c35 100644 --- a/diesel_derives/src/model.rs +++ b/diesel_derives/src/model.rs @@ -2,6 +2,7 @@ use proc_macro2::Span; use std::slice::from_ref; use syn::punctuated::Punctuated; use syn::token::Comma; +use syn::Result; use syn::{ Data, DataStruct, DeriveInput, Field as SynField, Fields, FieldsNamed, FieldsUnnamed, Ident, LitBool, Path, Type, @@ -35,7 +36,7 @@ impl Model { item: &DeriveInput, allow_unit_structs: bool, allow_multiple_table: bool, - ) -> Self { + ) -> Result { let DeriveInput { data, ident, attrs, .. } = item; @@ -50,7 +51,10 @@ impl Model { .. }) => Some(unnamed), _ if !allow_unit_structs => { - abort_call_site!("This derive can only be used on non-unit structs") + return Err(syn::Error::new( + proc_macro2::Span::call_site(), + "This derive can only be used on non-unit structs", + )); } _ => None, }; @@ -69,15 +73,16 @@ impl Model { let mut postgres_type = None; let mut check_for_backend = None; - for attr in parse_attributes(attrs) { + for attr in parse_attributes(attrs)? { match attr.item { StructAttr::SqlType(_, value) => sql_types.push(Type::Path(value)), StructAttr::TableName(ident, value) => { if !allow_multiple_table && !table_names.is_empty() { - abort!( - ident, "expected a single table name attribute"; - note = "remove this attribute"; - ) + return Err(syn::Error::new( + ident.span(), + "expected a single table name attribute\n\ + note: remove this attribute", + )); } table_names.push(value) } @@ -103,7 +108,7 @@ impl Model { let name = Ident::new(&infer_table_name(&ident.to_string()), ident.span()).into(); - Self { + Ok(Self { name, table_names, primary_key_names, @@ -117,9 +122,9 @@ impl Model { mysql_type, sqlite_type, postgres_type, - fields: fields_from_item_data(fields), + fields: fields_from_item_data(fields)?, check_for_backend, - } + }) } pub fn table_names(&self) -> &[Path] { @@ -133,11 +138,20 @@ impl Model { &self.fields } - pub fn find_column(&self, column_name: &Ident) -> &Field { + pub fn find_column(&self, column_name: &Ident) -> Result<&Field> { self.fields() .iter() - .find(|f| f.column_name() == *column_name) - .unwrap_or_else(|| abort!(column_name, "No field with column name {}", column_name)) + .find(|f| { + f.column_name() + .map(|c| c == *column_name) + .unwrap_or_default() + }) + .ok_or_else(|| { + syn::Error::new( + column_name.span(), + format!("No field with column name {column_name}"), + ) + }) } pub fn treat_none_as_default_value(&self) -> bool { @@ -155,16 +169,16 @@ impl Model { } } -fn fields_from_item_data(fields: Option<&Punctuated>) -> Vec { +fn fields_from_item_data(fields: Option<&Punctuated>) -> Result> { fields .map(|fields| { fields .iter() .enumerate() .map(|(i, f)| Field::from_struct_field(f, i)) - .collect::>() + .collect::>>() }) - .unwrap_or_default() + .unwrap_or_else(|| Ok(Vec::new())) } pub fn infer_table_name(name: &str) -> String { diff --git a/diesel_derives/src/parsers/belongs_to.rs b/diesel_derives/src/parsers/belongs_to.rs index e59d07b2e498..7ca79faf2159 100644 --- a/diesel_derives/src/parsers/belongs_to.rs +++ b/diesel_derives/src/parsers/belongs_to.rs @@ -17,7 +17,7 @@ impl Parse for Attr { match &*name_str { "foreign_key" => Ok(Attr::ForeignKey(name, parse_eq(input, BELONGS_TO_NOTE)?)), - _ => unknown_attribute(&name, &["foreign_key"]), + _ => Err(unknown_attribute(&name, &["foreign_key"])), } } } diff --git a/diesel_derives/src/parsers/mysql_type.rs b/diesel_derives/src/parsers/mysql_type.rs index d994d6755b67..6ee926d785e8 100644 --- a/diesel_derives/src/parsers/mysql_type.rs +++ b/diesel_derives/src/parsers/mysql_type.rs @@ -17,7 +17,7 @@ impl Parse for Attr { match &*name_str { "name" => Ok(Attr::Name(name, parse_eq(input, MYSQL_TYPE_NOTE)?)), - _ => unknown_attribute(&name, &["name"]), + _ => Err(unknown_attribute(&name, &["name"])), } } } @@ -39,10 +39,14 @@ impl Parse for MysqlType { if let Some(name) = name { Ok(MysqlType { name }) } else { - abort!( - input.span(), "expected attribute `name`"; - help = "The correct format looks like #[diesel({})]", MYSQL_TYPE_NOTE - ); + Err(syn::Error::new( + input.span(), + format!( + "expected attribute `name`\n\ + help: The correct format looks like #[diesel({})]", + MYSQL_TYPE_NOTE + ), + )) } } } diff --git a/diesel_derives/src/parsers/postgres_type.rs b/diesel_derives/src/parsers/postgres_type.rs index 103841d1b12c..feb1d6855e65 100644 --- a/diesel_derives/src/parsers/postgres_type.rs +++ b/diesel_derives/src/parsers/postgres_type.rs @@ -1,4 +1,3 @@ -use proc_macro_error::abort; use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::token::Comma; @@ -27,7 +26,10 @@ impl Parse for Attr { "name" => Ok(Attr::Name(name, parse_eq(input, POSTGRES_TYPE_NOTE)?)), "schema" => Ok(Attr::Schema(name, parse_eq(input, POSTGRES_TYPE_NOTE)?)), - _ => unknown_attribute(&name, &["oid", "array_oid", "name", "schema"]), + _ => Err(unknown_attribute( + &name, + &["oid", "array_oid", "name", "schema"], + )), } } } @@ -71,31 +73,35 @@ impl PostgresType { if let Some((_, name)) = name { if let Some((oid, _)) = oid { - abort!( - oid, "unexpected `oid` when `name` is present"; - help = "{}", help - ); + Err(syn::Error::new( + oid.span(), + format!("unexpected `oid` when `name` is present\nhelp: {help}"), + )) } else if let Some((array_oid, _)) = array_oid { - abort!( - array_oid, "unexpected `array_oid` when `name` is present"; - help = "{}", help - ); + Err(syn::Error::new( + array_oid.span(), + format!("unexpected `array_oid` when `name` is present\nhelp: {help}"), + )) + } else { + Ok(PostgresType::Lookup(name, schema.map(|s| s.1))) } - - Ok(PostgresType::Lookup(name, schema.map(|s| s.1))) } else if let Some((schema, lit)) = schema { - abort!( - schema, "expected `name` to be also present"; - help = "make sure `name` is present, `#[diesel(postgres_type(name = \"...\", schema = \"{}\"))]`", lit.value() - ); + Err(syn::Error::new( + schema.span(), + format!( + "expected `name` to be also present\n\ + help: make sure `name` is present, `#[diesel(postgres_type(name = \"...\", schema = \"{}\"))]`", lit.value() + ), + )) } else if let (Some((_, oid)), Some((_, array_oid))) = (oid, array_oid) { Ok(PostgresType::Fixed(oid, array_oid)) } else { - abort!( + Err(syn::Error::new( input.span(), - "expected `oid` and `array_oid` attribute or `name` attribute"; - help = "{}", help - ); + format!( + "expected `oid` and `array_oid` attribute or `name` attribute\nhelp: {help}" + ), + )) } } } diff --git a/diesel_derives/src/parsers/sqlite_type.rs b/diesel_derives/src/parsers/sqlite_type.rs index dec5dc37b261..f27bdafcef36 100644 --- a/diesel_derives/src/parsers/sqlite_type.rs +++ b/diesel_derives/src/parsers/sqlite_type.rs @@ -17,7 +17,7 @@ impl Parse for Attr { match &*name_str { "name" => Ok(Attr::Name(name, parse_eq(input, SQLITE_TYPE_NOTE)?)), - _ => unknown_attribute(&name, &["name"]), + _ => Err(unknown_attribute(&name, &["name"])), } } } @@ -39,10 +39,14 @@ impl Parse for SqliteType { if let Some(name) = name { Ok(SqliteType { name }) } else { - abort!( - input.span(), "expected attribute `name`"; - help = "The correct format looks like #[diesel({})]", SQLITE_TYPE_NOTE - ); + Err(syn::Error::new( + input.span(), + format!( + "expected attribute `name`\n\ + help: The correct format looks like #[diesel({})]", + SQLITE_TYPE_NOTE + ), + )) } } } diff --git a/diesel_derives/src/query_id.rs b/diesel_derives/src/query_id.rs index 2c681d523a42..bdfc958cb84b 100644 --- a/diesel_derives/src/query_id.rs +++ b/diesel_derives/src/query_id.rs @@ -1,4 +1,6 @@ use proc_macro2::TokenStream; +use quote::quote; +use syn::parse_quote; use syn::DeriveInput; use util::wrap_in_dummy_mod; diff --git a/diesel_derives/src/queryable.rs b/diesel_derives/src/queryable.rs index e934caac42a5..b6dc2247ad2a 100644 --- a/diesel_derives/src/queryable.rs +++ b/diesel_derives/src/queryable.rs @@ -1,12 +1,13 @@ use proc_macro2::{Span, TokenStream}; -use syn::{DeriveInput, Ident, Index}; +use quote::quote; +use syn::{parse_quote, DeriveInput, Ident, Index, Result}; use field::Field; use model::Model; use util::wrap_in_dummy_mod; -pub fn derive(item: DeriveInput) -> TokenStream { - let model = Model::from_item(&item, false, false); +pub fn derive(item: DeriveInput) -> Result { + let model = Model::from_item(&item, false, false)?; let struct_name = &item.ident; let field_ty = &model @@ -43,7 +44,7 @@ pub fn derive(item: DeriveInput) -> TokenStream { } let (impl_generics, _, where_clause) = generics.split_for_impl(); - wrap_in_dummy_mod(quote! { + Ok(wrap_in_dummy_mod(quote! { use diesel::deserialize::{self, FromStaticSqlRow, Queryable}; use diesel::row::{Row, Field}; use std::convert::TryInto; @@ -59,5 +60,5 @@ pub fn derive(item: DeriveInput) -> TokenStream { }) } } - }) + })) } diff --git a/diesel_derives/src/queryable_by_name.rs b/diesel_derives/src/queryable_by_name.rs index 95caa90706f8..a8e50949faa7 100644 --- a/diesel_derives/src/queryable_by_name.rs +++ b/diesel_derives/src/queryable_by_name.rs @@ -1,35 +1,40 @@ use proc_macro2::TokenStream; -use syn::{DeriveInput, Ident, LitStr, Type}; +use quote::quote; +use syn::{parse_quote, DeriveInput, Ident, LitStr, Result, Type}; use attrs::AttributeSpanWrapper; use field::{Field, FieldName}; use model::Model; use util::wrap_in_dummy_mod; -pub fn derive(item: DeriveInput) -> TokenStream { - let model = Model::from_item(&item, false, false); +pub fn derive(item: DeriveInput) -> Result { + let model = Model::from_item(&item, false, 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); - 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.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) - } - ) - } - }); + if f.embed() { + Ok(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()); + Ok(quote!( + { + let field = diesel::row::NamedRow::get(row, #name)?; + <#deserialize_ty as Into<#field_ty>>::into(field) + } + )) + } + }) + .collect::>>()?; let (_, ty_generics, ..) = item.generics.split_for_impl(); let mut generics = item.generics.clone(); @@ -45,7 +50,7 @@ pub fn derive(item: DeriveInput) -> TokenStream { .predicates .push(parse_quote!(#field_ty: QueryableByName<__DB>)); } else { - let st = sql_type(field, &model); + let st = sql_type(field, &model)?; where_clause .predicates .push(parse_quote!(#field_ty: diesel::deserialize::FromSql<#st, __DB>)); @@ -54,7 +59,7 @@ pub fn derive(item: DeriveInput) -> TokenStream { let (impl_generics, _, where_clause) = generics.split_for_impl(); - wrap_in_dummy_mod(quote! { + Ok(wrap_in_dummy_mod(quote! { use diesel::deserialize::{self, QueryableByName}; use diesel::row::{NamedRow}; use diesel::sql_types::Untyped; @@ -75,7 +80,7 @@ pub fn derive(item: DeriveInput) -> TokenStream { }) } } - }) + })) } fn get_ident(field: &Field) -> Ident { @@ -85,14 +90,14 @@ fn get_ident(field: &Field) -> Ident { } } -fn sql_type(field: &Field, model: &Model) -> Type { +fn sql_type(field: &Field, model: &Model) -> Result { let table_name = &model.table_names()[0]; match field.sql_type { - Some(AttributeSpanWrapper { item: ref st, .. }) => st.clone(), + Some(AttributeSpanWrapper { item: ref st, .. }) => Ok(st.clone()), None => { - let column_name = field.column_name(); - parse_quote!(diesel::dsl::SqlTypeOf<#table_name::#column_name>) + let column_name = field.column_name()?; + Ok(parse_quote!(diesel::dsl::SqlTypeOf<#table_name::#column_name>)) } } } diff --git a/diesel_derives/src/selectable.rs b/diesel_derives/src/selectable.rs index 242560b97eaa..eb20c5075f43 100644 --- a/diesel_derives/src/selectable.rs +++ b/diesel_derives/src/selectable.rs @@ -1,13 +1,15 @@ use proc_macro2::TokenStream; +use quote::quote; use syn::spanned::Spanned; use syn::DeriveInput; +use syn::{parse_quote, Result}; use field::Field; use model::Model; use util::wrap_in_dummy_mod; -pub fn derive(item: DeriveInput) -> TokenStream { - let model = Model::from_item(&item, false, false); +pub fn derive(item: DeriveInput) -> Result { + let model = Model::from_item(&item, false, false)?; let (_, ty_generics, _) = item.generics.split_for_impl(); @@ -33,8 +35,12 @@ pub fn derive(item: DeriveInput) -> TokenStream { .fields() .iter() .map(|f| field_column_ty(f, &model)) - .collect::>(); - let field_columns_inst = model.fields().iter().map(|f| field_column_inst(f, &model)); + .collect::>>()?; + let field_columns_inst = model + .fields() + .iter() + .map(|f| field_column_inst(f, &model)) + .collect::>>()?; let check_function = if let Some(ref backends) = model.check_for_backend { let field_check_bound = model @@ -63,7 +69,7 @@ pub fn derive(item: DeriveInput) -> TokenStream { None }; - wrap_in_dummy_mod(quote! { + Ok(wrap_in_dummy_mod(quote! { use diesel::expression::Selectable; impl #impl_generics Selectable<__DB> @@ -78,7 +84,7 @@ pub fn derive(item: DeriveInput) -> TokenStream { } #check_function - }) + })) } fn to_field_ty_bound(field_ty: &syn::Type) -> Option { @@ -129,31 +135,31 @@ fn to_field_ty_bound(field_ty: &syn::Type) -> Option { } } -fn field_column_ty(field: &Field, model: &Model) -> TokenStream { +fn field_column_ty(field: &Field, model: &Model) -> Result { if let Some(ref select_expression_type) = field.select_expression_type { let ty = &select_expression_type.item; - quote!(#ty) + Ok(quote!(#ty)) } else if field.embed() { let embed_ty = &field.ty; - quote!(<#embed_ty as Selectable<__DB>>::SelectExpression) + Ok(quote!(<#embed_ty as Selectable<__DB>>::SelectExpression)) } else { let table_name = &model.table_names()[0]; - let column_name = field.column_name(); - quote!(#table_name::#column_name) + let column_name = field.column_name()?; + Ok(quote!(#table_name::#column_name)) } } -fn field_column_inst(field: &Field, model: &Model) -> TokenStream { +fn field_column_inst(field: &Field, model: &Model) -> Result { if let Some(ref select_expression) = field.select_expression { let expr = &select_expression.item; let span = expr.span(); - quote::quote_spanned!(span => #expr) + Ok(quote::quote_spanned!(span => #expr)) } else if field.embed() { let embed_ty = &field.ty; - quote!(<#embed_ty as Selectable<__DB>>::construct_selection()) + Ok(quote!(<#embed_ty as Selectable<__DB>>::construct_selection())) } else { let table_name = &model.table_names()[0]; - let column_name = field.column_name(); - quote!(#table_name::#column_name) + let column_name = field.column_name()?; + Ok(quote!(#table_name::#column_name)) } } diff --git a/diesel_derives/src/sql_function.rs b/diesel_derives/src/sql_function.rs index 13bbf628faaf..20e2f2013a43 100644 --- a/diesel_derives/src/sql_function.rs +++ b/diesel_derives/src/sql_function.rs @@ -1,9 +1,11 @@ use proc_macro2::TokenStream; +use quote::quote; use quote::ToTokens; use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::{ - Attribute, GenericArgument, Generics, Ident, Lit, Meta, MetaNameValue, PathArguments, Type, + parenthesized, parse_quote, Attribute, GenericArgument, Generics, Ident, Meta, MetaNameValue, + PathArguments, Token, Type, }; pub(crate) fn expand(input: SqlFunctionDecl) -> TokenStream { @@ -18,15 +20,16 @@ pub(crate) fn expand(input: SqlFunctionDecl) -> TokenStream { let sql_name = attributes .iter() - .find(|attr| { - attr.parse_meta() - .map(|m| m.path().is_ident("sql_name")) - .unwrap_or(false) - }) + .find(|attr| attr.meta.path().is_ident("sql_name")) .and_then(|attr| { - if let Ok(Meta::NameValue(MetaNameValue { - lit: Lit::Str(lit), .. - })) = attr.parse_meta() + if let Meta::NameValue(MetaNameValue { + value: + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(ref lit), + .. + }), + .. + }) = attr.meta { Some(lit.value()) } else { @@ -35,16 +38,12 @@ pub(crate) fn expand(input: SqlFunctionDecl) -> TokenStream { }) .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) - }); + let is_aggregate = attributes + .iter() + .any(|attr| attr.meta.path().is_ident("aggregate")); attributes.retain(|attr| { - attr.parse_meta() - .map(|m| !m.path().is_ident("sql_name") && !m.path().is_ident("aggregate")) - .unwrap_or(true) + !attr.meta.path().is_ident("sql_name") && !attr.meta.path().is_ident("aggregate") }); let args = &args; @@ -431,7 +430,7 @@ impl Parse for SqlFunctionDecl { let generics = Generics::parse(input)?; let args; let _paren = parenthesized!(args in input); - let args = args.parse_terminated::<_, Token![,]>(StrictFnArg::parse)?; + let args = args.parse_terminated(StrictFnArg::parse, Token![,])?; let return_type = if Option::]>::parse(input)?.is_some() { Type::parse(input)? } else { diff --git a/diesel_derives/src/sql_type.rs b/diesel_derives/src/sql_type.rs index 87b25b29efae..9e378d0a404e 100644 --- a/diesel_derives/src/sql_type.rs +++ b/diesel_derives/src/sql_type.rs @@ -1,12 +1,14 @@ use proc_macro2::{Span, TokenStream}; +use quote::quote; +use syn::Result; use syn::{DeriveInput, Ident}; 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, false); +pub fn derive(item: DeriveInput) -> Result { + let model = Model::from_item(&item, true, false)?; let struct_name = &item.ident; let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl(); @@ -15,7 +17,7 @@ pub fn derive(item: DeriveInput) -> TokenStream { let mysql_tokens = mysql_tokens(&item, &model); let pg_tokens = pg_tokens(&item, &model); - wrap_in_dummy_mod(quote! { + Ok(wrap_in_dummy_mod(quote! { impl #impl_generics diesel::sql_types::SqlType for #struct_name #ty_generics #where_clause @@ -32,7 +34,7 @@ pub fn derive(item: DeriveInput) -> TokenStream { #sqlite_tokens #mysql_tokens #pg_tokens - }) + })) } fn sqlite_tokens(item: &DeriveInput, model: &Model) -> Option { diff --git a/diesel_derives/src/table.rs b/diesel_derives/src/table.rs index 9d7494191672..46a1b6b4066f 100644 --- a/diesel_derives/src/table.rs +++ b/diesel_derives/src/table.rs @@ -1,5 +1,6 @@ use diesel_table_macro_syntax::{ColumnDef, TableDecl}; use proc_macro2::TokenStream; +use syn::parse_quote; use syn::Ident; const DEFAULT_PRIMARY_KEY_NAME: &str = "id"; diff --git a/diesel_derives/src/util.rs b/diesel_derives/src/util.rs index 42eeddb4c029..fdaa16c8f58d 100644 --- a/diesel_derives/src/util.rs +++ b/diesel_derives/src/util.rs @@ -1,7 +1,8 @@ use proc_macro2::TokenStream; -use syn::parse::{Parse, ParseStream, Result}; +use quote::quote; +use syn::parse::{Parse, ParseStream, Peek, Result}; use syn::token::Eq; -use syn::{parenthesized, Data, DeriveInput, GenericArgument, Ident, Type}; +use syn::{parenthesized, parse_quote, Data, DeriveInput, GenericArgument, Ident, Type}; use model::Model; @@ -23,24 +24,27 @@ pub const SELECT_EXPRESSION_TYPE_NOTE: &str = "select_expression_type = dsl::IsNotNull"; pub const CHECK_FOR_BACKEND_NOTE: &str = "diesel::pg::Pg"; -pub fn unknown_attribute(name: &Ident, valid: &[&str]) -> ! { +pub fn unknown_attribute(name: &Ident, valid: &[&str]) -> syn::Error { let prefix = if valid.len() == 1 { "" } else { " one of" }; - abort!( - name, - "unknown attribute, expected{} `{}`", - prefix, - valid.join("`, `") + syn::Error::new( + name.span(), + format!( + "unknown attribute, expected{prefix} `{}`", + valid.join("`, `") + ), ) } pub fn parse_eq(input: ParseStream, help: &str) -> Result { if input.is_empty() { - abort!( + return Err(syn::Error::new( input.span(), - "unexpected end of input, expected `=`"; - help = "The correct format looks like `#[diesel({})]`", help - ); + format!( + "unexpected end of input, expected `=`\n\ + help: The correct format looks like `#[diesel({help})]`", + ), + )); } input.parse::()?; @@ -49,11 +53,13 @@ pub fn parse_eq(input: ParseStream, help: &str) -> Result { pub fn parse_paren(input: ParseStream, help: &str) -> Result { if input.is_empty() { - abort!( + return Err(syn::Error::new( input.span(), - "unexpected end of input, expected parentheses"; - help = "The correct format looks like `#[diesel({})]`", help - ); + format!( + "unexpected end of input, expected parentheses\n\ + help: The correct format looks like `#[diesel({help})]`", + ), + )); } let content; @@ -61,21 +67,29 @@ pub fn parse_paren(input: ParseStream, help: &str) -> Result { content.parse() } -pub fn parse_paren_list( +pub fn parse_paren_list( input: ParseStream, help: &str, -) -> Result> { + sep: D, +) -> Result::Token>> +where + T: Parse, + D: Peek, + D::Token: Parse, +{ if input.is_empty() { - abort!( + return Err(syn::Error::new( input.span(), - "unexpected end of input, expected parentheses"; - help = "The correct format looks like `#[diesel({})]`", help - ); + format!( + "unexpected end of input, expected parentheses\n\ + help: The correct format looks like `#[diesel({help})]`", + ), + )); } let content; parenthesized!(content in input); - content.parse_terminated(T::parse) + content.parse_terminated(T::parse, sep) } pub fn wrap_in_dummy_mod(item: TokenStream) -> TokenStream { @@ -123,19 +137,25 @@ fn option_ty_arg(ty: &Type) -> Option<&Type> { } } -pub fn ty_for_foreign_derive(item: &DeriveInput, model: &Model) -> Type { +pub fn ty_for_foreign_derive(item: &DeriveInput, model: &Model) -> Result { if model.foreign_derive { match item.data { Data::Struct(ref body) => match body.fields.iter().next() { - Some(field) => field.ty.clone(), - None => abort_call_site!("foreign_derive requires at least one field"), + Some(field) => Ok(field.ty.clone()), + None => Err(syn::Error::new( + proc_macro2::Span::call_site(), + "foreign_derive requires at least one field", + )), }, - _ => abort_call_site!("foreign_derive can only be used with structs"), + _ => Err(syn::Error::new( + proc_macro2::Span::call_site(), + "foreign_derive can only be used with structs", + )), } } else { let ident = &item.ident; let (_, ty_generics, ..) = item.generics.split_for_impl(); - parse_quote!(#ident #ty_generics) + Ok(parse_quote!(#ident #ty_generics)) } } diff --git a/diesel_derives/src/valid_grouping.rs b/diesel_derives/src/valid_grouping.rs index bbb43ff740a0..750849eab8a8 100644 --- a/diesel_derives/src/valid_grouping.rs +++ b/diesel_derives/src/valid_grouping.rs @@ -1,12 +1,15 @@ use proc_macro2::TokenStream; +use quote::quote; +use syn::parse_quote; use syn::DeriveInput; +use syn::Result; 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, false); - let struct_ty = ty_for_foreign_derive(&item, &model); +pub fn derive(mut item: DeriveInput) -> Result { + let model = Model::from_item(&item, true, false)?; + let struct_ty = ty_for_foreign_derive(&item, &model)?; let type_params = item .generics @@ -25,7 +28,7 @@ pub fn derive(mut item: DeriveInput) -> TokenStream { item.generics.params.push(parse_quote!(__GroupByClause)); let (impl_generics, _, where_clause) = item.generics.split_for_impl(); - wrap_in_dummy_mod(quote! { + Ok(wrap_in_dummy_mod(quote! { use diesel::expression::{ValidGrouping, MixedAggregates, is_aggregate}; impl #impl_generics ValidGrouping<__GroupByClause> for #struct_ty @@ -33,7 +36,7 @@ pub fn derive(mut item: DeriveInput) -> TokenStream { { type IsAggregate = is_aggregate::Yes; } - }) + })) } else { let mut aggregates = item .generics @@ -58,7 +61,7 @@ pub fn derive(mut item: DeriveInput) -> TokenStream { item.generics.params.push(parse_quote!(__GroupByClause)); let (impl_generics, _, where_clause) = item.generics.split_for_impl(); - wrap_in_dummy_mod(quote! { + Ok(wrap_in_dummy_mod(quote! { use diesel::expression::{ValidGrouping, MixedAggregates, is_aggregate}; impl #impl_generics ValidGrouping<__GroupByClause> for #struct_ty @@ -66,6 +69,6 @@ pub fn derive(mut item: DeriveInput) -> TokenStream { { type IsAggregate = #is_aggregate; } - }) + })) } } diff --git a/diesel_table_macro_syntax/Cargo.toml b/diesel_table_macro_syntax/Cargo.toml index cd142c56c668..5bffb8fce353 100644 --- a/diesel_table_macro_syntax/Cargo.toml +++ b/diesel_table_macro_syntax/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -syn = {version = "1", features = ["full"]} +syn = {version = "2", features = ["full"]} diff --git a/diesel_table_macro_syntax/src/lib.rs b/diesel_table_macro_syntax/src/lib.rs index b535fab76fcb..f32084a0a933 100644 --- a/diesel_table_macro_syntax/src/lib.rs +++ b/diesel_table_macro_syntax/src/lib.rs @@ -1,4 +1,6 @@ +use syn::spanned::Spanned; use syn::Ident; +use syn::MetaNameValue; #[allow(dead_code)] // paren_token is currently unused pub struct PrimaryKey { @@ -33,6 +35,27 @@ struct SqlNameAttribute { eq: syn::Token![=], lit: syn::LitStr, } +impl SqlNameAttribute { + fn from_attribute(element: syn::Attribute) -> Result { + if let syn::Meta::NameValue(MetaNameValue { + eq_token, + value: + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit), + .. + }), + .. + }) = element.meta + { + Ok(SqlNameAttribute { eq: eq_token, lit }) + } else { + Err(syn::Error::new( + element.span(), + "Invalid `#[sql_name = \"column_name\"]` attribute", + )) + } + } +} impl syn::parse::Parse for TableDecl { fn parse(buf: &syn::parse::ParseBuffer<'_>) -> Result { @@ -82,7 +105,7 @@ impl syn::parse::Parse for PrimaryKey { fn parse(input: syn::parse::ParseStream) -> syn::Result { let content; let paren_token = syn::parenthesized!(content in input); - let keys = content.parse_terminated(Ident::parse)?; + let keys = content.parse_terminated(Ident::parse, syn::Token![,])?; Ok(Self { paren_token, keys }) } } @@ -122,12 +145,14 @@ fn get_sql_name( mut meta: Vec, ident: &syn::Ident, ) -> Result<(String, Vec), syn::Error> { - if let Some(pos) = meta - .iter() - .position(|m| m.path.get_ident().map(|i| i == "sql_name").unwrap_or(false)) - { + if let Some(pos) = meta.iter().position(|m| { + m.path() + .get_ident() + .map(|i| i == "sql_name") + .unwrap_or(false) + }) { let element = meta.remove(pos); - let inner: SqlNameAttribute = syn::parse2(element.tokens)?; + let inner = SqlNameAttribute::from_attribute(element)?; Ok((inner.lit.value(), meta)) } else { Ok((ident.to_string(), meta))