diff --git a/utils.go b/utils.go index 6acad861..55190b8d 100644 --- a/utils.go +++ b/utils.go @@ -37,20 +37,31 @@ func newSafeMap() *safeMap { var smap = newSafeMap() var umap = newSafeMap() -func toSnake(u string) string { - if v := smap.Get(u); v != "" { - return v - } - +func toSnakeBody(u string) string { buf := bytes.NewBufferString("") + caps := 0 + length := len(u) for i, v := range u { - if i > 0 && v >= 'A' && v <= 'Z' { - buf.WriteRune('_') + if i > 0 && v >= 'A' && v <= 'Z' { + caps++ + if caps == 1 || (i < length-1 && !(u[i+1] >= 'A' && u[i+1] <= 'Z')) { + buf.WriteRune('_') + } + } else { + caps = 0 } buf.WriteRune(v) } - s := strings.ToLower(buf.String()) + return strings.ToLower(buf.String()) +} + +func toSnake(u string) string { + if v := smap.Get(u); v != "" { + return v + } + s := toSnakeBody(u) + go smap.Set(u, s) return s } diff --git a/utils_test.go b/utils_test.go new file mode 100644 index 00000000..28ff24b8 --- /dev/null +++ b/utils_test.go @@ -0,0 +1,28 @@ +package gorm + +import "testing" + +func TestToSnakeWithCapWord(t *testing.T) { + in, out := "BlockIOCount", "block_io_count" + + if s := toSnake(in); s != out { + t.Errorf("toSnake(%v) = %v, want %v", in, s, out ) + } +} + +func TestToSnakeWithCapWordAtEnd(t *testing.T) { + in, out := "BlockIO", "block_io" + + if s := toSnake(in); s != out { + t.Errorf("toSnake(%v) = %v, want %v", in, s, out ) + } +} + +func BenchmarkToSnake(b *testing.B) { + in := "BlockIOCount" + + for i := 0; i < b.N; i++ { + toSnakeBody(in) + } + +}