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)) } } }