formatter.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package crud
  2. import (
  3. "context"
  4. "database/sql"
  5. "fmt"
  6. "git.nspix.com/golang/rest/orm/schema"
  7. "gorm.io/gorm"
  8. "reflect"
  9. "strconv"
  10. "sync"
  11. "time"
  12. )
  13. var (
  14. DefaultFormat = NewFormatter()
  15. )
  16. type HandleFunc func(ctx context.Context, value interface{}, model interface{}, scm *schema.Schema) interface{}
  17. type Formatter struct {
  18. ctx context.Context
  19. locker sync.RWMutex
  20. formats map[string]HandleFunc
  21. }
  22. func stringFormat(ctx context.Context, value interface{}, model interface{}, scm *schema.Schema) interface{} {
  23. return fmt.Sprint(value)
  24. }
  25. func integerFormat(ctx context.Context, value interface{}, model interface{}, scm *schema.Schema) interface{} {
  26. var (
  27. n int
  28. )
  29. switch value.(type) {
  30. case float32, float64:
  31. n = int(reflect.ValueOf(value).Float())
  32. case int, int8, int16, int32, int64:
  33. n = int(reflect.ValueOf(value).Int())
  34. case uint, uint8, uint16, uint32, uint64:
  35. n = int(reflect.ValueOf(value).Uint())
  36. case string:
  37. n, _ = strconv.Atoi(reflect.ValueOf(value).String())
  38. case []byte:
  39. n, _ = strconv.Atoi(string(reflect.ValueOf(value).Bytes()))
  40. }
  41. return n
  42. }
  43. func decimalFormat(ctx context.Context, value interface{}, model interface{}, scm *schema.Schema) interface{} {
  44. var (
  45. n float64
  46. )
  47. switch value.(type) {
  48. case float32, float64:
  49. n = float64(reflect.ValueOf(value).Float())
  50. case int, int8, int16, int32, int64:
  51. n = float64(reflect.ValueOf(value).Int())
  52. case uint, uint8, uint16, uint32, uint64:
  53. n = float64(reflect.ValueOf(value).Uint())
  54. case string:
  55. n, _ = strconv.ParseFloat(reflect.ValueOf(value).String(), 64)
  56. case []byte:
  57. n, _ = strconv.ParseFloat(string(reflect.ValueOf(value).Bytes()), 64)
  58. }
  59. return n
  60. }
  61. func dateFormat(ctx context.Context, value interface{}, model interface{}, scm *schema.Schema) interface{} {
  62. if t, ok := value.(time.Time); ok {
  63. return t.Format("2006-01-02")
  64. }
  65. if t, ok := value.(*sql.NullTime); ok {
  66. if t != nil && t.Valid {
  67. return t.Time.Format("2006-01-02")
  68. }
  69. }
  70. return ""
  71. }
  72. func timeFormat(ctx context.Context, value interface{}, model interface{}, scm *schema.Schema) interface{} {
  73. if t, ok := value.(time.Time); ok {
  74. return t.Format("15:04:05")
  75. }
  76. if t, ok := value.(*sql.NullTime); ok {
  77. if t != nil && t.Valid {
  78. return t.Time.Format("15:04:05")
  79. }
  80. }
  81. return ""
  82. }
  83. func datetimeFormat(ctx context.Context, value interface{}, model interface{}, scm *schema.Schema) interface{} {
  84. if t, ok := value.(time.Time); ok {
  85. return t.Format("2006-01-02 15:04:05")
  86. }
  87. if t, ok := value.(*sql.NullTime); ok {
  88. if t != nil && t.Valid {
  89. return t.Time.Format("2006-01-02 15:04:05")
  90. }
  91. }
  92. return ""
  93. }
  94. func durationFormat(ctx context.Context, value interface{}, model interface{}, scm *schema.Schema) interface{} {
  95. var (
  96. hour int
  97. min int
  98. sec int
  99. )
  100. n := integerFormat(ctx, value, model, scm).(int)
  101. hour = n / 3600
  102. min = (n - hour*3600) / 60
  103. sec = n - hour*3600 - min*60
  104. return fmt.Sprintf("%02d:%02d:%02d", hour, min, sec)
  105. }
  106. func dropdownFormat(ctx context.Context, value interface{}, model interface{}, scm *schema.Schema) interface{} {
  107. opts := scm.GetOptions()
  108. if opts != nil && opts.Items != nil {
  109. for _, v := range opts.Items {
  110. if v.Key == value {
  111. return v.Val
  112. }
  113. }
  114. }
  115. return value
  116. }
  117. func (format *Formatter) Register(f string, fun HandleFunc) {
  118. format.locker.Lock()
  119. format.formats[f] = fun
  120. format.locker.Unlock()
  121. }
  122. func (format *Formatter) Format(ft string, value interface{}, model interface{}, scm *schema.Schema) interface{} {
  123. format.locker.RLock()
  124. f, ok := format.formats[ft]
  125. format.locker.RUnlock()
  126. if ok {
  127. return f(format.ctx, value, model, scm)
  128. }
  129. return value
  130. }
  131. func (format *Formatter) formatSchema(val interface{}, schemas []*schema.Schema, stmt *gorm.Statement) interface{} {
  132. values := make(map[string]interface{})
  133. refVal := reflect.Indirect(reflect.ValueOf(val))
  134. for _, field := range schemas {
  135. f := stmt.Schema.LookUpField(field.Column)
  136. values[field.Column] = format.Format(field.Format, refVal.FieldByName(f.Name).Interface(), val, field)
  137. }
  138. return values
  139. }
  140. func (format *Formatter) formatSchemas(val interface{}, schemas []*schema.Schema, stmt *gorm.Statement) interface{} {
  141. reflectValue := reflect.Indirect(reflect.ValueOf(val))
  142. if reflectValue.Type().Kind() != reflect.Slice {
  143. return nil
  144. }
  145. length := reflectValue.Len()
  146. values := make([]interface{}, length)
  147. for i := 0; i < length; i++ {
  148. values[i] = format.formatSchema(reflectValue.Index(i).Interface(), schemas, stmt)
  149. }
  150. return values
  151. }
  152. func NewFormatter() *Formatter {
  153. f := &Formatter{
  154. ctx: context.Background(),
  155. formats: make(map[string]HandleFunc),
  156. }
  157. f.Register("string", stringFormat)
  158. f.Register("integer", integerFormat)
  159. f.Register("decimal", decimalFormat)
  160. f.Register("date", dateFormat)
  161. f.Register("time", timeFormat)
  162. f.Register("datetime", datetimeFormat)
  163. f.Register("duration", durationFormat)
  164. f.Register("dropdown", dropdownFormat)
  165. return f
  166. }