synapsecns/sanguine

View on GitHub
core/dbcommon/enum.go

Summary

Maintainability
A
0 mins
Test Coverage
package dbcommon

import (
    "database/sql"
    "database/sql/driver"
    "fmt"
    "github.com/rung/go-safecast"
    "reflect"
)

// EnumInter ensures an enum has a type to access an integer.
type EnumInter interface {
    Int() uint8
}

// Enum is a type used to define interfaces db enums must conform to.
// it is kept here so it can be used throughout the app.
type Enum interface {
    EnumInter
    fmt.Stringer
    GormDataType() string
    sql.Scanner
    driver.Valuer
}

// EnumDataType is exported here to be passed as GormDataType.
// TODO: support string types.
const EnumDataType = "integer"

// EnumValue converts the enum to a value.
func EnumValue(enum EnumInter) (driver.Value, error) {
    converter := driver.NotNull{Converter: driver.DefaultParameterConverter}
    rawValue := enum.Int()
    val, err := converter.ConvertValue(rawValue)
    if err != nil {
        return nil, fmt.Errorf("could not convert rawValue %d of type %T: %w", rawValue, rawValue, err)
    }
    return val, nil
}

// EnumScan converts the enum to a value.
// the returned uint 8 should be used. Note this should only be used for a non-nullable enum.
// TODO: consider using generics to make this more type safe.
func EnumScan(src interface{}) (uint8, error) {
    res := sql.NullInt32{}
    err := res.Scan(src)
    if err != nil {
        return 0, fmt.Errorf("could not scan enum: %w", err)
    }
    if res.Int32 < 0 {
        return 0, fmt.Errorf("enum value cannot be a negative number, got: %w", err)
    }
    cast, err := safecast.Int8(int(res.Int32))
    if err != nil {
        return 0, fmt.Errorf("could not cast %d (type %s) to %s: %w", res.Int32, reflect.TypeOf(res.Int32), reflect.TypeOf(cast), err)
    }
    return uint8(cast), nil
}