package callbacks

import (
	
	

	
	
	
	
)

func ( *gorm.DB) {
	if .Error == nil && .Statement.Schema != nil {
		if !.Statement.ReflectValue.CanAddr() || .Statement.Model != .Statement.Dest {
			.Statement.ReflectValue = reflect.ValueOf(.Statement.Model)
			for .Statement.ReflectValue.Kind() == reflect.Ptr {
				.Statement.ReflectValue = .Statement.ReflectValue.Elem()
			}

			if ,  := .Statement.Dest.(map[string]interface{});  {
				for ,  := range .Statement.Schema.Relationships.BelongsTo {
					if ,  := [.Name];  {
						.AddError(.Field.Set(.Statement.Context, .Statement.ReflectValue, [.Name]))
					}
				}
			}
		}
	}
}

// BeforeUpdate before update hooks
func ( *gorm.DB) {
	if .Error == nil && .Statement.Schema != nil && !.Statement.SkipHooks && (.Statement.Schema.BeforeSave || .Statement.Schema.BeforeUpdate) {
		callMethod(, func( interface{},  *gorm.DB) ( bool) {
			if .Statement.Schema.BeforeSave {
				if ,  := .(BeforeSaveInterface);  {
					 = true
					.AddError(.BeforeSave())
				}
			}

			if .Statement.Schema.BeforeUpdate {
				if ,  := .(BeforeUpdateInterface);  {
					 = true
					.AddError(.BeforeUpdate())
				}
			}

			return 
		})
	}
}

// Update update hook
func ( *Config) func( *gorm.DB) {
	 := utils.Contains(.UpdateClauses, "RETURNING")

	return func( *gorm.DB) {
		if .Error != nil {
			return
		}

		if .Statement.Schema != nil {
			for ,  := range .Statement.Schema.UpdateClauses {
				.Statement.AddClause()
			}
		}

		if .Statement.SQL.Len() == 0 {
			.Statement.SQL.Grow(180)
			.Statement.AddClauseIfNotExists(clause.Update{})
			if ,  := .Statement.Clauses["SET"]; ! {
				if  := ConvertToAssignments(.Statement); len() != 0 {
					defer delete(.Statement.Clauses, "SET")
					.Statement.AddClause()
				} else {
					return
				}
			}

			.Statement.Build(.Statement.BuildClauses...)
		}

		checkMissingWhereConditions()

		if !.DryRun && .Error == nil {
			if ,  := hasReturning(, );  {
				if ,  := .Statement.ConnPool.QueryContext(.Statement.Context, .Statement.SQL.String(), .Statement.Vars...); .AddError() == nil {
					 := .Statement.Dest
					.Statement.Dest = .Statement.ReflectValue.Addr().Interface()
					gorm.Scan(, , )
					.Statement.Dest = 
					.AddError(.Close())
				}
			} else {
				,  := .Statement.ConnPool.ExecContext(.Statement.Context, .Statement.SQL.String(), .Statement.Vars...)

				if .AddError() == nil {
					.RowsAffected, _ = .RowsAffected()
				}
			}
		}
	}
}

// AfterUpdate after update hooks
func ( *gorm.DB) {
	if .Error == nil && .Statement.Schema != nil && !.Statement.SkipHooks && (.Statement.Schema.AfterSave || .Statement.Schema.AfterUpdate) {
		callMethod(, func( interface{},  *gorm.DB) ( bool) {
			if .Statement.Schema.AfterUpdate {
				if ,  := .(AfterUpdateInterface);  {
					 = true
					.AddError(.AfterUpdate())
				}
			}

			if .Statement.Schema.AfterSave {
				if ,  := .(AfterSaveInterface);  {
					 = true
					.AddError(.AfterSave())
				}
			}

			return 
		})
	}
}

