mirror of
https://github.com/ent/ent.git
synced 2026-03-05 19:35:23 +03:00
schema/field: allow non-string ValueScanner types for enum fields (#1577)
* Make non-string ValueScanner types work with enum fields This change fixes #1575 which now makes it possible to specify a GoType for an enum that is not a string alias. It requires that if the specified type is not a string alias, the type must satisfy the Stringer interface. * remove default, rename field * wip * remove comment * go generate * make optional * generate 🤦 * handle NULL case * turns out mysql stores strings as []uint8
This commit is contained in:
@@ -808,6 +808,12 @@ type EnumValues interface {
|
||||
func (b *enumBuilder) GoType(ev EnumValues) *enumBuilder {
|
||||
b.Values(ev.Values()...)
|
||||
b.desc.goType(ev, stringType)
|
||||
// If an error already exists, let that be returned instead.
|
||||
// Otherwise check that the underlying type is either a string
|
||||
// or implements Stringer.
|
||||
if b.desc.Err == nil && b.desc.Info.RType.rtype.Kind() != reflect.String && !b.desc.Info.Stringer() {
|
||||
b.desc.Err = errors.New("enum values which implement ValueScanner must also implement Stringer")
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ package field_test
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -470,6 +471,45 @@ func (Role) Values() []string {
|
||||
return []string{"admin", "owner"}
|
||||
}
|
||||
|
||||
type RoleInt int32
|
||||
|
||||
func (RoleInt) Values() []string {
|
||||
return []string{"unknown", "admin", "owner"}
|
||||
}
|
||||
|
||||
func (i RoleInt) String() string {
|
||||
switch i {
|
||||
case 1:
|
||||
return "admin"
|
||||
case 2:
|
||||
return "owner"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func (i RoleInt) Value() (driver.Value, error) {
|
||||
return i.String(), nil
|
||||
}
|
||||
|
||||
func (i *RoleInt) Scan(val interface{}) error {
|
||||
switch v := val.(type) {
|
||||
case string:
|
||||
switch v {
|
||||
case "admin":
|
||||
*i = 1
|
||||
case "owner":
|
||||
*i = 2
|
||||
default:
|
||||
*i = 0
|
||||
}
|
||||
default:
|
||||
return errors.New("bad enum value")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestField_Enums(t *testing.T) {
|
||||
fd := field.Enum("role").
|
||||
Values(
|
||||
@@ -505,6 +545,18 @@ func TestField_Enums(t *testing.T) {
|
||||
assert.False(t, fd.Info.ValueScanner())
|
||||
assert.Equal(t, "admin", fd.Enums[0].V)
|
||||
assert.Equal(t, "owner", fd.Enums[1].V)
|
||||
assert.False(t, fd.Info.Stringer())
|
||||
|
||||
fd = field.Enum("role").GoType(RoleInt(0)).Descriptor()
|
||||
assert.Equal(t, "field_test.RoleInt", fd.Info.Ident)
|
||||
assert.Equal(t, "entgo.io/ent/schema/field_test", fd.Info.PkgPath)
|
||||
assert.Equal(t, "field_test.RoleInt", fd.Info.String())
|
||||
assert.False(t, fd.Info.Nillable)
|
||||
assert.True(t, fd.Info.ValueScanner())
|
||||
assert.Equal(t, "unknown", fd.Enums[0].V)
|
||||
assert.Equal(t, "admin", fd.Enums[1].V)
|
||||
assert.Equal(t, "owner", fd.Enums[2].V)
|
||||
assert.True(t, fd.Info.Stringer())
|
||||
}
|
||||
|
||||
func TestField_UUID(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user