Skip to content

Commit

Permalink
feat: support for converting map, json or yaml to go struct
Browse files Browse the repository at this point in the history
  • Loading branch information
NICEXAI committed Sep 17, 2021
1 parent 87d8405 commit 9793f68
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.idea
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/NICEXAI/go2struct

go 1.17

require gopkg.in/yaml.v2 v2.4.0
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
14 changes: 14 additions & 0 deletions json2struct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package go2struct

import "encoding/json"

// JSON2Struct convert json to struct
func JSON2Struct(data []byte) (string, error) {
var m map[string]interface{}

if err := json.Unmarshal(data, &m); err != nil {
return "", err
}

return Map2Struct(m), nil
}
24 changes: 24 additions & 0 deletions json2struct_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package go2struct

import (
"testing"
)

func TestJSON2Struct(t *testing.T) {
temp := `
{
"code": 200,
"success": true,
"msg": {
"content": "Hello"
}
}
`

res, err := JSON2Struct([]byte(temp))
if err != nil {
t.Fatalf("json to struct failed, error: \n%v", err)
return
}
t.Logf("json to struct success, result: \n%s", res)
}
71 changes: 71 additions & 0 deletions map2struct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package go2struct

import (
"fmt"
"github.com/NICEXAI/go2struct/util"
"strings"
)

const (
structFirst = "type "
structLast = "}"
structStartTag = "%s struct {\n"
structEndTag = "%s} `json:\"%s\"`\n"
structSpace = " "
structFieldTag = "%s%s %s `json:\"%s\"`\n"
)

// Map2Struct convert map to struct
func Map2Struct(m map[string]interface{}) string {
cellNodes := convertMapToCellNode("message", m, 0)
return strings.Join(cellNodes, "")
}

func convertMapToCellNode(name string, m map[string]interface{}, tier int) (cn []string) {
if tier == 0 {
cn = append(cn, structFirst)
}
wrapperSpace := getSpaceByTier(tier - 1)
cn = append(cn, fmt.Sprintf(structStartTag, wrapperSpace+util.UnderscoreToUpperCamelCase(name)))

for field, val := range m {
fName := util.UnderscoreToUpperCamelCase(field)
fType := ""

switch val.(type) {
case float64:
if strings.Contains(fmt.Sprintf("%v", val), ".") {
fType = "float64"
} else {
fType = "int"
}
case bool:
fType = "bool"
case string:
fType = "string"
case map[string]interface{}:
fType = "struct"
}

if fType != "struct" {
cn = append(cn, fmt.Sprintf(structFieldTag, getSpaceByTier(tier), fName, fType, util.UpperCamelCaseToUnderscore(field)))
} else {
child := convertMapToCellNode(field, val.(map[string]interface{}), tier+1)
cn = append(cn, child...)
}
}

if tier == 0 {
cn = append(cn, structLast)
} else {
cn = append(cn, fmt.Sprintf(structEndTag, wrapperSpace, name))
}
return cn
}

func getSpaceByTier(tier int) (s string) {
for i := 0; i < tier+1; i++ {
s += structSpace
}
return s
}
31 changes: 31 additions & 0 deletions map2struct_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package go2struct

import (
"encoding/json"
"testing"
)

type Message struct {
Code int `json:"code"`
Success bool `json:"success"`
Msg struct {
Content string
} `json:"msg"`
}

func TestMap2Struct(t *testing.T) {
var options map[string]interface{}

message := Message{
Code: 200,
Msg: struct{ Content string }{Content: "Hello"},
}

bData, err := json.Marshal(message)
if err != nil {
t.Fatalf("json marshal failed, error: %v", err)
return
}
_ = json.Unmarshal(bData, &options)
t.Logf("map to struct success, result: \n%s", Map2Struct(options))
}
40 changes: 40 additions & 0 deletions util/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package util

import (
"strings"
"unicode"
)

// UnderscoreToUpperCamelCase word change from underscore to upperCamelCase
func UnderscoreToUpperCamelCase(n string) string {
var cList []string

for _, cell := range strings.Split(n, "_") {
cList = append(cList, strings.Title(cell))
}

return strings.Join(cList, "")
}

// UpperCamelCaseToUnderscore word change from upperCamelCase to underscore
func UpperCamelCaseToUnderscore(n string) string {
var (
cList []rune
isUpper bool
)

for i, cell := range n {
if unicode.IsUpper(cell) {
if i != 0 && !isUpper {
cList = append(cList, '_')
}
cList = append(cList, unicode.ToLower(cell))
isUpper = true
} else {
cList = append(cList, cell)
isUpper = false
}
}

return string(cList)
}
14 changes: 14 additions & 0 deletions yaml2struct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package go2struct

import "gopkg.in/yaml.v2"

// YAML2Struct convert yaml to struct
func YAML2Struct(data []byte) (string, error) {
var m map[string]interface{}

if err := yaml.Unmarshal(data, &m); err != nil {
return "", err
}

return Map2Struct(m), nil
}
19 changes: 19 additions & 0 deletions yaml2struct_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package go2struct

import "testing"

func TestYAML2Struct(t *testing.T) {
temp := `
code: 200
success: true
msg:
content: Hello
`

res, err := YAML2Struct([]byte(temp))
if err != nil {
t.Fatalf("yaml to struct failed, error: \n%v", err)
return
}
t.Logf("yaml to struct success, result: \n%s", res)
}

0 comments on commit 9793f68

Please sign in to comment.