123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- package glom
- import (
- "fmt"
- "reflect"
- "strconv"
- "strings"
- "github.com/fatih/structs"
- )
- func mapToInterface(data interface{}) (map[string]interface{}, error) {
- mapV := reflect.ValueOf(data)
- if mapV.Kind() != reflect.Map {
- return nil, fmt.Errorf("Failed to convert %v, given %v type to map[string]interface{}", mapV, reflect.TypeOf(data))
- }
- if mapV.IsNil() || !mapV.IsValid() {
- return nil, fmt.Errorf("Given nil or empty map!")
- }
- result := make(map[string]interface{})
- keys := mapV.MapKeys()
- for k := range keys {
-
- result[keys[k].String()] = mapV.MapIndex(keys[k]).Interface()
- }
- return result, nil
- }
- func sliceToInterface(data interface{}) ([]interface{}, error) {
- sliceV := reflect.ValueOf(data)
- if sliceV.Kind() == reflect.Slice {
- switch data.(type) {
- case []interface{}:
- return data.([]interface{}), nil
- }
- }
- if sliceV.Kind() != reflect.Slice && sliceV.Kind() != reflect.Array {
- return nil, fmt.Errorf("Failed to convert %v, given %v type to []interface{}", sliceV, reflect.TypeOf(data))
- }
- if sliceV.IsNil() || !sliceV.IsValid() {
- return nil, fmt.Errorf("Given nil or empty slice!")
- }
- length := sliceV.Len()
- result := make([]interface{}, length)
- for i := 0; i < length; i++ {
-
- result[i] = sliceV.Index(i).Interface()
- }
- return result, nil
- }
- func GetPossible(data interface{}) []string {
- var result []string
-
-
- switch reflect.TypeOf(data).Kind() {
- case reflect.Map:
- mapV := reflect.ValueOf(data)
- keysV := mapV.MapKeys()
- for key := range keysV {
- result = append(result, keysV[key].String())
- }
- case reflect.Array, reflect.Slice:
- sliceV := reflect.ValueOf(data)
- for idx := 0; idx < sliceV.Len(); idx++ {
- result = append(result, fmt.Sprintf("%d", idx))
- }
- case reflect.Struct:
- result = structs.Names(data)
- }
- return result
- }
- func inside(possible []string, target string) bool {
- for _, val := range possible {
- if target == val {
- return true
- }
- }
- return false
- }
- func next_level(current_level interface{}, go_to string) (interface{}, error) {
- if inside(GetPossible(current_level), go_to) {
-
- switch reflect.TypeOf(current_level).Kind() {
- case reflect.Map:
- CL, err := mapToInterface(current_level)
- if err != nil {
- return nil, err
- }
- return CL[go_to], nil
- case reflect.Array, reflect.Slice:
- val, err := strconv.Atoi(go_to)
- if err == nil {
- CL, err := sliceToInterface(current_level)
- if err != nil {
- return nil, err
- }
- return CL[val], nil
- } else {
- return nil, err
- }
- case reflect.Struct:
- structV := reflect.ValueOf(current_level)
- return structV.FieldByName(go_to).Interface(), nil
- }
- }
- return nil, fmt.Errorf("Failed moving to '%s' from '%s' (%v)", go_to, current_level, reflect.TypeOf(current_level))
- }
- func list_possible(possible []string) []string {
- var result []string
- for _, val := range possible {
- result = append(result, fmt.Sprintf("'%s'", val))
- }
- return result
- }
- func Glom(data interface{}, path string) (interface{}, error) {
- complete_path := strings.Split(path, ".")
-
- var path_taken []string
- var currently interface{}
- currently = data
- for _, hop := range complete_path {
-
-
- if hop != "*" && !inside(GetPossible(currently), hop) {
- return nil, fmt.Errorf("Failed moving to '%s' from path of '%s', options are %s (%d)", hop, strings.Join(path_taken, "."), strings.Join(list_possible(GetPossible(currently)), ", "), len(GetPossible(currently)))
- } else {
- if hop != "*" {
- next, err := next_level(currently, hop)
- if err != nil {
-
- return nil, err
- } else {
- path_taken = append(path_taken, hop)
- currently = next
- }
- } else {
- return currently, nil
- }
- }
- }
- return currently, nil
- }
|