I have a struct and now want to instantiate it from received http data. But now the code I write is cumbersome and has a lot of lines of code. Is there any way to simplify the code? All fields except the field id can correspond
model
type ALiNotifyLog struct {
ID *int `json:"id"`
APPId *string `json:"app_id"`
AuthAppId *string `json:"auth_app_id"`
BuyerId *string `json:"buyer_id"`
BuyerPayAmount *string `json:"buyer_pay_amount"`
GmtCreate *string `json:"gmt_create"`
GmtPayment *string `json:"gmt_payment"`
InvoiceAmount *string `json:"invoice_amount"`
NotifyId *string `json:"notify_id"`
NotifyTime *string `json:"notify_time"`
OutTradeNo *string `json:"out_trade_no"`
PointAmount *string `json:"point_amount"`
ReceiptAmount *string `json:"receipt_amount"`
Sign *string `json:"sign"`
TotalAmount *string `json:"total_amount"`
TradeNo *string `json:"trade_no"`
TradeStatus *string `json:"trade_status"`
}
func
func SaveData(data map[string]interface{}) {
app_id := data["app_id"].(string)
auth_app_id := data["auth_app_id"].(string)
buyer_id := data["buyer_id"].(string)
buyer_pay_amount := data["buyer_pay_amount"].(string)
gmt_create := data["gmt_create"].(string)
gmt_payment := data["gmt_payment"].(string)
invoice_amount := data["invoice_amount"].(string)
notify_id := data["notify_id"].(string)
notify_time := data["notify_time"].(string)
out_trade_no := data["out_trade_no"].(string)
point_amount := data["point_amount"].(string)
receipt_amount := data["receipt_amount"].(string)
sign := data["sign"].(string)
total_amount := data["total_amount"].(string)
trade_no := data["trade_no"].(string)
trade_status := data["trade_status"].(string)
model := payment.ALiNotifyLog{
APPId: &app_id,
AuthAppId: &auth_app_id,
BuyerId: &buyer_id,
BuyerPayAmount: &buyer_pay_amount,
GmtCreate: &gmt_create,
GmtPayment: &gmt_payment,
InvoiceAmount: &invoice_amount,
NotifyId: ¬ify_id,
NotifyTime: ¬ify_time,
OutTradeNo: &out_trade_no,
PointAmount: &point_amount,
ReceiptAmount: &receipt_amount,
Sign: &sign,
TotalAmount: &total_amount,
TradeNo: &trade_no,
TradeStatus: &trade_status}
res := global.Orm.Table(paynotifylog).Create(&model)
fmt.Println(res)
}
CodePudding user response:
I'd say converting the map to json then unmarshalling it would be the easiest way, not very efficient though.
https://go.dev/play/p/zxgupUCPpe2
func GhettoConvert[E any](in map[string]any) (out E) {
j, _ := json.Marshal(in) // should check the error
_ = json.Unmarshal(j, &out)
return
}
There was a library that used reflection to do that directly, but for the life of me I can't find it.
CodePudding user response:
I see that you are JSON. May be decode the JSON directly into a struct instance.
I will structure the code something like the below snippet:
type ALiNotifyLog struct {
// your fields here
}
func parseRequest(r *http.Request) {
var notifyLog ALiNotifyLog
err := json.NewDecoder(r.Body).Decode(¬ifyLog)
if err != nil {
// do something
}
// ............ more code
}
func SaveData(data ALiNotifyLog) {
res := global.Orm.Table(paynotifylog).Create(&data)
fmt.Println(res)
// ........... more code
}
CodePudding user response:
Use the reflect package to programmatically iterate over the fields:
func setStringpFields(pmodel any, data map[string]any) {
v := reflect.ValueOf(pmodel).Elem()
t := v.Type()
for i := 0; i < t.NumField(); i {
sf := t.Field(i)
if sf.Type != stringpType {
continue
}
name, _, _ := strings.Cut(sf.Tag.Get("json"), ",")
if s, ok := data[name].(string); ok {
v.Field(i).Set(reflect.ValueOf(&s))
}
}
}
var stringpType = reflect.PtrTo(reflect.TypeOf(""))
Use it like this:
var model ALiNotifyLog
setStringpFields(&model, data)
Run an example on the Go Playground.
I took the liberty of skipping fields that are missing from data
. The code in the question panics on a missing value.
A simpler approach is to create a function with the repeated functionality:
func stringp(data map[string]interface{}, name string) *string {
if s, ok := data[name].(string); ok {
return &s
}
return nil
}
Use that function to initialize the fields:
model := payment.ALiNotifyLog{
APPId: stringp("app_id"),
AuthAppId: stringp("auth_app_id"),
...
TradeStatus: stringp("trade_status")}
res := global.Orm.Table(paynotifylog).Create(&model)
fmt.Println(res)
CodePudding user response:
1: ScanMapToStruct
func scanMapToStruct(dest interface{}, vals map[string]interface{}) error {
srcValue := indirect(reflect.ValueOf(dest))
srcType := indirectType(reflect.TypeOf(dest))
for m := 0; m < srcType.NumField(); m {
field := srcType.Field(m)
fieldName, _ := getFieldName(field)
jsonTypeName := getJsonDataType(field.Type)
if jsonTypeName == "" {
continue
}
v, ok := vals[fieldName].(string)
if !ok {
continue
}
dec := decoders[field.Type.Kind()]
if dec == nil {
continue
}
err := dec(srcValue.Field(m), v)
if err != nil {
fmt.Printf("set field(%s)=%s err:%v\n", fieldName, v, err)
continue
}
}
return nil
}
2: copier.Copy()