package reflectutil import ( "reflect" "strings" ) // Deref dereferences pointers until it reaches a non-pointer value // Returns the dereferenced value and true if successful, or the original value and false if nil func Deref(v reflect.Value) (reflect.Value, bool) { for v.Kind() == reflect.Ptr { if v.IsNil() { return v, false } v = v.Elem() } return v, true } // DerefInterface dereferences an interface{} until it reaches a non-pointer value func DerefInterface(i interface{}) reflect.Value { v := reflect.ValueOf(i) v, _ = Deref(v) return v } // GetFieldValue extracts a field value from a struct, map, or pointer // Returns nil if the field doesn't exist or can't be accessed func GetFieldValue(item interface{}, field string) interface{} { v := reflect.ValueOf(item) v, ok := Deref(v) if !ok { return nil } switch v.Kind() { case reflect.Struct: fieldVal := v.FieldByName(field) if fieldVal.IsValid() { return fieldVal.Interface() } return nil case reflect.Map: keyVal := reflect.ValueOf(field) mapVal := v.MapIndex(keyVal) if mapVal.IsValid() { return mapVal.Interface() } return nil default: return nil } } // IsSliceOrArray checks if an interface{} is a slice or array func IsSliceOrArray(i interface{}) bool { v := reflect.ValueOf(i) v, ok := Deref(v) if !ok { return false } k := v.Kind() return k == reflect.Slice || k == reflect.Array } // IsMap checks if an interface{} is a map func IsMap(i interface{}) bool { v := reflect.ValueOf(i) v, ok := Deref(v) if !ok { return false } return v.Kind() == reflect.Map } // SliceLen returns the length of a slice/array, or 0 if not a slice/array func SliceLen(i interface{}) int { v := reflect.ValueOf(i) v, ok := Deref(v) if !ok { return 0 } if v.Kind() != reflect.Slice && v.Kind() != reflect.Array { return 0 } return v.Len() } // MapLen returns the length of a map, or 0 if not a map func MapLen(i interface{}) int { v := reflect.ValueOf(i) v, ok := Deref(v) if !ok { return 0 } if v.Kind() != reflect.Map { return 0 } return v.Len() } // SliceToInterfaces converts a slice/array to []interface{} // Returns empty slice if not a slice/array func SliceToInterfaces(i interface{}) []interface{} { v := reflect.ValueOf(i) v, ok := Deref(v) if !ok { return []interface{}{} } if v.Kind() != reflect.Slice && v.Kind() != reflect.Array { return []interface{}{} } result := make([]interface{}, v.Len()) for i := 0; i < v.Len(); i++ { result[i] = v.Index(i).Interface() } return result } // MapKeys returns all keys from a map as []interface{} // Returns empty slice if not a map func MapKeys(i interface{}) []interface{} { v := reflect.ValueOf(i) v, ok := Deref(v) if !ok { return []interface{}{} } if v.Kind() != reflect.Map { return []interface{}{} } keys := v.MapKeys() result := make([]interface{}, len(keys)) for i, key := range keys { result[i] = key.Interface() } return result } // MapValues returns all values from a map as []interface{} // Returns empty slice if not a map func MapValues(i interface{}) []interface{} { v := reflect.ValueOf(i) v, ok := Deref(v) if !ok { return []interface{}{} } if v.Kind() != reflect.Map { return []interface{}{} } result := make([]interface{}, 0, v.Len()) iter := v.MapRange() for iter.Next() { result = append(result, iter.Value().Interface()) } return result } // MapGet safely gets a value from a map by key // Returns nil if key doesn't exist or not a map func MapGet(m interface{}, key interface{}) interface{} { v := reflect.ValueOf(m) v, ok := Deref(v) if !ok { return nil } if v.Kind() != reflect.Map { return nil } keyVal := reflect.ValueOf(key) mapVal := v.MapIndex(keyVal) if mapVal.IsValid() { return mapVal.Interface() } return nil } // SliceIndex safely gets an element from a slice/array by index // Returns nil if index out of bounds or not a slice/array func SliceIndex(slice interface{}, index int) interface{} { v := reflect.ValueOf(slice) v, ok := Deref(v) if !ok { return nil } if v.Kind() != reflect.Slice && v.Kind() != reflect.Array { return nil } if index < 0 || index >= v.Len() { return nil } return v.Index(index).Interface() } // CompareValues compares two values for sorting // Returns -1 if a < b, 0 if a == b, 1 if a > b func CompareValues(a, b interface{}) int { if a == nil && b == nil { return 0 } if a == nil { return -1 } if b == nil { return 1 } va := reflect.ValueOf(a) vb := reflect.ValueOf(b) // Handle different types switch va.Kind() { case reflect.String: if vb.Kind() == reflect.String { as := va.String() bs := vb.String() if as < bs { return -1 } else if as > bs { return 1 } return 0 } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if vb.Kind() >= reflect.Int && vb.Kind() <= reflect.Int64 { ai := va.Int() bi := vb.Int() if ai < bi { return -1 } else if ai > bi { return 1 } return 0 } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if vb.Kind() >= reflect.Uint && vb.Kind() <= reflect.Uint64 { au := va.Uint() bu := vb.Uint() if au < bu { return -1 } else if au > bu { return 1 } return 0 } case reflect.Float32, reflect.Float64: if vb.Kind() == reflect.Float32 || vb.Kind() == reflect.Float64 { af := va.Float() bf := vb.Float() if af < bf { return -1 } else if af > bf { return 1 } return 0 } } return 0 } // GetNestedValue gets a nested value using dot notation path // Example: GetNestedValue(obj, "database.schema.table") func GetNestedValue(m interface{}, path string) interface{} { if path == "" { return m } parts := strings.Split(path, ".") current := m for _, part := range parts { if current == nil { return nil } v := reflect.ValueOf(current) v, ok := Deref(v) if !ok { return nil } switch v.Kind() { case reflect.Map: keyVal := reflect.ValueOf(part) mapVal := v.MapIndex(keyVal) if !mapVal.IsValid() { return nil } current = mapVal.Interface() case reflect.Struct: fieldVal := v.FieldByName(part) if !fieldVal.IsValid() { return nil } current = fieldVal.Interface() default: return nil } } return current } // DeepEqual performs a deep equality check between two values func DeepEqual(a, b interface{}) bool { return reflect.DeepEqual(a, b) }