Rust SeaORM DeriveEntity and DeriveRelation

287 Views Asked by At

I have 2 models, a user and a refresh token model. I am generating my entity using the DeriveEntityModel macro on my struct. However when I try to make the relationship following the documentation, DeriveRelation seems to raise an error saying that the columns are an ambiguous type, so I am assuming that the compiler isn't able to figure out which column is which?

#user_model.rs
use chrono::NaiveDateTime;
use sea_orm::{entity::prelude::*, prelude::async_trait::async_trait};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::models::refresh_token_model::Entity as RefreshTokenEntity;

#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "users")]
pub struct Model {
    #[sea_orm(primary_key)]
    pub id: Uuid,
    #[sea_orm(unique)]
    pub username: String,
    #[sea_orm(unique)]
    pub email: String,
    pub password: String,
    pub created_at: NaiveDateTime,
    pub updated_at: Option<NaiveDateTime>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
    #[sea_orm(has_many = "crate::models::refresh_token_model::Entity")]
    RefreshTokenEntity,
}

impl Related<RefreshTokenEntity> for Entity {
    fn to() -> RelationDef {
        Relation::RefreshTokenEntity.def()
    }
}

#refresh_models.rs
use chrono::NaiveDateTime;
use sea_orm::{entity::prelude::*, prelude::async_trait::async_trait};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::models::user_model::Entity as UserEntity;

#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "refresh_token")]
pub struct Model {
    #[sea_orm(primary_key)]
    pub id: Uuid,
    pub user_id: Uuid,
    pub token: String,
    pub issued_at: NaiveDateTime,
    pub expires_at: Option<NaiveDateTime>,
    pub revoked: bool
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
        #[sea_orm(
        belongs_to = "crate::models::user_model::Entity", 
        from = "Column::UserId",
        to = "crate::models::user_model::Entity::Column::Id",
        on_update = "Cascade",
        on_delete = "Cascade")]
    UserEntity,
}

impl Related<UserEntity> for Entity {
    fn to() -> RelationDef {
        Relation::UserEntity.def()
    }
}


Any help would be appreciated. I have also tried using super::_____::Entity with no luck and also using something like

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
        #[sea_orm(
        belongs_to = "UserEntity", 
        from = "Column::UserId",
        to = "UserEntity::Column::Id",
        on_update = "Cascade",
        on_delete = "Cascade")]
    UserEntity,
}

The error I get is:

error[E0223]: ambiguous associated type
  --> src\models\refresh_token_model.rs:20:40
   |
20 | #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
   |                                        ^^^^^^^^^^^^^^
   |
   = note: this error originates in the derive macro `DeriveRelation` (in Nightly builds, run with -Z macro-backtrace for more info)
help: if there were a trait named `Example` with associated type `Column` implemented for `user_model::Entity`, you could use the fully-qualified path
   |
20 | #[derive(Copy, Clone, Debug, EnumIter, <user_model::Entity as Example>::Column)]
   |                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1

There are 1 best solutions below

0
taennan On

There are actually two separate problems with the code you've provided.

The first is in the refresh_token_model's Relation enum. The DeriveEntityModel macro generates the Column enum in the module that the Model is declared in.

Therefore, we don't write <model>::Entity::Column, but rather <model>::Column

So you just have to point the relation along the correct path:

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
    #[sea_orm(
        belongs_to = "crate::models::user_model::Entity",
        from = "Column::UserId",
        // Change this...
        // to = "crate::models::user_model::Entity::Column::Id",
        // ...to this
        to = "crate::models::user_model::Column::Id",
        on_update = "Cascade",
        on_delete = "Cascade")
    ]
    UserEntity,
}

Secondly, you've got to add this line in your user_model.rs and refresh_token_model.rs files:

impl ActiveModelBehavior for ActiveModel {}

This one is technically a separate problem, but you still need it for the code to compile.