From c299cb8db606d4cc784f2861a597b5970f5e8c09 Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Tue, 26 May 2020 09:48:12 +0800 Subject: [PATCH] Refactor association --- association.go | 197 ++-- tests/associations_belongs_to_test.go | 216 +++++ tests/associations_has_many_test.go | 456 ++++++++++ tests/associations_has_one_test.go | 241 +++++ tests/associations_many2many_test.go | 299 +++++++ tests/associations_test.go | 1185 +------------------------ 6 files changed, 1311 insertions(+), 1283 deletions(-) create mode 100644 tests/associations_belongs_to_test.go create mode 100644 tests/associations_has_many_test.go create mode 100644 tests/associations_has_one_test.go create mode 100644 tests/associations_many2many_test.go diff --git a/association.go b/association.go index 4871a72f..5b777465 100644 --- a/association.go +++ b/association.go @@ -41,7 +41,7 @@ func (association *Association) Find(out interface{}, conds ...interface{}) erro if association.Error == nil { var ( queryConds = association.Relationship.ToQueryConditions(association.DB.Statement.ReflectValue) - tx = association.DB.Model(out).Table("") + tx = association.DB.Model(out) ) if association.Relationship.JoinTable != nil { @@ -80,10 +80,12 @@ func (association *Association) Append(values ...interface{}) error { func (association *Association) Replace(values ...interface{}) error { if association.Error == nil { + // save associations association.saveAssociation(true, values...) + + // set old associations's foreign key to null reflectValue := association.DB.Statement.ReflectValue rel := association.Relationship - switch rel.Type { case schema.BelongsTo: if len(values) == 0 { @@ -97,21 +99,17 @@ func (association *Association) Replace(values ...interface{}) error { } case schema.HasOne, schema.HasMany: var ( - tx = association.DB - primaryFields []*schema.Field - foreignKeys []string - updateMap = map[string]interface{}{} - relPrimaryKeys = []string{} - relValues = schema.GetRelationsValues(reflectValue, []*schema.Relationship{rel}) - modelValue = reflect.New(rel.FieldSchema.ModelType).Interface() + primaryFields []*schema.Field + foreignKeys []string + updateMap = map[string]interface{}{} + relValues = schema.GetRelationsValues(reflectValue, []*schema.Relationship{rel}) + modelValue = reflect.New(rel.FieldSchema.ModelType).Interface() + tx = association.DB.Model(modelValue) ) - for _, field := range rel.FieldSchema.PrimaryFields { - relPrimaryKeys = append(relPrimaryKeys, field.DBName) - } - if _, qvs := schema.GetIdentityFieldValuesMap(relValues, rel.FieldSchema.PrimaryFields); len(qvs) > 0 { - if column, values := schema.ToQueryValues(relPrimaryKeys, qvs); len(values) > 0 { - tx = tx.Not(clause.IN{Column: column, Values: values}) + if _, rvs := schema.GetIdentityFieldValuesMap(relValues, rel.FieldSchema.PrimaryFields); len(rvs) > 0 { + if column, values := schema.ToQueryValues(rel.FieldSchema.PrimaryFieldDBNames, rvs); len(values) > 0 { + tx.Not(clause.IN{Column: column, Values: values}) } } @@ -120,16 +118,22 @@ func (association *Association) Replace(values ...interface{}) error { primaryFields = append(primaryFields, ref.PrimaryKey) foreignKeys = append(foreignKeys, ref.ForeignKey.DBName) updateMap[ref.ForeignKey.DBName] = nil + } else if ref.PrimaryValue != "" { + tx.Where(clause.Eq{Column: ref.ForeignKey.DBName, Value: ref.PrimaryValue}) } } - if _, qvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields); len(qvs) > 0 { - column, values := schema.ToQueryValues(foreignKeys, qvs) - tx.Model(modelValue).Where(clause.IN{Column: column, Values: values}).UpdateColumns(updateMap) + + if _, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields); len(pvs) > 0 { + column, values := schema.ToQueryValues(foreignKeys, pvs) + tx.Where(clause.IN{Column: column, Values: values}).UpdateColumns(updateMap) } case schema.Many2Many: - var primaryFields, relPrimaryFields []*schema.Field - var joinPrimaryKeys, joinRelPrimaryKeys []string - var conds []clause.Expression + var ( + primaryFields, relPrimaryFields []*schema.Field + joinPrimaryKeys, joinRelPrimaryKeys []string + modelValue = reflect.New(rel.JoinTable.ModelType).Interface() + tx = association.DB.Model(modelValue) + ) for _, ref := range rel.References { if ref.PrimaryValue == "" { @@ -141,27 +145,23 @@ func (association *Association) Replace(values ...interface{}) error { joinRelPrimaryKeys = append(joinRelPrimaryKeys, ref.ForeignKey.DBName) } } else { - conds = append(conds, clause.Eq{Column: ref.ForeignKey.DBName, Value: ref.PrimaryValue}) + tx.Clauses(clause.Eq{Column: ref.ForeignKey.DBName, Value: ref.PrimaryValue}) } } - var ( - modelValue = reflect.New(rel.JoinTable.ModelType).Interface() - _, queryValues = schema.GetIdentityFieldValuesMap(reflectValue, primaryFields) - _, relQueryValues = schema.GetIdentityFieldValuesMapFromValues(values, relPrimaryFields) - ) - - if column, values := schema.ToQueryValues(joinPrimaryKeys, queryValues); len(values) > 0 { - conds = append(conds, clause.IN{Column: column, Values: values}) + _, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields) + if column, values := schema.ToQueryValues(joinPrimaryKeys, pvs); len(values) > 0 { + tx.Where(clause.IN{Column: column, Values: values}) } else { return ErrorPrimaryKeyRequired } - if relColumn, relValues := schema.ToQueryValues(joinRelPrimaryKeys, relQueryValues); len(relValues) > 0 { - conds = append(conds, clause.Not(clause.IN{Column: relColumn, Values: relValues})) + _, rvs := schema.GetIdentityFieldValuesMapFromValues(values, relPrimaryFields) + if relColumn, relValues := schema.ToQueryValues(joinRelPrimaryKeys, rvs); len(relValues) > 0 { + tx.Where(clause.Not(clause.IN{Column: relColumn, Values: relValues})) } - association.DB.Where(clause.Where{Exprs: conds}).Model(nil).Delete(modelValue) + tx.Delete(modelValue) } } return association.Error @@ -172,7 +172,6 @@ func (association *Association) Delete(values ...interface{}) error { var ( reflectValue = association.DB.Statement.ReflectValue rel = association.Relationship - tx = association.DB primaryFields, foreignFields []*schema.Field foreignKeys []string updateAttrs = map[string]interface{}{} @@ -191,35 +190,36 @@ func (association *Association) Delete(values ...interface{}) error { } switch rel.Type { - case schema.HasOne, schema.HasMany: - var ( - modelValue = reflect.New(rel.FieldSchema.ModelType).Interface() - _, queryValues = schema.GetIdentityFieldValuesMap(reflectValue, primaryFields) - _, relQueryValues = schema.GetIdentityFieldValuesMapFromValues(values, rel.FieldSchema.PrimaryFields) - ) - - column, values := schema.ToQueryValues(foreignKeys, queryValues) - conds = append(conds, clause.IN{Column: column, Values: values}) - relColumn, relValues := schema.ToQueryValues(rel.FieldSchema.PrimaryFieldDBNames, relQueryValues) - conds = append(conds, clause.IN{Column: relColumn, Values: relValues}) - - tx.Session(&Session{}).Model(modelValue).Clauses(conds...).UpdateColumns(updateAttrs) case schema.BelongsTo: - var ( - modelValue = reflect.New(rel.Schema.ModelType).Interface() - _, queryValues = schema.GetIdentityFieldValuesMap(reflectValue, rel.Schema.PrimaryFields) - _, relQueryValues = schema.GetIdentityFieldValuesMapFromValues(values, primaryFields) - ) + tx := association.DB.Model(reflect.New(rel.Schema.ModelType).Interface()) - column, values := schema.ToQueryValues(rel.Schema.PrimaryFieldDBNames, queryValues) - conds = append(conds, clause.IN{Column: column, Values: values}) - relColumn, relValues := schema.ToQueryValues(foreignKeys, relQueryValues) + _, pvs := schema.GetIdentityFieldValuesMap(reflectValue, rel.Schema.PrimaryFields) + pcolumn, pvalues := schema.ToQueryValues(rel.Schema.PrimaryFieldDBNames, pvs) + conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues}) + + _, rvs := schema.GetIdentityFieldValuesMapFromValues(values, primaryFields) + relColumn, relValues := schema.ToQueryValues(foreignKeys, rvs) conds = append(conds, clause.IN{Column: relColumn, Values: relValues}) - tx.Session(&Session{}).Model(modelValue).Clauses(conds...).UpdateColumns(updateAttrs) + association.Error = tx.Clauses(conds...).UpdateColumns(updateAttrs).Error + case schema.HasOne, schema.HasMany: + tx := association.DB.Model(reflect.New(rel.FieldSchema.ModelType).Interface()) + + _, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields) + pcolumn, pvalues := schema.ToQueryValues(foreignKeys, pvs) + conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues}) + + _, rvs := schema.GetIdentityFieldValuesMapFromValues(values, rel.FieldSchema.PrimaryFields) + relColumn, relValues := schema.ToQueryValues(rel.FieldSchema.PrimaryFieldDBNames, rvs) + conds = append(conds, clause.IN{Column: relColumn, Values: relValues}) + + association.Error = tx.Clauses(conds...).UpdateColumns(updateAttrs).Error case schema.Many2Many: - var primaryFields, relPrimaryFields []*schema.Field - var joinPrimaryKeys, joinRelPrimaryKeys []string + var ( + primaryFields, relPrimaryFields []*schema.Field + joinPrimaryKeys, joinRelPrimaryKeys []string + modelValue = reflect.New(rel.JoinTable.ModelType).Interface() + ) for _, ref := range rel.References { if ref.PrimaryValue == "" { @@ -235,41 +235,34 @@ func (association *Association) Delete(values ...interface{}) error { } } - var ( - modelValue = reflect.New(rel.JoinTable.ModelType).Interface() - _, queryValues = schema.GetIdentityFieldValuesMap(reflectValue, primaryFields) - _, relQueryValues = schema.GetIdentityFieldValuesMapFromValues(values, relPrimaryFields) - ) + _, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields) + pcolumn, pvalues := schema.ToQueryValues(joinPrimaryKeys, pvs) + conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues}) - if column, values := schema.ToQueryValues(joinPrimaryKeys, queryValues); len(values) > 0 { - conds = append(conds, clause.IN{Column: column, Values: values}) - } else { - return ErrorPrimaryKeyRequired - } - - relColumn, relValues := schema.ToQueryValues(joinRelPrimaryKeys, relQueryValues) + _, rvs := schema.GetIdentityFieldValuesMapFromValues(values, relPrimaryFields) + relColumn, relValues := schema.ToQueryValues(joinRelPrimaryKeys, rvs) conds = append(conds, clause.IN{Column: relColumn, Values: relValues}) - tx.Where(clause.Where{Exprs: conds}).Model(nil).Delete(modelValue) + association.Error = association.DB.Where(clause.Where{Exprs: conds}).Model(nil).Delete(modelValue).Error } - relValuesMap, _ := schema.GetIdentityFieldValuesMapFromValues(values, rel.FieldSchema.PrimaryFields) + if association.Error == nil { + relValuesMap, _ := schema.GetIdentityFieldValuesMapFromValues(values, rel.FieldSchema.PrimaryFields) - if tx.Error == nil { cleanUpDeletedRelations := func(data reflect.Value) { if _, zero := rel.Field.ValueOf(data); !zero { fieldValue := reflect.Indirect(rel.Field.ReflectValueOf(data)) + primaryValues := make([]interface{}, len(rel.FieldSchema.PrimaryFields)) - fieldValues := make([]interface{}, len(rel.FieldSchema.PrimaryFields)) switch fieldValue.Kind() { case reflect.Slice, reflect.Array: - validFieldValues := reflect.Zero(rel.Field.FieldType) + validFieldValues := reflect.Zero(rel.Field.IndirectFieldType) for i := 0; i < fieldValue.Len(); i++ { for idx, field := range rel.FieldSchema.PrimaryFields { - fieldValues[idx], _ = field.ValueOf(fieldValue.Index(i)) + primaryValues[idx], _ = field.ValueOf(fieldValue.Index(i)) } - if _, ok := relValuesMap[utils.ToStringKey(fieldValues...)]; !ok { + if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; !ok { validFieldValues = reflect.Append(validFieldValues, fieldValue.Index(i)) } } @@ -277,16 +270,19 @@ func (association *Association) Delete(values ...interface{}) error { rel.Field.Set(data, validFieldValues.Interface()) case reflect.Struct: for idx, field := range rel.FieldSchema.PrimaryFields { - fieldValues[idx], _ = field.ValueOf(fieldValue) + primaryValues[idx], _ = field.ValueOf(fieldValue) } - if _, ok := relValuesMap[utils.ToStringKey(fieldValues...)]; ok { + + if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; ok { rel.Field.Set(data, reflect.Zero(rel.FieldSchema.ModelType).Interface()) - for _, ref := range rel.References { - if ref.OwnPrimaryKey { - ref.ForeignKey.Set(fieldValue, reflect.Zero(ref.ForeignKey.FieldType).Interface()) - } else if ref.PrimaryValue == "" { - // FIXME - ref.ForeignKey.Set(data, reflect.Zero(ref.ForeignKey.FieldType).Interface()) + + if rel.JoinTable == nil { + for _, ref := range rel.References { + if ref.OwnPrimaryKey || ref.PrimaryValue != "" { + ref.ForeignKey.Set(fieldValue, reflect.Zero(ref.ForeignKey.FieldType).Interface()) + } else { + ref.ForeignKey.Set(data, reflect.Zero(ref.ForeignKey.FieldType).Interface()) + } } } } @@ -302,10 +298,9 @@ func (association *Association) Delete(values ...interface{}) error { case reflect.Struct: cleanUpDeletedRelations(reflectValue) } - } else { - association.Error = tx.Error } } + return association.Error } @@ -349,7 +344,7 @@ type assignBack struct { func (association *Association) saveAssociation(clear bool, values ...interface{}) { var ( reflectValue = association.DB.Statement.ReflectValue - assignBacks []assignBack + assignBacks []assignBack // assign association values back to arguments after save ) appendToRelations := func(source, rv reflect.Value, clear bool) { @@ -359,12 +354,14 @@ func (association *Association) saveAssociation(clear bool, values ...interface{ case reflect.Slice, reflect.Array: if rv.Len() > 0 { association.Error = association.Relationship.Field.Set(source, rv.Index(0).Addr().Interface()) + if association.Relationship.Field.FieldType.Kind() == reflect.Struct { assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv.Index(0)}) } } case reflect.Struct: association.Error = association.Relationship.Field.Set(source, rv.Addr().Interface()) + if association.Relationship.Field.FieldType.Kind() == reflect.Struct { assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv}) } @@ -385,12 +382,8 @@ func (association *Association) saveAssociation(clear bool, values ...interface{ association.Error = fmt.Errorf("unsupported data type: %v for relation %v", ev.Type(), association.Relationship.Name) } - if association.Relationship.Field.IndirectFieldType.Elem().Kind() == reflect.Struct { - assignBacks = append(assignBacks, assignBack{ - Source: source, - Index: fieldValue.Len(), - Dest: ev, - }) + if elemType.Kind() == reflect.Struct { + assignBacks = append(assignBacks, assignBack{Source: source, Dest: ev, Index: fieldValue.Len()}) } } @@ -409,10 +402,10 @@ func (association *Association) saveAssociation(clear bool, values ...interface{ } } - selectedColumns := []string{association.Relationship.Name} + selectedSaveColumns := []string{association.Relationship.Name} for _, ref := range association.Relationship.References { if !ref.OwnPrimaryKey { - selectedColumns = append(selectedColumns, ref.ForeignKey.Name) + selectedSaveColumns = append(selectedSaveColumns, ref.ForeignKey.Name) } } @@ -422,6 +415,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{ if clear && len(values) == 0 { for i := 0; i < reflectValue.Len(); i++ { association.Relationship.Field.Set(reflectValue.Index(i), reflect.New(association.Relationship.Field.IndirectFieldType).Interface()) + if association.Relationship.JoinTable == nil { for _, ref := range association.Relationship.References { if !ref.OwnPrimaryKey && ref.PrimaryValue == "" { @@ -432,6 +426,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{ } break } + association.Error = errors.New("invalid association values, length doesn't match") return } @@ -439,15 +434,13 @@ func (association *Association) saveAssociation(clear bool, values ...interface{ for i := 0; i < reflectValue.Len(); i++ { appendToRelations(reflectValue.Index(i), reflect.Indirect(reflect.ValueOf(values[i])), clear) - if len(values) > 0 { - // TODO support save slice data, sql with case - err := association.DB.Session(&Session{}).Select(selectedColumns).Model(nil).Save(reflectValue.Index(i).Addr().Interface()).Error - association.DB.AddError(err) - } + // TODO support save slice data, sql with case? + association.Error = association.DB.Session(&Session{}).Select(selectedSaveColumns).Model(nil).Save(reflectValue.Index(i).Addr().Interface()).Error } case reflect.Struct: if clear && len(values) == 0 { association.Relationship.Field.Set(reflectValue, reflect.New(association.Relationship.Field.IndirectFieldType).Interface()) + if association.Relationship.JoinTable == nil { for _, ref := range association.Relationship.References { if !ref.OwnPrimaryKey && ref.PrimaryValue == "" { @@ -463,7 +456,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{ } if len(values) > 0 { - association.DB.Session(&Session{}).Select(selectedColumns).Model(nil).Save(reflectValue.Addr().Interface()) + association.Error = association.DB.Session(&Session{}).Select(selectedSaveColumns).Model(nil).Save(reflectValue.Addr().Interface()).Error } } diff --git a/tests/associations_belongs_to_test.go b/tests/associations_belongs_to_test.go new file mode 100644 index 00000000..236af191 --- /dev/null +++ b/tests/associations_belongs_to_test.go @@ -0,0 +1,216 @@ +package tests_test + +import ( + "testing" + + . "github.com/jinzhu/gorm/tests" +) + +func TestBelongsToAssociation(t *testing.T) { + var user = *GetUser("belongs-to", Config{Company: true, Manager: true}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + CheckUser(t, user, user) + + // Find + var user2 User + DB.Find(&user2, "id = ?", user.ID) + DB.Model(&user2).Association("Company").Find(&user2.Company) + user2.Manager = &User{} + DB.Model(&user2).Association("Manager").Find(user2.Manager) + CheckUser(t, user2, user) + + // Count + AssertAssociationCount(t, user, "Company", 1, "") + AssertAssociationCount(t, user, "Manager", 1, "") + + // Append + var company = Company{Name: "company-belongs-to-append"} + var manager = GetUser("manager-belongs-to-append", Config{}) + + if err := DB.Model(&user2).Association("Company").Append(&company); err != nil { + t.Fatalf("Error happened when append Company, got %v", err) + } + + if company.ID == 0 { + t.Fatalf("Company's ID should be created") + } + + if err := DB.Model(&user2).Association("Manager").Append(manager); err != nil { + t.Fatalf("Error happened when append Manager, got %v", err) + } + + if manager.ID == 0 { + t.Fatalf("Manager's ID should be created") + } + + user.Company = company + user.Manager = manager + user.CompanyID = &company.ID + user.ManagerID = &manager.ID + CheckUser(t, user2, user) + + AssertAssociationCount(t, user2, "Company", 1, "AfterAppend") + AssertAssociationCount(t, user2, "Manager", 1, "AfterAppend") + + // Replace + var company2 = Company{Name: "company-belongs-to-replace"} + var manager2 = GetUser("manager-belongs-to-replace", Config{}) + + if err := DB.Model(&user2).Association("Company").Replace(&company2); err != nil { + t.Fatalf("Error happened when replace Company, got %v", err) + } + + if company2.ID == 0 { + t.Fatalf("Company's ID should be created") + } + + if err := DB.Model(&user2).Association("Manager").Replace(manager2); err != nil { + t.Fatalf("Error happened when replace Manager, got %v", err) + } + + if manager2.ID == 0 { + t.Fatalf("Manager's ID should be created") + } + + user.Company = company2 + user.Manager = manager2 + user.CompanyID = &company2.ID + user.ManagerID = &manager2.ID + CheckUser(t, user2, user) + + AssertAssociationCount(t, user2, "Company", 1, "AfterReplace") + AssertAssociationCount(t, user2, "Manager", 1, "AfterReplace") + + // Delete + if err := DB.Model(&user2).Association("Company").Delete(&Company{}); err != nil { + t.Fatalf("Error happened when delete Company, got %v", err) + } + AssertAssociationCount(t, user2, "Company", 1, "after delete non-existing data") + + if err := DB.Model(&user2).Association("Company").Delete(&company2); err != nil { + t.Fatalf("Error happened when delete Company, got %v", err) + } + AssertAssociationCount(t, user2, "Company", 0, "after delete") + + if err := DB.Model(&user2).Association("Manager").Delete(&User{}); err != nil { + t.Fatalf("Error happened when delete Manager, got %v", err) + } + AssertAssociationCount(t, user2, "Manager", 1, "after delete non-existing data") + + if err := DB.Model(&user2).Association("Manager").Delete(manager2); err != nil { + t.Fatalf("Error happened when delete Manager, got %v", err) + } + AssertAssociationCount(t, user2, "Manager", 0, "after delete") + + // Prepare Data for Clear + if err := DB.Model(&user2).Association("Company").Append(&company); err != nil { + t.Fatalf("Error happened when append Company, got %v", err) + } + + if err := DB.Model(&user2).Association("Manager").Append(manager); err != nil { + t.Fatalf("Error happened when append Manager, got %v", err) + } + + AssertAssociationCount(t, user2, "Company", 1, "after prepare data") + AssertAssociationCount(t, user2, "Manager", 1, "after prepare data") + + // Clear + if err := DB.Model(&user2).Association("Company").Clear(); err != nil { + t.Errorf("Error happened when clear Company, got %v", err) + } + + if err := DB.Model(&user2).Association("Manager").Clear(); err != nil { + t.Errorf("Error happened when clear Manager, got %v", err) + } + + AssertAssociationCount(t, user2, "Company", 0, "after clear") + AssertAssociationCount(t, user2, "Manager", 0, "after clear") +} + +func TestBelongsToAssociationForSlice(t *testing.T) { + var users = []User{ + *GetUser("slice-belongs-to-1", Config{Company: true, Manager: true}), + *GetUser("slice-belongs-to-2", Config{Company: true, Manager: false}), + *GetUser("slice-belongs-to-3", Config{Company: true, Manager: true}), + } + + DB.Create(&users) + + AssertAssociationCount(t, users, "Company", 3, "") + AssertAssociationCount(t, users, "Manager", 2, "") + + // Find + var companies []Company + if DB.Model(&users).Association("Company").Find(&companies); len(companies) != 3 { + t.Errorf("companies count should be %v, but got %v", 3, len(companies)) + } + + var managers []User + if DB.Model(&users).Association("Manager").Find(&managers); len(managers) != 2 { + t.Errorf("managers count should be %v, but got %v", 2, len(managers)) + } + + // Append + DB.Model(&users).Association("Company").Append( + &Company{Name: "company-slice-append-1"}, + &Company{Name: "company-slice-append-2"}, + &Company{Name: "company-slice-append-3"}, + ) + + AssertAssociationCount(t, users, "Company", 3, "After Append") + + DB.Model(&users).Association("Manager").Append( + GetUser("manager-slice-belongs-to-1", Config{}), + GetUser("manager-slice-belongs-to-2", Config{}), + GetUser("manager-slice-belongs-to-3", Config{}), + ) + AssertAssociationCount(t, users, "Manager", 3, "After Append") + + if err := DB.Model(&users).Association("Manager").Append( + GetUser("manager-slice-belongs-to-test-1", Config{}), + ).Error; err == nil { + t.Errorf("unmatched length when update user's manager") + } + + // Replace -> same as append + + // Delete + if err := DB.Model(&users).Association("Company").Delete(&users[0].Company); err != nil { + t.Errorf("no error should happend when deleting company, but got %v", err) + } + + if users[0].CompanyID != nil || users[0].Company.ID != 0 { + t.Errorf("users[0]'s company should be deleted'") + } + + AssertAssociationCount(t, users, "Company", 2, "After Delete") + + // Clear + DB.Model(&users).Association("Company").Clear() + AssertAssociationCount(t, users, "Company", 0, "After Clear") + + DB.Model(&users).Association("Manager").Clear() + AssertAssociationCount(t, users, "Manager", 0, "After Clear") + + // shared company + company := Company{Name: "shared"} + if err := DB.Model(&users[0]).Association("Company").Append(&company); err != nil { + t.Errorf("Error happened when append company to user, got %v", err) + } + + if err := DB.Model(&users[1]).Association("Company").Append(&company); err != nil { + t.Errorf("Error happened when append company to user, got %v", err) + } + + if users[0].CompanyID == nil || users[1].CompanyID == nil || *users[0].CompanyID != *users[1].CompanyID { + t.Errorf("user's company id should exists and equal, but its: %v, %v", users[0].CompanyID, users[1].CompanyID) + } + + DB.Model(&users[0]).Association("Company").Delete(&company) + AssertAssociationCount(t, users[0], "Company", 0, "After Delete") + AssertAssociationCount(t, users[1], "Company", 1, "After other user Delete") +} diff --git a/tests/associations_has_many_test.go b/tests/associations_has_many_test.go new file mode 100644 index 00000000..2269d701 --- /dev/null +++ b/tests/associations_has_many_test.go @@ -0,0 +1,456 @@ +package tests_test + +import ( + "testing" + + . "github.com/jinzhu/gorm/tests" +) + +func TestHasManyAssociation(t *testing.T) { + var user = *GetUser("hasmany", Config{Pets: 2}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + CheckUser(t, user, user) + + // Find + var user2 User + DB.Find(&user2, "id = ?", user.ID) + DB.Model(&user2).Association("Pets").Find(&user2.Pets) + CheckUser(t, user2, user) + + // Count + AssertAssociationCount(t, user, "Pets", 2, "") + + // Append + var pet = Pet{Name: "pet-has-many-append"} + + if err := DB.Model(&user2).Association("Pets").Append(&pet); err != nil { + t.Fatalf("Error happened when append account, got %v", err) + } + + if pet.ID == 0 { + t.Fatalf("Pet's ID should be created") + } + + user.Pets = append(user.Pets, &pet) + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Pets", 3, "AfterAppend") + + var pets = []Pet{{Name: "pet-has-many-append-1-1"}, {Name: "pet-has-many-append-1-1"}} + + if err := DB.Model(&user2).Association("Pets").Append(&pets); err != nil { + t.Fatalf("Error happened when append pet, got %v", err) + } + + for _, pet := range pets { + var pet = pet + if pet.ID == 0 { + t.Fatalf("Pet's ID should be created") + } + + user.Pets = append(user.Pets, &pet) + } + + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Pets", 5, "AfterAppendSlice") + + // Replace + var pet2 = Pet{Name: "pet-has-many-replace"} + + if err := DB.Model(&user2).Association("Pets").Replace(&pet2); err != nil { + t.Fatalf("Error happened when append pet, got %v", err) + } + + if pet2.ID == 0 { + t.Fatalf("pet2's ID should be created") + } + + user.Pets = []*Pet{&pet2} + CheckUser(t, user2, user) + + AssertAssociationCount(t, user2, "Pets", 1, "AfterReplace") + + // Delete + if err := DB.Model(&user2).Association("Pets").Delete(&Pet{}); err != nil { + t.Fatalf("Error happened when delete pet, got %v", err) + } + AssertAssociationCount(t, user2, "Pets", 1, "after delete non-existing data") + + if err := DB.Model(&user2).Association("Pets").Delete(&pet2); err != nil { + t.Fatalf("Error happened when delete Pets, got %v", err) + } + AssertAssociationCount(t, user2, "Pets", 0, "after delete") + + // Prepare Data for Clear + if err := DB.Model(&user2).Association("Pets").Append(&pet); err != nil { + t.Fatalf("Error happened when append Pets, got %v", err) + } + + AssertAssociationCount(t, user2, "Pets", 1, "after prepare data") + + // Clear + if err := DB.Model(&user2).Association("Pets").Clear(); err != nil { + t.Errorf("Error happened when clear Pets, got %v", err) + } + + AssertAssociationCount(t, user2, "Pets", 0, "after clear") +} + +func TestSingleTableHasManyAssociation(t *testing.T) { + var user = *GetUser("hasmany", Config{Team: 2}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + CheckUser(t, user, user) + + // Find + var user2 User + DB.Find(&user2, "id = ?", user.ID) + DB.Model(&user2).Association("Team").Find(&user2.Team) + CheckUser(t, user2, user) + + // Count + AssertAssociationCount(t, user, "Team", 2, "") + + // Append + var team = *GetUser("team", Config{}) + + if err := DB.Model(&user2).Association("Team").Append(&team); err != nil { + t.Fatalf("Error happened when append account, got %v", err) + } + + if team.ID == 0 { + t.Fatalf("Team's ID should be created") + } + + user.Team = append(user.Team, team) + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Team", 3, "AfterAppend") + + var teams = []User{*GetUser("team-append-1", Config{}), *GetUser("team-append-2", Config{})} + + if err := DB.Model(&user2).Association("Team").Append(&teams); err != nil { + t.Fatalf("Error happened when append team, got %v", err) + } + + for _, team := range teams { + var team = team + if team.ID == 0 { + t.Fatalf("Team's ID should be created") + } + + user.Team = append(user.Team, team) + } + + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Team", 5, "AfterAppendSlice") + + // Replace + var team2 = *GetUser("team-replace", Config{}) + + if err := DB.Model(&user2).Association("Team").Replace(&team2); err != nil { + t.Fatalf("Error happened when append team, got %v", err) + } + + if team2.ID == 0 { + t.Fatalf("team2's ID should be created") + } + + user.Team = []User{team2} + CheckUser(t, user2, user) + + AssertAssociationCount(t, user2, "Team", 1, "AfterReplace") + + // Delete + if err := DB.Model(&user2).Association("Team").Delete(&User{}); err != nil { + t.Fatalf("Error happened when delete team, got %v", err) + } + AssertAssociationCount(t, user2, "Team", 1, "after delete non-existing data") + + if err := DB.Model(&user2).Association("Team").Delete(&team2); err != nil { + t.Fatalf("Error happened when delete Team, got %v", err) + } + AssertAssociationCount(t, user2, "Team", 0, "after delete") + + // Prepare Data for Clear + if err := DB.Model(&user2).Association("Team").Append(&team); err != nil { + t.Fatalf("Error happened when append Team, got %v", err) + } + + AssertAssociationCount(t, user2, "Team", 1, "after prepare data") + + // Clear + if err := DB.Model(&user2).Association("Team").Clear(); err != nil { + t.Errorf("Error happened when clear Team, got %v", err) + } + + AssertAssociationCount(t, user2, "Team", 0, "after clear") +} + +func TestHasManyAssociationForSlice(t *testing.T) { + var users = []User{ + *GetUser("slice-hasmany-1", Config{Pets: 2}), + *GetUser("slice-hasmany-2", Config{Pets: 0}), + *GetUser("slice-hasmany-3", Config{Pets: 4}), + } + + DB.Create(&users) + + // Count + AssertAssociationCount(t, users, "Pets", 6, "") + + // Find + var pets []Pet + if DB.Model(&users).Association("Pets").Find(&pets); len(pets) != 6 { + t.Errorf("pets count should be %v, but got %v", 6, len(pets)) + } + + // Append + DB.Model(&users).Association("Pets").Append( + &Pet{Name: "pet-slice-append-1"}, + []*Pet{{Name: "pet-slice-append-2-1"}, {Name: "pet-slice-append-2-2"}}, + &Pet{Name: "pet-slice-append-3"}, + ) + + AssertAssociationCount(t, users, "Pets", 10, "After Append") + + // Replace -> same as append + DB.Model(&users).Association("Pets").Replace( + []*Pet{{Name: "pet-slice-replace-1-1"}, {Name: "pet-slice-replace-1-2"}}, + []*Pet{{Name: "pet-slice-replace-2-1"}, {Name: "pet-slice-replace-2-2"}}, + &Pet{Name: "pet-slice-replace-3"}, + ) + + AssertAssociationCount(t, users, "Pets", 5, "After Append") + + // Delete + if err := DB.Model(&users).Association("Pets").Delete(&users[2].Pets); err != nil { + t.Errorf("no error should happend when deleting pet, but got %v", err) + } + + AssertAssociationCount(t, users, "Pets", 4, "after delete") + + if err := DB.Model(&users).Association("Pets").Delete(users[0].Pets[0], users[1].Pets[1]); err != nil { + t.Errorf("no error should happend when deleting pet, but got %v", err) + } + + AssertAssociationCount(t, users, "Pets", 2, "after delete") + + // Clear + DB.Model(&users).Association("Pets").Clear() + AssertAssociationCount(t, users, "Pets", 0, "After Clear") +} + +func TestSingleTableHasManyAssociationForSlice(t *testing.T) { + var users = []User{ + *GetUser("slice-hasmany-1", Config{Team: 2}), + *GetUser("slice-hasmany-2", Config{Team: 0}), + *GetUser("slice-hasmany-3", Config{Team: 4}), + } + + if err := DB.Create(&users).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + // Count + AssertAssociationCount(t, users, "Team", 6, "") + + // Find + var teams []User + if DB.Model(&users).Association("Team").Find(&teams); len(teams) != 6 { + t.Errorf("teams count should be %v, but got %v", 6, len(teams)) + } + + // Append + DB.Model(&users).Association("Team").Append( + &User{Name: "pet-slice-append-1"}, + []*User{{Name: "pet-slice-append-2-1"}, {Name: "pet-slice-append-2-2"}}, + &User{Name: "pet-slice-append-3"}, + ) + + AssertAssociationCount(t, users, "Team", 10, "After Append") + + // Replace -> same as append + DB.Model(&users).Association("Team").Replace( + []*User{{Name: "pet-slice-replace-1-1"}, {Name: "pet-slice-replace-1-2"}}, + []*User{{Name: "pet-slice-replace-2-1"}, {Name: "pet-slice-replace-2-2"}}, + &User{Name: "pet-slice-replace-3"}, + ) + + AssertAssociationCount(t, users, "Team", 5, "After Append") + + // Delete + if err := DB.Model(&users).Association("Team").Delete(&users[2].Team); err != nil { + t.Errorf("no error should happend when deleting pet, but got %v", err) + } + + AssertAssociationCount(t, users, "Team", 4, "after delete") + + if err := DB.Model(&users).Association("Team").Delete(users[0].Team[0], users[1].Team[1]); err != nil { + t.Errorf("no error should happend when deleting pet, but got %v", err) + } + + AssertAssociationCount(t, users, "Team", 2, "after delete") + + // Clear + DB.Model(&users).Association("Team").Clear() + AssertAssociationCount(t, users, "Team", 0, "After Clear") +} + +func TestPolymorphicHasManyAssociation(t *testing.T) { + var user = *GetUser("hasmany", Config{Toys: 2}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + CheckUser(t, user, user) + + // Find + var user2 User + DB.Find(&user2, "id = ?", user.ID) + DB.Model(&user2).Association("Toys").Find(&user2.Toys) + CheckUser(t, user2, user) + + // Count + AssertAssociationCount(t, user, "Toys", 2, "") + + // Append + var toy = Toy{Name: "toy-has-many-append"} + + if err := DB.Model(&user2).Association("Toys").Append(&toy); err != nil { + t.Fatalf("Error happened when append account, got %v", err) + } + + if toy.ID == 0 { + t.Fatalf("Toy's ID should be created") + } + + user.Toys = append(user.Toys, toy) + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Toys", 3, "AfterAppend") + + var toys = []Toy{{Name: "toy-has-many-append-1-1"}, {Name: "toy-has-many-append-1-1"}} + + if err := DB.Model(&user2).Association("Toys").Append(&toys); err != nil { + t.Fatalf("Error happened when append toy, got %v", err) + } + + for _, toy := range toys { + var toy = toy + if toy.ID == 0 { + t.Fatalf("Toy's ID should be created") + } + + user.Toys = append(user.Toys, toy) + } + + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Toys", 5, "AfterAppendSlice") + + // Replace + var toy2 = Toy{Name: "toy-has-many-replace"} + + if err := DB.Model(&user2).Association("Toys").Replace(&toy2); err != nil { + t.Fatalf("Error happened when append toy, got %v", err) + } + + if toy2.ID == 0 { + t.Fatalf("toy2's ID should be created") + } + + user.Toys = []Toy{toy2} + CheckUser(t, user2, user) + + AssertAssociationCount(t, user2, "Toys", 1, "AfterReplace") + + // Delete + if err := DB.Model(&user2).Association("Toys").Delete(&Toy{}); err != nil { + t.Fatalf("Error happened when delete toy, got %v", err) + } + AssertAssociationCount(t, user2, "Toys", 1, "after delete non-existing data") + + if err := DB.Model(&user2).Association("Toys").Delete(&toy2); err != nil { + t.Fatalf("Error happened when delete Toys, got %v", err) + } + AssertAssociationCount(t, user2, "Toys", 0, "after delete") + + // Prepare Data for Clear + if err := DB.Model(&user2).Association("Toys").Append(&toy); err != nil { + t.Fatalf("Error happened when append Toys, got %v", err) + } + + AssertAssociationCount(t, user2, "Toys", 1, "after prepare data") + + // Clear + if err := DB.Model(&user2).Association("Toys").Clear(); err != nil { + t.Errorf("Error happened when clear Toys, got %v", err) + } + + AssertAssociationCount(t, user2, "Toys", 0, "after clear") +} + +func TestPolymorphicHasManyAssociationForSlice(t *testing.T) { + var users = []User{ + *GetUser("slice-hasmany-1", Config{Toys: 2}), + *GetUser("slice-hasmany-2", Config{Toys: 0}), + *GetUser("slice-hasmany-3", Config{Toys: 4}), + } + + DB.Create(&users) + + // Count + AssertAssociationCount(t, users, "Toys", 6, "") + + // Find + var toys []Toy + if DB.Model(&users).Association("Toys").Find(&toys); len(toys) != 6 { + t.Errorf("toys count should be %v, but got %v", 6, len(toys)) + } + + // Append + DB.Model(&users).Association("Toys").Append( + &Toy{Name: "toy-slice-append-1"}, + []Toy{{Name: "toy-slice-append-2-1"}, {Name: "toy-slice-append-2-2"}}, + &Toy{Name: "toy-slice-append-3"}, + ) + + AssertAssociationCount(t, users, "Toys", 10, "After Append") + + // Replace -> same as append + DB.Model(&users).Association("Toys").Replace( + []*Toy{{Name: "toy-slice-replace-1-1"}, {Name: "toy-slice-replace-1-2"}}, + []*Toy{{Name: "toy-slice-replace-2-1"}, {Name: "toy-slice-replace-2-2"}}, + &Toy{Name: "toy-slice-replace-3"}, + ) + + AssertAssociationCount(t, users, "Toys", 5, "After Append") + + // Delete + if err := DB.Model(&users).Association("Toys").Delete(&users[2].Toys); err != nil { + t.Errorf("no error should happend when deleting toy, but got %v", err) + } + + AssertAssociationCount(t, users, "Toys", 4, "after delete") + + if err := DB.Model(&users).Association("Toys").Delete(users[0].Toys[0], users[1].Toys[1]); err != nil { + t.Errorf("no error should happend when deleting toy, but got %v", err) + } + + AssertAssociationCount(t, users, "Toys", 2, "after delete") + + // Clear + DB.Model(&users).Association("Toys").Clear() + AssertAssociationCount(t, users, "Toys", 0, "After Clear") +} diff --git a/tests/associations_has_one_test.go b/tests/associations_has_one_test.go new file mode 100644 index 00000000..a863cb36 --- /dev/null +++ b/tests/associations_has_one_test.go @@ -0,0 +1,241 @@ +package tests_test + +import ( + "testing" + + . "github.com/jinzhu/gorm/tests" +) + +func TestHasOneAssociation(t *testing.T) { + var user = *GetUser("hasone", Config{Account: true}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + CheckUser(t, user, user) + + // Find + var user2 User + DB.Find(&user2, "id = ?", user.ID) + DB.Model(&user2).Association("Account").Find(&user2.Account) + CheckUser(t, user2, user) + + // Count + AssertAssociationCount(t, user, "Account", 1, "") + + // Append + var account = Account{Number: "account-has-one-append"} + + if err := DB.Model(&user2).Association("Account").Append(&account); err != nil { + t.Fatalf("Error happened when append account, got %v", err) + } + + if account.ID == 0 { + t.Fatalf("Account's ID should be created") + } + + user.Account = account + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Account", 1, "AfterAppend") + + // Replace + var account2 = Account{Number: "account-has-one-replace"} + + if err := DB.Model(&user2).Association("Account").Replace(&account2); err != nil { + t.Fatalf("Error happened when append Account, got %v", err) + } + + if account2.ID == 0 { + t.Fatalf("account2's ID should be created") + } + + user.Account = account2 + CheckUser(t, user2, user) + + AssertAssociationCount(t, user2, "Account", 1, "AfterReplace") + + // Delete + if err := DB.Model(&user2).Association("Account").Delete(&Account{}); err != nil { + t.Fatalf("Error happened when delete account, got %v", err) + } + AssertAssociationCount(t, user2, "Account", 1, "after delete non-existing data") + + if err := DB.Model(&user2).Association("Account").Delete(&account2); err != nil { + t.Fatalf("Error happened when delete Account, got %v", err) + } + AssertAssociationCount(t, user2, "Account", 0, "after delete") + + // Prepare Data for Clear + if err := DB.Model(&user2).Association("Account").Append(&account); err != nil { + t.Fatalf("Error happened when append Account, got %v", err) + } + + AssertAssociationCount(t, user2, "Account", 1, "after prepare data") + + // Clear + if err := DB.Model(&user2).Association("Account").Clear(); err != nil { + t.Errorf("Error happened when clear Account, got %v", err) + } + + AssertAssociationCount(t, user2, "Account", 0, "after clear") +} + +func TestHasOneAssociationForSlice(t *testing.T) { + var users = []User{ + *GetUser("slice-hasone-1", Config{Account: true}), + *GetUser("slice-hasone-2", Config{Account: false}), + *GetUser("slice-hasone-3", Config{Account: true}), + } + + DB.Create(&users) + + // Count + AssertAssociationCount(t, users, "Account", 2, "") + + // Find + var accounts []Account + if DB.Model(&users).Association("Account").Find(&accounts); len(accounts) != 2 { + t.Errorf("accounts count should be %v, but got %v", 3, len(accounts)) + } + + // Append + DB.Model(&users).Association("Account").Append( + &Account{Number: "account-slice-append-1"}, + &Account{Number: "account-slice-append-2"}, + &Account{Number: "account-slice-append-3"}, + ) + + AssertAssociationCount(t, users, "Account", 3, "After Append") + + // Replace -> same as append + + // Delete + if err := DB.Model(&users).Association("Account").Delete(&users[0].Account); err != nil { + t.Errorf("no error should happend when deleting account, but got %v", err) + } + + AssertAssociationCount(t, users, "Account", 2, "after delete") + + // Clear + DB.Model(&users).Association("Account").Clear() + AssertAssociationCount(t, users, "Account", 0, "After Clear") +} + +func TestPolymorphicHasOneAssociation(t *testing.T) { + var pet = Pet{Name: "hasone", Toy: Toy{Name: "toy-has-one"}} + + if err := DB.Create(&pet).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + CheckPet(t, pet, pet) + + // Find + var pet2 Pet + DB.Find(&pet2, "id = ?", pet.ID) + DB.Model(&pet2).Association("Toy").Find(&pet2.Toy) + CheckPet(t, pet2, pet) + + // Count + AssertAssociationCount(t, pet, "Toy", 1, "") + + // Append + var toy = Toy{Name: "toy-has-one-append"} + + if err := DB.Model(&pet2).Association("Toy").Append(&toy); err != nil { + t.Fatalf("Error happened when append toy, got %v", err) + } + + if toy.ID == 0 { + t.Fatalf("Toy's ID should be created") + } + + pet.Toy = toy + CheckPet(t, pet2, pet) + + AssertAssociationCount(t, pet, "Toy", 1, "AfterAppend") + + // Replace + var toy2 = Toy{Name: "toy-has-one-replace"} + + if err := DB.Model(&pet2).Association("Toy").Replace(&toy2); err != nil { + t.Fatalf("Error happened when append Toy, got %v", err) + } + + if toy2.ID == 0 { + t.Fatalf("toy2's ID should be created") + } + + pet.Toy = toy2 + CheckPet(t, pet2, pet) + + AssertAssociationCount(t, pet2, "Toy", 1, "AfterReplace") + + // Delete + if err := DB.Model(&pet2).Association("Toy").Delete(&Toy{}); err != nil { + t.Fatalf("Error happened when delete toy, got %v", err) + } + AssertAssociationCount(t, pet2, "Toy", 1, "after delete non-existing data") + + if err := DB.Model(&pet2).Association("Toy").Delete(&toy2); err != nil { + t.Fatalf("Error happened when delete Toy, got %v", err) + } + AssertAssociationCount(t, pet2, "Toy", 0, "after delete") + + // Prepare Data for Clear + if err := DB.Model(&pet2).Association("Toy").Append(&toy); err != nil { + t.Fatalf("Error happened when append Toy, got %v", err) + } + + AssertAssociationCount(t, pet2, "Toy", 1, "after prepare data") + + // Clear + if err := DB.Model(&pet2).Association("Toy").Clear(); err != nil { + t.Errorf("Error happened when clear Toy, got %v", err) + } + + AssertAssociationCount(t, pet2, "Toy", 0, "after clear") +} + +func TestPolymorphicHasOneAssociationForSlice(t *testing.T) { + var pets = []Pet{ + {Name: "hasone-1", Toy: Toy{Name: "toy-has-one"}}, + {Name: "hasone-2", Toy: Toy{}}, + {Name: "hasone-3", Toy: Toy{Name: "toy-has-one"}}, + } + + DB.Create(&pets) + + // Count + AssertAssociationCount(t, pets, "Toy", 2, "") + + // Find + var toys []Toy + if DB.Model(&pets).Association("Toy").Find(&toys); len(toys) != 2 { + t.Errorf("toys count should be %v, but got %v", 3, len(toys)) + } + + // Append + DB.Model(&pets).Association("Toy").Append( + &Toy{Name: "toy-slice-append-1"}, + &Toy{Name: "toy-slice-append-2"}, + &Toy{Name: "toy-slice-append-3"}, + ) + + AssertAssociationCount(t, pets, "Toy", 3, "After Append") + + // Replace -> same as append + + // Delete + if err := DB.Model(&pets).Association("Toy").Delete(&pets[0].Toy); err != nil { + t.Errorf("no error should happend when deleting toy, but got %v", err) + } + + AssertAssociationCount(t, pets, "Toy", 2, "after delete") + + // Clear + DB.Model(&pets).Association("Toy").Clear() + AssertAssociationCount(t, pets, "Toy", 0, "After Clear") +} diff --git a/tests/associations_many2many_test.go b/tests/associations_many2many_test.go new file mode 100644 index 00000000..a2db9675 --- /dev/null +++ b/tests/associations_many2many_test.go @@ -0,0 +1,299 @@ +package tests_test + +import ( + "testing" + + . "github.com/jinzhu/gorm/tests" +) + +func TestMany2ManyAssociation(t *testing.T) { + var user = *GetUser("many2many", Config{Languages: 2}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + CheckUser(t, user, user) + + // Find + var user2 User + DB.Find(&user2, "id = ?", user.ID) + DB.Model(&user2).Association("Languages").Find(&user2.Languages) + + CheckUser(t, user2, user) + + // Count + AssertAssociationCount(t, user, "Languages", 2, "") + + // Append + var language = Language{Code: "language-many2many-append", Name: "language-many2many-append"} + DB.Create(&language) + + if err := DB.Model(&user2).Association("Languages").Append(&language); err != nil { + t.Fatalf("Error happened when append account, got %v", err) + } + + user.Languages = append(user.Languages, language) + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Languages", 3, "AfterAppend") + + var languages = []Language{ + {Code: "language-many2many-append-1-1", Name: "language-many2many-append-1-1"}, + {Code: "language-many2many-append-2-1", Name: "language-many2many-append-2-1"}, + } + DB.Create(&languages) + + if err := DB.Model(&user2).Association("Languages").Append(&languages); err != nil { + t.Fatalf("Error happened when append language, got %v", err) + } + + user.Languages = append(user.Languages, languages...) + + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Languages", 5, "AfterAppendSlice") + + // Replace + var language2 = Language{Code: "language-many2many-replace", Name: "language-many2many-replace"} + DB.Create(&language2) + + if err := DB.Model(&user2).Association("Languages").Replace(&language2); err != nil { + t.Fatalf("Error happened when append language, got %v", err) + } + + user.Languages = []Language{language2} + CheckUser(t, user2, user) + + AssertAssociationCount(t, user2, "Languages", 1, "AfterReplace") + + // Delete + if err := DB.Model(&user2).Association("Languages").Delete(&Language{}); err != nil { + t.Fatalf("Error happened when delete language, got %v", err) + } + AssertAssociationCount(t, user2, "Languages", 1, "after delete non-existing data") + + if err := DB.Model(&user2).Association("Languages").Delete(&language2); err != nil { + t.Fatalf("Error happened when delete Languages, got %v", err) + } + AssertAssociationCount(t, user2, "Languages", 0, "after delete") + + // Prepare Data for Clear + if err := DB.Model(&user2).Association("Languages").Append(&language); err != nil { + t.Fatalf("Error happened when append Languages, got %v", err) + } + + AssertAssociationCount(t, user2, "Languages", 1, "after prepare data") + + // Clear + if err := DB.Model(&user2).Association("Languages").Clear(); err != nil { + t.Errorf("Error happened when clear Languages, got %v", err) + } + + AssertAssociationCount(t, user2, "Languages", 0, "after clear") +} + +func TestMany2ManyAssociationForSlice(t *testing.T) { + var users = []User{ + *GetUser("slice-many2many-1", Config{Languages: 2}), + *GetUser("slice-many2many-2", Config{Languages: 0}), + *GetUser("slice-many2many-3", Config{Languages: 4}), + } + + DB.Create(&users) + + // Count + AssertAssociationCount(t, users, "Languages", 6, "") + + // Find + var languages []Language + if DB.Model(&users).Association("Languages").Find(&languages); len(languages) != 6 { + t.Errorf("languages count should be %v, but got %v", 6, len(languages)) + } + + // Append + var languages1 = []Language{ + {Code: "language-many2many-append-1", Name: "language-many2many-append-1"}, + } + var languages2 = []Language{} + var languages3 = []Language{ + {Code: "language-many2many-append-3-1", Name: "language-many2many-append-3-1"}, + {Code: "language-many2many-append-3-2", Name: "language-many2many-append-3-2"}, + } + DB.Create(&languages1) + DB.Create(&languages3) + + DB.Model(&users).Association("Languages").Append(&languages1, &languages2, &languages3) + + AssertAssociationCount(t, users, "Languages", 9, "After Append") + + languages2_1 := []*Language{ + {Code: "language-slice-replace-1-1", Name: "language-slice-replace-1-1"}, + {Code: "language-slice-replace-1-2", Name: "language-slice-replace-1-2"}, + } + languages2_2 := []*Language{ + {Code: "language-slice-replace-2-1", Name: "language-slice-replace-2-1"}, + {Code: "language-slice-replace-2-2", Name: "language-slice-replace-2-2"}, + } + languages2_3 := &Language{Code: "language-slice-replace-3", Name: "language-slice-replace-3"} + DB.Create(&languages2_1) + DB.Create(&languages2_2) + DB.Create(&languages2_3) + + // Replace + DB.Model(&users).Association("Languages").Replace(&languages2_1, &languages2_2, languages2_3) + + AssertAssociationCount(t, users, "Languages", 5, "After Replace") + + // Delete + if err := DB.Model(&users).Association("Languages").Delete(&users[2].Languages); err != nil { + t.Errorf("no error should happend when deleting language, but got %v", err) + } + + AssertAssociationCount(t, users, "Languages", 4, "after delete") + + if err := DB.Model(&users).Association("Languages").Delete(users[0].Languages[0], users[1].Languages[1]); err != nil { + t.Errorf("no error should happend when deleting language, but got %v", err) + } + + AssertAssociationCount(t, users, "Languages", 2, "after delete") + + // Clear + DB.Model(&users).Association("Languages").Clear() + AssertAssociationCount(t, users, "Languages", 0, "After Clear") +} + +func TestSingleTableMany2ManyAssociation(t *testing.T) { + var user = *GetUser("many2many", Config{Friends: 2}) + + if err := DB.Create(&user).Error; err != nil { + t.Fatalf("errors happened when create: %v", err) + } + + CheckUser(t, user, user) + + // Find + var user2 User + DB.Find(&user2, "id = ?", user.ID) + DB.Model(&user2).Association("Friends").Find(&user2.Friends) + + CheckUser(t, user2, user) + + // Count + AssertAssociationCount(t, user, "Friends", 2, "") + + // Append + var friend = *GetUser("friend", Config{}) + + if err := DB.Model(&user2).Association("Friends").Append(&friend); err != nil { + t.Fatalf("Error happened when append account, got %v", err) + } + + user.Friends = append(user.Friends, &friend) + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Friends", 3, "AfterAppend") + + var friends = []*User{GetUser("friend-append-1", Config{}), GetUser("friend-append-2", Config{})} + + if err := DB.Model(&user2).Association("Friends").Append(&friends); err != nil { + t.Fatalf("Error happened when append friend, got %v", err) + } + + user.Friends = append(user.Friends, friends...) + + CheckUser(t, user2, user) + + AssertAssociationCount(t, user, "Friends", 5, "AfterAppendSlice") + + // Replace + var friend2 = *GetUser("friend-replace-2", Config{}) + + if err := DB.Model(&user2).Association("Friends").Replace(&friend2); err != nil { + t.Fatalf("Error happened when append friend, got %v", err) + } + + user.Friends = []*User{&friend2} + CheckUser(t, user2, user) + + AssertAssociationCount(t, user2, "Friends", 1, "AfterReplace") + + // Delete + if err := DB.Model(&user2).Association("Friends").Delete(&User{}); err != nil { + t.Fatalf("Error happened when delete friend, got %v", err) + } + AssertAssociationCount(t, user2, "Friends", 1, "after delete non-existing data") + + if err := DB.Model(&user2).Association("Friends").Delete(&friend2); err != nil { + t.Fatalf("Error happened when delete Friends, got %v", err) + } + AssertAssociationCount(t, user2, "Friends", 0, "after delete") + + // Prepare Data for Clear + if err := DB.Model(&user2).Association("Friends").Append(&friend); err != nil { + t.Fatalf("Error happened when append Friends, got %v", err) + } + + AssertAssociationCount(t, user2, "Friends", 1, "after prepare data") + + // Clear + if err := DB.Model(&user2).Association("Friends").Clear(); err != nil { + t.Errorf("Error happened when clear Friends, got %v", err) + } + + AssertAssociationCount(t, user2, "Friends", 0, "after clear") +} + +func TestSingleTableMany2ManyAssociationForSlice(t *testing.T) { + var users = []User{ + *GetUser("slice-many2many-1", Config{Team: 2}), + *GetUser("slice-many2many-2", Config{Team: 0}), + *GetUser("slice-many2many-3", Config{Team: 4}), + } + + DB.Create(&users) + + // Count + AssertAssociationCount(t, users, "Team", 6, "") + + // Find + var teams []User + if DB.Model(&users).Association("Team").Find(&teams); len(teams) != 6 { + t.Errorf("teams count should be %v, but got %v", 6, len(teams)) + } + + // Append + var teams1 = []User{*GetUser("friend-append-1", Config{})} + var teams2 = []User{} + var teams3 = []*User{GetUser("friend-append-3-1", Config{}), GetUser("friend-append-3-2", Config{})} + + DB.Model(&users).Association("Team").Append(&teams1, &teams2, &teams3) + + AssertAssociationCount(t, users, "Team", 9, "After Append") + + var teams2_1 = []User{*GetUser("friend-replace-1", Config{}), *GetUser("friend-replace-2", Config{})} + var teams2_2 = []User{*GetUser("friend-replace-2-1", Config{}), *GetUser("friend-replace-2-2", Config{})} + var teams2_3 = GetUser("friend-replace-3-1", Config{}) + + // Replace + DB.Model(&users).Association("Team").Replace(&teams2_1, &teams2_2, teams2_3) + + AssertAssociationCount(t, users, "Team", 5, "After Replace") + + // Delete + if err := DB.Model(&users).Association("Team").Delete(&users[2].Team); err != nil { + t.Errorf("no error should happend when deleting team, but got %v", err) + } + + AssertAssociationCount(t, users, "Team", 4, "after delete") + + if err := DB.Model(&users).Association("Team").Delete(users[0].Team[0], users[1].Team[1]); err != nil { + t.Errorf("no error should happend when deleting team, but got %v", err) + } + + AssertAssociationCount(t, users, "Team", 2, "after delete") + + // Clear + DB.Model(&users).Association("Team").Clear() + AssertAssociationCount(t, users, "Team", 0, "After Clear") +} diff --git a/tests/associations_test.go b/tests/associations_test.go index a102fa54..89bbe142 100644 --- a/tests/associations_test.go +++ b/tests/associations_test.go @@ -25,1186 +25,9 @@ func AssertAssociationCount(t *testing.T, data interface{}, name string, result } } -func TestBelongsToAssociation(t *testing.T) { - var user = *GetUser("belongs-to", Config{Company: true, Manager: true}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) +func TestInvalidAssociation(t *testing.T) { + var user = *GetUser("invalid", Config{Company: true, Manager: true}) + if err := DB.Model(&user).Association("Invalid").Find(&user.Company).Error; err == nil { + t.Errorf("should return errors for invalid association, but got nil") } - - CheckUser(t, user, user) - - // Find - var user2 User - DB.Find(&user2, "id = ?", user.ID) - DB.Model(&user2).Association("Company").Find(&user2.Company) - user2.Manager = &User{} - DB.Model(&user2).Association("Manager").Find(user2.Manager) - CheckUser(t, user2, user) - - // Count - AssertAssociationCount(t, user, "Company", 1, "") - AssertAssociationCount(t, user, "Manager", 1, "") - - // Append - var company = Company{Name: "company-belongs-to-append"} - var manager = GetUser("manager-belongs-to-append", Config{}) - - if err := DB.Model(&user2).Association("Company").Append(&company); err != nil { - t.Fatalf("Error happened when append Company, got %v", err) - } - - if company.ID == 0 { - t.Fatalf("Company's ID should be created") - } - - if err := DB.Model(&user2).Association("Manager").Append(manager); err != nil { - t.Fatalf("Error happened when append Manager, got %v", err) - } - - if manager.ID == 0 { - t.Fatalf("Manager's ID should be created") - } - - user.Company = company - user.Manager = manager - user.CompanyID = &company.ID - user.ManagerID = &manager.ID - CheckUser(t, user2, user) - - AssertAssociationCount(t, user2, "Company", 1, "AfterAppend") - AssertAssociationCount(t, user2, "Manager", 1, "AfterAppend") - - // Replace - var company2 = Company{Name: "company-belongs-to-replace"} - var manager2 = GetUser("manager-belongs-to-replace", Config{}) - - if err := DB.Model(&user2).Association("Company").Replace(&company2); err != nil { - t.Fatalf("Error happened when replace Company, got %v", err) - } - - if company2.ID == 0 { - t.Fatalf("Company's ID should be created") - } - - if err := DB.Model(&user2).Association("Manager").Replace(manager2); err != nil { - t.Fatalf("Error happened when replace Manager, got %v", err) - } - - if manager2.ID == 0 { - t.Fatalf("Manager's ID should be created") - } - - user.Company = company2 - user.Manager = manager2 - user.CompanyID = &company2.ID - user.ManagerID = &manager2.ID - CheckUser(t, user2, user) - - AssertAssociationCount(t, user2, "Company", 1, "AfterReplace") - AssertAssociationCount(t, user2, "Manager", 1, "AfterReplace") - - // Delete - if err := DB.Model(&user2).Association("Company").Delete(&Company{}); err != nil { - t.Fatalf("Error happened when delete Company, got %v", err) - } - AssertAssociationCount(t, user2, "Company", 1, "after delete non-existing data") - - if err := DB.Model(&user2).Association("Company").Delete(&company2); err != nil { - t.Fatalf("Error happened when delete Company, got %v", err) - } - AssertAssociationCount(t, user2, "Company", 0, "after delete") - - if err := DB.Model(&user2).Association("Manager").Delete(&User{}); err != nil { - t.Fatalf("Error happened when delete Manager, got %v", err) - } - AssertAssociationCount(t, user2, "Manager", 1, "after delete non-existing data") - - if err := DB.Model(&user2).Association("Manager").Delete(manager2); err != nil { - t.Fatalf("Error happened when delete Manager, got %v", err) - } - AssertAssociationCount(t, user2, "Manager", 0, "after delete") - - // Prepare Data for Clear - if err := DB.Model(&user2).Association("Company").Append(&company); err != nil { - t.Fatalf("Error happened when append Company, got %v", err) - } - - if err := DB.Model(&user2).Association("Manager").Append(manager); err != nil { - t.Fatalf("Error happened when append Manager, got %v", err) - } - - AssertAssociationCount(t, user2, "Company", 1, "after prepare data") - AssertAssociationCount(t, user2, "Manager", 1, "after prepare data") - - // Clear - if err := DB.Model(&user2).Association("Company").Clear(); err != nil { - t.Errorf("Error happened when clear Company, got %v", err) - } - - if err := DB.Model(&user2).Association("Manager").Clear(); err != nil { - t.Errorf("Error happened when clear Manager, got %v", err) - } - - AssertAssociationCount(t, user2, "Company", 0, "after clear") - AssertAssociationCount(t, user2, "Manager", 0, "after clear") -} - -func TestBelongsToAssociationForSlice(t *testing.T) { - var users = []User{ - *GetUser("slice-belongs-to-1", Config{Company: true, Manager: true}), - *GetUser("slice-belongs-to-2", Config{Company: true, Manager: false}), - *GetUser("slice-belongs-to-3", Config{Company: true, Manager: true}), - } - - DB.Create(&users) - - AssertAssociationCount(t, users, "Company", 3, "") - AssertAssociationCount(t, users, "Manager", 2, "") - - // Find - var companies []Company - if DB.Model(&users).Association("Company").Find(&companies); len(companies) != 3 { - t.Errorf("companies count should be %v, but got %v", 3, len(companies)) - } - - var managers []User - if DB.Model(&users).Association("Manager").Find(&managers); len(managers) != 2 { - t.Errorf("managers count should be %v, but got %v", 2, len(managers)) - } - - // Append - DB.Model(&users).Association("Company").Append( - &Company{Name: "company-slice-append-1"}, - &Company{Name: "company-slice-append-2"}, - &Company{Name: "company-slice-append-3"}, - ) - - AssertAssociationCount(t, users, "Company", 3, "After Append") - - DB.Model(&users).Association("Manager").Append( - GetUser("manager-slice-belongs-to-1", Config{}), - GetUser("manager-slice-belongs-to-2", Config{}), - GetUser("manager-slice-belongs-to-3", Config{}), - ) - AssertAssociationCount(t, users, "Manager", 3, "After Append") - - if err := DB.Model(&users).Association("Manager").Append( - GetUser("manager-slice-belongs-to-test-1", Config{}), - ).Error; err == nil { - t.Errorf("unmatched length when update user's manager") - } - - // Replace -> same as append - - // Delete - if err := DB.Model(&users).Association("Company").Delete(&users[0].Company); err != nil { - t.Errorf("no error should happend when deleting company, but got %v", err) - } - - if users[0].CompanyID != nil || users[0].Company.ID != 0 { - t.Errorf("users[0]'s company should be deleted'") - } - - AssertAssociationCount(t, users, "Company", 2, "After Delete") - - // Clear - DB.Model(&users).Association("Company").Clear() - AssertAssociationCount(t, users, "Company", 0, "After Clear") - - DB.Model(&users).Association("Manager").Clear() - AssertAssociationCount(t, users, "Manager", 0, "After Clear") - - // shared company - company := Company{Name: "shared"} - if err := DB.Model(&users[0]).Association("Company").Append(&company); err != nil { - t.Errorf("Error happened when append company to user, got %v", err) - } - - if err := DB.Model(&users[1]).Association("Company").Append(&company); err != nil { - t.Errorf("Error happened when append company to user, got %v", err) - } - - if users[0].CompanyID == nil || users[1].CompanyID == nil || *users[0].CompanyID != *users[1].CompanyID { - t.Errorf("user's company id should exists and equal, but its: %v, %v", users[0].CompanyID, users[1].CompanyID) - } - - DB.Model(&users[0]).Association("Company").Delete(&company) - AssertAssociationCount(t, users[0], "Company", 0, "After Delete") - AssertAssociationCount(t, users[1], "Company", 1, "After other user Delete") -} - -func TestHasOneAssociation(t *testing.T) { - var user = *GetUser("hasone", Config{Account: true}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - CheckUser(t, user, user) - - // Find - var user2 User - DB.Find(&user2, "id = ?", user.ID) - DB.Model(&user2).Association("Account").Find(&user2.Account) - CheckUser(t, user2, user) - - // Count - AssertAssociationCount(t, user, "Account", 1, "") - - // Append - var account = Account{Number: "account-has-one-append"} - - if err := DB.Model(&user2).Association("Account").Append(&account); err != nil { - t.Fatalf("Error happened when append account, got %v", err) - } - - if account.ID == 0 { - t.Fatalf("Account's ID should be created") - } - - user.Account = account - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Account", 1, "AfterAppend") - - // Replace - var account2 = Account{Number: "account-has-one-replace"} - - if err := DB.Model(&user2).Association("Account").Replace(&account2); err != nil { - t.Fatalf("Error happened when append Account, got %v", err) - } - - if account2.ID == 0 { - t.Fatalf("account2's ID should be created") - } - - user.Account = account2 - CheckUser(t, user2, user) - - AssertAssociationCount(t, user2, "Account", 1, "AfterReplace") - - // Delete - if err := DB.Model(&user2).Association("Account").Delete(&Account{}); err != nil { - t.Fatalf("Error happened when delete account, got %v", err) - } - AssertAssociationCount(t, user2, "Account", 1, "after delete non-existing data") - - if err := DB.Model(&user2).Association("Account").Delete(&account2); err != nil { - t.Fatalf("Error happened when delete Account, got %v", err) - } - AssertAssociationCount(t, user2, "Account", 0, "after delete") - - // Prepare Data for Clear - if err := DB.Model(&user2).Association("Account").Append(&account); err != nil { - t.Fatalf("Error happened when append Account, got %v", err) - } - - AssertAssociationCount(t, user2, "Account", 1, "after prepare data") - - // Clear - if err := DB.Model(&user2).Association("Account").Clear(); err != nil { - t.Errorf("Error happened when clear Account, got %v", err) - } - - AssertAssociationCount(t, user2, "Account", 0, "after clear") -} - -func TestHasOneAssociationForSlice(t *testing.T) { - var users = []User{ - *GetUser("slice-hasone-1", Config{Account: true}), - *GetUser("slice-hasone-2", Config{Account: false}), - *GetUser("slice-hasone-3", Config{Account: true}), - } - - DB.Create(&users) - - // Count - AssertAssociationCount(t, users, "Account", 2, "") - - // Find - var accounts []Account - if DB.Model(&users).Association("Account").Find(&accounts); len(accounts) != 2 { - t.Errorf("accounts count should be %v, but got %v", 3, len(accounts)) - } - - // Append - DB.Model(&users).Association("Account").Append( - &Account{Number: "account-slice-append-1"}, - &Account{Number: "account-slice-append-2"}, - &Account{Number: "account-slice-append-3"}, - ) - - AssertAssociationCount(t, users, "Account", 3, "After Append") - - // Replace -> same as append - - // Delete - if err := DB.Model(&users).Association("Account").Delete(&users[0].Account); err != nil { - t.Errorf("no error should happend when deleting account, but got %v", err) - } - - AssertAssociationCount(t, users, "Account", 2, "after delete") - - // Clear - DB.Model(&users).Association("Account").Clear() - AssertAssociationCount(t, users, "Account", 0, "After Clear") -} - -func TestPolymorphicHasOneAssociation(t *testing.T) { - var pet = Pet{Name: "hasone", Toy: Toy{Name: "toy-has-one"}} - - if err := DB.Create(&pet).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - CheckPet(t, pet, pet) - - // Find - var pet2 Pet - DB.Find(&pet2, "id = ?", pet.ID) - DB.Model(&pet2).Association("Toy").Find(&pet2.Toy) - CheckPet(t, pet2, pet) - - // Count - AssertAssociationCount(t, pet, "Toy", 1, "") - - // Append - var toy = Toy{Name: "toy-has-one-append"} - - if err := DB.Model(&pet2).Association("Toy").Append(&toy); err != nil { - t.Fatalf("Error happened when append toy, got %v", err) - } - - if toy.ID == 0 { - t.Fatalf("Toy's ID should be created") - } - - pet.Toy = toy - CheckPet(t, pet2, pet) - - AssertAssociationCount(t, pet, "Toy", 1, "AfterAppend") - - // Replace - var toy2 = Toy{Name: "toy-has-one-replace"} - - if err := DB.Model(&pet2).Association("Toy").Replace(&toy2); err != nil { - t.Fatalf("Error happened when append Toy, got %v", err) - } - - if toy2.ID == 0 { - t.Fatalf("toy2's ID should be created") - } - - pet.Toy = toy2 - CheckPet(t, pet2, pet) - - AssertAssociationCount(t, pet2, "Toy", 1, "AfterReplace") - - // Delete - if err := DB.Model(&pet2).Association("Toy").Delete(&Toy{}); err != nil { - t.Fatalf("Error happened when delete toy, got %v", err) - } - AssertAssociationCount(t, pet2, "Toy", 1, "after delete non-existing data") - - if err := DB.Model(&pet2).Association("Toy").Delete(&toy2); err != nil { - t.Fatalf("Error happened when delete Toy, got %v", err) - } - AssertAssociationCount(t, pet2, "Toy", 0, "after delete") - - // Prepare Data for Clear - if err := DB.Model(&pet2).Association("Toy").Append(&toy); err != nil { - t.Fatalf("Error happened when append Toy, got %v", err) - } - - AssertAssociationCount(t, pet2, "Toy", 1, "after prepare data") - - // Clear - if err := DB.Model(&pet2).Association("Toy").Clear(); err != nil { - t.Errorf("Error happened when clear Toy, got %v", err) - } - - AssertAssociationCount(t, pet2, "Toy", 0, "after clear") -} - -func TestPolymorphicHasOneAssociationForSlice(t *testing.T) { - var pets = []Pet{ - {Name: "hasone-1", Toy: Toy{Name: "toy-has-one"}}, - {Name: "hasone-2", Toy: Toy{}}, - {Name: "hasone-3", Toy: Toy{Name: "toy-has-one"}}, - } - - DB.Create(&pets) - - // Count - AssertAssociationCount(t, pets, "Toy", 2, "") - - // Find - var toys []Toy - if DB.Model(&pets).Association("Toy").Find(&toys); len(toys) != 2 { - t.Errorf("toys count should be %v, but got %v", 3, len(toys)) - } - - // Append - DB.Model(&pets).Association("Toy").Append( - &Toy{Name: "toy-slice-append-1"}, - &Toy{Name: "toy-slice-append-2"}, - &Toy{Name: "toy-slice-append-3"}, - ) - - AssertAssociationCount(t, pets, "Toy", 3, "After Append") - - // Replace -> same as append - - // Delete - if err := DB.Model(&pets).Association("Toy").Delete(&pets[0].Toy); err != nil { - t.Errorf("no error should happend when deleting toy, but got %v", err) - } - - AssertAssociationCount(t, pets, "Toy", 2, "after delete") - - // Clear - DB.Model(&pets).Association("Toy").Clear() - AssertAssociationCount(t, pets, "Toy", 0, "After Clear") -} - -func TestHasManyAssociation(t *testing.T) { - var user = *GetUser("hasmany", Config{Pets: 2}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - CheckUser(t, user, user) - - // Find - var user2 User - DB.Find(&user2, "id = ?", user.ID) - DB.Model(&user2).Association("Pets").Find(&user2.Pets) - CheckUser(t, user2, user) - - // Count - AssertAssociationCount(t, user, "Pets", 2, "") - - // Append - var pet = Pet{Name: "pet-has-many-append"} - - if err := DB.Model(&user2).Association("Pets").Append(&pet); err != nil { - t.Fatalf("Error happened when append account, got %v", err) - } - - if pet.ID == 0 { - t.Fatalf("Pet's ID should be created") - } - - user.Pets = append(user.Pets, &pet) - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Pets", 3, "AfterAppend") - - var pets = []Pet{{Name: "pet-has-many-append-1-1"}, {Name: "pet-has-many-append-1-1"}} - - if err := DB.Model(&user2).Association("Pets").Append(&pets); err != nil { - t.Fatalf("Error happened when append pet, got %v", err) - } - - for _, pet := range pets { - var pet = pet - if pet.ID == 0 { - t.Fatalf("Pet's ID should be created") - } - - user.Pets = append(user.Pets, &pet) - } - - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Pets", 5, "AfterAppendSlice") - - // Replace - var pet2 = Pet{Name: "pet-has-many-replace"} - - if err := DB.Model(&user2).Association("Pets").Replace(&pet2); err != nil { - t.Fatalf("Error happened when append pet, got %v", err) - } - - if pet2.ID == 0 { - t.Fatalf("pet2's ID should be created") - } - - user.Pets = []*Pet{&pet2} - CheckUser(t, user2, user) - - AssertAssociationCount(t, user2, "Pets", 1, "AfterReplace") - - // Delete - if err := DB.Model(&user2).Association("Pets").Delete(&Pet{}); err != nil { - t.Fatalf("Error happened when delete pet, got %v", err) - } - AssertAssociationCount(t, user2, "Pets", 1, "after delete non-existing data") - - if err := DB.Model(&user2).Association("Pets").Delete(&pet2); err != nil { - t.Fatalf("Error happened when delete Pets, got %v", err) - } - AssertAssociationCount(t, user2, "Pets", 0, "after delete") - - // Prepare Data for Clear - if err := DB.Model(&user2).Association("Pets").Append(&pet); err != nil { - t.Fatalf("Error happened when append Pets, got %v", err) - } - - AssertAssociationCount(t, user2, "Pets", 1, "after prepare data") - - // Clear - if err := DB.Model(&user2).Association("Pets").Clear(); err != nil { - t.Errorf("Error happened when clear Pets, got %v", err) - } - - AssertAssociationCount(t, user2, "Pets", 0, "after clear") -} - -func TestSingleTableHasManyAssociation(t *testing.T) { - var user = *GetUser("hasmany", Config{Team: 2}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - CheckUser(t, user, user) - - // Find - var user2 User - DB.Find(&user2, "id = ?", user.ID) - DB.Model(&user2).Association("Team").Find(&user2.Team) - CheckUser(t, user2, user) - - // Count - AssertAssociationCount(t, user, "Team", 2, "") - - // Append - var team = *GetUser("team", Config{}) - - if err := DB.Model(&user2).Association("Team").Append(&team); err != nil { - t.Fatalf("Error happened when append account, got %v", err) - } - - if team.ID == 0 { - t.Fatalf("Team's ID should be created") - } - - user.Team = append(user.Team, team) - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Team", 3, "AfterAppend") - - var teams = []User{*GetUser("team-append-1", Config{}), *GetUser("team-append-2", Config{})} - - if err := DB.Model(&user2).Association("Team").Append(&teams); err != nil { - t.Fatalf("Error happened when append team, got %v", err) - } - - for _, team := range teams { - var team = team - if team.ID == 0 { - t.Fatalf("Team's ID should be created") - } - - user.Team = append(user.Team, team) - } - - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Team", 5, "AfterAppendSlice") - - // Replace - var team2 = *GetUser("team-replace", Config{}) - - if err := DB.Model(&user2).Association("Team").Replace(&team2); err != nil { - t.Fatalf("Error happened when append team, got %v", err) - } - - if team2.ID == 0 { - t.Fatalf("team2's ID should be created") - } - - user.Team = []User{team2} - CheckUser(t, user2, user) - - AssertAssociationCount(t, user2, "Team", 1, "AfterReplace") - - // Delete - if err := DB.Model(&user2).Association("Team").Delete(&User{}); err != nil { - t.Fatalf("Error happened when delete team, got %v", err) - } - AssertAssociationCount(t, user2, "Team", 1, "after delete non-existing data") - - if err := DB.Model(&user2).Association("Team").Delete(&team2); err != nil { - t.Fatalf("Error happened when delete Team, got %v", err) - } - AssertAssociationCount(t, user2, "Team", 0, "after delete") - - // Prepare Data for Clear - if err := DB.Model(&user2).Association("Team").Append(&team); err != nil { - t.Fatalf("Error happened when append Team, got %v", err) - } - - AssertAssociationCount(t, user2, "Team", 1, "after prepare data") - - // Clear - if err := DB.Model(&user2).Association("Team").Clear(); err != nil { - t.Errorf("Error happened when clear Team, got %v", err) - } - - AssertAssociationCount(t, user2, "Team", 0, "after clear") -} - -func TestHasManyAssociationForSlice(t *testing.T) { - var users = []User{ - *GetUser("slice-hasmany-1", Config{Pets: 2}), - *GetUser("slice-hasmany-2", Config{Pets: 0}), - *GetUser("slice-hasmany-3", Config{Pets: 4}), - } - - DB.Create(&users) - - // Count - AssertAssociationCount(t, users, "Pets", 6, "") - - // Find - var pets []Pet - if DB.Model(&users).Association("Pets").Find(&pets); len(pets) != 6 { - t.Errorf("pets count should be %v, but got %v", 6, len(pets)) - } - - // Append - DB.Model(&users).Association("Pets").Append( - &Pet{Name: "pet-slice-append-1"}, - []*Pet{{Name: "pet-slice-append-2-1"}, {Name: "pet-slice-append-2-2"}}, - &Pet{Name: "pet-slice-append-3"}, - ) - - AssertAssociationCount(t, users, "Pets", 10, "After Append") - - // Replace -> same as append - DB.Model(&users).Association("Pets").Replace( - []*Pet{{Name: "pet-slice-replace-1-1"}, {Name: "pet-slice-replace-1-2"}}, - []*Pet{{Name: "pet-slice-replace-2-1"}, {Name: "pet-slice-replace-2-2"}}, - &Pet{Name: "pet-slice-replace-3"}, - ) - - AssertAssociationCount(t, users, "Pets", 5, "After Append") - - // Delete - if err := DB.Model(&users).Association("Pets").Delete(&users[2].Pets); err != nil { - t.Errorf("no error should happend when deleting pet, but got %v", err) - } - - AssertAssociationCount(t, users, "Pets", 4, "after delete") - - if err := DB.Model(&users).Association("Pets").Delete(users[0].Pets[0], users[1].Pets[1]); err != nil { - t.Errorf("no error should happend when deleting pet, but got %v", err) - } - - AssertAssociationCount(t, users, "Pets", 2, "after delete") - - // Clear - DB.Model(&users).Association("Pets").Clear() - AssertAssociationCount(t, users, "Pets", 0, "After Clear") -} - -func TestSingleTableHasManyAssociationForSlice(t *testing.T) { - var users = []User{ - *GetUser("slice-hasmany-1", Config{Team: 2}), - *GetUser("slice-hasmany-2", Config{Team: 0}), - *GetUser("slice-hasmany-3", Config{Team: 4}), - } - - if err := DB.Create(&users).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - // Count - AssertAssociationCount(t, users, "Team", 6, "") - - // Find - var teams []User - if DB.Model(&users).Association("Team").Find(&teams); len(teams) != 6 { - t.Errorf("teams count should be %v, but got %v", 6, len(teams)) - } - - // Append - DB.Model(&users).Association("Team").Append( - &User{Name: "pet-slice-append-1"}, - []*User{{Name: "pet-slice-append-2-1"}, {Name: "pet-slice-append-2-2"}}, - &User{Name: "pet-slice-append-3"}, - ) - - AssertAssociationCount(t, users, "Team", 10, "After Append") - - // Replace -> same as append - DB.Model(&users).Association("Team").Replace( - []*User{{Name: "pet-slice-replace-1-1"}, {Name: "pet-slice-replace-1-2"}}, - []*User{{Name: "pet-slice-replace-2-1"}, {Name: "pet-slice-replace-2-2"}}, - &User{Name: "pet-slice-replace-3"}, - ) - - AssertAssociationCount(t, users, "Team", 5, "After Append") - - // Delete - if err := DB.Model(&users).Association("Team").Delete(&users[2].Team); err != nil { - t.Errorf("no error should happend when deleting pet, but got %v", err) - } - - AssertAssociationCount(t, users, "Team", 4, "after delete") - - if err := DB.Model(&users).Association("Team").Delete(users[0].Team[0], users[1].Team[1]); err != nil { - t.Errorf("no error should happend when deleting pet, but got %v", err) - } - - AssertAssociationCount(t, users, "Team", 2, "after delete") - - // Clear - DB.Model(&users).Association("Team").Clear() - AssertAssociationCount(t, users, "Team", 0, "After Clear") -} - -func TestPolymorphicHasManyAssociation(t *testing.T) { - var user = *GetUser("hasmany", Config{Toys: 2}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - CheckUser(t, user, user) - - // Find - var user2 User - DB.Find(&user2, "id = ?", user.ID) - DB.Model(&user2).Association("Toys").Find(&user2.Toys) - CheckUser(t, user2, user) - - // Count - AssertAssociationCount(t, user, "Toys", 2, "") - - // Append - var toy = Toy{Name: "toy-has-many-append"} - - if err := DB.Model(&user2).Association("Toys").Append(&toy); err != nil { - t.Fatalf("Error happened when append account, got %v", err) - } - - if toy.ID == 0 { - t.Fatalf("Toy's ID should be created") - } - - user.Toys = append(user.Toys, toy) - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Toys", 3, "AfterAppend") - - var toys = []Toy{{Name: "toy-has-many-append-1-1"}, {Name: "toy-has-many-append-1-1"}} - - if err := DB.Model(&user2).Association("Toys").Append(&toys); err != nil { - t.Fatalf("Error happened when append toy, got %v", err) - } - - for _, toy := range toys { - var toy = toy - if toy.ID == 0 { - t.Fatalf("Toy's ID should be created") - } - - user.Toys = append(user.Toys, toy) - } - - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Toys", 5, "AfterAppendSlice") - - // Replace - var toy2 = Toy{Name: "toy-has-many-replace"} - - if err := DB.Model(&user2).Association("Toys").Replace(&toy2); err != nil { - t.Fatalf("Error happened when append toy, got %v", err) - } - - if toy2.ID == 0 { - t.Fatalf("toy2's ID should be created") - } - - user.Toys = []Toy{toy2} - CheckUser(t, user2, user) - - AssertAssociationCount(t, user2, "Toys", 1, "AfterReplace") - - // Delete - if err := DB.Model(&user2).Association("Toys").Delete(&Toy{}); err != nil { - t.Fatalf("Error happened when delete toy, got %v", err) - } - AssertAssociationCount(t, user2, "Toys", 1, "after delete non-existing data") - - if err := DB.Model(&user2).Association("Toys").Delete(&toy2); err != nil { - t.Fatalf("Error happened when delete Toys, got %v", err) - } - AssertAssociationCount(t, user2, "Toys", 0, "after delete") - - // Prepare Data for Clear - if err := DB.Model(&user2).Association("Toys").Append(&toy); err != nil { - t.Fatalf("Error happened when append Toys, got %v", err) - } - - AssertAssociationCount(t, user2, "Toys", 1, "after prepare data") - - // Clear - if err := DB.Model(&user2).Association("Toys").Clear(); err != nil { - t.Errorf("Error happened when clear Toys, got %v", err) - } - - AssertAssociationCount(t, user2, "Toys", 0, "after clear") -} - -func TestPolymorphicHasManyAssociationForSlice(t *testing.T) { - var users = []User{ - *GetUser("slice-hasmany-1", Config{Toys: 2}), - *GetUser("slice-hasmany-2", Config{Toys: 0}), - *GetUser("slice-hasmany-3", Config{Toys: 4}), - } - - DB.Create(&users) - - // Count - AssertAssociationCount(t, users, "Toys", 6, "") - - // Find - var toys []Toy - if DB.Model(&users).Association("Toys").Find(&toys); len(toys) != 6 { - t.Errorf("toys count should be %v, but got %v", 6, len(toys)) - } - - // Append - DB.Model(&users).Association("Toys").Append( - &Toy{Name: "toy-slice-append-1"}, - []Toy{{Name: "toy-slice-append-2-1"}, {Name: "toy-slice-append-2-2"}}, - &Toy{Name: "toy-slice-append-3"}, - ) - - AssertAssociationCount(t, users, "Toys", 10, "After Append") - - // Replace -> same as append - DB.Model(&users).Association("Toys").Replace( - []*Toy{{Name: "toy-slice-replace-1-1"}, {Name: "toy-slice-replace-1-2"}}, - []*Toy{{Name: "toy-slice-replace-2-1"}, {Name: "toy-slice-replace-2-2"}}, - &Toy{Name: "toy-slice-replace-3"}, - ) - - AssertAssociationCount(t, users, "Toys", 5, "After Append") - - // Delete - if err := DB.Model(&users).Association("Toys").Delete(&users[2].Toys); err != nil { - t.Errorf("no error should happend when deleting toy, but got %v", err) - } - - AssertAssociationCount(t, users, "Toys", 4, "after delete") - - if err := DB.Model(&users).Association("Toys").Delete(users[0].Toys[0], users[1].Toys[1]); err != nil { - t.Errorf("no error should happend when deleting toy, but got %v", err) - } - - AssertAssociationCount(t, users, "Toys", 2, "after delete") - - // Clear - DB.Model(&users).Association("Toys").Clear() - AssertAssociationCount(t, users, "Toys", 0, "After Clear") -} - -func TestMany2ManyAssociation(t *testing.T) { - var user = *GetUser("many2many", Config{Languages: 2}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - CheckUser(t, user, user) - - // Find - var user2 User - DB.Find(&user2, "id = ?", user.ID) - DB.Model(&user2).Association("Languages").Find(&user2.Languages) - - CheckUser(t, user2, user) - - // Count - AssertAssociationCount(t, user, "Languages", 2, "") - - // Append - var language = Language{Code: "language-many2many-append", Name: "language-many2many-append"} - DB.Create(&language) - - if err := DB.Model(&user2).Association("Languages").Append(&language); err != nil { - t.Fatalf("Error happened when append account, got %v", err) - } - - user.Languages = append(user.Languages, language) - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Languages", 3, "AfterAppend") - - var languages = []Language{ - {Code: "language-many2many-append-1-1", Name: "language-many2many-append-1-1"}, - {Code: "language-many2many-append-2-1", Name: "language-many2many-append-2-1"}, - } - DB.Create(&languages) - - if err := DB.Model(&user2).Association("Languages").Append(&languages); err != nil { - t.Fatalf("Error happened when append language, got %v", err) - } - - user.Languages = append(user.Languages, languages...) - - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Languages", 5, "AfterAppendSlice") - - // Replace - var language2 = Language{Code: "language-many2many-replace", Name: "language-many2many-replace"} - DB.Create(&language2) - - if err := DB.Model(&user2).Association("Languages").Replace(&language2); err != nil { - t.Fatalf("Error happened when append language, got %v", err) - } - - user.Languages = []Language{language2} - CheckUser(t, user2, user) - - AssertAssociationCount(t, user2, "Languages", 1, "AfterReplace") - - // Delete - if err := DB.Model(&user2).Association("Languages").Delete(&Language{}); err != nil { - t.Fatalf("Error happened when delete language, got %v", err) - } - AssertAssociationCount(t, user2, "Languages", 1, "after delete non-existing data") - - if err := DB.Model(&user2).Association("Languages").Delete(&language2); err != nil { - t.Fatalf("Error happened when delete Languages, got %v", err) - } - AssertAssociationCount(t, user2, "Languages", 0, "after delete") - - // Prepare Data for Clear - if err := DB.Model(&user2).Association("Languages").Append(&language); err != nil { - t.Fatalf("Error happened when append Languages, got %v", err) - } - - AssertAssociationCount(t, user2, "Languages", 1, "after prepare data") - - // Clear - if err := DB.Model(&user2).Association("Languages").Clear(); err != nil { - t.Errorf("Error happened when clear Languages, got %v", err) - } - - AssertAssociationCount(t, user2, "Languages", 0, "after clear") -} - -func TestMany2ManyAssociationForSlice(t *testing.T) { - var users = []User{ - *GetUser("slice-many2many-1", Config{Languages: 2}), - *GetUser("slice-many2many-2", Config{Languages: 0}), - *GetUser("slice-many2many-3", Config{Languages: 4}), - } - - DB.Create(&users) - - // Count - AssertAssociationCount(t, users, "Languages", 6, "") - - // Find - var languages []Language - if DB.Model(&users).Association("Languages").Find(&languages); len(languages) != 6 { - t.Errorf("languages count should be %v, but got %v", 6, len(languages)) - } - - // Append - var languages1 = []Language{ - {Code: "language-many2many-append-1", Name: "language-many2many-append-1"}, - } - var languages2 = []Language{} - var languages3 = []Language{ - {Code: "language-many2many-append-3-1", Name: "language-many2many-append-3-1"}, - {Code: "language-many2many-append-3-2", Name: "language-many2many-append-3-2"}, - } - DB.Create(&languages1) - DB.Create(&languages3) - - DB.Model(&users).Association("Languages").Append(&languages1, &languages2, &languages3) - - AssertAssociationCount(t, users, "Languages", 9, "After Append") - - languages2_1 := []*Language{ - {Code: "language-slice-replace-1-1", Name: "language-slice-replace-1-1"}, - {Code: "language-slice-replace-1-2", Name: "language-slice-replace-1-2"}, - } - languages2_2 := []*Language{ - {Code: "language-slice-replace-2-1", Name: "language-slice-replace-2-1"}, - {Code: "language-slice-replace-2-2", Name: "language-slice-replace-2-2"}, - } - languages2_3 := &Language{Code: "language-slice-replace-3", Name: "language-slice-replace-3"} - DB.Create(&languages2_1) - DB.Create(&languages2_2) - DB.Create(&languages2_3) - - // Replace - DB.Model(&users).Association("Languages").Replace(&languages2_1, &languages2_2, languages2_3) - - AssertAssociationCount(t, users, "Languages", 5, "After Replace") - - // Delete - if err := DB.Model(&users).Association("Languages").Delete(&users[2].Languages); err != nil { - t.Errorf("no error should happend when deleting language, but got %v", err) - } - - AssertAssociationCount(t, users, "Languages", 4, "after delete") - - if err := DB.Model(&users).Association("Languages").Delete(users[0].Languages[0], users[1].Languages[1]); err != nil { - t.Errorf("no error should happend when deleting language, but got %v", err) - } - - AssertAssociationCount(t, users, "Languages", 2, "after delete") - - // Clear - DB.Model(&users).Association("Languages").Clear() - AssertAssociationCount(t, users, "Languages", 0, "After Clear") -} - -func TestSingleTableMany2ManyAssociation(t *testing.T) { - var user = *GetUser("many2many", Config{Friends: 2}) - - if err := DB.Create(&user).Error; err != nil { - t.Fatalf("errors happened when create: %v", err) - } - - CheckUser(t, user, user) - - // Find - var user2 User - DB.Find(&user2, "id = ?", user.ID) - DB.Model(&user2).Association("Friends").Find(&user2.Friends) - - CheckUser(t, user2, user) - - // Count - AssertAssociationCount(t, user, "Friends", 2, "") - - // Append - var friend = *GetUser("friend", Config{}) - - if err := DB.Model(&user2).Association("Friends").Append(&friend); err != nil { - t.Fatalf("Error happened when append account, got %v", err) - } - - user.Friends = append(user.Friends, &friend) - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Friends", 3, "AfterAppend") - - var friends = []*User{GetUser("friend-append-1", Config{}), GetUser("friend-append-2", Config{})} - - if err := DB.Model(&user2).Association("Friends").Append(&friends); err != nil { - t.Fatalf("Error happened when append friend, got %v", err) - } - - user.Friends = append(user.Friends, friends...) - - CheckUser(t, user2, user) - - AssertAssociationCount(t, user, "Friends", 5, "AfterAppendSlice") - - // Replace - var friend2 = *GetUser("friend-replace-2", Config{}) - - if err := DB.Model(&user2).Association("Friends").Replace(&friend2); err != nil { - t.Fatalf("Error happened when append friend, got %v", err) - } - - user.Friends = []*User{&friend2} - CheckUser(t, user2, user) - - AssertAssociationCount(t, user2, "Friends", 1, "AfterReplace") - - // Delete - if err := DB.Model(&user2).Association("Friends").Delete(&User{}); err != nil { - t.Fatalf("Error happened when delete friend, got %v", err) - } - AssertAssociationCount(t, user2, "Friends", 1, "after delete non-existing data") - - if err := DB.Model(&user2).Association("Friends").Delete(&friend2); err != nil { - t.Fatalf("Error happened when delete Friends, got %v", err) - } - AssertAssociationCount(t, user2, "Friends", 0, "after delete") - - // Prepare Data for Clear - if err := DB.Model(&user2).Association("Friends").Append(&friend); err != nil { - t.Fatalf("Error happened when append Friends, got %v", err) - } - - AssertAssociationCount(t, user2, "Friends", 1, "after prepare data") - - // Clear - if err := DB.Model(&user2).Association("Friends").Clear(); err != nil { - t.Errorf("Error happened when clear Friends, got %v", err) - } - - AssertAssociationCount(t, user2, "Friends", 0, "after clear") -} - -func TestSingleTableMany2ManyAssociationForSlice(t *testing.T) { - var users = []User{ - *GetUser("slice-many2many-1", Config{Team: 2}), - *GetUser("slice-many2many-2", Config{Team: 0}), - *GetUser("slice-many2many-3", Config{Team: 4}), - } - - DB.Create(&users) - - // Count - AssertAssociationCount(t, users, "Team", 6, "") - - // Find - var teams []User - if DB.Model(&users).Association("Team").Find(&teams); len(teams) != 6 { - t.Errorf("teams count should be %v, but got %v", 6, len(teams)) - } - - // Append - var teams1 = []User{*GetUser("friend-append-1", Config{})} - var teams2 = []User{} - var teams3 = []*User{GetUser("friend-append-3-1", Config{}), GetUser("friend-append-3-2", Config{})} - - DB.Model(&users).Association("Team").Append(&teams1, &teams2, &teams3) - - AssertAssociationCount(t, users, "Team", 9, "After Append") - - var teams2_1 = []User{*GetUser("friend-replace-1", Config{}), *GetUser("friend-replace-2", Config{})} - var teams2_2 = []User{*GetUser("friend-replace-2-1", Config{}), *GetUser("friend-replace-2-2", Config{})} - var teams2_3 = GetUser("friend-replace-3-1", Config{}) - - // Replace - DB.Model(&users).Association("Team").Replace(&teams2_1, &teams2_2, teams2_3) - - AssertAssociationCount(t, users, "Team", 5, "After Replace") - - // Delete - if err := DB.Model(&users).Association("Team").Delete(&users[2].Team); err != nil { - t.Errorf("no error should happend when deleting team, but got %v", err) - } - - AssertAssociationCount(t, users, "Team", 4, "after delete") - - if err := DB.Model(&users).Association("Team").Delete(users[0].Team[0], users[1].Team[1]); err != nil { - t.Errorf("no error should happend when deleting team, but got %v", err) - } - - AssertAssociationCount(t, users, "Team", 2, "after delete") - - // Clear - DB.Model(&users).Association("Team").Clear() - AssertAssociationCount(t, users, "Team", 0, "After Clear") }