naming.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package schema
  2. import (
  3. "crypto/sha1"
  4. "fmt"
  5. "strings"
  6. "sync"
  7. "unicode/utf8"
  8. "github.com/jinzhu/inflection"
  9. )
  10. // Namer namer interface
  11. type Namer interface {
  12. TableName(table string) string
  13. ColumnName(table, column string) string
  14. JoinTableName(table string) string
  15. RelationshipFKName(Relationship) string
  16. CheckerName(table, column string) string
  17. IndexName(table, column string) string
  18. }
  19. // NamingStrategy tables, columns naming strategy
  20. type NamingStrategy struct {
  21. TablePrefix string
  22. SingularTable bool
  23. }
  24. // TableName convert string to table name
  25. func (ns NamingStrategy) TableName(str string) string {
  26. if ns.SingularTable {
  27. return ns.TablePrefix + toDBName(str)
  28. }
  29. return ns.TablePrefix + inflection.Plural(toDBName(str))
  30. }
  31. // ColumnName convert string to column name
  32. func (ns NamingStrategy) ColumnName(table, column string) string {
  33. return toDBName(column)
  34. }
  35. // JoinTableName convert string to join table name
  36. func (ns NamingStrategy) JoinTableName(str string) string {
  37. return ns.TablePrefix + inflection.Plural(toDBName(str))
  38. }
  39. // RelationshipFKName generate fk name for relation
  40. func (ns NamingStrategy) RelationshipFKName(rel Relationship) string {
  41. return fmt.Sprintf("fk_%s_%s", rel.Schema.Table, toDBName(rel.Field.Name))
  42. }
  43. // CheckerName generate checker name
  44. func (ns NamingStrategy) CheckerName(table, column string) string {
  45. return fmt.Sprintf("chk_%s_%s", table, column)
  46. }
  47. // IndexName generate index name
  48. func (ns NamingStrategy) IndexName(table, column string) string {
  49. idxName := fmt.Sprintf("idx_%v_%v", table, toDBName(column))
  50. if utf8.RuneCountInString(idxName) > 64 {
  51. h := sha1.New()
  52. h.Write([]byte(idxName))
  53. bs := h.Sum(nil)
  54. idxName = fmt.Sprintf("idx%v%v", table, column)[0:56] + string(bs)[:8]
  55. }
  56. return idxName
  57. }
  58. var (
  59. smap sync.Map
  60. // https://github.com/golang/lint/blob/master/lint.go#L770
  61. commonInitialisms = []string{"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SSH", "TLS", "TTL", "UID", "UI", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS"}
  62. commonInitialismsReplacer *strings.Replacer
  63. )
  64. func init() {
  65. var commonInitialismsForReplacer []string
  66. for _, initialism := range commonInitialisms {
  67. commonInitialismsForReplacer = append(commonInitialismsForReplacer, initialism, strings.Title(strings.ToLower(initialism)))
  68. }
  69. commonInitialismsReplacer = strings.NewReplacer(commonInitialismsForReplacer...)
  70. }
  71. func toDBName(name string) string {
  72. if name == "" {
  73. return ""
  74. } else if v, ok := smap.Load(name); ok {
  75. return fmt.Sprint(v)
  76. }
  77. var (
  78. value = commonInitialismsReplacer.Replace(name)
  79. buf strings.Builder
  80. lastCase, nextCase, nextNumber bool // upper case == true
  81. curCase = value[0] <= 'Z' && value[0] >= 'A'
  82. )
  83. for i, v := range value[:len(value)-1] {
  84. nextCase = value[i+1] <= 'Z' && value[i+1] >= 'A'
  85. nextNumber = value[i+1] >= '0' && value[i+1] <= '9'
  86. if curCase {
  87. if lastCase && (nextCase || nextNumber) {
  88. buf.WriteRune(v + 32)
  89. } else {
  90. if i > 0 && value[i-1] != '_' && value[i+1] != '_' {
  91. buf.WriteByte('_')
  92. }
  93. buf.WriteRune(v + 32)
  94. }
  95. } else {
  96. buf.WriteRune(v)
  97. }
  98. lastCase = curCase
  99. curCase = nextCase
  100. }
  101. if curCase {
  102. if !lastCase && len(value) > 1 {
  103. buf.WriteByte('_')
  104. }
  105. buf.WriteByte(value[len(value)-1] + 32)
  106. } else {
  107. buf.WriteByte(value[len(value)-1])
  108. }
  109. return buf.String()
  110. }