-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Stronger Types for Enums and Improve Set Encoding #151
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,12 +38,28 @@ func (i *Info) SetField(column string, value interface{}) error { | |
return fmt.Errorf("column %s not found in orm info", column) | ||
} | ||
fieldValue := reflect.ValueOf(i.obj).Elem().FieldByName(fieldName) | ||
|
||
v := reflect.ValueOf(value) | ||
if !fieldValue.Type().AssignableTo(reflect.TypeOf(value)) { | ||
return fmt.Errorf("column %s: native value %v (%s) is not assignable to field %s (%s)", | ||
column, value, reflect.TypeOf(value), fieldName, fieldValue.Type()) | ||
if v.Type().ConvertibleTo(fieldValue.Type()) { | ||
// handle enum | ||
v = v.Convert(fieldValue.Type()) | ||
} else if fieldValue.Kind() == reflect.Slice { | ||
// handle set of enums | ||
if !v.Type().Elem().ConvertibleTo(fieldValue.Type().Elem()) { | ||
return fmt.Errorf("column %s: element %v (%s) is not convertible to field %s element (%s)", | ||
column, value, reflect.TypeOf(value), fieldName, fieldValue.Type()) | ||
} | ||
nv := reflect.Zero(fieldValue.Type()) | ||
for i := 0; i < v.Len(); i++ { | ||
nv = reflect.Append(nv, v.Index(i).Convert(fieldValue.Type().Elem())) | ||
} | ||
v = nv | ||
} else { | ||
return fmt.Errorf("column %s: native value %v (%s) is not assignable or convertible to field %s (%s)", | ||
column, value, reflect.TypeOf(value), fieldName, fieldValue.Type()) | ||
} | ||
} | ||
fieldValue.Set(reflect.ValueOf(value)) | ||
fieldValue.Set(v) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a shame that we have to split the conversion of a type between Ovs2Native and this function. |
||
return nil | ||
} | ||
|
||
|
@@ -133,7 +149,12 @@ func NewInfo(table *ovsdb.TableSchema, obj interface{}) (*Info, error) { | |
|
||
// Perform schema-based type checking | ||
expType := ovsdb.NativeType(column) | ||
if expType != field.Type { | ||
// check for slice of enums | ||
if expType.Kind() == reflect.Slice && expType.Elem().Kind() == reflect.String { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should distinguish between slice of strings and slice of enums. We should check the ColumnSchema here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternatively, do we want to allow all kind of type aliases? e.g:
|
||
// it's a slice of enums | ||
} else if expType.Kind() == reflect.String && field.Type.Kind() == reflect.String { | ||
// it' an enum | ||
} else if expType != field.Type { | ||
return nil, &ErrMapper{ | ||
objType: objType.String(), | ||
field: field.Name, | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -182,11 +182,28 @@ func NativeToOvsAtomic(basicType string, nativeElem interface{}) (interface{}, e | |
// NativeToOvs transforms an native type to a ovs type based on the column type information | ||
func NativeToOvs(column *ColumnSchema, rawElem interface{}) (interface{}, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In order to keep things more or less tidy and symetric, how about moving this logic to mapper.info? bindings.NativeToOvs & bindings.OvsToNative: Convert from/to OVS types to a neutral, common, generic, native type that can hold the column info.SetField & info.FieldByPtr & info.FieldByColumn : May perform an extra conversion step to adjust the neutral, common, generic native type to whatever type the Field actually has WDYT? |
||
naType := NativeType(column) | ||
|
||
if t := reflect.TypeOf(rawElem); t != naType { | ||
rawElemType := reflect.TypeOf(rawElem) | ||
if column.Type == TypeEnum && rawElemType != strType && rawElemType.Kind() == reflect.String { | ||
// cast type alias back to string | ||
rawElem = rawElem.(string) | ||
rawElemType = reflect.TypeOf(rawElem) | ||
} | ||
if column.Type == TypeSet && len(column.TypeObj.Key.Enum) > 0 && rawElemType.Elem() != strType && rawElemType.Elem().Kind() == reflect.String { | ||
// convert a set of enums where the type is an alias, to a set of strings | ||
tmp := []string{} | ||
v := reflect.ValueOf(rawElem) | ||
for i := 0; i < v.Len(); i++ { | ||
// convert value to string first, because the String method won't panic | ||
// but will instead return a string of <T value> which isn't what we want | ||
vi := v.Index(i).Convert(strType) | ||
tmp = append(tmp, vi.String()) | ||
} | ||
rawElem = tmp | ||
rawElemType = reflect.TypeOf(rawElem) | ||
} | ||
if t := rawElemType; t != naType { | ||
return nil, NewErrWrongType("NativeToOvs", naType.String(), rawElem) | ||
} | ||
|
||
switch column.Type { | ||
case TypeInteger, TypeReal, TypeString, TypeBoolean, TypeEnum: | ||
return rawElem, nil | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would explicitly check the tableSchema to make sure it's a Enum