package rest import ( "fmt" "reflect" "git.ali33.ru/fcg-xvii/go-tools/json" ) type OrderType byte func parseOrder(order json.Map, parent string) (IOrderObject, error) { parentName := func(name string) string { if len(parent) > 0 { return fmt.Sprintf("%s.%s", parent, name) } return name } obj := &_orderObject{ orders: make(map[string]IOrder), } for k, v := range order { rv := reflect.ValueOf(v) switch rv.Kind() { case reflect.Bool: obj.orders[k] = &_orderField{ fieldName: k, isAsc: v.(bool), } case reflect.Map: t := reflect.TypeOf(order) if rv.CanConvert(t) { childRV := rv.Convert(t) child, err := parseOrder(childRV.Interface().(json.Map), parentName(k)) if err != nil { return nil, err } obj.orders[k] = child } default: return nil, fmt.Errorf("unexpected type in [%v]", parentName(k)) } } return obj, nil } const ( OrderField OrderType = iota OrderObject ) //////////////////////////////////////////// type IOrder interface { Type() OrderType } type IOrderField interface { IOrder FieldName() string IsAsc() bool } type IOrderObject interface { IOrder MapOrder() map[string]IOrder MapFields() map[string]IOrderField MapObjects() map[string]IOrderObject } //////////////////////////////////////////// type _orderField struct { fieldName string isAsc bool } func (s *_orderField) FieldName() string { return s.fieldName } func (s *_orderField) IsAsc() bool { return s.isAsc } func (s *_orderField) Type() OrderType { return OrderField } func (s *_orderField) String() string { return fmt.Sprintf("%v: %v\n", s.fieldName, s.isAsc) } //////////////////////////////////////////// type _orderObject struct { orders map[string]IOrder } func (s *_orderObject) Type() OrderType { return OrderObject } func (s *_orderObject) MapOrder() map[string]IOrder { return s.orders } func (s *_orderObject) MapFields() map[string]IOrderField { res := make(map[string]IOrderField) for k, v := range s.orders { if v.Type() == OrderField { res[k] = v.(IOrderField) } } return res } func (s *_orderObject) MapObjects() map[string]IOrderObject { res := make(map[string]IOrderObject) for k, v := range s.orders { if v.Type() == OrderObject { res[k] = v.(IOrderObject) } } return res } func (s *_orderObject) String() string { res := "{\n" for k, v := range s.orders { res += fmt.Sprintf("\t%s: %v", k, v) } res += "}\n" return res }