Files
commons/struct.go
George Suntres ebdf370c23 Initial import
2026-03-29 10:32:25 -04:00

135 lines
2.9 KiB
Go

package commons
import (
"log"
"reflect"
"strings"
// "encoding/json"
"go.mongodb.org/mongo-driver/v2/bson"
)
// MapToStruct will convert a map[string]any to a struct.
func MapToStruct(m map[string]any, o any) error {
b, err := bson.Marshal(m)
if err != nil {
log.Printf("Failed marshal %v", err)
return err
}
err = bson.Unmarshal(b, o)
if err != nil {
log.Printf("Failed to unmarshal %v", err)
return err
}
return nil
}
// MapIsSubset given two map[string]any m1 and m2 will determine if m1 is a subset of m2.
// Only fields' name is evaluated not their values.
func MapIsSubset(subset, superset any) bool {
sub := subset.(map[string]any)
sup := superset.(map[string]any)
isSubset := true
for k, _ := range sub {
_, ok := sup[k]
if !ok {
isSubset = false
}
}
return isSubset
}
// MapIsSubsetOfStruct given a map[string]any and a struct will determine if the map is a subset of the struct.
// Only fields' name is evaluated not their values.
func MapIsSubsetOfStruct(m map[string]any, s any) bool {
v := reflect.ValueOf(s)
if v.Kind() == reflect.Ptr {
v = v.Elem() // Dereference if it's a pointer
}
// Ensure we are working with a struct
if v.Kind() != reflect.Struct {
return false
}
isSubset := true
t := v.Type()
for key := range m {
// FieldByName only finds exported fields
if _, found := t.FieldByName(key); !found {
isSubset = false
break
}
}
return isSubset
}
// StructHasJsonName determines if a struct has the given json tag name.
func StructHasJsonName(s any, targetName string) bool {
t := reflect.TypeOf(s)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tag := field.Tag.Get("json")
// The name is the first part before any commas (e.g., "user_id,omitempty")
name := strings.Split(tag, ",")[0]
if name == targetName {
return true
}
}
return false
}
// StructHasJsonName determines if a struct has the given bson tag name.
func StructHasBsonName(s any, targetName string) bool {
t := reflect.TypeOf(s)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tag := field.Tag.Get("bson")
// The name is the first part before any commas (e.g., "user_id,omitempty")
name := strings.Split(tag, ",")[0]
if name == targetName {
return true
}
}
return false
}
// StructCopyMatching copies the fields of one struct to another only if they have the same name and type.
func StructCopyMatching(source, target any) {
sVal := reflect.ValueOf(source).Elem()
tVal := reflect.ValueOf(target).Elem()
for i := 0; i < sVal.NumField(); i++ {
sField := sVal.Type().Field(i)
tField, ok := tVal.Type().FieldByName(sField.Name)
if ok && sField.Type == tField.Type {
tVal.FieldByName(sField.Name).Set(sVal.Field(i))
}
}
}