SeaQL / sea-orm

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

Generated Rust enum ordering does not match underlying database enum ordering #2285

Open foxfriends opened 1 month ago

foxfriends commented 1 month ago

Description

At least for Postgres (I have no experience with other databases) enums are ordered by definition order, but sea-orm-cli generate generates enums in alphabetical order. This is particularly problematic when I add --enum-extra-derives 'Ord,PartialOrd' --enum-extra-attributes 'repr(u32)' and now the rust-level comparison operator is not the same as the db-level comparison, and neither is the underlying u32 repr the same. This is also annoying if trying to use ActiveEnum::iter() but the ordering is not the meaningful order defined in the enum, but the alphabetical order of the Rust enum.

Steps to Reproduce

  1. Define an enum e.g. for months of the year
CREATE TYPE month AS ENUM (
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
);
  1. Generate the enum using

sea-orm-cli generate entity -o ./entity --with-serde both --enum-extra-derives 'Copy,Ord,PartialOrd' --enum-extra-attributes 'repr(u32)'

#[derive(
    Debug,
    Clone,
    PartialEq,
    Eq,
    EnumIter,
    DeriveActiveEnum,
    Serialize,
    Deserialize,
    Copy,
    Ord,
    PartialOrd,
)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "month")]
#[repr(u32)]
pub enum Month {
    #[sea_orm(string_value = "April")]
    April,
    #[sea_orm(string_value = "August")]
    August,
    #[sea_orm(string_value = "December")]
    December,
    #[sea_orm(string_value = "February")]
    February,
    #[sea_orm(string_value = "January")]
    January,
    #[sea_orm(string_value = "July")]
    July,
    #[sea_orm(string_value = "June")]
    June,
    #[sea_orm(string_value = "March")]
    March,
    #[sea_orm(string_value = "May")]
    May,
    #[sea_orm(string_value = "November")]
    November,
    #[sea_orm(string_value = "October")]
    October,
    #[sea_orm(string_value = "September")]
    September,
}

Expected Behavior

The Rust enum should match the order of the Postgres enum.

Actual Behavior

The Rust enum is in alphabetical order.

Reproduces How Often

Always

Workarounds

Manually implement the enum separately.

Versions

β”œβ”€β”€ sea-orm v0.12.15
β”‚   β”œβ”€β”€ sea-orm-macros v0.12.15 (proc-macro)
β”‚   β”‚   β”œβ”€β”€ sea-bae v0.2.0 (proc-macro)
β”‚   β”œβ”€β”€ sea-query v0.30.7
β”‚   β”‚   β”œβ”€β”€ sea-query-derive v0.4.1 (proc-macro)
β”‚   β”œβ”€β”€ sea-query-binder v0.5.0
β”‚   β”‚   β”œβ”€β”€ sea-query v0.30.7 (*)
β”œβ”€β”€ sea-query v0.30.7 (*)

Using postgres:latest in Docker on Mac.

Expurple commented 1 month ago

The Rust enum should match the order of the Postgres enum.

Actually, enum ordering differs across databases. See #2132. For SQLite, SeaORM emulates enums as strings and SQLite compares them alphabetically. So, the current Rust behavior is consistent with SQLite. I'm not sure which default makes more sense. This should probably be configurable.