2014-07-30 10:30:21 +04:00
package gorm
2014-07-30 12:22:26 +04:00
import (
"errors"
"fmt"
"reflect"
)
2014-07-30 10:30:21 +04:00
type Association struct {
2015-02-17 17:55:14 +03:00
Scope * Scope
PrimaryKey interface { }
Column string
Error error
Field * Field
2014-07-30 10:30:21 +04:00
}
2015-02-13 06:26:02 +03:00
func ( association * Association ) setErr ( err error ) * Association {
2014-07-30 16:48:36 +04:00
if err != nil {
association . Error = err
2014-07-30 12:22:26 +04:00
}
2014-07-30 16:48:36 +04:00
return association
}
func ( association * Association ) Find ( value interface { } ) * Association {
association . Scope . related ( value , association . Column )
2015-02-13 06:26:02 +03:00
return association . setErr ( association . Scope . db . Error )
2014-07-30 16:48:36 +04:00
}
2014-07-30 12:22:26 +04:00
2014-07-30 16:48:36 +04:00
func ( association * Association ) Append ( values ... interface { } ) * Association {
scope := association . Scope
2014-09-02 15:03:01 +04:00
field := association . Field
2014-07-30 16:48:36 +04:00
for _ , value := range values {
2015-02-17 14:17:21 +03:00
reflectvalue := reflect . Indirect ( reflect . ValueOf ( value ) )
if reflectvalue . Kind ( ) == reflect . Struct {
2014-09-02 15:03:01 +04:00
field . Set ( reflect . Append ( field . Field , reflectvalue ) )
2015-02-17 14:17:21 +03:00
} else if reflectvalue . Kind ( ) == reflect . Slice {
2014-09-02 15:03:01 +04:00
field . Set ( reflect . AppendSlice ( field . Field , reflectvalue ) )
2014-07-30 12:22:26 +04:00
} else {
2015-02-13 06:26:02 +03:00
association . setErr ( errors . New ( "invalid association type" ) )
2014-07-30 12:22:26 +04:00
}
}
2014-07-30 16:48:36 +04:00
scope . callCallbacks ( scope . db . parent . callback . updates )
2015-02-13 06:26:02 +03:00
return association . setErr ( scope . db . Error )
2014-07-30 10:30:21 +04:00
}
2014-07-30 18:10:12 +04:00
func ( association * Association ) getPrimaryKeys ( values ... interface { } ) [ ] interface { } {
2014-07-30 16:48:36 +04:00
primaryKeys := [ ] interface { } { }
scope := association . Scope
2014-07-30 18:10:12 +04:00
2014-07-30 16:48:36 +04:00
for _ , value := range values {
2015-02-17 14:17:21 +03:00
reflectValue := reflect . Indirect ( reflect . ValueOf ( value ) )
2014-07-30 16:48:36 +04:00
if reflectValue . Kind ( ) == reflect . Slice {
for i := 0 ; i < reflectValue . Len ( ) ; i ++ {
2015-02-17 15:19:47 +03:00
if primaryField := scope . New ( reflectValue . Index ( i ) . Interface ( ) ) . PrimaryKeyField ( ) ; ! primaryField . IsBlank {
2015-02-17 14:17:21 +03:00
primaryKeys = append ( primaryKeys , primaryField . Field . Interface ( ) )
2014-07-30 16:48:36 +04:00
}
}
} else if reflectValue . Kind ( ) == reflect . Struct {
2015-02-17 15:19:47 +03:00
if primaryField := scope . New ( value ) . PrimaryKeyField ( ) ; ! primaryField . IsBlank {
2015-02-17 14:17:21 +03:00
primaryKeys = append ( primaryKeys , primaryField . Field . Interface ( ) )
2014-07-30 16:48:36 +04:00
}
}
}
2014-07-30 18:10:12 +04:00
return primaryKeys
}
func ( association * Association ) Delete ( values ... interface { } ) * Association {
primaryKeys := association . getPrimaryKeys ( values ... )
2014-07-30 16:48:36 +04:00
if len ( primaryKeys ) == 0 {
2015-02-13 06:26:02 +03:00
association . setErr ( errors . New ( "no primary key found" ) )
2014-07-30 16:48:36 +04:00
} else {
2015-02-28 06:48:18 +03:00
scope := association . Scope
2014-07-30 16:59:52 +04:00
relationship := association . Field . Relationship
2014-07-30 16:48:36 +04:00
// many to many
2014-07-31 07:08:26 +04:00
if relationship . Kind == "many_to_many" {
2015-02-28 06:48:18 +03:00
sql := fmt . Sprintf ( "%v.%v = ? AND %v.%v IN (?)" ,
scope . Quote ( relationship . JoinTable ) , scope . Quote ( relationship . ForeignDBName ) ,
scope . Quote ( relationship . JoinTable ) , scope . Quote ( relationship . AssociationForeignDBName ) )
query := scope . NewDB ( ) . Table ( relationship . JoinTable ) . Where ( sql , association . PrimaryKey , primaryKeys )
if err := scope . db . GetJoinTableHandler ( relationship . JoinTable ) . Delete ( query , relationship ) ; err == nil {
2015-02-24 13:48:48 +03:00
leftValues := reflect . Zero ( association . Field . Field . Type ( ) )
for i := 0 ; i < association . Field . Field . Len ( ) ; i ++ {
value := association . Field . Field . Index ( i )
if primaryField := association . Scope . New ( value . Interface ( ) ) . PrimaryKeyField ( ) ; primaryField != nil {
var included = false
for _ , primaryKey := range primaryKeys {
if equalAsString ( primaryKey , primaryField . Field . Interface ( ) ) {
included = true
}
}
if ! included {
leftValues = reflect . Append ( leftValues , value )
}
}
}
association . Field . Set ( leftValues )
}
2014-07-30 16:48:36 +04:00
} else {
2015-02-13 06:26:02 +03:00
association . setErr ( errors . New ( "delete only support many to many" ) )
2014-07-30 16:48:36 +04:00
}
}
2014-07-30 12:22:26 +04:00
return association
2014-07-30 10:30:21 +04:00
}
2014-07-30 18:10:12 +04:00
func ( association * Association ) Replace ( values ... interface { } ) * Association {
relationship := association . Field . Relationship
scope := association . Scope
2014-07-31 07:08:26 +04:00
if relationship . Kind == "many_to_many" {
2014-09-02 15:03:01 +04:00
field := association . Field . Field
2014-07-30 18:10:12 +04:00
oldPrimaryKeys := association . getPrimaryKeys ( field . Interface ( ) )
2015-02-24 13:48:48 +03:00
association . Field . Set ( reflect . Zero ( association . Field . Field . Type ( ) ) )
2014-07-30 18:10:12 +04:00
association . Append ( values ... )
newPrimaryKeys := association . getPrimaryKeys ( field . Interface ( ) )
var addedPrimaryKeys = [ ] interface { } { }
2015-02-17 14:17:21 +03:00
for _ , newKey := range newPrimaryKeys {
2014-07-30 18:10:12 +04:00
hasEqual := false
2015-02-17 14:17:21 +03:00
for _ , oldKey := range oldPrimaryKeys {
if reflect . DeepEqual ( newKey , oldKey ) {
2014-07-30 18:10:12 +04:00
hasEqual = true
break
}
}
if ! hasEqual {
2015-02-17 14:17:21 +03:00
addedPrimaryKeys = append ( addedPrimaryKeys , newKey )
2014-07-30 18:10:12 +04:00
}
}
for _ , primaryKey := range association . getPrimaryKeys ( values ... ) {
addedPrimaryKeys = append ( addedPrimaryKeys , primaryKey )
}
2015-02-28 06:48:18 +03:00
sql := fmt . Sprintf ( "%v.%v = ? AND %v.%v NOT IN (?)" , scope . Quote ( relationship . JoinTable ) , scope . Quote ( relationship . ForeignDBName ) , scope . Quote ( relationship . JoinTable ) , scope . Quote ( relationship . AssociationForeignDBName ) )
query := scope . NewDB ( ) . Table ( relationship . JoinTable ) . Where ( sql , association . PrimaryKey , addedPrimaryKeys )
association . setErr ( scope . db . GetJoinTableHandler ( relationship . JoinTable ) . Delete ( query , relationship ) )
2014-07-30 18:10:12 +04:00
} else {
2015-02-13 06:26:02 +03:00
association . setErr ( errors . New ( "replace only support many to many" ) )
2014-07-30 18:10:12 +04:00
}
2014-07-30 12:22:26 +04:00
return association
2014-07-30 10:30:21 +04:00
}
2014-07-30 18:15:31 +04:00
func ( association * Association ) Clear ( ) * Association {
relationship := association . Field . Relationship
scope := association . Scope
2014-07-31 07:08:26 +04:00
if relationship . Kind == "many_to_many" {
2015-02-28 06:48:18 +03:00
sql := fmt . Sprintf ( "%v.%v = ?" , relationship . JoinTable , scope . Quote ( relationship . ForeignDBName ) )
query := scope . NewDB ( ) . Table ( relationship . JoinTable ) . Where ( sql , association . PrimaryKey )
if err := scope . db . GetJoinTableHandler ( relationship . JoinTable ) . Delete ( query , relationship ) ; err == nil {
2015-02-24 13:48:48 +03:00
association . Field . Set ( reflect . Zero ( association . Field . Field . Type ( ) ) )
} else {
association . setErr ( err )
}
2014-07-30 18:15:31 +04:00
} else {
2015-02-13 06:26:02 +03:00
association . setErr ( errors . New ( "clear only support many to many" ) )
2014-07-30 18:15:31 +04:00
}
2014-07-30 12:22:26 +04:00
return association
2014-07-30 10:30:21 +04:00
}
2014-07-30 17:43:53 +04:00
func ( association * Association ) Count ( ) int {
count := - 1
2014-07-30 16:59:52 +04:00
relationship := association . Field . Relationship
2014-07-30 16:48:36 +04:00
scope := association . Scope
2015-02-17 15:19:47 +03:00
newScope := scope . New ( association . Field . Field . Interface ( ) )
2014-07-30 10:30:21 +04:00
2014-07-31 07:08:26 +04:00
if relationship . Kind == "many_to_many" {
2015-02-28 06:48:18 +03:00
query := scope . DB ( ) . Table ( relationship . JoinTable ) .
2015-02-26 11:08:15 +03:00
Select ( "COUNT(DISTINCT ?)" , relationship . AssociationForeignDBName ) .
2015-02-28 06:48:18 +03:00
Where ( relationship . ForeignDBName + " = ?" , association . PrimaryKey )
scope . db . GetJoinTableHandler ( relationship . JoinTable ) . Scope ( query , relationship ) . Row ( ) . Scan ( & count )
2014-11-25 22:42:05 +03:00
} else if relationship . Kind == "has_many" || relationship . Kind == "has_one" {
2015-02-17 13:57:50 +03:00
whereSql := fmt . Sprintf ( "%v.%v = ?" , newScope . QuotedTableName ( ) , newScope . Quote ( relationship . ForeignDBName ) )
2015-02-26 11:08:15 +03:00
countScope := scope . DB ( ) . Table ( newScope . TableName ( ) ) . Where ( whereSql , association . PrimaryKey )
2015-02-18 07:30:09 +03:00
if relationship . PolymorphicType != "" {
countScope = countScope . Where ( fmt . Sprintf ( "%v.%v = ?" , newScope . QuotedTableName ( ) , newScope . Quote ( relationship . PolymorphicDBName ) ) , scope . TableName ( ) )
2014-11-26 08:23:43 +03:00
}
countScope . Count ( & count )
2014-07-31 07:08:26 +04:00
} else if relationship . Kind == "belongs_to" {
2015-02-17 17:55:14 +03:00
if v , ok := scope . FieldByName ( association . Column ) ; ok {
2015-02-17 13:57:50 +03:00
whereSql := fmt . Sprintf ( "%v.%v = ?" , newScope . QuotedTableName ( ) , newScope . Quote ( relationship . ForeignDBName ) )
2015-02-26 11:08:15 +03:00
scope . DB ( ) . Table ( newScope . TableName ( ) ) . Where ( whereSql , v ) . Count ( & count )
2014-07-30 17:43:53 +04:00
}
2014-07-30 16:48:36 +04:00
}
2014-07-30 17:43:53 +04:00
return count
2014-07-30 10:30:21 +04:00
}