Keep refactoring on callbacks

This commit is contained in:
Jinzhu 2016-01-17 20:51:11 +08:00
parent 58a7252251
commit 07773cc367
4 changed files with 84 additions and 87 deletions

View File

@ -148,75 +148,66 @@ func getRIndex(strs []string, str string) int {
// sortProcessors sort callback processors based on its before, after, remove, replace // sortProcessors sort callback processors based on its before, after, remove, replace
func sortProcessors(cps []*CallbackProcessor) []*func(scope *Scope) { func sortProcessors(cps []*CallbackProcessor) []*func(scope *Scope) {
var sortCallbackProcessor func(c *CallbackProcessor) var (
var names, sortedNames = []string{}, []string{} allNames, sortedNames []string
sortCallbackProcessor func(c *CallbackProcessor)
)
for _, cp := range cps { for _, cp := range cps {
if index := getRIndex(names, cp.name); index > -1 { // show warning message the callback name already exists
if !cp.replace && !cp.remove { if index := getRIndex(allNames, cp.name); index > -1 && !cp.replace && !cp.remove {
fmt.Printf("[warning] duplicated callback `%v` from %v\n", cp.name, fileWithLineNum()) fmt.Printf("[warning] duplicated callback `%v` from %v\n", cp.name, fileWithLineNum())
} }
} allNames = append(allNames, cp.name)
names = append(names, cp.name)
} }
sortCallbackProcessor = func(c *CallbackProcessor) { sortCallbackProcessor = func(c *CallbackProcessor) {
if getRIndex(sortedNames, c.name) > -1 { if getRIndex(sortedNames, c.name) == -1 { // if not sorted
return if c.before != "" { // if defined before callback
} if index := getRIndex(sortedNames, c.before); index != -1 {
// if before callback already sorted, append current callback just after it
if len(c.before) > 0 {
if index := getRIndex(sortedNames, c.before); index > -1 {
sortedNames = append(sortedNames[:index], append([]string{c.name}, sortedNames[index:]...)...) sortedNames = append(sortedNames[:index], append([]string{c.name}, sortedNames[index:]...)...)
} else if index := getRIndex(names, c.before); index > -1 { } else if index := getRIndex(allNames, c.before); index != -1 {
// if before callback exists but haven't sorted, append current callback to last
sortedNames = append(sortedNames, c.name) sortedNames = append(sortedNames, c.name)
sortCallbackProcessor(cps[index]) sortCallbackProcessor(cps[index])
} else {
sortedNames = append(sortedNames, c.name)
} }
} }
if len(c.after) > 0 { if c.after != "" { // if defined after callback
if index := getRIndex(sortedNames, c.after); index > -1 { if index := getRIndex(sortedNames, c.after); index != -1 {
// if after callback already sorted, append current callback just before it
sortedNames = append(sortedNames[:index+1], append([]string{c.name}, sortedNames[index+1:]...)...) sortedNames = append(sortedNames[:index+1], append([]string{c.name}, sortedNames[index+1:]...)...)
} else if index := getRIndex(names, c.after); index > -1 { } else if index := getRIndex(allNames, c.after); index != -1 {
// if after callback exists but haven't sorted
cp := cps[index] cp := cps[index]
if len(cp.before) == 0 { // set after callback's before callback to current callback
if cp.before == "" {
cp.before = c.name cp.before = c.name
} }
sortCallbackProcessor(cp) sortCallbackProcessor(cp)
} else {
sortedNames = append(sortedNames, c.name)
} }
} }
// if current callback haven't been sorted, append it to last
if getRIndex(sortedNames, c.name) == -1 { if getRIndex(sortedNames, c.name) == -1 {
sortedNames = append(sortedNames, c.name) sortedNames = append(sortedNames, c.name)
} }
} }
}
for _, cp := range cps { for _, cp := range cps {
sortCallbackProcessor(cp) sortCallbackProcessor(cp)
} }
var funcs = []*func(scope *Scope){} var sortedFuncs []*func(scope *Scope)
var sortedFuncs = []*func(scope *Scope){}
for _, name := range sortedNames { for _, name := range sortedNames {
index := getRIndex(names, name) if index := getRIndex(allNames, name); !cps[index].remove {
if !cps[index].remove {
sortedFuncs = append(sortedFuncs, cps[index].processor) sortedFuncs = append(sortedFuncs, cps[index].processor)
} }
} }
for _, cp := range cps { return sortedFuncs
if sindex := getRIndex(sortedNames, cp.name); sindex == -1 {
if !cp.remove {
funcs = append(funcs, cp.processor)
}
}
}
return append(sortedFuncs, funcs...)
} }
// reorder all registered processors, and reset CURD callbacks // reorder all registered processors, and reset CURD callbacks

View File

@ -2,6 +2,7 @@ package gorm
import "fmt" import "fmt"
// Define callbacks for deleting
func init() { func init() {
defaultCallback.Delete().Register("gorm:begin_transaction", beginTransactionCallback) defaultCallback.Delete().Register("gorm:begin_transaction", beginTransactionCallback)
defaultCallback.Delete().Register("gorm:before_delete", beforeDeleteCallback) defaultCallback.Delete().Register("gorm:before_delete", beforeDeleteCallback)
@ -10,12 +11,14 @@ func init() {
defaultCallback.Delete().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback) defaultCallback.Delete().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback)
} }
// beforeDeleteCallback will invoke `BeforeDelete` method before deleting
func beforeDeleteCallback(scope *Scope) { func beforeDeleteCallback(scope *Scope) {
if !scope.HasError() { if !scope.HasError() {
scope.CallMethod("BeforeDelete") scope.CallMethod("BeforeDelete")
} }
} }
// deleteCallback used to delete data from database or set deleted_at to current time (when using with soft delete)
func deleteCallback(scope *Scope) { func deleteCallback(scope *Scope) {
if !scope.HasError() { if !scope.HasError() {
if !scope.Search.Unscoped && scope.HasColumn("DeletedAt") { if !scope.Search.Unscoped && scope.HasColumn("DeletedAt") {
@ -24,15 +27,14 @@ func deleteCallback(scope *Scope) {
scope.QuotedTableName(), scope.QuotedTableName(),
scope.AddToVars(NowFunc()), scope.AddToVars(NowFunc()),
scope.CombinedConditionSql(), scope.CombinedConditionSql(),
)) )).Exec()
} else { } else {
scope.Raw(fmt.Sprintf("DELETE FROM %v %v", scope.QuotedTableName(), scope.CombinedConditionSql())) scope.Raw(fmt.Sprintf("DELETE FROM %v %v", scope.QuotedTableName(), scope.CombinedConditionSql())).Exec()
} }
scope.Exec()
} }
} }
// afterDeleteCallback will invoke `AfterDelete` method after deleting
func afterDeleteCallback(scope *Scope) { func afterDeleteCallback(scope *Scope) {
if !scope.HasError() { if !scope.HasError() {
scope.CallMethod("AfterDelete") scope.CallMethod("AfterDelete")

View File

@ -6,40 +6,42 @@ import (
"reflect" "reflect"
) )
// Define callbacks for querying
func init() { func init() {
defaultCallback.Query().Register("gorm:query", queryCallback) defaultCallback.Query().Register("gorm:query", queryCallback)
defaultCallback.Query().Register("gorm:after_query", afterQueryCallback) defaultCallback.Query().Register("gorm:after_query", afterQueryCallback)
defaultCallback.Query().Register("gorm:preload", preloadCallback) defaultCallback.Query().Register("gorm:preload", preloadCallback)
} }
// queryCallback used to query data from database
func queryCallback(scope *Scope) { func queryCallback(scope *Scope) {
defer scope.trace(NowFunc()) defer scope.trace(NowFunc())
var ( var (
isSlice bool isSlice bool
isPtr bool isPtr bool
destType reflect.Type results = scope.IndirectValue()
resultType reflect.Type
) )
if orderBy, ok := scope.Get("gorm:order_by_primary_key"); ok { if orderBy, ok := scope.Get("gorm:order_by_primary_key"); ok {
if primaryKey := scope.PrimaryKey(); primaryKey != "" { if primaryField := scope.PrimaryField(); primaryField != nil {
scope.Search.Order(fmt.Sprintf("%v.%v %v", scope.QuotedTableName(), scope.Quote(primaryKey), orderBy)) scope.Search.Order(fmt.Sprintf("%v.%v %v", scope.QuotedTableName(), scope.Quote(primaryField.DBName), orderBy))
} }
} }
var dest = scope.IndirectValue()
if value, ok := scope.Get("gorm:query_destination"); ok { if value, ok := scope.Get("gorm:query_destination"); ok {
dest = reflect.Indirect(reflect.ValueOf(value)) results = reflect.Indirect(reflect.ValueOf(value))
} }
if kind := dest.Kind(); kind == reflect.Slice { if kind := results.Kind(); kind == reflect.Slice {
isSlice = true isSlice = true
destType = dest.Type().Elem() resultType = results.Type().Elem()
dest.Set(reflect.MakeSlice(dest.Type(), 0, 0)) results.Set(reflect.MakeSlice(results.Type(), 0, 0))
if destType.Kind() == reflect.Ptr { if resultType.Kind() == reflect.Ptr {
isPtr = true isPtr = true
destType = destType.Elem() resultType = resultType.Elem()
} }
} else if kind != reflect.Struct { } else if kind != reflect.Struct {
scope.Err(errors.New("unsupported destination, should be slice or struct")) scope.Err(errors.New("unsupported destination, should be slice or struct"))
@ -49,31 +51,26 @@ func queryCallback(scope *Scope) {
scope.prepareQuerySql() scope.prepareQuerySql()
if !scope.HasError() { if !scope.HasError() {
rows, err := scope.SqlDB().Query(scope.Sql, scope.SqlVars...)
scope.db.RowsAffected = 0 scope.db.RowsAffected = 0
if rows, err := scope.SqlDB().Query(scope.Sql, scope.SqlVars...); scope.Err(err) == nil {
if scope.Err(err) != nil {
return
}
defer rows.Close() defer rows.Close()
columns, _ := rows.Columns() columns, _ := rows.Columns()
for rows.Next() { for rows.Next() {
scope.db.RowsAffected++ scope.db.RowsAffected++
elem := dest elem := results
if isSlice { if isSlice {
elem = reflect.New(destType).Elem() elem = reflect.New(resultType).Elem()
} }
fields := scope.New(elem.Addr().Interface()).Fields() scope.scan(rows, columns, scope.New(elem.Addr().Interface()).Fields())
scope.scan(rows, columns, fields)
if isSlice { if isSlice {
if isPtr { if isPtr {
dest.Set(reflect.Append(dest, elem.Addr())) results.Set(reflect.Append(results, elem.Addr()))
} else { } else {
dest.Set(reflect.Append(dest, elem)) results.Set(reflect.Append(results, elem))
} }
} }
} }
@ -82,8 +79,10 @@ func queryCallback(scope *Scope) {
scope.Err(RecordNotFound) scope.Err(RecordNotFound)
} }
} }
}
} }
// afterQueryCallback will invoke `AfterFind` method after querying
func afterQueryCallback(scope *Scope) { func afterQueryCallback(scope *Scope) {
if !scope.HasError() { if !scope.HasError() {
scope.CallMethod("AfterFind") scope.CallMethod("AfterFind")

View File

@ -7,6 +7,7 @@ import (
"strings" "strings"
) )
// preloadCallback used to preload associations
func preloadCallback(scope *Scope) { func preloadCallback(scope *Scope) {
if scope.Search.preload == nil || scope.HasError() { if scope.Search.preload == nil || scope.HasError() {
return return
@ -72,6 +73,7 @@ func preloadCallback(scope *Scope) {
} }
} }
// handleHasOnePreload used to preload has one associations
func (scope *Scope) handleHasOnePreload(field *Field, conditions []interface{}) { func (scope *Scope) handleHasOnePreload(field *Field, conditions []interface{}) {
relation := field.Relationship relation := field.Relationship
@ -107,6 +109,7 @@ func (scope *Scope) handleHasOnePreload(field *Field, conditions []interface{})
} }
} }
// handleHasManyPreload used to preload has many associations
func (scope *Scope) handleHasManyPreload(field *Field, conditions []interface{}) { func (scope *Scope) handleHasManyPreload(field *Field, conditions []interface{}) {
relation := field.Relationship relation := field.Relationship
@ -144,6 +147,7 @@ func (scope *Scope) handleHasManyPreload(field *Field, conditions []interface{})
} }
} }
// handleBelongsToPreload used to preload belongs to associations
func (scope *Scope) handleBelongsToPreload(field *Field, conditions []interface{}) { func (scope *Scope) handleBelongsToPreload(field *Field, conditions []interface{}) {
relation := field.Relationship relation := field.Relationship
@ -179,6 +183,7 @@ func (scope *Scope) handleBelongsToPreload(field *Field, conditions []interface{
} }
} }
// handleManyToManyPreload used to preload many to many associations
func (scope *Scope) handleManyToManyPreload(field *Field, conditions []interface{}) { func (scope *Scope) handleManyToManyPreload(field *Field, conditions []interface{}) {
var ( var (
relation = field.Relationship relation = field.Relationship