From 28ddaa685e3b17660351db8634cdb8da3654811a Mon Sep 17 00:00:00 2001 From: Yan Zhu Date: Tue, 8 Jun 2021 13:51:04 +0800 Subject: [PATCH] add enum support for modelgen Fix https://github.com/ovn-org/libovsdb/issues/133 --- modelgen/table.go | 83 ++++++++++++++++++++++++++++++-- modelgen/table_test.go | 105 ++++++++++++++++++++++++++++++----------- 2 files changed, 156 insertions(+), 32 deletions(-) diff --git a/modelgen/table.go b/modelgen/table.go index 679d0234..e245910b 100644 --- a/modelgen/table.go +++ b/modelgen/table.go @@ -22,6 +22,23 @@ const BASE_TABLE_TEMPLATE = `{{ template "header" . }} package {{ index . "PackageName" }} +{{ if index . "Enums" }} +type ( +{{ range index . "Enums" }} +{{ .Alias }} = {{ .Type }} +{{- end }} +) + +const ( +{{ range index . "Enums" }} +{{- $e := . }} +{{- range .Sets }} +{{ $e.Alias }}{{ camelCase . }} {{ $e.Alias }} = {{ printVal . $e.Type }} +{{- end }} +{{- end }} +) +{{ end }} + {{ template "preStructDefinitions" }} {{ template "structComment" . }} type {{ index . "StructName" }} struct { @@ -53,6 +70,13 @@ const DEFAULT_EXTRA_FIELDS_TEMPLATE = `{{ define "extraFields" }}{{ end }}` // DEFAULT_POST_TABLE_TEMPLATE is the default template for "postStructDefinitions" const DEFAULT_POST_TABLE_TEMPLATE = `{{ define "postStructDefinitions" }}{{ end }}` +// Enum represents the enum schema type +type Enum struct { + Type string + Alias string + Sets []interface{} +} + // Field represents the field information type Field struct { Column string @@ -72,6 +96,7 @@ func GetTableTemplateData(pkg, name string, table *ovsdb.TableSchema) map[string data["PackageName"] = pkg data["StructName"] = StructName(name) Fields := []Field{} + Enums := []Enum{} // First, add UUID Fields = append(Fields, @@ -95,18 +120,26 @@ func GetTableTemplateData(pkg, name string, table *ovsdb.TableSchema) map[string Fields = append(Fields, Field{ Column: columnName, Name: FieldName(columnName), - Type: FieldType(columnSchema), + Type: FieldType(name, columnName, columnSchema), Tag: Tag(columnName), }) + if enum := FieldEnum(name, columnName, columnSchema); enum != nil { + Enums = append(Enums, *enum) + } } data["Fields"] = Fields + data["Enums"] = Enums return data } // NewTableTemplate returns a new TableTemplate and the TableTemplate data map // See BASE_TABLE_TEMPLATE to a detailed explanation of the possible ways this template can be expanded func NewTableTemplate(pkg string, name string, table *ovsdb.TableSchema) (*template.Template, map[string]interface{}) { - main, err := template.New(name).Parse(BASE_TABLE_TEMPLATE) + funcMap := template.FuncMap{ + "printVal": printVal, + "camelCase": camelCase, + } + main, err := template.New(name).Funcs(funcMap).Parse(BASE_TABLE_TEMPLATE) if err != nil { panic(err) } @@ -144,24 +177,44 @@ func FieldName(column string) string { // StructName returns the name of the table struct func StructName(tableName string) string { - return strings.ReplaceAll(tableName, "_", "") + return strings.Title(strings.ReplaceAll(tableName, "_", "")) +} + +// EnumName returns the name of the enum field +func EnumName(tableName, columnName string) string { + return strings.Title(StructName(tableName)) + camelCase(columnName) } // FieldType returns the string representation of a column type -func FieldType(column *ovsdb.ColumnSchema) string { +func FieldType(tableName, columnName string, column *ovsdb.ColumnSchema) string { switch column.Type { case ovsdb.TypeEnum: - return AtomicType(column.TypeObj.Key.Type) + return EnumName(tableName, columnName) case ovsdb.TypeMap: return fmt.Sprintf("map[%s]%s", AtomicType(column.TypeObj.Key.Type), AtomicType(column.TypeObj.Value.Type)) case ovsdb.TypeSet: + if FieldEnum(tableName, columnName, column) != nil { + return fmt.Sprintf("[]%s", EnumName(tableName, columnName)) + } return fmt.Sprintf("[]%s", AtomicType(column.TypeObj.Key.Type)) default: return AtomicType(column.Type) } } +// FieldEnum returns the Enum if the column is an enum type +func FieldEnum(tableName, columnName string, column *ovsdb.ColumnSchema) *Enum { + if column.TypeObj.Key.Enum == nil { + return nil + } + return &Enum{ + Type: column.TypeObj.Key.Type, + Alias: EnumName(tableName, columnName), + Sets: column.TypeObj.Key.Enum, + } +} + // BasicType returns the string type of an AtomicType func AtomicType(atype string) string { switch atype { @@ -211,9 +264,15 @@ var initialisms = map[string]bool{ "SSL": true, "STP": true, "TCP": true, + "SCTP": true, "UDP": true, "UUID": true, "VLAN": true, + "STT": true, + "DNAT": true, + "SNAT": true, + "ICMP": true, + "SLB": true, } func camelCase(field string) string { @@ -246,3 +305,17 @@ func expandInitilaisms(s string) string { } return s } + +func printVal(v interface{}, t string) string { + switch t { + case "int": + return fmt.Sprintf(`%d`, v) + case "float64": + return fmt.Sprintf(`%f`, v) + case "bool": + return fmt.Sprintf(`%t`, v) + case "string": + return fmt.Sprintf(`"%s"`, v) + } + return "" +} diff --git a/modelgen/table_test.go b/modelgen/table_test.go index c82f2454..1b129094 100644 --- a/modelgen/table_test.go +++ b/modelgen/table_test.go @@ -26,7 +26,13 @@ func TestNewTableTemplate(t *testing.T) { }, "float": { "type": "real" - } + }, + "protocol": { + "type": {"key": {"type": "string", + "enum": ["set", ["tcp", "udp", "sctp"]]}, + "min": 0, "max": 1}}, + "event_type": {"type": {"key": {"type": "string", + "enum": ["set", ["empty_lb_backends"]]}}} } } } @@ -46,12 +52,26 @@ func TestNewTableTemplate(t *testing.T) { package test -// test defines an object in test table -type test struct { - UUID string ` + "`" + `ovs:"_uuid"` + "`" + ` - Float float64 ` + "`" + `ovs:"float"` + "`" + ` - Int int ` + "`" + `ovs:"int"` + "`" + ` - Str string ` + "`" + `ovs:"str"` + "`" + ` +type ( + AtomicTableEventType = string + AtomicTableProtocol = string +) + +const ( + AtomicTableEventTypeEmptyLbBackends AtomicTableEventType = "empty_lb_backends" + AtomicTableProtocolTCP AtomicTableProtocol = "tcp" + AtomicTableProtocolUDP AtomicTableProtocol = "udp" + AtomicTableProtocolSCTP AtomicTableProtocol = "sctp" +) + +// AtomicTable defines an object in atomicTable table +type AtomicTable struct { + UUID string ` + "`" + `ovs:"_uuid"` + "`" + ` + EventType AtomicTableEventType ` + "`" + `ovs:"event_type"` + "`" + ` + Float float64 ` + "`" + `ovs:"float"` + "`" + ` + Int int ` + "`" + `ovs:"int"` + "`" + ` + Protocol []AtomicTableProtocol ` + "`" + `ovs:"protocol"` + "`" + ` + Str string ` + "`" + `ovs:"str"` + "`" + ` } `, }, @@ -70,17 +90,33 @@ type test struct { package test -// test defines an object in test table -type test struct { - UUID string ` + "`" + `ovs:"_uuid"` + "`" + ` - Float float64 ` + "`" + `ovs:"float"` + "`" + ` - Int int ` + "`" + `ovs:"int"` + "`" + ` - Str string ` + "`" + `ovs:"str"` + "`" + ` - - OtherUUID string - OtherFloat float64 - OtherInt int - OtherStr string +type ( + AtomicTableEventType = string + AtomicTableProtocol = string +) + +const ( + AtomicTableEventTypeEmptyLbBackends AtomicTableEventType = "empty_lb_backends" + AtomicTableProtocolTCP AtomicTableProtocol = "tcp" + AtomicTableProtocolUDP AtomicTableProtocol = "udp" + AtomicTableProtocolSCTP AtomicTableProtocol = "sctp" +) + +// AtomicTable defines an object in atomicTable table +type AtomicTable struct { + UUID string ` + "`" + `ovs:"_uuid"` + "`" + ` + EventType AtomicTableEventType ` + "`" + `ovs:"event_type"` + "`" + ` + Float float64 ` + "`" + `ovs:"float"` + "`" + ` + Int int ` + "`" + `ovs:"int"` + "`" + ` + Protocol []AtomicTableProtocol ` + "`" + `ovs:"protocol"` + "`" + ` + Str string ` + "`" + `ovs:"str"` + "`" + ` + + OtherUUID string + OtherEventType AtomicTableEventType + OtherFloat float64 + OtherInt int + OtherProtocol []AtomicTableProtocol + OtherStr string } `, }, @@ -103,16 +139,30 @@ func {{ index . "TestName" }} () string { package test -// test defines an object in test table -type test struct { - UUID string ` + "`" + `ovs:"_uuid"` + "`" + ` - Float float64 ` + "`" + `ovs:"float"` + "`" + ` - Int int ` + "`" + `ovs:"int"` + "`" + ` - Str string ` + "`" + `ovs:"str"` + "`" + ` +type ( + AtomicTableEventType = string + AtomicTableProtocol = string +) + +const ( + AtomicTableEventTypeEmptyLbBackends AtomicTableEventType = "empty_lb_backends" + AtomicTableProtocolTCP AtomicTableProtocol = "tcp" + AtomicTableProtocolUDP AtomicTableProtocol = "udp" + AtomicTableProtocolSCTP AtomicTableProtocol = "sctp" +) + +// AtomicTable defines an object in atomicTable table +type AtomicTable struct { + UUID string ` + "`" + `ovs:"_uuid"` + "`" + ` + EventType AtomicTableEventType ` + "`" + `ovs:"event_type"` + "`" + ` + Float float64 ` + "`" + `ovs:"float"` + "`" + ` + Int int ` + "`" + `ovs:"int"` + "`" + ` + Protocol []AtomicTableProtocol ` + "`" + `ovs:"protocol"` + "`" + ` + Str string ` + "`" + `ovs:"str"` + "`" + ` } func TestFunc() string { - return "test" + return "AtomicTable" } `, }, @@ -140,10 +190,11 @@ WRONG FORMAT for _, tt := range test { t.Run(fmt.Sprintf("Table Test: %s", tt.name), func(t *testing.T) { - table := schema.Tables["atomicTable"] + fakeTable := "atomicTable" + table := schema.Tables[fakeTable] templ, data := NewTableTemplate( "test", - "test", + fakeTable, &table, ) if tt.err {