Repository: SeaQL/sea-query (language: rust)

Issue:
syn 1.x and 2.x both used in sea-query
## Description

I'm shipping a crate that uses sea-query, but getting a warning that multiple versions of `syn` are being pulled in.

I'm sure it wouldn't be trivial to upgrade `sea-query-derive` to `syn` 2.x, but it would make downstream compile times faster, (possibly) binaries smaller, and reduce warnings that are not feasibly fixable.

## Steps to Reproduce

1. `cargo new --lib foo`
2. `cd foo`
3. add `#![warn(clippy::cargo)]` to the top of `src/lib.rs`
4. `cargo add sea-query`
5. `cargo clippy`

### Expected Behavior

Adding `sea-query` to my project is `clippy::cargo`-clean.

### Actual Behavior

Adding `sea-query` to my project generates a new `clippy::cargo` warning;

```
warning: multiple versions for dependency `syn`: 1.0.109, 2.0.35
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
```

### Reproduces How Often

Every time.

## Versions

```
λ cargo tree | grep sea-
└── sea-query v0.30.1
    └── sea-query-derive v0.4.0 (proc-macro)
```

## Additional Information

`sea-query-derive` depends on `syn` 1.x here: https://github.com/SeaQL/sea-query/blob/b80f14eaa1d4b02389db033ad64953fbc8c925d6/sea-query-derive/Cargo.toml#L18
where `syn` 2.x is pulled in via `inherent` and `thiserror`.


Discussion / hints:
Thanks for raising this.

Yeah, SeaORM went through an exercise of upgrading to syn2. It was an involving process, and it left us just there without touching SeaQuery. Contribution is of course welcome.

However, I would like to point out this is an ecosystem problem. Unless *every crate* in a dependency tree upgrades to syn2, it will be pretty hard to avoid having two `syn`.
I wouldn't mind taking a look at this in my spare time. Need more proc macro practice anyway

Fix patch:
diff --git a/sea-query-derive/Cargo.toml b/sea-query-derive/Cargo.toml
index 7c3d749fa..b301d55d7 100644
--- a/sea-query-derive/Cargo.toml
+++ b/sea-query-derive/Cargo.toml
@@ -15,7 +15,7 @@ rust-version = "1.60"
 proc-macro = true
 
 [dependencies]
-syn = { version = "1", default-features = false, features = ["parsing", "proc-macro", "derive", "printing"] }
+syn = { version = "2", default-features = false, features = ["parsing", "proc-macro", "derive", "printing"] }
 quote = { version = "1", default-features = false }
 heck = { version = "0.4", default-features = false }
 proc-macro2 = { version = "1", default-features = false }
diff --git a/sea-query-derive/src/iden_attr.rs b/sea-query-derive/src/iden_attr.rs
index 545c9738c..e07b00553 100644
--- a/sea-query-derive/src/iden_attr.rs
+++ b/sea-query-derive/src/iden_attr.rs
@@ -1,6 +1,7 @@
 use std::convert::{TryFrom, TryInto};
 
-use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, NestedMeta};
+use syn::spanned::Spanned;
+use syn::{Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta};
 
 use crate::{error::ErrorMsg, iden_path::IdenPath};
 
