Refactor association Delete
This commit is contained in:
		
							parent
							
								
									e65f94b287
								
							
						
					
					
						commit
						300b74f15f
					
				@ -169,37 +169,30 @@ func (association *Association) Delete(values ...interface{}) *Association {
 | 
			
		||||
		return association
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var deletingResourcePrimaryFieldNames, deletingResourcePrimaryDBNames []string
 | 
			
		||||
	for _, field := range scope.New(reflect.New(field.Type()).Interface()).Fields() {
 | 
			
		||||
		if field.IsPrimaryKey {
 | 
			
		||||
			deletingResourcePrimaryFieldNames = append(deletingResourcePrimaryFieldNames, field.Name)
 | 
			
		||||
			deletingResourcePrimaryDBNames = append(deletingResourcePrimaryDBNames, field.DBName)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	deletingPrimaryKeys := association.getPrimaryKeys(deletingResourcePrimaryFieldNames, values...)
 | 
			
		||||
 | 
			
		||||
	if relationship.Kind == "many_to_many" {
 | 
			
		||||
		// many to many
 | 
			
		||||
		// current value's foreign keys
 | 
			
		||||
		// source value's foreign keys
 | 
			
		||||
		for idx, foreignKey := range relationship.ForeignDBNames {
 | 
			
		||||
			if field, ok := scope.FieldByName(relationship.ForeignFieldNames[idx]); ok {
 | 
			
		||||
				newDB = newDB.Where(fmt.Sprintf("%v = ?", scope.Quote(foreignKey)), field.Field.Interface())
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// deleting value's foreign keys
 | 
			
		||||
		primaryKeys := association.getPrimaryKeys(relationship.AssociationForeignFieldNames, values...)
 | 
			
		||||
		sql := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(primaryKeys))
 | 
			
		||||
		newDB = newDB.Where(sql, toQueryValues(primaryKeys)...)
 | 
			
		||||
		// association value's foreign keys
 | 
			
		||||
		deletingPrimaryKeys := association.getPrimaryKeys(relationship.AssociationForeignFieldNames, values...)
 | 
			
		||||
		sql := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(deletingPrimaryKeys))
 | 
			
		||||
		newDB = newDB.Where(sql, toQueryValues(deletingPrimaryKeys)...)
 | 
			
		||||
 | 
			
		||||
		if err := relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB, relationship); err == nil {
 | 
			
		||||
			leftValues := reflect.Zero(association.Field.Field.Type())
 | 
			
		||||
			for i := 0; i < association.Field.Field.Len(); i++ {
 | 
			
		||||
				reflectValue := association.Field.Field.Index(i)
 | 
			
		||||
				primaryKey := association.getPrimaryKeys(relationship.ForeignFieldNames, reflectValue.Interface())[0]
 | 
			
		||||
				var included = false
 | 
			
		||||
				for _, pk := range primaryKeys {
 | 
			
		||||
					if equalAsString(primaryKey, pk) {
 | 
			
		||||
						included = true
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if !included {
 | 
			
		||||
					leftValues = reflect.Append(leftValues, reflectValue)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			association.Field.Set(leftValues)
 | 
			
		||||
		}
 | 
			
		||||
		association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB, relationship))
 | 
			
		||||
	} else {
 | 
			
		||||
		var foreignKeyMap = map[string]interface{}{}
 | 
			
		||||
		for _, foreignKey := range relationship.ForeignDBNames {
 | 
			
		||||
@ -225,23 +218,45 @@ func (association *Association) Delete(values ...interface{}) *Association {
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			// only include those deleting relations
 | 
			
		||||
			var primaryFieldNames, primaryFieldDBNames []string
 | 
			
		||||
			for _, field := range scope.New(reflect.New(field.Type()).Interface()).Fields() {
 | 
			
		||||
				if field.IsPrimaryKey {
 | 
			
		||||
					primaryFieldNames = append(primaryFieldNames, field.Name)
 | 
			
		||||
					primaryFieldDBNames = append(primaryFieldDBNames, field.DBName)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			relationsPrimaryKeys := association.getPrimaryKeys(primaryFieldNames, values...)
 | 
			
		||||
			newDB = newDB.Where(
 | 
			
		||||
				fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, primaryFieldDBNames), toQueryMarks(relationsPrimaryKeys)),
 | 
			
		||||
				toQueryValues(relationsPrimaryKeys)...,
 | 
			
		||||
				fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, deletingResourcePrimaryDBNames), toQueryMarks(deletingPrimaryKeys)),
 | 
			
		||||
				toQueryValues(deletingPrimaryKeys)...,
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			// set matched relation's foreign key to be null
 | 
			
		||||
			fieldValue := reflect.New(association.Field.Field.Type()).Interface()
 | 
			
		||||
			newDB.Model(fieldValue).UpdateColumn(foreignKeyMap)
 | 
			
		||||
			association.setErr(newDB.Model(fieldValue).UpdateColumn(foreignKeyMap).Error)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Remove deleted records from field
 | 
			
		||||
	if association.Error == nil {
 | 
			
		||||
		if association.Field.Field.Kind() == reflect.Slice {
 | 
			
		||||
			leftValues := reflect.Zero(association.Field.Field.Type())
 | 
			
		||||
 | 
			
		||||
			for i := 0; i < association.Field.Field.Len(); i++ {
 | 
			
		||||
				reflectValue := association.Field.Field.Index(i)
 | 
			
		||||
				primaryKey := association.getPrimaryKeys(deletingResourcePrimaryFieldNames, reflectValue.Interface())[0]
 | 
			
		||||
				var included = false
 | 
			
		||||
				for _, pk := range deletingPrimaryKeys {
 | 
			
		||||
					if equalAsString(primaryKey, pk) {
 | 
			
		||||
						included = true
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if !included {
 | 
			
		||||
					leftValues = reflect.Append(leftValues, reflectValue)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			association.Field.Set(leftValues)
 | 
			
		||||
		} else if association.Field.Field.Kind() == reflect.Struct {
 | 
			
		||||
			for _, pk := range deletingPrimaryKeys {
 | 
			
		||||
				primaryKey := association.getPrimaryKeys(deletingResourcePrimaryFieldNames, association.Field.Field)[0]
 | 
			
		||||
				if equalAsString(primaryKey, pk) {
 | 
			
		||||
					association.Field.Set(reflect.Zero(association.Field.Field.Type()))
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
package gorm_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"testing"
 | 
			
		||||
@ -103,7 +102,6 @@ func TestPolymorphic(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	var dogToys2 []Toy
 | 
			
		||||
	DB.Model(&dog).Association("Toys").Find(&dogToys2)
 | 
			
		||||
	fmt.Println(dogToys2)
 | 
			
		||||
	if !compareToys(dogToys2, []string{"dog toy 1", "dog toy 2", "dog toy 3"}) {
 | 
			
		||||
		t.Errorf("Dog's toys should be updated with Append")
 | 
			
		||||
	}
 | 
			
		||||
@ -111,7 +109,111 @@ func TestPolymorphic(t *testing.T) {
 | 
			
		||||
	if DB.Model(&dog).Association("Toys").Count() != 3 {
 | 
			
		||||
		t.Errorf("Should return three polymorphic has many associations")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Replace
 | 
			
		||||
	DB.Model(&cat).Association("Toy").Replace(&Toy{
 | 
			
		||||
		Name: "cat toy 3",
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	var catToy3 Toy
 | 
			
		||||
	DB.Model(&cat).Association("Toy").Find(&catToy3)
 | 
			
		||||
	if catToy3.Name != "cat toy 3" {
 | 
			
		||||
		t.Errorf("Should update has one polymorphic association with Replace")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&cat).Association("Toy").Count() != 1 {
 | 
			
		||||
		t.Errorf("Cat's toys count should be 1 after Replace")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&dog).Association("Toys").Count() != 3 {
 | 
			
		||||
		t.Errorf("Should return three polymorphic has many associations")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DB.Model(&dog).Association("Toys").Replace(&Toy{
 | 
			
		||||
		Name: "dog toy 4",
 | 
			
		||||
	}, []Toy{
 | 
			
		||||
		{Name: "dog toy 5"}, {Name: "dog toy 6"}, {Name: "dog toy 7"},
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	var dogToys3 []Toy
 | 
			
		||||
	DB.Model(&dog).Association("Toys").Find(&dogToys3)
 | 
			
		||||
	if !compareToys(dogToys3, []string{"dog toy 4", "dog toy 5", "dog toy 6", "dog toy 7"}) {
 | 
			
		||||
		t.Errorf("Dog's toys should be updated with Replace")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&dog).Association("Toys").Count() != 4 {
 | 
			
		||||
		t.Errorf("Should return three polymorphic has many associations")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete
 | 
			
		||||
	DB.Model(&cat).Association("Toy").Delete(&catToy2)
 | 
			
		||||
 | 
			
		||||
	var catToy4 Toy
 | 
			
		||||
	DB.Model(&cat).Association("Toy").Find(&catToy4)
 | 
			
		||||
	if catToy4.Name != "cat toy 3" {
 | 
			
		||||
		t.Errorf("Should not update has one polymorphic association when Delete a unrelated Toy")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&cat).Association("Toy").Count() != 1 {
 | 
			
		||||
		t.Errorf("Cat's toys count should be 1")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&dog).Association("Toys").Count() != 4 {
 | 
			
		||||
		t.Errorf("Dog's toys count should be 4")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DB.Model(&cat).Association("Toy").Delete(&catToy3)
 | 
			
		||||
 | 
			
		||||
	if !DB.Model(&cat).Related(&Toy{}, "Toy").RecordNotFound() {
 | 
			
		||||
		t.Errorf("Toy should be deleted with Delete")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&cat).Association("Toy").Count() != 0 {
 | 
			
		||||
		t.Errorf("Cat's toys count should be 0 after Delete")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&dog).Association("Toys").Count() != 4 {
 | 
			
		||||
		t.Errorf("Dog's toys count should not be changed when delete cat's toy")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DB.Model(&dog).Association("Toys").Delete(&dogToys2)
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&dog).Association("Toys").Count() != 4 {
 | 
			
		||||
		t.Errorf("Dog's toys count should not be changed when delete unrelated toys")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DB.Model(&dog).Association("Toys").Delete(&dogToys3)
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&dog).Association("Toys").Count() != 0 {
 | 
			
		||||
		t.Errorf("Dog's toys count should be deleted with Delete")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Clear
 | 
			
		||||
	DB.Model(&cat).Association("Toy").Append(&Toy{
 | 
			
		||||
		Name: "cat toy 2",
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&cat).Association("Toy").Count() != 1 {
 | 
			
		||||
		t.Errorf("Cat's toys should be added with Append")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DB.Model(&cat).Association("Toy").Clear()
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&cat).Association("Toy").Count() != 0 {
 | 
			
		||||
		t.Errorf("Cat's toys should be cleared with Clear")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DB.Model(&dog).Association("Toys").Append(&Toy{
 | 
			
		||||
		Name: "dog toy 8",
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&dog).Association("Toys").Count() != 1 {
 | 
			
		||||
		t.Errorf("Dog's toys should be added with Append")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DB.Model(&dog).Association("Toys").Clear()
 | 
			
		||||
 | 
			
		||||
	if DB.Model(&dog).Association("Toys").Count() != 0 {
 | 
			
		||||
		t.Errorf("Dog's toys should be cleared with Clear")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user