--- /dev/null
+package gorm
+
+import (
+ "bytes"
+ "strings"
+)
+
+// Namer is a function type which is given a string and return a string
+type Namer func(string) string
+
+// NamingStrategy represents naming strategies
+type NamingStrategy struct {
+ DB Namer
+ Table Namer
+ Column Namer
+}
+
+// TheNamingStrategy is being initialized with defaultNamingStrategy
+var TheNamingStrategy = &NamingStrategy{
+ DB: defaultNamer,
+ Table: defaultNamer,
+ Column: defaultNamer,
+}
+
+// AddNamingStrategy sets the naming strategy
+func AddNamingStrategy(ns *NamingStrategy) {
+ if ns.DB == nil {
+ ns.DB = defaultNamer
+ }
+ if ns.Table == nil {
+ ns.Table = defaultNamer
+ }
+ if ns.Column == nil {
+ ns.Column = defaultNamer
+ }
+ TheNamingStrategy = ns
+}
+
+// DBName alters the given name by DB
+func (ns *NamingStrategy) DBName(name string) string {
+ return ns.DB(name)
+}
+
+// TableName alters the given name by Table
+func (ns *NamingStrategy) TableName(name string) string {
+ return ns.Table(name)
+}
+
+// ColumnName alters the given name by Column
+func (ns *NamingStrategy) ColumnName(name string) string {
+ return ns.Column(name)
+}
+
+// ToDBName convert string to db name
+func ToDBName(name string) string {
+ return TheNamingStrategy.DBName(name)
+}
+
+// ToTableName convert string to table name
+func ToTableName(name string) string {
+ return TheNamingStrategy.TableName(name)
+}
+
+// ToColumnName convert string to db name
+func ToColumnName(name string) string {
+ return TheNamingStrategy.ColumnName(name)
+}
+
+var smap = newSafeMap()
+
+func defaultNamer(name string) string {
+ const (
+ lower = false
+ upper = true
+ )
+
+ if v := smap.Get(name); v != "" {
+ return v
+ }
+
+ if name == "" {
+ return ""
+ }
+
+ var (
+ value = commonInitialismsReplacer.Replace(name)
+ buf = bytes.NewBufferString("")
+ lastCase, currCase, nextCase, nextNumber bool
+ )
+
+ for i, v := range value[:len(value)-1] {
+ nextCase = bool(value[i+1] >= 'A' && value[i+1] <= 'Z')
+ nextNumber = bool(value[i+1] >= '0' && value[i+1] <= '9')
+
+ if i > 0 {
+ if currCase == upper {
+ if lastCase == upper && (nextCase == upper || nextNumber == upper) {
+ buf.WriteRune(v)
+ } else {
+ if value[i-1] != '_' && value[i+1] != '_' {
+ buf.WriteRune('_')
+ }
+ buf.WriteRune(v)
+ }
+ } else {
+ buf.WriteRune(v)
+ if i == len(value)-2 && (nextCase == upper && nextNumber == lower) {
+ buf.WriteRune('_')
+ }
+ }
+ } else {
+ currCase = upper
+ buf.WriteRune(v)
+ }
+ lastCase = currCase
+ currCase = nextCase
+ }
+
+ buf.WriteByte(value[len(value)-1])
+
+ s := strings.ToLower(buf.String())
+ smap.Set(name, s)
+ return s
+}