SeaQL / SeaQL/sea-orm

Uncompilable code generated by sea-orm-cli

Open
#2,585 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Area:code-gen Area:schema
Dominant language
Rust
Stars
9.9k
Forks
734
Avg merge
6h 36m
Merged PRs (30d)
8

Description

Description

Uncompilable entities files are generated when using sea-orm-cli against Postgres, when:

  1. the table's primary key is multi-columned, AND
  2. the table itself contains SelfRef, AND
  3. the said table is refereneced by foreign keys from other tables.

Steps to Reproduce

  1. Copy this as your main.rs
use sea_orm::sea_query::{ColumnDef, ForeignKey, Index, Table};
use sea_orm::DbErr;
use sea_orm_migration::{async_trait, MigrationName, MigrationTrait, MigratorTrait, SchemaManager};
use sea_orm_migration::{cli, sea_query};

// !! Uncomment this line after generating entities rs files at ./entities/*
// mod entities;

pub struct Migrator;
pub struct Migration;

#[async_trait::async_trait]
impl MigratorTrait for Migrator {
    fn migrations() -> Vec<Box<dyn MigrationTrait>> {
        vec![Box::new(Migration)]
    }
}

impl MigrationName for Migration {
    fn name(&self) -> &str {
        "m20250101_000001_demo"
    }
}

#[async_trait::async_trait]
impl MigrationTrait for Migration {
    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
        // Create DemoTable table
        {
            let mut main_table = Table::create();
            let mut table = main_table.table(DemoTable::Table);

            table = table.col(ColumnDef::new(DemoTable::CompKey1).uuid().not_null());
            table = table.col(ColumnDef::new(DemoTable::CompKey2).uuid().not_null());
            table = table.col(ColumnDef::new(DemoTable::RefCompKey1).uuid().not_null());
            table = table.col(ColumnDef::new(DemoTable::RefCompKey2).uuid().not_null());

            table = table.primary_key(
                Index::create()
                    .col(DemoTable::CompKey1)
                    .col(DemoTable::CompKey2),
            );
            table = table.foreign_key(
                ForeignKey::create()
                    .take()
                    .from(
                        DemoTable::Table,
                        (DemoTable::RefCompKey1, DemoTable::RefCompKey2),
                    )
                    .to(DemoTable::Table, (DemoTable::CompKey1, DemoTable::CompKey2)),
            );
            let _ = manager.create_table(table.to_owned()).await?;
        }

        // Create DemoTableForeign table
        {
            let mut main_table = Table::create();
            let mut table = main_table.table(DemoTableForeign::Table);
            table = table.col(ColumnDef::new(DemoTableForeign::Id).uuid().not_null());
            table = table.col(
                ColumnDef::new(DemoTableForeign::PointerKey1)
                    .uuid()
                    .not_null(),
            );
            table = table.col(
                ColumnDef::new(DemoTableForeign::PointerKey2)
                    .uuid()
                    .not_null(),
            );
            table = table.primary_key(Index::create().col(DemoTableForeign::Id));
            table = table.foreign_key(
                ForeignKey::create()
                    .take()
                    .from(
                        DemoTableForeign::Table,
                        (DemoTableForeign::PointerKey1, DemoTableForeign::PointerKey2),
                    )
                    .to(DemoTable::Table, (DemoTable::CompKey1, DemoTable::CompKey2)),
            );
            let _ = manager.create_table(table.to_owned()).await?;
        }

        Ok(())
    }

    async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
        todo!(); // not relevant to this report
    }
}

#[derive(sea_orm::Iden)]
pub enum DemoTable {
    Table,
    CompKey1,
    CompKey2,
    RefCompKey1,
    RefCompKey2,
}

#[derive(sea_orm::Iden)]
pub enum DemoTableForeign {
    Table,
    Id,
    PointerKey1,
    PointerKey2,
}

#[async_std::main]
async fn main() {
    cli::run_cli(Migrator).await;
}
  1. Run cargo run && sea-orm-cli generate entity -o ./src/entities/ -u postgres://U:P@localhost/TESTDB (replace the url with your test db)

  2. Uncomment line 7 mod entities; of the above given main.rs.

  3. The entities files demo_table_foreign.rs and demo_table.rs both report a compile time error.

Expected Behavior

The generated entities files should NOT contain compile-time errors.

Actual Behavior

The generated entities files (when included in the project), fails cargo check and report compile-time errors.

error[E0599]: no variant or associated item named `DemoTable` found for enum `demo_table::Relation` in the current scope
  --> src\entities\demo_table.rs:35:43
   |
17 | pub enum Relation {
   | ----------------- variant or associated item `DemoTable` not found for this enum
...
35 |         Some(super::demo_table::Relation::DemoTable.def().rev())
   |                                           ^^^^^^^^^ variant or associated item not found in `Relation`

error[E0599]: no variant or associated item named `DemoTable` found for enum `demo_table::Relation` in the current scope
  --> src\entities\demo_table_foreign.rs:28:38
   |
28 |         super::demo_table::Relation::DemoTable.def()
   |                                      ^^^^^^^^^ variant or associated item not found in `Relation`
   |
  ::: src\entities\demo_table.rs:17:1
   |
17 | pub enum Relation {
   | ----------------- variant or associated item `DemoTable` not found for this enum
Reproduces How Often

This is always reproducible, tested on Postgres as the backend.

Workarounds

The current workaround is to manually change the line in the entity files from:

Some(super::demo_table::Relation::DemoTable.def().rev())

to

Some(super::demo_table::Relation::SelfRef.def().rev())

This has to be done manually for EACH of the problematic file.
After some testings, there seem to be no problems / incorrect behaviour when reading / writing to database after the above manual change.

Reproducible Example

The min. reproducible example is provided above.

Versions

Crate deps:

$ cargo tree | grep sea-
├── sea-orm v1.1.10
│   ├── sea-orm-macros v1.1.10 (proc-macro)
│   │   ├── sea-bae v0.2.1 (proc-macro)
│   ├── sea-query v0.32.4
│   │   ├── sea-query-derive v0.4.3 (proc-macro)
│   ├── sea-query-binder v0.7.0
│   │   ├── sea-query v0.32.4 (*)
└── sea-orm-migration v1.1.10
    ├── sea-orm v1.1.10 (*)
    ├── sea-orm-cli v1.1.10
    │   ├── sea-schema v0.16.1
    │   │   ├── sea-query v0.32.4 (*)
    │   │   └── sea-schema-derive v0.3.0 (proc-macro)
    ├── sea-schema v0.16.1 (*)

Cargo.toml:

...
[dependencies]
async-std = { version = "1", features = ["attributes", "tokio1"] }
sea-orm = { version = "1.1.7", features = [
    "sqlx-sqlite",
    "sqlx-postgres",
    "runtime-async-std-native-tls",
    "macros",
    "with-json",
    "debug-print",
    "with-uuid",
] }
sea-orm-migration = "1.1.10"

Rust edition: 2024
OS: Windows 11 23H2
Database: Postgres (running in Docker, sha256:f49abb9855df03f1829d6bd95bc8f5e9a24e1fd1bd11cab99bc2ef90f6960f6d)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the provided migration and sea-orm-cli generate entity command, then inspect the generated demo_table.rs and demo_table_foreign.rs files. Trace why the generated relation refers to DemoTable instead of SelfRef, and verify that uncommenting mod entities allows cargo check to pass without manual edits.

Written by the indexing model from the issue text.

Assessment

Tech stack
postgres, rust
Domain
database, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.