0x4a52466c696e74 1 سال پیش
والد
کامیت
d9c13c97d0
4فایلهای تغییر یافته به همراه99 افزوده شده و 6 حذف شده
  1. 30 6
      fielder.go
  2. 13 0
      serialize.go
  3. 30 0
      time.go
  4. 26 0
      z_test.go

+ 30 - 6
fielder.go

@@ -8,6 +8,10 @@ import (
 	"git.ali33.ru/fcg-xvii/go-tools/json"
 )
 
+type IRestFielder interface {
+	RestFields(fieldName string, names ...any) (any, IErrorArgs)
+}
+
 // Field реализует ...
 type Field struct {
 	Name  string
@@ -29,8 +33,8 @@ func (s FieldList) Field(name string) (*Field, bool) {
 // RestFields будет вызван после завершения автматического формирования полей объекта
 // result - массив с полями, сформированными автоматически, в него можно вносить правки
 // files - глобальный массив файловых дескрипторов, который будет передан в ответе клиенту
-type IFielder interface {
-	RestFields(result json.Map, files map[string]IReadCloserLen, names FieldList)
+type IFielderPost interface {
+	RestFieldsPost(result json.Map, files map[string]IReadCloserLen, names FieldList)
 }
 
 func fieldsDefault(t reflect.Type) (res []any) {
@@ -81,6 +85,25 @@ func fieldVal(val reflect.Value, fieldName string, files RequestFiles, names ...
 	case reflect.Ptr, reflect.Interface:
 		return fieldVal(val.Elem(), fieldName, files, names...)
 	case reflect.Struct:
+		// check fielder interface
+		if f, check := val.Interface().(IRestFielder); check {
+			rVal, err := f.RestFields(fieldName, names...)
+			if err != nil {
+				return reflect.Value{}, err
+			}
+			return reflect.ValueOf(rVal), nil
+		}
+		// check fieler addr
+		if val.CanAddr() {
+			if f, check := val.Addr().Interface().(IRestFielder); check {
+				rVal, err := f.RestFields(fieldName, names...)
+				if err != nil {
+					return reflect.Value{}, err
+				}
+				return reflect.ValueOf(rVal), nil
+			}
+		}
+		// parse struct public fields
 		if len(names) == 0 {
 			names = fieldsDefault(val.Type())
 		}
@@ -122,11 +145,12 @@ func fieldVal(val reflect.Value, fieldName string, files RequestFiles, names ...
 			}
 			jm[rField.Name] = fVal.Interface()
 		}
-		if fielder, check := val.Interface().(IFielder); check {
-			fielder.RestFields(jm, files, fields)
+		// post (когда результирующий объект уже сформирован)
+		if fielder, check := val.Interface().(IFielderPost); check {
+			fielder.RestFieldsPost(jm, files, fields)
 		} else if val.CanAddr() {
-			if fielder, check := val.Addr().Interface().(IFielder); check {
-				fielder.RestFields(jm, files, fields)
+			if fielder, check := val.Addr().Interface().(IFielderPost); check {
+				fielder.RestFieldsPost(jm, files, fields)
 			}
 		}
 		res = reflect.ValueOf(jm)

+ 13 - 0
serialize.go

@@ -8,6 +8,10 @@ import (
 	"git.ali33.ru/fcg-xvii/go-tools/json"
 )
 
+type IRestConverter interface {
+	RestFrom(any) IErrorArgs
+}
+
 func parseVal(from, to reflect.Value, fieldName string) IErrorArgs {
 	if from.Kind() == reflect.Interface {
 		from = from.Elem()
@@ -50,6 +54,7 @@ func realValue(val reflect.Value) reflect.Value {
 		if val.IsNil() {
 			val.Set(reflect.New(val.Type().Elem()))
 		}
+		// check
 		val = val.Elem()
 		if val.Kind() == reflect.Ptr {
 			return realValue(val)
@@ -77,6 +82,14 @@ func parseSlice(from, to reflect.Value, fieldName string) IErrorArgs {
 }
 
 func parseStruct(from, to reflect.Value, fieldName string) IErrorArgs {
+	if f, check := to.Interface().(IRestConverter); check {
+		return f.RestFrom(from.Interface())
+	}
+	if to.CanAddr() {
+		if f, check := to.Addr().Interface().(IRestConverter); check {
+			return f.RestFrom(from.Interface())
+		}
+	}
 	for i := 0; i < to.NumField(); i++ {
 		required := false
 		// устанавливаем тип и указатель поля объекта, куда копируем

+ 30 - 0
time.go

@@ -0,0 +1,30 @@
+package rest
+
+import (
+	"fmt"
+	"reflect"
+	"time"
+)
+
+// Time используется для формирования объекта времени из формата UnixMilli, а так же выгрузки в этот формат в результирующем объекте
+type Time time.Time
+
+// RestFields выгружает объект в результирующий объект в формат UnixMilli
+func (s *Time) RestFields(fieldName string, names ...any) (any, IErrorArgs) {
+	if len(names) > 0 {
+		return nil, ErrorFiled(fmt.Sprintf("%v.%v", fieldName, names[0]), "field is not exists")
+	}
+	return time.Time(*s).UnixMilli(), nil
+}
+
+// RestFrom формирует из поля типа int64 объект времени
+func (s *Time) RestFrom(source any) (err IErrorArgs) {
+	defer func() {
+		if r := recover(); r != nil {
+			err = ErrorMessage("ErrParse", fmt.Sprintf("time: expected millisecond timestamp, given: %v", source))
+		}
+	}()
+	rVal := reflect.ValueOf(source)
+	*s = Time(time.UnixMilli(rVal.Int()))
+	return
+}

+ 26 - 0
z_test.go

@@ -4,6 +4,7 @@ import (
 	"log"
 	"reflect"
 	"testing"
+	"time"
 
 	"git.ali33.ru/fcg-xvii/go-tools/json"
 )
@@ -156,3 +157,28 @@ func TestFielderVal(t *testing.T) {
 	log.Println("========================================")
 	mVal.LogPretty()
 }
+
+type TimeObj struct {
+	Created Time `rest:"default"`
+}
+
+func TestTime(t *testing.T) {
+	obj := TimeObj{
+		Created: Time(time.Now()),
+	}
+	log.Println(obj)
+	f, _ := Fields(&obj, nil)
+	f.LogPretty()
+
+	var rObj TimeObj
+	if err := Serialize(f, &rObj); err != nil {
+		t.Fatal(err.Map().JSONPrettyString())
+	}
+	log.Println(rObj)
+	jm := json.Map{
+		"created": 1232131,
+	}
+	if err := Serialize(jm, &rObj); err != nil {
+		t.Fatal(err.Map().JSONPrettyString())
+	}
+}