I'm new to Go and I'm trying to write a little program to save enumerated values to a database. The way I declare my values is as follows:
type FileType int64
const (
    movie FileType = iota
    music
    book
    etc
)
I use these values in my struct like this:
type File struct {
    Name     string
    Type     FileType
    Size     int64
}
I use gorp for my database stuff, but I guess the use of gorp isn't relevant to my problem. I put stuff in my DB like this:
dbmap.Insert(&File{"MyBook.pdf",movie,1000})
but when I try to retrieve stuff…
dbmap.Select(&dbFiles, "select * from Files")
I get the following error:
panic: reflect.Set: value of type int64 is not assignable to type main.FileType
When I use int64 as the type for the const(...) and for the File.Type field, everything works fine, but I'm new to Go and want to understand the problem.
The way I see it, I have two problems:
I figured out, that one can implement the sql.Scanner interface by implementing the following method:
Scan(src interface{}) error
I tried to implement the method and I even was able to get the right value from src and convert it to a FileType, but I was confused if I should implement the method for "(f *FileType) or (f FileType). Either way the method gets invoked, however I'm not able to overwrite f (or at least the update gets lost later) and the File instances read from the DB always had a "0" as value for File.Type.
Do you have any ideas on those two points?
By keeping the enum in your database, and adding a foreign key on the table that contains an enum value you ensure that no code ever enters incorrect values for that column. This helps your data integrity and is the most obvious reason IMO you should have tables for enums.
A standard enum is usually implemented as an int32, the compiler will handle your enum as a synonym of int32 . Once a list of values is created for a enumeration those values are stored as literals against their display name(access name given at the time of declaration of enum).
Implementation Details. Enumerated (enum) types are data types that comprise a static, ordered set of values. They are equivalent to the enum types supported in a number of programming languages. An example of an enum type might be the days of the week, or a set of status values for a piece of data.
The ENUM data type is stored in two locations: the set of values is stored in the table metadata; in each row, only the set index is stored, as integer, which requires one byte for enums up to 255 entries large, then two for up to 65535 entries (see MySQL reference)
I recently had the same need, and the solution is to implement two interfaces:
Here's a working example:
type FileType int64
func (u *FileType) Scan(value interface{}) error { *u = FileType(value.(int64)); return nil }
func (u FileType) Value() (driver.Value, error)  { return int64(u), nil }
                        Slightly off-topic, but may be useful to others as I kept revisiting this question/answer when solving a similar problem when working with postgres enum fields in golang (which are returned as bytes).
 // Status values
 const ( 
     incomplete Status = "incomplete"
     complete   Status = "complete" 
     reject     Status = "reject"
 )
 type Status string
 func (s *Status) Scan(value interface{}) error {
     asBytes, ok := value.([]byte)
     if !ok {
         return errors.New("Scan source is not []byte")
     }
     *s = Status(string(asBytes))
     return nil
 }
 func (s SubjectStatus) Value() (driver.Value, error) {
     // validation would go here
     return string(s), nil
 }
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With