Refactor association
This commit is contained in:
		
							parent
							
								
									8de2bb4eab
								
							
						
					
					
						commit
						c299cb8db6
					
				
							
								
								
									
										197
									
								
								association.go
									
									
									
									
									
								
							
							
						
						
									
										197
									
								
								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 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										216
									
								
								tests/associations_belongs_to_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								tests/associations_belongs_to_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -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") | ||||
| } | ||||
							
								
								
									
										456
									
								
								tests/associations_has_many_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										456
									
								
								tests/associations_has_many_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -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") | ||||
| } | ||||
							
								
								
									
										241
									
								
								tests/associations_has_one_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								tests/associations_has_one_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -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") | ||||
| } | ||||
							
								
								
									
										299
									
								
								tests/associations_many2many_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								tests/associations_many2many_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -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") | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jinzhu
						Jinzhu