naming.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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(joinTable 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. if strings.ToLower(str) == str {
  38. return ns.TablePrefix + str
  39. }
  40. if ns.SingularTable {
  41. return ns.TablePrefix + toDBName(str)
  42. }
  43. return ns.TablePrefix + inflection.Plural(toDBName(str))
  44. }
  45. // RelationshipFKName generate fk name for relation
  46. func (ns NamingStrategy) RelationshipFKName(rel Relationship) string {
  47. return strings.Replace(fmt.Sprintf("fk_%s_%s", rel.Schema.Table, toDBName(rel.Name)), ".", "_", -1)
  48. }
  49. // CheckerName generate checker name
  50. func (ns NamingStrategy) CheckerName(table, column string) string {
  51. return strings.Replace(fmt.Sprintf("chk_%s_%s", table, column), ".", "_", -1)
  52. }
  53. // IndexName generate index name
  54. func (ns NamingStrategy) IndexName(table, column string) string {
  55. idxName := fmt.Sprintf("idx_%v_%v", table, toDBName(column))
  56. idxName = strings.Replace(idxName, ".", "_", -1)
  57. if utf8.RuneCountInString(idxName) > 64 {
  58. h := sha1.New()
  59. h.Write([]byte(idxName))
  60. bs := h.Sum(nil)
  61. idxName = fmt.Sprintf("idx%v%v", table, column)[0:56] + string(bs)[:8]
  62. }
  63. return idxName
  64. }
  65. var (
  66. smap sync.Map
  67. // https://github.com/golang/lint/blob/master/lint.go#L770
  68. 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"}
  69. commonInitialismsReplacer *strings.Replacer
  70. )
  71. func init() {
  72. var commonInitialismsForReplacer []string
  73. for _, initialism := range commonInitialisms {
  74. commonInitialismsForReplacer = append(commonInitialismsForReplacer, initialism, strings.Title(strings.ToLower(initialism)))
  75. }
  76. commonInitialismsReplacer = strings.NewReplacer(commonInitialismsForReplacer...)
  77. }
  78. func toDBName(name string) string {
  79. if name == "" {
  80. return ""
  81. } else if v, ok := smap.Load(name); ok {
  82. return fmt.Sprint(v)
  83. }
  84. var (
  85. value = commonInitialismsReplacer.Replace(name)
  86. buf strings.Builder
  87. lastCase, nextCase, nextNumber bool // upper case == true
  88. curCase = value[0] <= 'Z' && value[0] >= 'A'
  89. )
  90. for i, v := range value[:len(value)-1] {
  91. nextCase = value[i+1] <= 'Z' && value[i+1] >= 'A'
  92. nextNumber = value[i+1] >= '0' && value[i+1] <= '9'
  93. if curCase {
  94. if lastCase && (nextCase || nextNumber) {
  95. buf.WriteRune(v + 32)
  96. } else {
  97. if i > 0 && value[i-1] != '_' && value[i+1] != '_' {
  98. buf.WriteByte('_')
  99. }
  100. buf.WriteRune(v + 32)
  101. }
  102. } else {
  103. buf.WriteRune(v)
  104. }
  105. lastCase = curCase
  106. curCase = nextCase
  107. }
  108. if curCase {
  109. if !lastCase && len(value) > 1 {
  110. buf.WriteByte('_')
  111. }
  112. buf.WriteByte(value[len(value)-1] + 32)
  113. } else {
  114. buf.WriteByte(value[len(value)-1])
  115. }
  116. return buf.String()
  117. }