This commit is contained in:
mohammad ali ashraf 2023-03-28 18:57:50 +05:00
parent cc2d46e5be
commit f3503275da
6 changed files with 54 additions and 13 deletions

15
gorm.go
View File

@ -144,7 +144,20 @@ func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
} }
if config.NamingStrategy == nil { if config.NamingStrategy == nil {
config.NamingStrategy = schema.NamingStrategy{} // Set default value of IdentifierMaxLength according to the database type
identifierMaxLength := 64
switch dialector.Name() {
case "mysql":
identifierMaxLength = 64
case "postgres":
identifierMaxLength = 63
case "sqlite":
identifierMaxLength = 64
case "sqlserver":
identifierMaxLength = 128
}
config.NamingStrategy = schema.NamingStrategy{NamingStrategyConfig: schema.NamingStrategyConfig{IdentifierMaxLength: identifierMaxLength}}
} }
if config.Logger == nil { if config.Logger == nil {

View File

@ -15,7 +15,7 @@ type UserCheck struct {
} }
func TestParseCheck(t *testing.T) { func TestParseCheck(t *testing.T) {
user, err := schema.Parse(&UserCheck{}, &sync.Map{}, schema.NamingStrategy{}) user, err := schema.Parse(&UserCheck{}, &sync.Map{}, schema.NamingStrategy{NamingStrategyConfig: schema.NamingStrategyConfig{IdentifierMaxLength: 64}})
if err != nil { if err != nil {
t.Fatalf("failed to parse user check, got error %v", err) t.Fatalf("failed to parse user check, got error %v", err)
} }

View File

@ -52,7 +52,7 @@ type CompIdxLevel2B struct {
} }
func TestParseIndex(t *testing.T) { func TestParseIndex(t *testing.T) {
user, err := schema.Parse(&UserIndex{}, &sync.Map{}, schema.NamingStrategy{}) user, err := schema.Parse(&UserIndex{}, &sync.Map{}, schema.NamingStrategy{NamingStrategyConfig: schema.NamingStrategyConfig{IdentifierMaxLength: 64}})
if err != nil { if err != nil {
t.Fatalf("failed to parse user index, got error %v", err) t.Fatalf("failed to parse user index, got error %v", err)
} }

View File

@ -32,6 +32,17 @@ type NamingStrategy struct {
SingularTable bool SingularTable bool
NameReplacer Replacer NameReplacer Replacer
NoLowerCase bool NoLowerCase bool
NamingStrategyConfig
}
// This struct is used to configure the behavior NamingStrategy, according to DB.
// For example, in MySQL, the maximum length of an identifier is 64 characters.
// In PostgreSQL, the maximum length of an identifier is 63 characters.
// In SQL Server, the maximum length of an identifier is 128 characters.
// In SQLite, the maximum length of an identifier is unlimited.
// In future, we may add more options to NamingStrategyConfig.
type NamingStrategyConfig struct {
IdentifierMaxLength int
} }
// TableName convert string to table name // TableName convert string to table name
@ -89,12 +100,12 @@ func (ns NamingStrategy) formatName(prefix, table, name string) string {
prefix, table, name, prefix, table, name,
}, "_"), ".", "_") }, "_"), ".", "_")
if utf8.RuneCountInString(formattedName) > 64 { if utf8.RuneCountInString(formattedName) > ns.IdentifierMaxLength {
h := sha1.New() h := sha1.New()
h.Write([]byte(formattedName)) h.Write([]byte(formattedName))
bs := h.Sum(nil) bs := h.Sum(nil)
formattedName = formattedName[0:56] + hex.EncodeToString(bs)[:8] formattedName = formattedName[0:ns.IdentifierMaxLength-8] + hex.EncodeToString(bs)[:8]
} }
return formattedName return formattedName
} }

View File

@ -57,9 +57,10 @@ func TestToDBName(t *testing.T) {
func TestNamingStrategy(t *testing.T) { func TestNamingStrategy(t *testing.T) {
ns := NamingStrategy{ ns := NamingStrategy{
TablePrefix: "public.", TablePrefix: "public.",
SingularTable: true, SingularTable: true,
NameReplacer: strings.NewReplacer("CID", "Cid"), NameReplacer: strings.NewReplacer("CID", "Cid"),
NamingStrategyConfig: NamingStrategyConfig{IdentifierMaxLength: 64},
} }
idxName := ns.IndexName("public.table", "name") idxName := ns.IndexName("public.table", "name")
@ -111,7 +112,8 @@ func TestCustomReplacer(t *testing.T) {
return strings.NewReplacer("CID", "_Cid").Replace(replaced) return strings.NewReplacer("CID", "_Cid").Replace(replaced)
}, },
}, },
NoLowerCase: false, NamingStrategyConfig: NamingStrategyConfig{IdentifierMaxLength: 64},
NoLowerCase: false,
} }
idxName := ns.IndexName("public.table", "name") idxName := ns.IndexName("public.table", "name")
@ -155,7 +157,8 @@ func TestCustomReplacerWithNoLowerCase(t *testing.T) {
return strings.NewReplacer("CID", "_Cid").Replace(replaced) return strings.NewReplacer("CID", "_Cid").Replace(replaced)
}, },
}, },
NoLowerCase: true, NamingStrategyConfig: NamingStrategyConfig{IdentifierMaxLength: 64},
NoLowerCase: true,
} }
idxName := ns.IndexName("public.table", "name") idxName := ns.IndexName("public.table", "name")
@ -189,13 +192,27 @@ func TestCustomReplacerWithNoLowerCase(t *testing.T) {
} }
} }
func TestFormatNameWithStringLongerThan64Characters(t *testing.T) { func TestFormatNameWithStringLongerThanMaxIdentifierLength(t *testing.T) {
ns := NamingStrategy{} ns := NamingStrategy{NamingStrategyConfig: NamingStrategyConfig{IdentifierMaxLength: 63}}
formattedName := ns.formatName("prefix", "table", "thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString") formattedName := ns.formatName("prefix", "table", "thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString")
if formattedName != "prefix_table_thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVer180f2c67" {
t.Errorf("invalid formatted name generated, got %v", formattedName)
}
ns = NamingStrategy{NamingStrategyConfig: NamingStrategyConfig{IdentifierMaxLength: 64}}
formattedName = ns.formatName("prefix", "table", "thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString")
if formattedName != "prefix_table_thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVery180f2c67" { if formattedName != "prefix_table_thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVery180f2c67" {
t.Errorf("invalid formatted name generated, got %v", formattedName) t.Errorf("invalid formatted name generated, got %v", formattedName)
} }
ns = NamingStrategy{NamingStrategyConfig: NamingStrategyConfig{IdentifierMaxLength: 128}}
formattedName = ns.formatName("prefix", "table", "thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString")
if formattedName != "prefix_table_thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVery81f06061" {
t.Errorf("invalid formatted name generated, got %v", formattedName)
}
} }
func TestReplaceEmptyTableName(t *testing.T) { func TestReplaceEmptyTableName(t *testing.T) {

View File

@ -642,7 +642,7 @@ func TestParseConstraintNameWithSchemaQualifiedLongTableName(t *testing.T) {
s, err := schema.Parse( s, err := schema.Parse(
&Book{}, &Book{},
&sync.Map{}, &sync.Map{},
schema.NamingStrategy{}, schema.NamingStrategy{NamingStrategyConfig: schema.NamingStrategyConfig{IdentifierMaxLength: 64}},
) )
if err != nil { if err != nil {
t.Fatalf("Failed to parse schema") t.Fatalf("Failed to parse schema")