Skip to content

Instantly share code, notes, and snippets.

@locona
Created January 7, 2019 03:27
Show Gist options
  • Save locona/648eaeacf13ec2e75b734ed7df14c26f to your computer and use it in GitHub Desktop.
Save locona/648eaeacf13ec2e75b734ed7df14c26f to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"reflect"
"strconv"
"strings"
"github.com/k0kubun/pp"
)
type InputTransferAWSRedshift struct {
Database string `json:"database" valid:"required" args:"database"`
Schema string `json:"schema" valid:"required" args:"schema"`
Query string `json:"query" valid:"required" args:"query"`
Args []string `json:"args" valid:"required" args:"args"`
Connection *Connection
}
type Connection struct {
AccessKeyID string `args:"access_key_id"`
}
func main() {
// marshal()
unmarshal()
}
func marshal() {
input := InputTransferAWSRedshift{
Database: "databasee",
Schema: "databasee",
Query: "SELECT * FROM hogehogeho",
Args: []string{"A", "B", "C", "D"},
Connection: &Connection{
AccessKeyID: "accesskeyid",
},
}
data := Marshal(input)
pp.Println(data)
}
func unmarshal() {
data := []string{"--database=database", "--schema=schema", "--query=0", "--args=1,2,3", "--access_key_id=eowfejojfeoifjwo"}
input := &InputTransferAWSRedshift{}
Unmarshal(data, input)
pp.Println("RESULT: ", input)
}
func Marshal(v interface{}) []string {
rv := reflect.ValueOf(v)
for rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface {
rv = rv.Elem()
}
args := make([]string, 0)
argsFormat := "--%v=%v"
for i := 0; i < rv.NumField(); i++ {
switch rv.Field(i).Kind() {
case reflect.Ptr:
args = append(args, Marshal(rv.Field(i).Interface())...)
case reflect.Struct:
args = append(args, Marshal(rv.Field(i).Interface())...)
case reflect.Slice:
args = append(args, fmt.Sprintf(argsFormat, rv.Type().Field(i).Tag.Get("args"), strings.Join(rv.Field(i).Interface().([]string), ",")))
default:
args = append(args, fmt.Sprintf(argsFormat, rv.Type().Field(i).Tag.Get("args"), rv.Field(i).Interface()))
}
}
return args
}
func Unmarshal(data []string, v interface{}) {
m := make(map[string]interface{})
for idx := range data {
k, v := parse(data[idx])
m[k] = v
}
rv := reflect.ValueOf(v)
for rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface {
rv = rv.Elem()
}
for i := 0; i < rv.NumField(); i++ {
tag := rv.Type().Field(i).Tag.Get("args")
tagValue := m[tag]
switch rv.Field(i).Kind() {
case reflect.Ptr:
rf := reflect.New(rv.Field(i).Type().Elem()).Interface()
Unmarshal(data, rf)
rv.Field(i).Set(reflect.ValueOf(rf))
case reflect.Slice:
arr := strings.Split(tagValue.(string), ",")
rv.Field(i).Set(reflect.ValueOf(arr))
case reflect.Struct:
rf := reflect.New(rv.Field(i).Type()).Interface()
Unmarshal(data, rf)
rr := reflect.Indirect(reflect.ValueOf(rf))
rv.Field(i).Set(rr)
case reflect.String:
rv.Field(i).SetString(tagValue.(string))
case reflect.Int, reflect.Int8, reflect.Int32, reflect.Int64:
v, err := strconv.ParseInt(tagValue.(string), 10, 64)
if err != nil {
panic(err)
}
rv.Field(i).SetInt(v)
default:
pp.Println("DEFALUT", rv.Field(i).Kind(), tag, tagValue)
}
}
}
func parse(s string) (string, string) {
if isLong(s) {
arr := strings.Split(s, "=")
return strings.TrimPrefix(arr[0], "--"), arr[1]
}
if isShort(s) {
arr := strings.Split(s, "=")
return strings.TrimPrefix(arr[0], "-"), arr[1]
}
return "", ""
}
func isLong(s string) bool {
return strings.HasPrefix(s, "--")
}
func isShort(s string) bool {
return strings.HasPrefix(s, "-")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment