forked from mirror/gorm
97 lines
2.4 KiB
Go
97 lines
2.4 KiB
Go
|
package schema
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
"sync"
|
||
|
|
||
|
"github.com/jinzhu/inflection"
|
||
|
)
|
||
|
|
||
|
// Namer namer interface
|
||
|
type Namer interface {
|
||
|
TableName(string) string
|
||
|
ColumnName(string) string
|
||
|
}
|
||
|
|
||
|
// NamingStrategy tables, columns naming strategy
|
||
|
type NamingStrategy struct {
|
||
|
TablePrefix string
|
||
|
SingularTable bool
|
||
|
}
|
||
|
|
||
|
// TableName convert string to table name
|
||
|
func (ns NamingStrategy) TableName(str string) string {
|
||
|
if ns.SingularTable {
|
||
|
return ns.TablePrefix + toDBName(str)
|
||
|
}
|
||
|
return ns.TablePrefix + inflection.Plural(toDBName(str))
|
||
|
}
|
||
|
|
||
|
// ColumnName convert string to column name
|
||
|
func (ns NamingStrategy) ColumnName(str string) string {
|
||
|
return toDBName(str)
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
smap sync.Map
|
||
|
// https://github.com/golang/lint/blob/master/lint.go#L770
|
||
|
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"}
|
||
|
commonInitialismsReplacer *strings.Replacer
|
||
|
)
|
||
|
|
||
|
func init() {
|
||
|
var commonInitialismsForReplacer []string
|
||
|
for _, initialism := range commonInitialisms {
|
||
|
commonInitialismsForReplacer = append(commonInitialismsForReplacer, initialism, strings.Title(strings.ToLower(initialism)))
|
||
|
}
|
||
|
commonInitialismsReplacer = strings.NewReplacer(commonInitialismsForReplacer...)
|
||
|
}
|
||
|
|
||
|
func toDBName(name string) string {
|
||
|
if name == "" {
|
||
|
return ""
|
||
|
} else if v, ok := smap.Load(name); ok {
|
||
|
return fmt.Sprint(v)
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
value = commonInitialismsReplacer.Replace(name)
|
||
|
buf strings.Builder
|
||
|
lastCase, nextCase, nextNumber bool // upper case == true
|
||
|
curCase = value[0] <= 'Z' && value[0] >= 'A'
|
||
|
)
|
||
|
|
||
|
for i, v := range value[:len(value)-1] {
|
||
|
nextCase = value[i+1] <= 'Z' && value[i+1] >= 'A'
|
||
|
nextNumber = value[i+1] >= '0' && value[i+1] <= '9'
|
||
|
|
||
|
if curCase {
|
||
|
if lastCase && (nextCase || nextNumber) {
|
||
|
buf.WriteRune(v + 32)
|
||
|
} else {
|
||
|
if i > 0 && value[i-1] != '_' && value[i+1] != '_' {
|
||
|
buf.WriteByte('_')
|
||
|
}
|
||
|
buf.WriteRune(v + 32)
|
||
|
}
|
||
|
} else {
|
||
|
buf.WriteRune(v)
|
||
|
}
|
||
|
|
||
|
lastCase = curCase
|
||
|
curCase = nextCase
|
||
|
}
|
||
|
|
||
|
if curCase {
|
||
|
if !lastCase && len(value) > 1 {
|
||
|
buf.WriteByte('_')
|
||
|
}
|
||
|
buf.WriteByte(value[len(value)-1] + 32)
|
||
|
} else {
|
||
|
buf.WriteByte(value[len(value)-1])
|
||
|
}
|
||
|
|
||
|
return buf.String()
|
||
|
}
|