Skip to content

Enumeration #252

@tyt2y3

Description

@tyt2y3

This issue is to outline the design of how to allow custom Enums to be used in SeaORM Entity.

It will be supported in 3 steps:

  • Rust enum support (but serialize to string or integer)
  • Mapping to a database native enum
  • Schema discovery & code generation

A proposed trait ActiveEnum (or DbEnum or OrmEnum etc) would be:

trait ActiveEnum {
    type Value: ValueType;

    fn to_value(&self) -> Self::Value;
    fn try_from_value(v: &Self::Value) -> Result<Self, DbErr>;
    fn db_type() -> ColumnDef;
}

A sample model would be like:

enum Category {
    Big,
    Small,
}

struct Model {
    category: Category;
}

impl ActiveEnum for Category {
    type Value = String;

    fn to_value(&self) -> Self::Value {
        match self {
            Big => "B",
            Small => "S",
        }.to_owned()
    }
    fn from_value(v: &Self::Value) -> Result<Self, DbErr> {
        match v.as_ref {
            "B" => Ok(Self::Big),
            "S" => Ok(Self::Small),
            _ => Err(DbErr::TypeErr(format!("unexpected value for Category: {}", v))),
        }
    }
    fn db_type() -> ColumnDef {
        ColumnType::String(Some(1)).def
    }
}

Such a trait should be all it takes for using a custom enum (we need to eliminate all boilerplate as in #196 (reply in thread)). And it will be converted automatically during Select, Insert and Update.

We can also make a DeriveActiveEnum macro to make it easier:

#[derive(DeriveActiveEnum)]
#[sea_orm(db_type = "String(Some(1))")]
enum Category {
    #[sea_orm(string_value = "B")]
    Big,
    #[sea_orm(string_value = "S")]
    Small,
}

(because of the excess String("B"), we'd better divide into string_value and num_value)

After some discussion with @acidic9, to support native enum in Postgres, we basically have to cast everywhere:

SELECT CAST("category" AS text) from "mytable";
INSERT INTO "mytable" ("category") VALUES (CAST($1 AS CategoryEnum));
UPDATE "mytable" SET "category" = CAST($1 AS CategoryEnum);

For MySQL, casting is not needed.

Ref: #196

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions