Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[sea-orm-cli] Better handling of relation generations #239

Closed
tyt2y3 opened this issue Oct 11, 2021 · 13 comments · Fixed by #347
Closed

[sea-orm-cli] Better handling of relation generations #239

tyt2y3 opened this issue Oct 11, 2021 · 13 comments · Fixed by #347
Assignees

Comments

@tyt2y3
Copy link
Member

tyt2y3 commented Oct 11, 2021

It has been reported that the codegen can generate non-compilable code when dealing with relations.

As the first step, we can simply skip generating the relations if:

  1. the related entity is self::Entity (How to define a one-to-one relationship on a table. #231 (comment))
  2. there exist multiple relations to the same related Entity (Cannot define multiple columns within the same table that have the same relationship to another table #218)

Later, we can also try to generate Links inplace of those relations.

@tyt2y3 tyt2y3 added this to the 0.4.x - Enumeration milestone Oct 16, 2021
@AngelOnFira
Copy link
Contributor

Hey, this doesn't look like too hard of an issue, can I take it? Also, is this repo participating in Hacktoberfest (or rather, would you be willing to add the hacktoberfest-accepted tag once I get to the PR stage?)

@tyt2y3
Copy link
Member Author

tyt2y3 commented Oct 17, 2021

Well, I think the 'skipping' part should be reasonably easy if you are already familiar with Rust's code generation facilities.

The 'Link' generation part could be substantial, but I imagine it being very similar to the original 'Related' implementation.

We can separate these two tasks as two PRs.

Sure. Oh, I was not aware how to join Hacktoberfest. Indeed. Seems fun!

We’ve changed the program to only count pull requests that are made to repositories with a 'hacktoberfest' topic or labeled with **hacktoberfest-accepted**. 

https://hacktoberfest.digitalocean.com/faq

I added the topic to our repo now. It's kind of sad because we are already half way through October (

Let us know if there is anything we can help to help you earn a reward!

@tyt2y3
Copy link
Member Author

tyt2y3 commented Oct 19, 2021

@AngelOnFira do you want to assign this to yourself or you have other ideas?

@AngelOnFira
Copy link
Contributor

@AngelOnFira do you want to assign this to yourself or you have other ideas?

Ya, if I can be assigned this it would be good 😄 I just got caught up in the other PR I was working on 😛

@AngelOnFira
Copy link
Contributor

So I'm working on what's the minimum work that has to be done to remove the duplication. I've set up two simple tables for testing, where one table has two columns that relate to the other:

image

(The naming might be a little confusing, imagine it's bank_account and bank_transaction)

So getting this with the sea-orm-cli would generate this for the transaction's relation:

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
    #[sea_orm(
        belongs_to = "super::forms_account::Entity",
        from = "Column::FromAccountId",
        to = "super::forms_account::Column::Id",
        on_update = "NoAction",
        on_delete = "NoAction"
    )]
    FormsAccount,
    #[sea_orm(
        belongs_to = "super::forms_account::Entity",
        from = "Column::ToAccountId",
        to = "super::forms_account::Column::Id",
        on_update = "NoAction",
        on_delete = "NoAction"
    )]
    FormsAccount,
}

Now, if our solution was simply to de-duplicate these so that there is only one relation, this would require throwing away data about one of the relations. For example:

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
    #[sea_orm(
        belongs_to = "super::forms_account::Entity",
        from = "Column::FromAccountId",
        to = "super::forms_account::Column::Id",
        on_update = "NoAction",
        on_delete = "NoAction"
    )]
    FormsAccount,
}

On the other hand, this solution wouldn't be too bad for the accounts relation. By default, it looks like:

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
    #[sea_orm(has_many = "super::forms_transaction::Entity")]
    FormsTransaction,
    #[sea_orm(has_many = "super::forms_transaction::Entity")]
    FormsTransaction,
}