@@ -14,8 +15,13 @@ pub(crate) enum IdenAttr {
 impl IdenAttr {
     fn extract_method(meta: Meta) -> syn::Result<Self> {
         match meta {
-            Meta::NameValue(nv) => match nv.lit {
-                Lit::Str(name) => Ok(Self::Method(Ident::new(name.value().as_str(), name.span()))),
+            Meta::NameValue(nv) => match nv.value {
+                Expr::Lit(ExprLit { lit, .. }) => match lit {
+                    Lit::Str(name) => {
+                        Ok(Self::Method(Ident::new(name.value().as_str(), name.span())))
+                    }
+                    _ => Err(Error::new_spanned(nv.eq_token, ErrorMsg::WrongLiteral)),
+                },
                 _ => Err(Error::new_spanned(nv, ErrorMsg::WrongLiteral)),
             },
             a => Err(Error::new_spanned(
@@ -27,37 +33,39 @@ impl IdenAttr {
 
     fn extract_iden(meta: Meta) -> syn::Result<Self> {
         match &meta {
-            Meta::NameValue(nv) => match &nv.lit {
-                Lit::Str(lit) => Ok(IdenAttr::Rename(lit.value())),
-                _ => Err(Error::new_spanned(&nv.lit, ErrorMsg::WrongLiteral)),
-            },
-            Meta::List(list) => match list.nested.first() {
-                Some(NestedMeta::Meta(Meta::Path(p))) if p.is_ident(&IdenPath::Flatten) => {
-                    Ok(IdenAttr::Flatten)
-                }
-                Some(NestedMeta::Meta(Meta::NameValue(nv))) => Self::extract_named_value_iden(nv),
-                _ => Err(Error::new_spanned(meta, ErrorMsg::WrongListFormat)),
+            Meta::NameValue(nv) => match &nv.value {
+                Expr::Lit(ExprLit { lit, .. }) => match lit {
+                    Lit::Str(lit) => Ok(IdenAttr::Rename(lit.value())),
+                    _ => Err(Error::new_spanned(&nv.value, ErrorMsg::WrongLiteral)),
+                },
+                _ => Err(Error::new_spanned(nv, ErrorMsg::WrongLiteral)),
             },
-            a => Err(Error::new_spanned(a, ErrorMsg::WrongAttributeFormat)),
-        }
-    }
-
-    fn extract_named_value_iden(nv: &MetaNameValue) -> syn::Result<Self> {
-        match &nv.lit {
-            Lit::Str(name) => {
-                // Don't match "iden" since that would mean `#[iden(iden = "name")]` would be accepted
-                if nv.path.is_ident(&IdenPath::Rename) {
-                    Ok(Self::Rename(name.value()))
-                } else if nv.path.is_ident(&IdenPath::Method) {
-                    Ok(Self::Method(Ident::new(name.value().as_str(), name.span())))
-                } else {
-                    Err(Error::new_spanned(
-                        nv,
-                        ErrorMsg::UnsupportedKeyword(nv.path.get_ident().unwrap().clone()),
-                    ))
-                }
+            Meta::List(list) if list.path.is_ident("iden") => {
+                let mut iden_attr: Option<Self> = None;
+                list.parse_nested_meta(|nested| {
+                    if nested.path.is_ident(&IdenPath::Flatten) {
+                        iden_attr = Some(IdenAttr::Flatten);
+                        Ok(())
+                    } else if nested.path.is_ident(&IdenPath::Rename) {
+                        let value = nested.value()?;
+                        let value: LitStr = value.parse()?;
+                        iden_attr = Some(IdenAttr::Rename(value.value()));
+                        Ok(())
+                    } else if nested.path.is_ident(&IdenPath::Method) {
+                        let value = nested.value()?;
+                        let value: LitStr = value.parse()?;
+                        iden_attr = Some(IdenAttr::Method(Ident::new(&value.value(), meta.span())));
+                        Ok(())
+                    } else {
+                        Err(Error::new_spanned(
+                            &meta,
+                            ErrorMsg::UnsupportedKeyword(nested.path.get_ident().unwrap().clone()),
+                        ))
+                    }
+                })?;
+                iden_attr.ok_or(Error::new_spanned(meta, ErrorMsg::WrongListFormat))
             }
-            _ => Err(Error::new_spanned(&nv.lit, ErrorMsg::WrongLiteral)),
+            a => Err(Error::new_spanned(a, ErrorMsg::WrongAttributeFormat)),
         }
     }
 }
@@ -66,7 +74,7 @@ impl TryFrom<&Attribute> for IdenAttr {
     type Error = Error;
 
     fn try_from(value: &Attribute) -> Result<Self, Self::Error> {
-        value.parse_meta()?.try_into()
+        value.meta.clone().try_into()
     }
 }
 
diff --git a/sea-query-derive/src/lib.rs b/sea-query-derive/src/lib.rs
index 7c9e14136..30676b555 100644
--- a/sea-query-derive/src/lib.rs
+++ b/sea-query-derive/src/lib.rs
@@ -18,9 +18,9 @@ use self::{
 };
 
 fn find_attr(attrs: &[Attribute]) -> Option<&Attribute> {
-    attrs
-        .iter()
-        .find(|attr| attr.path.is_ident(&IdenPath::Iden) || attr.path.is_ident(&IdenPath::Method))
+    attrs.iter().find(|attr| {
+        attr.path().is_ident(&IdenPath::Iden) || attr.path().is_ident(&IdenPath::Method)
+    })
 }
 
 fn get_table_name(ident: &proc_macro2::Ident, attrs: Vec<Attribute>) -> Result<String, syn::Error> {


Test patch: