Make Replace support other associations

This commit is contained in:
Jinzhu 2015-12-25 15:49:41 +08:00
parent 0ce635cc67
commit d57867eb46
2 changed files with 54 additions and 46 deletions

View File

@ -124,46 +124,49 @@ func (association *Association) Delete(values ...interface{}) *Association {
func (association *Association) Replace(values ...interface{}) *Association {
relationship := association.Field.Relationship
scope := association.Scope
field := association.Field.Field
oldPrimaryKeys := association.getPrimaryKeys(relationship.AssociationForeignFieldNames, field.Interface())
association.Field.Set(reflect.Zero(association.Field.Field.Type()))
association.Append(values...)
newPrimaryKeys := association.getPrimaryKeys(relationship.AssociationForeignFieldNames, field.Interface())
var addedPrimaryKeys = [][]interface{}{}
for _, newKey := range newPrimaryKeys {
hasEqual := false
for _, oldKey := range oldPrimaryKeys {
if equalAsString(newKey, oldKey) {
hasEqual = true
break
}
}
if !hasEqual {
addedPrimaryKeys = append(addedPrimaryKeys, newKey)
}
}
for _, primaryKey := range association.getPrimaryKeys(relationship.AssociationForeignFieldNames, values...) {
addedPrimaryKeys = append(addedPrimaryKeys, primaryKey)
}
query := scope.NewDB()
var foreignKeyMap = map[string]string{}
for idx, foreignKey := range relationship.ForeignDBNames {
foreignKeyMap[foreignKey] = ""
if field, ok := scope.FieldByName(relationship.ForeignFieldNames[idx]); ok {
query = query.Where(fmt.Sprintf("%v = ?", scope.Quote(foreignKey)), field.Field.Interface())
}
}
if len(addedPrimaryKeys) > 0 {
sql := fmt.Sprintf("%v NOT IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(addedPrimaryKeys))
query = query.Where(sql, toQueryValues(addedPrimaryKeys)...)
}
if relationship.Kind == "many_to_many" {
field := association.Field.Field
oldPrimaryKeys := association.getPrimaryKeys(relationship.AssociationForeignFieldNames, field.Interface())
association.Field.Set(reflect.Zero(association.Field.Field.Type()))
association.Append(values...)
newPrimaryKeys := association.getPrimaryKeys(relationship.AssociationForeignFieldNames, field.Interface())
var addedPrimaryKeys = [][]interface{}{}
for _, newKey := range newPrimaryKeys {
hasEqual := false
for _, oldKey := range oldPrimaryKeys {
if equalAsString(newKey, oldKey) {
hasEqual = true
break
}
}
if !hasEqual {
addedPrimaryKeys = append(addedPrimaryKeys, newKey)
}
}
for _, primaryKey := range association.getPrimaryKeys(relationship.AssociationForeignFieldNames, values...) {
addedPrimaryKeys = append(addedPrimaryKeys, primaryKey)
}
query := scope.NewDB()
for idx, foreignKey := range relationship.ForeignDBNames {
if field, ok := scope.FieldByName(relationship.ForeignFieldNames[idx]); ok {
query = query.Where(fmt.Sprintf("%v = ?", scope.Quote(foreignKey)), field.Field.Interface())
}
}
if len(addedPrimaryKeys) > 0 {
sql := fmt.Sprintf("%v NOT IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(addedPrimaryKeys))
query = query.Where(sql, toQueryValues(addedPrimaryKeys)...)
}
association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, query, relationship))
} else {
association.setErr(errors.New("replace only support many to many"))
} else if relationship.Kind == "has_one" || relationship.Kind == "has_many" {
query.Update(foreignKeyMap)
}
return association
}

View File

@ -51,15 +51,20 @@ func TestHasOne(t *testing.T) {
}
// Replace
// DB.Model(&post).Association("Category").Replace(&Category{
// Name: "Category 3",
// })
var category3 = Category{
Name: "Category 3",
}
DB.Model(&post).Association("Category").Replace(&category3)
// var category3 Category
// DB.Model(&post).Related(&category3)
// if category3.Name != "Category 3" {
// t.Errorf("Category should be updated with Replace")
// }
if category3.Id == 0 {
t.Errorf("Category should has ID when created with Replace")
}
var category31 Category
DB.Model(&post).Related(&category31)
if category31.Name != "Category 3" {
t.Errorf("Category should be updated with Replace")
}
// Delete
// Clear