Ok cool, realizing, following on from earlier post, that to nicely test the case when I have a Merchant
and I am only making updates to it with UpdateMerchantRequest
, I would need a nice generic way to obtain a subset struct instance from the other. Getting ChatGPT to help, here is what I asked,
Okay I have a strategy I’m using, where I have a go struct for a merchant that mirrors a postgresql database table and also another struct for updates to it which is a subset,
import "time"
struct Merchant {
Id int
Name string
CreatedAt time.Time()
UpdatedAt time.Time()
}
struct UpdateMerchant {
Id int
Name string
}
I want to be able to easily take an instance of Merchant and convert it into UpdateMerchant. But this is not an isolated example so I don’t want to create a one-off function to do this manually.
I might have similarly,
Customer
andUpdateCustomer
, etc. theUpdate
struct always contains a subset of fields.
Is there a canonical way to handle this in Go, taking an instance of the super struct and creating the subset struct ?
And got back the idea of using reflection
Just the code from the response. Works out of the box.
package main
import (
"fmt"
"reflect"
"time"
)
type Merchant struct {
Id int
Name string
CreatedAt time.Time
UpdatedAt time.Time
}
type UpdateMerchant struct {
Id int
Name string
}
// CopyCommonFields copies fields from src to dst struct where fields are common.
// Both src and dst must be pointers to structs.
func CopyCommonFields(src, dst any) {
srcVal := reflect.ValueOf(src).Elem()
dstVal := reflect.ValueOf(dst).Elem()
for i := 0; i < dstVal.NumField(); i++ {
dstField := dstVal.Field(i)
srcField := srcVal.FieldByName(dstVal.Type().Field(i).Name)
if srcField.IsValid() && srcField.Type() == dstField.Type() {
dstField.Set(srcField)
}
}
}
func main() {
merchant := Merchant{
Id: 1,
Name: "Example Merchant",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
updateMerchant := UpdateMerchant{}
CopyCommonFields(&merchant, &updateMerchant)
fmt.Printf("Original Merchant: %+v\n", merchant)
fmt.Printf("Update Merchant: %+v\n", updateMerchant)
}