utils.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package utils
  2. import (
  3. "database/sql/driver"
  4. "fmt"
  5. "path/filepath"
  6. "reflect"
  7. "runtime"
  8. "strconv"
  9. "strings"
  10. "unicode"
  11. )
  12. var gormSourceDir string
  13. func init() {
  14. _, file, _, _ := runtime.Caller(0)
  15. // compatible solution to get gorm source directory with various operating systems
  16. gormSourceDir = sourceDir(file)
  17. }
  18. func sourceDir(file string) string {
  19. dir := filepath.Dir(file)
  20. dir = filepath.Dir(dir)
  21. s := filepath.Dir(dir)
  22. if filepath.Base(s) != "gorm.io" {
  23. s = dir
  24. }
  25. return filepath.ToSlash(s) + "/"
  26. }
  27. // FileWithLineNum return the file name and line number of the current file
  28. func FileWithLineNum() string {
  29. pcs := [13]uintptr{}
  30. // the third caller usually from gorm internal
  31. len := runtime.Callers(3, pcs[:])
  32. frames := runtime.CallersFrames(pcs[:len])
  33. for i := 0; i < len; i++ {
  34. // second return value is "more", not "ok"
  35. frame, _ := frames.Next()
  36. if (!strings.HasPrefix(frame.File, gormSourceDir) ||
  37. strings.HasSuffix(frame.File, "_test.go")) && !strings.HasSuffix(frame.File, ".gen.go") {
  38. return string(strconv.AppendInt(append([]byte(frame.File), ':'), int64(frame.Line), 10))
  39. }
  40. }
  41. return ""
  42. }
  43. func IsValidDBNameChar(c rune) bool {
  44. return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '*' && c != '_' && c != '$' && c != '@'
  45. }
  46. // CheckTruth check string true or not
  47. func CheckTruth(vals ...string) bool {
  48. for _, val := range vals {
  49. if val != "" && !strings.EqualFold(val, "false") {
  50. return true
  51. }
  52. }
  53. return false
  54. }
  55. func ToStringKey(values ...interface{}) string {
  56. results := make([]string, len(values))
  57. for idx, value := range values {
  58. if valuer, ok := value.(driver.Valuer); ok {
  59. value, _ = valuer.Value()
  60. }
  61. switch v := value.(type) {
  62. case string:
  63. results[idx] = v
  64. case []byte:
  65. results[idx] = string(v)
  66. case uint:
  67. results[idx] = strconv.FormatUint(uint64(v), 10)
  68. default:
  69. results[idx] = "nil"
  70. vv := reflect.ValueOf(v)
  71. if vv.IsValid() && !vv.IsZero() {
  72. results[idx] = fmt.Sprint(reflect.Indirect(vv).Interface())
  73. }
  74. }
  75. }
  76. return strings.Join(results, "_")
  77. }
  78. func Contains(elems []string, elem string) bool {
  79. for _, e := range elems {
  80. if elem == e {
  81. return true
  82. }
  83. }
  84. return false
  85. }
  86. func AssertEqual(x, y interface{}) bool {
  87. if reflect.DeepEqual(x, y) {
  88. return true
  89. }
  90. if x == nil || y == nil {
  91. return false
  92. }
  93. xval := reflect.ValueOf(x)
  94. yval := reflect.ValueOf(y)
  95. if xval.Kind() == reflect.Ptr && xval.IsNil() ||
  96. yval.Kind() == reflect.Ptr && yval.IsNil() {
  97. return false
  98. }
  99. if valuer, ok := x.(driver.Valuer); ok {
  100. x, _ = valuer.Value()
  101. }
  102. if valuer, ok := y.(driver.Valuer); ok {
  103. y, _ = valuer.Value()
  104. }
  105. return reflect.DeepEqual(x, y)
  106. }
  107. func ToString(value interface{}) string {
  108. switch v := value.(type) {
  109. case string:
  110. return v
  111. case int:
  112. return strconv.FormatInt(int64(v), 10)
  113. case int8:
  114. return strconv.FormatInt(int64(v), 10)
  115. case int16:
  116. return strconv.FormatInt(int64(v), 10)
  117. case int32:
  118. return strconv.FormatInt(int64(v), 10)
  119. case int64:
  120. return strconv.FormatInt(v, 10)
  121. case uint:
  122. return strconv.FormatUint(uint64(v), 10)
  123. case uint8:
  124. return strconv.FormatUint(uint64(v), 10)
  125. case uint16:
  126. return strconv.FormatUint(uint64(v), 10)
  127. case uint32:
  128. return strconv.FormatUint(uint64(v), 10)
  129. case uint64:
  130. return strconv.FormatUint(v, 10)
  131. }
  132. return ""
  133. }
  134. const nestedRelationSplit = "__"
  135. // NestedRelationName nested relationships like `Manager__Company`
  136. func NestedRelationName(prefix, name string) string {
  137. return prefix + nestedRelationSplit + name
  138. }
  139. // SplitNestedRelationName Split nested relationships to `[]string{"Manager","Company"}`
  140. func SplitNestedRelationName(name string) []string {
  141. return strings.Split(name, nestedRelationSplit)
  142. }
  143. // JoinNestedRelationNames nested relationships like `Manager__Company`
  144. func JoinNestedRelationNames(relationNames []string) string {
  145. return strings.Join(relationNames, nestedRelationSplit)
  146. }
  147. // RTrimSlice Right trims the given slice by given length
  148. func RTrimSlice[T any](v []T, trimLen int) []T {
  149. if trimLen >= len(v) { // trimLen greater than slice len means fully sliced
  150. return v[:0]
  151. }
  152. if trimLen < 0 { // negative trimLen is ignored
  153. return v[:]
  154. }
  155. return v[:len(v)-trimLen]
  156. }