SeaQL / sea-orm

🐚 An async & dynamic ORM for Rust
https://www.sea-ql.org/SeaORM/
Apache License 2.0
6.57k stars 461 forks source link

ambiguous associated type when access Entity::Column #2156

Closed Ayana-chan closed 2 months ago

Ayana-chan commented 3 months ago

Description

I use sea-orm-cli to genetate entity for my database, but I get ambiguous associated type when I'm trying access Entity::Column.

Steps to Reproduce

My table is called node. Therefore sea-orm-cli generate these codes in entity_crate:

//! module `node`
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "node")]
#[serde(rename_all = "camelCase")]
pub struct Model {
    #[sea_orm(primary_key, auto_increment = false)]
    pub id: String,
    #[sea_orm(unique)]
    pub peer_id: String,
    pub rpc_address: String,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

impl ActiveModelBehavior for ActiveModel {}

And it would set Node to be the alias of node::Entity:

//! module `prelude`
pub use super::node::Entity as Node;

Then I want to INSERT ... ON DUPLICATE KEY UPDATE, so I write:

// new node item
let new_node = node::ActiveModel {
    id: Set(new_uuid.clone()),
    peer_id: Set("abcd peer id".to_string()),
    rpc_address: Set("88.88.88.88:1234".to_string()),
};
// what to do when duplicate key (at column peer_id)
// The compile error occurs here
let dup_conflict = sea_query::OnConflict::column(Node::Column::PeerId)
    .update_columns([
        Node::Column::RpcAddress,
    ])
    .to_owned();
// execute
let result = Node::insert(new_node)
    .on_conflict(dup_conflict)
    .exec(&conn)
    .await.unwrap();

I get:

ambiguous associated type (at Node::Column)
help: use fully-qualified syntax: `<Entity as sea_orm::EntityTrait>::Column`

Expected Behavior

Should be no error. I want to access everything of node table by Node (entity_crate::node::Entity).

Actual Behavior

Compile error: ambiguous associated type.

Reproduces How Often

Always.

Workarounds

To avoid this compile error, I just directly import entity_crate::node and use node::Column. A little ugly.

To find out the reason, I use cargo-expand in entity_crate to expand all macros, and I found two trait with associated type called Column: sea_orm::PrimaryKeyToColumn and sea_orm::entity::EntityTrait. And the Entity only impl sea_orm::entity::EntityTrait. However, even though sea_orm::PrimaryKeyToColumn is not imported, the ambiguous associated type error still occurs.

This is a problem about associated type. The code below also have ambiguous associated type compile error:

trait T1 {
    type Name;
}

mod private_mod {
    trait T2 {
        type Name;
    }
}

struct MyStruct {}

impl T1 for MyStruct {
    type Name = i32;
}

fn main() {
    let v: MyStruct::Name = 12;
}

Maybe rename the sea_orm::PrimaryKeyToColumn::Column would solve it.

Reproducible Example

Minimal reproducible example:

use sea_orm::prelude::*;
use sea_orm::sea_query;

// === node ===

#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "node")]
pub struct Model {
    #[sea_orm(primary_key, auto_increment = false)]
    pub id: String,
    #[sea_orm(unique)]
    pub peer_id: String,
    pub rpc_address: String,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

impl ActiveModelBehavior for ActiveModel {}

// === alias of Entity ===

use Entity as Node;

// === access column ===

fn main() {
    let dup_conflict = sea_query::OnConflict::column(Node::Column::PeerId)
        .update_columns([
            Node::Column::RpcAddress,
        ])
        .to_owned();
}

Versions

sea-orm = "0.12"

sea-orm-cli version: 0.12.14

tyt2y3 commented 2 months ago

This should not be a bug, because it's been this way since 0.1. As you already know, there are two workarounds:

  1. do node::Column
  2. do <Node as EntityTrait>::Column

But you've made an interesting observation, and the solution is right here! Nobody is using PrimaryKeyToColumn directly, as I imagine, so we can actually afford to break PrimaryKeyToColumn by renaming Column to something else. And now is probably the last time I'd change the Entity type system.

tyt2y3 commented 2 months ago

PrimaryKeyToColumn by renaming Column to something else

Can you open a PR on this? I want to make this change

Ayana-chan commented 2 months ago

I apologize for my significant mistake. Renaming can't solve this problem. Actually, this problem would never be solved.

Look at this code:

trait T1 {
    type Name;
}

struct MyStruct {}

impl T1 for MyStruct {
    type Name = i32;
}

fn main() {
    let v: MyStruct::Name = 12;
}

Just one trait and just one associate type, but also get:

Compiling playground v0.0.1 (/playground)
error[E0223]: ambiguous associated type
  --> src/main.rs:13:12
   |
13 |     let v: MyStruct::Name = 12;
   |            ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<MyStruct as T1>::Name`

For more information about this error, try `rustc --explain E0223`.
error: could not compile `playground` (bin "playground") due to 1 previous error

It can be seen that the ambiguous associated type error is unrelated to associate types with duplicate names. It's easy to understand: If Rust allows to access associate type without fully-qualified syntax, any lib user who define an associate type with duplicate names would cause a break inside the lib.

As a conclusion, perhaps accessing associate types from outside of the trait must use fully-qualified syntax like <MyStruct as T1>::Name. So this issue dosen't point out any improvement points.

tyt2y3 commented 2 months ago

There was a discussion around this before, but I couldn't seem to find it.

tyt2y3 commented 2 months ago

Found it https://github.com/rust-lang/rust/issues/8995