SeaQL / sea-orm

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

`schema::custom()` requires `col` and `name` to be of same type #2325

Open sgoll opened 1 month ago

sgoll commented 1 month ago

Description

The migration method schema::custom() allows defining table columns of a custom type, e.g. enums in PostgreSQL. Right now, its type signature requires both arguments col and name to be of the same type T: IntoIden:

https://github.com/SeaQL/sea-orm/blob/aa0bbd9e017635ba646a76e7d7ac4f33bccd5db5/sea-orm-migration/src/schema.rs#L541-L543

This is problematic because it does not allow pulling column name and type name from two different DeriveIden structs as in the following example:

/// Some custom types in our schema.
#[derive(DeriveIden)]
enum CustomType {
    SpecialType,
}

/// A regular table in our schema.
#[derive(DeriveIden)]
enum SomeTable {
    Table,
    SomeColumn,
}

/// Runs migration.
fn migrate(manager: &SchemaManager) {
    manager
        .create_table(
            Table::create()
                .table(SomeTable::Table)
                .col(schema::custom(
                    SomeTable::SomeColumn,
                    CustomType::SpecialType, // This fails.
                ))
                .to_owned(),
        )
        .await?;
}

Steps to Reproduce

  1. Create migration.
  2. In migration, create custom type, e.g. using Type::create().as_enum(…).
  3. In migration, create table with column that uses this type.
  4. Try to use DeriveIden structs.

Expected Behavior

The call to schema::custom() should be valid even when both arguments come from different DeriveIden structs.

Actual Behavior

The call to schema::custom() is rejected.

Workarounds

For now, the workaround is to use Alias for both col and name arguments. However, this defeats the purpose of using reusable DeriveIden structs:

fn migrate(manager: &SchemaManager) {
    manager
        .create_table(
            Table::create()
                .table(SomeTable::Table)
                .col(schema::custom(
                    Alias::new("some_column"),
                    Alias::new("special_type"), // This works.
                ))
                .to_owned(),
        )
        .await?;
}

Alternatively, the method schema::custom() can be expanded. When doing so, care must be taken to include the implied constraint not_null() to get the same behaviour:

fn migrate(manager: &SchemaManager) {
    manager
        .create_table(
            Table::create()
                .table(SomeTable::Table)
                .col(
                    ColumnDef::new(SomeTable::SomeColumn)
                        .custom(CustomType::SpecialType)
                        .not_null(),
                )
                .to_owned(),
        )
        .await?;
}

Versions