// ConvertToAssignments convert to update assignments
func ( *gorm.Statement) ( clause.Set) {
	var (
		,  = .SelectAndOmitColumns(false, true)
		               func( *schema.Field,  interface{})
	)

	switch .ReflectValue.Kind() {
	case reflect.Slice, reflect.Array:
		 = func( *schema.Field,  interface{}) {
			for  := 0;  < .ReflectValue.Len(); ++ {
				if .ReflectValue.CanAddr() {
					.Set(.Context, .ReflectValue.Index(), )
				}
			}
		}
	case reflect.Struct:
		 = func( *schema.Field,  interface{}) {
			if .ReflectValue.CanAddr() {
				.Set(.Context, .ReflectValue, )
			}
		}
	default:
		 = func( *schema.Field,  interface{}) {
		}
	}

	 := reflect.ValueOf(.Dest)
	for .Kind() == reflect.Ptr {
		 = .Elem()
	}

	if !.CanAddr() || .Dest != .Model {
		switch .ReflectValue.Kind() {
		case reflect.Slice, reflect.Array:
			if  := .ReflectValue.Len();  > 0 {
				var  bool
				for  := 0;  < ; ++ {
					for ,  := range .Schema.PrimaryFields {
						_,  = .ValueOf(.Context, .ReflectValue.Index())
						if ! {
							break
						}
					}
				}

				if ! {
					,  := schema.GetIdentityFieldValuesMap(.Context, .ReflectValue, .Schema.PrimaryFields)
					,  := schema.ToQueryValues("", .Schema.PrimaryFieldDBNames, )
					.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: , Values: }}})
				}
			}
		case reflect.Struct:
			for ,  := range .Schema.PrimaryFields {
				if ,  := .ValueOf(.Context, .ReflectValue); ! {
					.AddClause(clause.Where{Exprs: []clause.Expression{clause.Eq{Column: .DBName, Value: }}})
				}
			}
		}
	}

	switch value := .Interface().(type) {
	case map[string]interface{}:
		 = make([]clause.Assignment, 0, len())

		 := make([]string, 0, len())
		for  := range  {
			 = append(, )
		}
		sort.Strings()

		for ,  := range  {
			 := []
			if ,  := .(*gorm.DB);  {
				 = []interface{}{}
			}

			if .Schema != nil {
				if  := .Schema.LookUpField();  != nil {
					if .DBName != "" {
						if ,  := [.DBName]; ( && ) || (! && !) {
							 = append(, clause.Assignment{Column: clause.Column{Name: .DBName}, Value: })
							(, [])
						}
					} else if ,  := [.Name]; ( && ) || (! && !) {
						(, [])
					}
					continue
				}
			}

			if ,  := []; ( && ) || (! && !) {
				 = append(, clause.Assignment{Column: clause.Column{Name: }, Value: })
			}
		}

		if !.SkipHooks && .Schema != nil {
			for ,  := range .Schema.DBNames {
				 := .Schema.LookUpField()
				if .AutoUpdateTime > 0 && [.Name] == nil && [.DBName] == nil {
					if ,  := [.DBName]; ( && ) || ! {
						 := .DB.NowFunc()
						(, )

						if .AutoUpdateTime == schema.UnixNanosecond {
							 = append(, clause.Assignment{Column: clause.Column{Name: .DBName}, Value: .UnixNano()})
						} else if .AutoUpdateTime == schema.UnixMillisecond {
							 = append(, clause.Assignment{Column: clause.Column{Name: .DBName}, Value: .UnixNano() / 1e6})
						} else if .AutoUpdateTime == schema.UnixSecond {
							 = append(, clause.Assignment{Column: clause.Column{Name: .DBName}, Value: .Unix()})
						} else {
							 = append(, clause.Assignment{Column: clause.Column{Name: .DBName}, Value: })
						}
					}
				}
			}
		}
	default:
		 := .Schema
		var  bool
		if !.CanAddr() || .Dest != .Model {
			// different schema
			 := &gorm.Statement{DB: .DB}
			if  := .Parse(.Dest);  == nil {
				 = .Schema
				 = true
			}
		}

		switch .Kind() {
		case reflect.Struct:
			 = make([]clause.Assignment, 0, len(.Schema.FieldsByDBName))
			for ,  := range .Schema.DBNames {
				if  := .LookUpField();  != nil {
					if !.PrimaryKey || !.CanAddr() || .Dest != .Model {
						if ,  := [.DBName]; ( && ) || (! && (! || (!.SkipHooks && .AutoUpdateTime > 0))) {
							,  := .ValueOf(.Context, )
							if !.SkipHooks && .AutoUpdateTime > 0 {
								if .AutoUpdateTime == schema.UnixNanosecond {
									 = .DB.NowFunc().UnixNano()
								} else if .AutoUpdateTime == schema.UnixMillisecond {
									 = .DB.NowFunc().UnixNano() / 1e6
								} else if .AutoUpdateTime == schema.UnixSecond {
									 = .DB.NowFunc().Unix()
								} else {
									 = .DB.NowFunc()
								}
								 = false
							}

							if ( || !) && .Updatable {
								 = append(, clause.Assignment{Column: clause.Column{Name: .DBName}, Value: })
								 := 
								if  {
									if  := .Schema.LookUpField();  != nil {
										 = 
									}
								}
								(, )
							}
						}
					} else {
						if ,  := .ValueOf(.Context, ); ! {
							.AddClause(clause.Where{Exprs: []clause.Expression{clause.Eq{Column: .DBName, Value: }}})
						}
					}
				}
			}
		default:
			.AddError(gorm.ErrInvalidData)
		}
	}

	return
}