| 382 | } |
| 383 | |
| 384 | func (association *Association) saveAssociation(clear bool, values ...interface{}) { |
| 385 | var ( |
| 386 | reflectValue = association.DB.Statement.ReflectValue |
| 387 | assignBacks []assignBack // assign association values back to arguments after save |
| 388 | ) |
| 389 | |
| 390 | appendToRelations := func(source, rv reflect.Value, clear bool) { |
| 391 | switch association.Relationship.Type { |
| 392 | case schema.HasOne, schema.BelongsTo: |
| 393 | switch rv.Kind() { |
| 394 | case reflect.Slice, reflect.Array: |
| 395 | if rv.Len() > 0 { |
| 396 | association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, rv.Index(0).Addr().Interface()) |
| 397 | |
| 398 | if association.Relationship.Field.FieldType.Kind() == reflect.Struct { |
| 399 | assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv.Index(0)}) |
| 400 | } |
| 401 | } |
| 402 | case reflect.Struct: |
| 403 | if !rv.CanAddr() { |
| 404 | association.Error = ErrInvalidValue |
| 405 | return |
| 406 | } |
| 407 | association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, rv.Addr().Interface()) |
| 408 | |
| 409 | if association.Relationship.Field.FieldType.Kind() == reflect.Struct { |
| 410 | assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv}) |
| 411 | } |
| 412 | } |
| 413 | case schema.HasMany, schema.Many2Many: |
| 414 | elemType := association.Relationship.Field.IndirectFieldType.Elem() |
| 415 | oldFieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, source)) |
| 416 | var fieldValue reflect.Value |
| 417 | if clear { |
| 418 | fieldValue = reflect.MakeSlice(oldFieldValue.Type(), 0, oldFieldValue.Cap()) |
| 419 | } else { |
| 420 | fieldValue = reflect.MakeSlice(oldFieldValue.Type(), oldFieldValue.Len(), oldFieldValue.Cap()) |
| 421 | reflect.Copy(fieldValue, oldFieldValue) |
| 422 | } |
| 423 | |
| 424 | appendToFieldValues := func(ev reflect.Value) { |
| 425 | if ev.Type().AssignableTo(elemType) { |
| 426 | fieldValue = reflect.Append(fieldValue, ev) |
| 427 | } else if ev.Type().Elem().AssignableTo(elemType) { |
| 428 | fieldValue = reflect.Append(fieldValue, ev.Elem()) |
| 429 | } else { |
| 430 | association.Error = fmt.Errorf("unsupported data type: %v for relation %s", ev.Type(), association.Relationship.Name) |
| 431 | } |
| 432 | |
| 433 | if elemType.Kind() == reflect.Struct { |
| 434 | assignBacks = append(assignBacks, assignBack{Source: source, Dest: ev, Index: fieldValue.Len()}) |
| 435 | } |
| 436 | } |
| 437 | |
| 438 | processMap := func(mapv reflect.Value) { |
| 439 | child := reflect.New(association.Relationship.FieldSchema.ModelType) |
| 440 | |
| 441 | switch association.Relationship.Type { |