Browse Source

conditions, orders

0x4a52466c696e74 4 months ago
parent
commit
72c0e647d5
4 changed files with 317 additions and 0 deletions
  1. 112 0
      conditions.go
  2. 135 0
      orders.go
  3. 32 0
      request.go
  4. 38 0
      z_test.go

+ 112 - 0
conditions.go

@@ -0,0 +1,112 @@
+package rest
+
+import (
+	"fmt"
+
+	"git.ali33.ru/fcg-xvii/go-tools/json"
+)
+
+func parseCondition(m json.Map, index int) (ICondition, error) {
+	errPrefix := func(errData string) error {
+		return fmt.Errorf("[%v]: %s", index, errData)
+	}
+	cond := _condition{
+		field:    m.String("field", ""),
+		logic:    _conditionLogic(m.String("logic", "")),
+		operator: _conditionOperator(m.String("operator", "")),
+		value:    m["value"],
+	}
+	if !cond.IsValid() {
+		if len(cond.field) == 0 {
+			return nil, errPrefix("empty field name")
+		} else if !cond.operator.IsValid() {
+			return nil, errPrefix(fmt.Sprintf("unexpected operator [%s]", cond.operator))
+		} else if !cond.operator.IsValid() {
+			return nil, errPrefix(fmt.Sprintf("unexpected logic [%s]", cond.logic))
+		} else {
+			return nil, errPrefix("unexpected error")
+		}
+	}
+	return &cond, nil
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+type ICondition interface {
+	Field() string
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+type _conditionOperator string
+
+const (
+	OperatorEqual     = "="
+	OperatorNotEqual  = "!="
+	OperatorMore      = ">"
+	OperatorLess      = "<"
+	OperatorMoreEqual = ">="
+	OperatorLessEqual = "<="
+	OperatorLike      = "like"
+)
+
+func (s _conditionOperator) IsValid() bool {
+	switch s {
+	case OperatorEqual:
+	case OperatorNotEqual:
+	case OperatorMore:
+	case OperatorLess:
+	case OperatorMoreEqual:
+	case OperatorLessEqual:
+	case OperatorLike:
+	default:
+		return false
+	}
+	return true
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+const (
+	LogicEmpty = ""
+	LogicOR    = "or"
+	LogicAND   = "and"
+)
+
+type _conditionLogic string
+
+func (s _conditionLogic) IsValid() bool {
+	switch s {
+	case LogicEmpty:
+	case LogicOR:
+	case LogicAND:
+	default:
+		return false
+	}
+	return true
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+type _condition struct {
+	field    string
+	logic    _conditionLogic
+	operator _conditionOperator
+	value    any
+}
+
+func (s *_condition) Field() string {
+	return s.field
+}
+
+func (s *_condition) Logic() _conditionLogic {
+	return s.logic
+}
+
+func (s *_condition) Operator() _conditionOperator {
+	return s.operator
+}
+
+func (s *_condition) IsValid() bool {
+	return len(s.field) > 0 && s.logic.IsValid() && s.operator.IsValid()
+}

+ 135 - 0
orders.go

@@ -0,0 +1,135 @@
+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
+}

+ 32 - 0
request.go

@@ -75,6 +75,38 @@ func (s *Request) Fields(obj any, files RequestFiles) (json.Map, IErrorArgs) {
 	return Fields(obj, files, s.Data.Slice("fields", nil)...)
 }
 
+func (s *Request) ParseOffset() int {
+	return s.Data.Int32("offset", 0)
+}
+
+func (s *Request) ParseLimit() int {
+	return s.Data.Int32("limit", 20)
+}
+
+func (s *Request) ParseOrder() (IOrderObject, IErrorArgs) {
+	res, err := parseOrder(
+		s.Data.Map("order", json.Map{}),
+		"",
+	)
+	if err != nil {
+		return nil, ErrorFiled("order", err.Error())
+	}
+	return res, nil
+}
+
+func (s *Request) ParseConditions() (res []ICondition, rErr IErrorArgs) {
+	s.Data.EachMap("conditions", func(index int, m json.Map) bool {
+		cond, err := parseCondition(m, index)
+		if err != nil {
+			rErr = ErrorFiled("conditions", err.Error())
+			return false
+		}
+		res = append(res, cond)
+		return true
+	})
+	return
+}
+
 ////////////////////////////////////////////////////////////
 
 type IRequestIn interface {

+ 38 - 0
z_test.go

@@ -250,3 +250,41 @@ func TestSerialize(t *testing.T) {
 func TestServer(t *testing.T) {
 
 }
+
+func TestOrder(t *testing.T) {
+	order := json.Map{
+		"one": true,
+		"two": false,
+		"three": json.Map{
+			"c_one": true,
+			"c_two": false,
+		},
+	}
+
+	obj, err := parseOrder(order, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log("obj ============================")
+	t.Log(obj)
+	t.Log("fields ============================")
+	t.Log(obj.MapFields())
+	t.Log("objects ============================")
+	t.Log(obj.MapObjects())
+	t.Log("order ============================")
+	t.Log(obj.MapOrder())
+}
+
+func TestConditions(t *testing.T) {
+	src := json.Map{
+		"field":    "id",
+		"operator": "=",
+		"logic":    "and",
+		"value":    1,
+	}
+	cond, err := parseCondition(src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(cond)
+}