123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- package rest
- import (
- "context"
- "database/sql"
- "fmt"
- "gorm.io/gorm"
- "reflect"
- "strconv"
- "sync"
- "time"
- )
- var (
- DefaultFormatter = NewFormatter()
- DefaultNullDisplay = ""
- )
- func init() {
- DefaultFormatter.Register("string", stringFormat)
- DefaultFormatter.Register("integer", integerFormat)
- DefaultFormatter.Register("decimal", decimalFormat)
- DefaultFormatter.Register("date", dateFormat)
- DefaultFormatter.Register("time", timeFormat)
- DefaultFormatter.Register("datetime", datetimeFormat)
- DefaultFormatter.Register("duration", durationFormat)
- DefaultFormatter.Register("dropdown", dropdownFormat)
- DefaultFormatter.Register("timestamp", datetimeFormat)
- }
- type FormatFunc func(ctx context.Context, value interface{}, model interface{}, scm *Schema) interface{}
- type Formatter struct {
- callbacks sync.Map
- }
- func (formatter *Formatter) Register(f string, fun FormatFunc) {
- formatter.callbacks.Store(f, fun)
- }
- func (formatter *Formatter) Format(ctx context.Context, format string, value interface{}, model interface{}, scm *Schema) interface{} {
- v, ok := formatter.callbacks.Load(format)
- if ok {
- return v.(FormatFunc)(ctx, value, model, scm)
- }
- return value
- }
- func (formatter *Formatter) formatModel(ctx context.Context, val interface{}, schemas []*Schema, stmt *gorm.Statement) interface{} {
- values := make(map[string]interface{})
- refVal := reflect.Indirect(reflect.ValueOf(val))
- for _, field := range schemas {
- if stmt.Schema != nil {
- f := stmt.Schema.LookUpField(field.Column)
- values[field.Column] = formatter.Format(ctx, field.Format, refVal.FieldByName(f.Name).Interface(), val, field)
- } else {
- values[field.Column] = ""
- }
- }
- return values
- }
- func (formatter *Formatter) formatModels(ctx context.Context, val interface{}, schemas []*Schema, stmt *gorm.Statement) interface{} {
- reflectValue := reflect.Indirect(reflect.ValueOf(val))
- if reflectValue.Type().Kind() != reflect.Slice {
- return nil
- }
- length := reflectValue.Len()
- values := make([]interface{}, length)
- for i := 0; i < length; i++ {
- values[i] = formatter.formatModel(ctx, reflectValue.Index(i).Interface(), schemas, stmt)
- }
- return values
- }
- func stringFormat(ctx context.Context, value interface{}, model interface{}, scm *Schema) interface{} {
- return fmt.Sprint(value)
- }
- func integerFormat(ctx context.Context, value interface{}, model interface{}, scm *Schema) interface{} {
- var (
- n int
- )
- switch value.(type) {
- case float32, float64:
- n = int(reflect.ValueOf(value).Float())
- case int, int8, int16, int32, int64:
- n = int(reflect.ValueOf(value).Int())
- case uint, uint8, uint16, uint32, uint64:
- n = int(reflect.ValueOf(value).Uint())
- case string:
- n, _ = strconv.Atoi(reflect.ValueOf(value).String())
- case []byte:
- n, _ = strconv.Atoi(string(reflect.ValueOf(value).Bytes()))
- }
- return n
- }
- func decimalFormat(ctx context.Context, value interface{}, model interface{}, scm *Schema) interface{} {
- var (
- n float64
- )
- switch value.(type) {
- case float32, float64:
- n = float64(reflect.ValueOf(value).Float())
- case int, int8, int16, int32, int64:
- n = float64(reflect.ValueOf(value).Int())
- case uint, uint8, uint16, uint32, uint64:
- n = float64(reflect.ValueOf(value).Uint())
- case string:
- n, _ = strconv.ParseFloat(reflect.ValueOf(value).String(), 64)
- case []byte:
- n, _ = strconv.ParseFloat(string(reflect.ValueOf(value).Bytes()), 64)
- }
- return n
- }
- func dateFormat(ctx context.Context, value interface{}, model interface{}, scm *Schema) interface{} {
- if t, ok := value.(time.Time); ok {
- return t.Format("2006-01-02")
- }
- if t, ok := value.(*sql.NullTime); ok {
- if t != nil && t.Valid {
- return t.Time.Format("2006-01-02")
- }
- }
- if t, ok := value.(int64); ok {
- tm := time.Unix(t, 0)
- return tm.Format("2006-01-02")
- }
- return DefaultNullDisplay
- }
- func timeFormat(ctx context.Context, value interface{}, model interface{}, scm *Schema) interface{} {
- if t, ok := value.(time.Time); ok {
- return t.Format("15:04:05")
- }
- if t, ok := value.(*sql.NullTime); ok {
- if t != nil && t.Valid {
- return t.Time.Format("15:04:05")
- }
- }
- if t, ok := value.(int64); ok {
- tm := time.Unix(t, 0)
- return tm.Format("15:04:05")
- }
- return DefaultNullDisplay
- }
- func datetimeFormat(ctx context.Context, value interface{}, model interface{}, scm *Schema) interface{} {
- if t, ok := value.(time.Time); ok {
- return t.Format("2006-01-02 15:04:05")
- }
- if t, ok := value.(*sql.NullTime); ok {
- if t != nil && t.Valid {
- return t.Time.Format("2006-01-02 15:04:05")
- }
- }
- if t, ok := value.(int64); ok {
- if t > 0 {
- tm := time.Unix(t, 0)
- return tm.Format("2006-01-02 15:04:05")
- }
- }
- return DefaultNullDisplay
- }
- func durationFormat(ctx context.Context, value interface{}, model interface{}, scm *Schema) interface{} {
- var (
- hour int
- min int
- sec int
- )
- n := integerFormat(ctx, value, model, scm).(int)
- hour = n / 3600
- min = (n - hour*3600) / 60
- sec = n - hour*3600 - min*60
- return fmt.Sprintf("%02d:%02d:%02d", hour, min, sec)
- }
- func dropdownFormat(ctx context.Context, value interface{}, model interface{}, scm *Schema) interface{} {
- attributes := scm.Attribute
- if attributes.Values != nil {
- for _, v := range attributes.Values {
- if v.Value == value {
- return v.Label
- }
- }
- }
- return value
- }
- func NewFormatter() *Formatter {
- formatter := &Formatter{}
- return formatter
- }
|