Once upon a time, a Postgres user who loves their enums encountered this error while trying to compile a freshly-generated Diesel schema.rs:

error[E0412]: cannot find type `User_role` in this scope
  --> src/schema.rs:27:17
   |
27 |         role -> User_role,
   |                 ^^^^^^^^^ not found in this scope

Some googling landed me on this issue, revealing that Postgres enums are unsupported and that I should roll a custom SQL types instead--a boilerplatey but reasonable way to map custom database types to Rust types.

Even better, there's already a neat diesel-derive-enum crate that nicely generates the impls for you. All you need is to #[derive(DbEnum)] and you're all set. How to use this crate with Diesel autogenerated migrations was not too obvious from its READMEs and examples though.

Theres two key information to get this to work:

  1. Diesel-cli's import_types field
  2. Diesel-derive-enum's renaming capabilites

Given that we have this nice little enum in sql_types.rs:

// In sql_types.rs
#[derive(DbEnum)]
 pub enum UserRole {
     Admin,
     Employee,
 }

And we add the import_types field in diesel.toml:

# In diesel.toml

[print_schema]
file = "src/schema.rs"
import_types = ["diesel::sql_types::*", "crate::sql_types::*"]

...Diesel will then generate use statements for every table you're defining with the table! macro. Run diesel migration run (it doesn't recognize the changes unless you run it, for me) and now Diesel can recognize our enums!

......or not?

error[E0412]: cannot find type `User_role` in this scope
  --> src/schema.rs:36:17
   |
36 |         role -> User_role,
   |                 ^^^^^^^^^ not found in this scope

So, it turns out that for type my_enum in Postgres, diesel-derive-enums will generate the Diesel type MyEnumMapping. Meanwhile, Diesel's autogenerated schema.rs will name it My_enum, so the names obviously don't match!

Diesel-derive-enums provides handy attributes to rename the generated type, both on the Diesel and Postgres side with #[DieselType = "Renamed_Enum"] and #[PgType = "Another_Renamed_Enum"], respectively. We don't need a rename on the postgres side now, so lets slap the Diesel rename on.

Additionally, Diesel seems to wants the struct to derive from Debug + PartialEq in order for it to work with print schema, so let's also add that.

Which gives us this working, neatly-decorated enum:

// In sql_types.rs

#[derive(Debug, PartialEq, DbEnum)]
#[DieselType = "User_role"]
 pub enum UserRole {
     Admin,
     Employee,
 }

Yay!

And so, our application runs happily ever after. The end.


I started this series documenting my Rust (mis)adventures--digging through git issues, layers of code, gitter channels, heap of test suites, etc--in hopes that it'll help someone out there.

Please shoot me a DM/email if you notice any mistakes, or would like to throw in additional tips!