MySQL's bit type maps to which Go type?

2020-04-13 07:21发布

问题:

I used Java before, so some columns' type in database table is bit(1). But now I want to use beego to rebuild my project and I don't want to alter my database table (need do much). I use beego's orm in my project. So which Go type should I use?

Table like this and the deleted column has the question:

+--------------+--------------+------+-----+---------+-------+
| Field        | Type         | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id           | varchar(255) | NO   | PRI | NULL    |       |
| created_time | datetime     | YES  |     | NULL    |       |
| deleted      | bit(1)       | NO   |     | NULL    |       |
| updated_time | datetime     | YES  |     | NULL    |       |
| icon_class   | varchar(255) | YES  |     | NULL    |       |
| mark         | varchar(255) | YES  |     | NULL    |       |
| name         | varchar(255) | YES  |     | NULL    |       |
| parent       | varchar(255) | YES  |     | NULL    |       |
+--------------+--------------+------+-----+---------+-------+

go struct like this:

type BaseModel struct {
    Id          string           `orm:"pk";form:"id"`
    CreatedTime time.Time        `orm:"auto_now_add;type(datetime)";form:"-"`
    UpdatedTime time.Time        `orm:"auto_now;type(datetime)";form:"-"`
    Deleted     bool `form:"-"`
}

When I use bool in my code, the error like this:

`[0]` convert to `*orm.BooleanField` failed, field: shareall-go/models.Category.BaseModel.Deleted err: strconv.ParseBool: parsing "\x00": invalid syntax

回答1:

Sqlx has created also a custom bool datatype for such situations and it works fine. Link to related code

// BitBool is an implementation of a bool for the MySQL type BIT(1).
// This type allows you to avoid wasting an entire byte for MySQL's boolean type TINYINT.
type BitBool bool

// Value implements the driver.Valuer interface,
// and turns the BitBool into a bitfield (BIT(1)) for MySQL storage.
func (b BitBool) Value() (driver.Value, error) {
    if b {
        return []byte{1}, nil
    } else {
        return []byte{0}, nil
    }
}

// Scan implements the sql.Scanner interface,
// and turns the bitfield incoming from MySQL into a BitBool
func (b *BitBool) Scan(src interface{}) error {
    v, ok := src.([]byte)
    if !ok {
        return errors.New("bad []byte type assertion")
    }
    *b = v[0] == 1
    return nil
}


回答2:

So which Go type should I use?

Generally, this depends on how you're using the data more than how it's stored. As you eluded to, you tried using it as a Bool (which makes sense) but got an error.

The problem is that MySQL expresses a BIT differently than a BOOL, and the Go MySQL driver expects a MySQL BOOL. You can fix this by using a custom type that implements the sql.Scanner interface. Since you presumably have only two (or maybe three, if you count NULL) inputs, it should be fairly easy. Note this code is incomplete and untested. It is meant to serve as a guide, not a copy-and-paste solution.

type MyBool bool

func (b *MyBool) Scan(src interface{}) error {
    str, ok := src.(string)
    if !ok {
        return fmt.Errorf("Unexpected type for MyBool: %T", src)
    }
    switch str {
    case "\x00":
        v := false
        *b = v
    case "\x01":
        v := true
        *b = v
    }
    return nil
}


标签: mysql go orm beego