forked from mirror/gorm
save_associations:true should store related item (#2067)
* save_associations:true should store related item, save_associations priority on related objects * code quality
This commit is contained in:
parent
12607e8bdf
commit
d3e666a1e0
|
@ -21,9 +21,7 @@ func saveAssociationCheck(scope *Scope, field *Field) (autoUpdate bool, autoCrea
|
||||||
|
|
||||||
if v, ok := value.(string); ok {
|
if v, ok := value.(string); ok {
|
||||||
v = strings.ToLower(v)
|
v = strings.ToLower(v)
|
||||||
if v == "false" || v != "skip" {
|
return v == "true"
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -36,9 +34,11 @@ func saveAssociationCheck(scope *Scope, field *Field) (autoUpdate bool, autoCrea
|
||||||
if value, ok := scope.Get("gorm:save_associations"); ok {
|
if value, ok := scope.Get("gorm:save_associations"); ok {
|
||||||
autoUpdate = checkTruth(value)
|
autoUpdate = checkTruth(value)
|
||||||
autoCreate = autoUpdate
|
autoCreate = autoUpdate
|
||||||
|
saveReference = autoUpdate
|
||||||
} else if value, ok := field.TagSettings["SAVE_ASSOCIATIONS"]; ok {
|
} else if value, ok := field.TagSettings["SAVE_ASSOCIATIONS"]; ok {
|
||||||
autoUpdate = checkTruth(value)
|
autoUpdate = checkTruth(value)
|
||||||
autoCreate = autoUpdate
|
autoCreate = autoUpdate
|
||||||
|
saveReference = autoUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := scope.Get("gorm:association_autoupdate"); ok {
|
if value, ok := scope.Get("gorm:association_autoupdate"); ok {
|
||||||
|
|
88
main_test.go
88
main_test.go
|
@ -933,6 +933,94 @@ func TestOpenWithOneParameter(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSaveAssociations(t *testing.T) {
|
||||||
|
db := DB.New()
|
||||||
|
deltaAddressCount := 0
|
||||||
|
if err := db.Model(&Address{}).Count(&deltaAddressCount).Error; err != nil {
|
||||||
|
t.Errorf("failed to fetch address count")
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
placeAddress := &Address{
|
||||||
|
Address1: "somewhere on earth",
|
||||||
|
}
|
||||||
|
ownerAddress1 := &Address{
|
||||||
|
Address1: "near place address",
|
||||||
|
}
|
||||||
|
ownerAddress2 := &Address{
|
||||||
|
Address1: "address2",
|
||||||
|
}
|
||||||
|
db.Create(placeAddress)
|
||||||
|
|
||||||
|
addressCountShouldBe := func(t *testing.T, expectedCount int) {
|
||||||
|
countFromDB := 0
|
||||||
|
t.Helper()
|
||||||
|
err := db.Model(&Address{}).Count(&countFromDB).Error
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to fetch address count")
|
||||||
|
}
|
||||||
|
if countFromDB != expectedCount {
|
||||||
|
t.Errorf("address count mismatch: %d", countFromDB)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addressCountShouldBe(t, deltaAddressCount+1)
|
||||||
|
|
||||||
|
// owner address should be created, place address should be reused
|
||||||
|
place1 := &Place{
|
||||||
|
PlaceAddressID: placeAddress.ID,
|
||||||
|
PlaceAddress: placeAddress,
|
||||||
|
OwnerAddress: ownerAddress1,
|
||||||
|
}
|
||||||
|
err := db.Create(place1).Error
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to store place: %s", err.Error())
|
||||||
|
}
|
||||||
|
addressCountShouldBe(t, deltaAddressCount+2)
|
||||||
|
|
||||||
|
// owner address should be created again, place address should be reused
|
||||||
|
place2 := &Place{
|
||||||
|
PlaceAddressID: placeAddress.ID,
|
||||||
|
PlaceAddress: &Address{
|
||||||
|
ID: 777,
|
||||||
|
Address1: "address1",
|
||||||
|
},
|
||||||
|
OwnerAddress: ownerAddress2,
|
||||||
|
OwnerAddressID: 778,
|
||||||
|
}
|
||||||
|
err = db.Create(place2).Error
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to store place: %s", err.Error())
|
||||||
|
}
|
||||||
|
addressCountShouldBe(t, deltaAddressCount+3)
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
db.Model(&Place{}).Where(&Place{
|
||||||
|
PlaceAddressID: placeAddress.ID,
|
||||||
|
OwnerAddressID: ownerAddress1.ID,
|
||||||
|
}).Count(&count)
|
||||||
|
if count != 1 {
|
||||||
|
t.Errorf("only one instance of (%d, %d) should be available, found: %d",
|
||||||
|
placeAddress.ID, ownerAddress1.ID, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Model(&Place{}).Where(&Place{
|
||||||
|
PlaceAddressID: placeAddress.ID,
|
||||||
|
OwnerAddressID: ownerAddress2.ID,
|
||||||
|
}).Count(&count)
|
||||||
|
if count != 1 {
|
||||||
|
t.Errorf("only one instance of (%d, %d) should be available, found: %d",
|
||||||
|
placeAddress.ID, ownerAddress2.ID, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Model(&Place{}).Where(&Place{
|
||||||
|
PlaceAddressID: placeAddress.ID,
|
||||||
|
}).Count(&count)
|
||||||
|
if count != 2 {
|
||||||
|
t.Errorf("two instances of (%d) should be available, found: %d",
|
||||||
|
placeAddress.ID, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBlockGlobalUpdate(t *testing.T) {
|
func TestBlockGlobalUpdate(t *testing.T) {
|
||||||
db := DB.New()
|
db := DB.New()
|
||||||
db.Create(&Toy{Name: "Stuffed Animal", OwnerType: "Nobody"})
|
db.Create(&Toy{Name: "Stuffed Animal", OwnerType: "Nobody"})
|
||||||
|
|
|
@ -118,6 +118,14 @@ type Company struct {
|
||||||
Owner *User `sql:"-"`
|
Owner *User `sql:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Place struct {
|
||||||
|
Id int64
|
||||||
|
PlaceAddressID int
|
||||||
|
PlaceAddress *Address `gorm:"save_associations:false"`
|
||||||
|
OwnerAddressID int
|
||||||
|
OwnerAddress *Address `gorm:"save_associations:true"`
|
||||||
|
}
|
||||||
|
|
||||||
type EncryptedData []byte
|
type EncryptedData []byte
|
||||||
|
|
||||||
func (data *EncryptedData) Scan(value interface{}) error {
|
func (data *EncryptedData) Scan(value interface{}) error {
|
||||||
|
@ -284,7 +292,7 @@ func runMigration() {
|
||||||
DB.Exec(fmt.Sprintf("drop table %v;", table))
|
DB.Exec(fmt.Sprintf("drop table %v;", table))
|
||||||
}
|
}
|
||||||
|
|
||||||
values := []interface{}{&Short{}, &ReallyLongThingThatReferencesShort{}, &ReallyLongTableNameToTestMySQLNameLengthLimit{}, &NotSoLongTableName{}, &Product{}, &Email{}, &Address{}, &CreditCard{}, &Company{}, &Role{}, &Language{}, &HNPost{}, &EngadgetPost{}, &Animal{}, &User{}, &JoinTable{}, &Post{}, &Category{}, &Comment{}, &Cat{}, &Dog{}, &Hamster{}, &Toy{}, &ElementWithIgnoredField{}}
|
values := []interface{}{&Short{}, &ReallyLongThingThatReferencesShort{}, &ReallyLongTableNameToTestMySQLNameLengthLimit{}, &NotSoLongTableName{}, &Product{}, &Email{}, &Address{}, &CreditCard{}, &Company{}, &Role{}, &Language{}, &HNPost{}, &EngadgetPost{}, &Animal{}, &User{}, &JoinTable{}, &Post{}, &Category{}, &Comment{}, &Cat{}, &Dog{}, &Hamster{}, &Toy{}, &ElementWithIgnoredField{}, &Place{}}
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
DB.DropTable(value)
|
DB.DropTable(value)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue