5

I am writing PostgreSQL table schema.

type TestTable struct {
    ID        int    `gorm:"column:id;primaryKey;autoIncrement"`
    CarType   string `gorm:"column:car_type"`
}

So how can i add car types like "SEDAN", "HATCHBACK", "MINIVAN" as enum data type

deepika azad
  • 111
  • 1
  • 6
  • 1
    Reffer to this github issue answer as manual - https://github.com/go-gorm/gorm/issues/1978#issuecomment-476673540 – Oleg Butuzov Aug 03 '21 at 14:02

3 Answers3

11

Assuming you are using GORM. First in your database create a type.

CREATE TYPE car_type AS ENUM (
    'SEDAN',
    'HATCHBACK',
    'MINIVAN');

Then you will need to define the following model:

type carType string

const (
    SEDAN  carType = "SEDAN"
    HATCHBACK carType = "HATCHBACK"
    MINIVAN carType = "MINIVAN"
)

func (ct *carType) Scan(value interface{}) error {
    *ct = carType(value.([]byte))
    return nil
}

func (ct carType) Value() (driver.Value, error) {
    return string(ct), nil
}

type MyTable struct {
    gorm.Model
    CarType carType `sql:"car_type"`
}

func (MyTable) TableName() string {
    return "my_table"
}
Nick
  • 597
  • 5
  • 9
  • Thanks, Nick for the response, but is there no support for Enum datatype? how we do for other data types like numeric etc. In this, I need to write the raw query to create an enum type in DB first. – deepika azad Aug 04 '21 at 09:47
  • You are right. There is no datatype given in the language as `enum` but we can represent it. Follow the first 3 responses to the following question, it will help you understanding `enums` in golang . https://stackoverflow.com/questions/14426366/what-is-an-idiomatic-way-of-representing-enums-in-go On the other part, I think you can try without creating `enum` in the database. But still without it being `enum` in the database, you will be risking parsing non-constant values in the database to the constants in your program. I think it's unsafe. – Nick Aug 04 '21 at 10:24
  • 1
    I followed the same steps and also referred it from the main github issue on which this answer is based, But for me the line => CarType carType `sql:"car_type"` is just creating a text(string) column in postgres DB, I already have created the enum in my DB. I tried everything, no error is thrown, don't know whats the problem. Anyone having the same issue or resolution please reply. – Mehta Dec 28 '21 at 06:46
  • @Mehta We made it work by using `gorm:"type:car_type"` – Roman Droppa Mar 30 '22 at 08:54
  • How would you make this (enum) work for a "Has Many" or "Many to Many" association? – BARJ Apr 04 '22 at 13:30
1

on a side note- if you decide to go with slightly different approach: you can define your enums as int, and leverage iota. then you can use code generator to create sql Scaner/Valuer but also json/text representations. for example: https://github.com/dmarkham/enumer

mihwyz
  • 21
  • 1
  • 2
1

in order to extend Nick's answer I am adding the following for automation:

Assuming you have DBClient struct, you can create a method that creates this car type:

func (psqlClient *DBClient) CreateCarTypeEnum() error {
    result := psqlClient.db.Exec("SELECT 1 FROM pg_type WHERE typname = 'car_type';")

    switch {
    case result.RowsAffected == 0:
        if err := psqlClient.db.Exec("CREATE TYPE car_type AS ENUM ('SEDAN', 'HATCHBACK', 'MINIVAN');").Error; err != nil {
            log.Error().Err(err).Msg("Error creating car_type ENUM")
            return err
        }

        return nil
    case result.Error != nil:
        return result.Error

    default:
        return nil
    }
}
Sabuhi Shukurov
  • 1,250
  • 14
  • 15