Fix naming longer then 64 chars with dots in table (#5045)

Ensures that foreign key relationships and indexes are given
syntactically valid names when their name length exceeds 64 characters
and they contained dot characters within the name. This is most often
relevant when a Postgres table name is fully qualified by including its schema
as part of its name
This commit is contained in:
Michael Nussbaum 2022-02-23 21:10:20 -05:00 committed by GitHub
parent b1201fce4e
commit 45ef1da7e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 3 deletions

View File

@ -3,7 +3,6 @@ package schema
import ( import (
"crypto/sha1" "crypto/sha1"
"encoding/hex" "encoding/hex"
"fmt"
"regexp" "regexp"
"strings" "strings"
"unicode/utf8" "unicode/utf8"
@ -95,7 +94,7 @@ func (ns NamingStrategy) formatName(prefix, table, name string) string {
h.Write([]byte(formattedName)) h.Write([]byte(formattedName))
bs := h.Sum(nil) bs := h.Sum(nil)
formattedName = fmt.Sprintf("%v%v%v", prefix, table, name)[0:56] + hex.EncodeToString(bs)[:8] formattedName = formattedName[0:56] + hex.EncodeToString(bs)[:8]
} }
return formattedName return formattedName
} }

View File

@ -193,7 +193,7 @@ func TestFormatNameWithStringLongerThan64Characters(t *testing.T) {
ns := NamingStrategy{} ns := NamingStrategy{}
formattedName := ns.formatName("prefix", "table", "thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString") formattedName := ns.formatName("prefix", "table", "thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString")
if formattedName != "prefixtablethisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLo180f2c67" { if formattedName != "prefix_table_thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVery180f2c67" {
t.Errorf("invalid formatted name generated, got %v", formattedName) t.Errorf("invalid formatted name generated, got %v", formattedName)
} }
} }

View File

@ -576,3 +576,39 @@ func TestHasManySameForeignKey(t *testing.T) {
References: []Reference{{"ID", "User", "UserRefer", "Profile", "", true}}, References: []Reference{{"ID", "User", "UserRefer", "Profile", "", true}},
}) })
} }
type Author struct {
gorm.Model
}
type Book struct {
gorm.Model
Author Author
AuthorID uint
}
func (Book) TableName() string {
return "my_schema.a_very_very_very_very_very_very_very_very_long_table_name"
}
func TestParseConstraintNameWithSchemaQualifiedLongTableName(t *testing.T) {
s, err := schema.Parse(
&Book{},
&sync.Map{},
schema.NamingStrategy{},
)
if err != nil {
t.Fatalf("Failed to parse schema")
}
expectedConstraintName := "fk_my_schema_a_very_very_very_very_very_very_very_very_l4db13eec"
constraint := s.Relationships.Relations["Author"].ParseConstraint()
if constraint.Name != expectedConstraintName {
t.Fatalf(
"expected constraint name %s, got %s",
expectedConstraintName,
constraint.Name,
)
}
}