// sf is the recursive function used to build the structure neeeded by SelectFields func sf(in interface{}, c echo.Context) (interface{}, error) { in = reflect.Indirect(reflect.ValueOf(in)).Interface() Type := reflect.TypeOf(in) switch Type.Kind() { case reflect.Struct: ret := make(map[string]interface{}) value := reflect.ValueOf(in) if fieldString := c.QueryParam("fields"); fieldString != "" { fields := strings.Split(fieldString, ",") for _, field := range fields { fieldName := utils.UpperFirst(field) if structField, ok := Type.FieldByName(fieldName); ok { jsonTag := structField.Tag.Get("json") if jsonTag != "-" && jsonTag != "" { ret[strings.Split(jsonTag, ",")[0]] = value.FieldByName(fieldName).Interface() } } else { // Else check if json field name is different from struct field name (with first letter in uppercase) // this is the user expected behaviour, but we prefer the above approach to speed up the process var found bool for i := 0; i < Type.NumField(); i++ { jsonTag := Type.Field(i).Tag.Get("json") if strings.Split(jsonTag, ",")[0] == field { ret[field] = value.Field(i).Interface() found = true break } } if !found { return nil, fmt.Errorf("Field %s does not exists", field) } } } } else { for i := 0; i < Type.NumField(); i++ { jsonTag := Type.Field(i).Tag.Get("json") if jsonTag != "-" && jsonTag != "" { ret[strings.Split(jsonTag, ",")[0]] = value.Field(i).Interface() } } } return &ret, nil case reflect.Slice: value := reflect.ValueOf(in) ret := make([]interface{}, value.Len()) for i := 0; i < value.Len(); i++ { if m, e := sf(value.Index(i).Elem().Interface(), c); e == nil { ret[i] = m } else { return nil, fmt.Errorf(`Error "%s" on field number %d`, e.Error(), i) } } return &ret, nil } return nil, errors.New("input parameter is not a struct or a slice of struct") }
func TestUpperFirst(t *testing.T) { if utils.UpperFirst("ciao") != "Ciao" { t.Errorf("UpperFirst does not work") } }