This would be quite easy to resolve. So going back to the transaction relations, I just made a simple tweak to include the column name as part of the Relation varient:

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
    #[sea_orm(
        belongs_to = "super::forms_account::Entity",
        from = "Column::FromAccountId",
        to = "super::forms_account::Column::Id",
        on_update = "NoAction",
        on_delete = "NoAction"
    )]
    FromAccountIdFormsAccount,
    #[sea_orm(
        belongs_to = "super::forms_account::Entity",
        from = "Column::ToAccountId",
        to = "super::forms_account::Column::Id",
        on_update = "NoAction",
        on_delete = "NoAction"
    )]
    ToAccountIdFormsAccount,
}

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

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

Although this allows for both to be unique as a Relation varient, it doesn't help with how the impl Related<super::forms_account::Entity> can only refer to one of the relations.

I wanted to write this down to get some feedback, but also because it helped me try to scope out the problem a little better.

@tyt2y3
Copy link
Member Author

tyt2y3 commented Oct 23, 2021

Yes. I think removing relation generation would be the first step. It compiles and at least remove the confusion to users.
Then, we can probably try to generate Link in place of Related, which can have multiple relations between an Entity pair.

use crate::entity::prelude::*;
#[derive(Debug)]
pub struct CakeToFilling;
impl Linked for CakeToFilling {
type FromEntity = super::cake::Entity;
type ToEntity = super::filling::Entity;
fn link(&self) -> Vec<RelationDef> {
vec![
super::cake_filling::Relation::Cake.def().rev(),
super::cake_filling::Relation::Filling.def(),
]
}
}
#[derive(Debug)]
pub struct CakeToFillingVendor;
impl Linked for CakeToFillingVendor {
type FromEntity = super::cake::Entity;
type ToEntity = super::vendor::Entity;
fn link(&self) -> Vec<RelationDef> {
vec![
super::cake_filling::Relation::Cake.def().rev(),
super::cake_filling::Relation::Filling.def(),
super::filling::Relation::Vendor.def(),
]
}
}

@AngelOnFira
Copy link
Contributor

@tyt2y3 But I am still wondering, what should happen in a case where multiple similar relations have different attribute macros? Should I just discard any that aren't the first?

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
    #[sea_orm(
        belongs_to = "super::forms_account::Entity",
        from = "Column::FromAccountId",
        to = "super::forms_account::Column::Id",
        on_update = "NoAction",
        on_delete = "NoAction"
    )]
    FormsAccount,
    #[sea_orm(
        belongs_to = "super::forms_account::Entity",
        from = "Column::ToAccountId",
        to = "super::forms_account::Column::Id",
        on_update = "NoAction",
        on_delete = "NoAction"
    )]
    FormsAccount,
}

@tyt2y3
Copy link
Member Author

tyt2y3 commented Oct 23, 2021

I think naming the enum variants differently would be good. May be FormsAccount1 and FormsAccount2?

@AngelOnFira
Copy link
Contributor

I think naming the enum variants differently would be good. May be FormsAccount1 and FormsAccount2?

Ya, this should work for a temporary solution, but in the long term I definitely think it should be based on the column name, or another alternative.

@billy1624
Copy link
Member

Hey @AngelOnFira, any updates on this? :P

@AngelOnFira
Copy link
Contributor

AngelOnFira commented Nov 25, 2021

Thanks for checking in, I need this for a project I have coming up, but I've been super busy with other work. As soon as I do have time, I do plan on hopping on this issue since it's quite important to me, but if someone else has time to work on it right now, I'd be very grateful for that as well 😄

@billy1624
Copy link
Member

Thanks for checking in, I need this for a project I have coming up, but I've been super busy with other work. As soon as I do have time, I do plan on hopping on this issue since it's quite important to me, but if someone else has time to work on it right now, I'd be very grateful for that as well 😄

Thanks!! @AngelOnFira. Take your time!

@billy1624
Copy link
Member

Hey @AngelOnFira, I have just open a PR for this. You can check it if you have time :))

arpancodes pushed a commit to arpancodes/sea-orm that referenced this issue Apr 8, 2022
* With clause and with queries

* Testing INSERT with CTE

* Allow arbitrary subqueries
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants