gorm/callback_create.go

195 lines
6.5 KiB
Go
Raw Normal View History

2014-01-26 08:41:37 +04:00
package gorm
2014-01-26 15:34:06 +04:00
import (
"fmt"
"strings"
)
2016-01-17 11:28:32 +03:00
// Define callbacks for creating
func init() {
DefaultCallback.Create().Register("gorm:begin_transaction", beginTransactionCallback)
DefaultCallback.Create().Register("gorm:before_create", beforeCreateCallback)
DefaultCallback.Create().Register("gorm:save_before_associations", saveBeforeAssociationsCallback)
DefaultCallback.Create().Register("gorm:update_time_stamp", updateTimeStampForCreateCallback)
DefaultCallback.Create().Register("gorm:create", createCallback)
DefaultCallback.Create().Register("gorm:force_reload_after_create", forceReloadAfterCreateCallback)
DefaultCallback.Create().Register("gorm:save_after_associations", saveAfterAssociationsCallback)
DefaultCallback.Create().Register("gorm:after_create", afterCreateCallback)
DefaultCallback.Create().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback)
2016-01-17 11:28:32 +03:00
}
// beforeCreateCallback will invoke `BeforeSave`, `BeforeCreate` method before creating
2016-01-17 10:30:42 +03:00
func beforeCreateCallback(scope *Scope) {
if !scope.HasError() {
scope.CallMethod("BeforeSave")
}
if !scope.HasError() {
scope.CallMethod("BeforeCreate")
}
2014-01-26 08:41:37 +04:00
}
2016-01-17 11:28:32 +03:00
// updateTimeStampForCreateCallback will set `CreatedAt`, `UpdatedAt` when creating
2016-01-17 10:30:42 +03:00
func updateTimeStampForCreateCallback(scope *Scope) {
2014-01-26 08:41:37 +04:00
if !scope.HasError() {
now := scope.db.nowFunc()
if createdAtField, ok := scope.FieldByName("CreatedAt"); ok {
if createdAtField.IsBlank {
createdAtField.Set(now)
}
}
if updatedAtField, ok := scope.FieldByName("UpdatedAt"); ok {
if updatedAtField.IsBlank {
updatedAtField.Set(now)
}
}
2014-01-27 07:06:13 +04:00
}
}
2014-01-26 17:23:53 +04:00
2016-01-17 11:28:32 +03:00
// createCallback the callback used to insert data into database
2016-01-17 10:30:42 +03:00
func createCallback(scope *Scope) {
2014-01-27 07:06:13 +04:00
if !scope.HasError() {
defer scope.trace(scope.db.nowFunc())
2016-01-17 11:37:17 +03:00
2016-01-17 12:46:56 +03:00
var (
columns, placeholders []string
blankColumnsWithDefaultValue []string
)
2016-03-07 07:15:15 +03:00
for _, field := range scope.Fields() {
2015-03-12 13:30:59 +03:00
if scope.changeableField(field) {
if field.IsNormal && !field.IsIgnored {
if field.IsBlank && field.HasDefaultValue {
blankColumnsWithDefaultValue = append(blankColumnsWithDefaultValue, scope.Quote(field.DBName))
scope.InstanceSet("gorm:blank_columns_with_default_value", blankColumnsWithDefaultValue)
} else if !field.IsPrimaryKey || !field.IsBlank {
columns = append(columns, scope.Quote(field.DBName))
placeholders = append(placeholders, scope.AddToVars(field.Field.Interface()))
2015-03-12 12:47:31 +03:00
}
2016-01-17 12:46:56 +03:00
} else if field.Relationship != nil && field.Relationship.Kind == "belongs_to" {
for _, foreignKey := range field.Relationship.ForeignDBNames {
2016-03-07 07:15:15 +03:00
if foreignField, ok := scope.FieldByName(foreignKey); ok && !scope.changeableField(foreignField) {
2016-01-17 12:46:56 +03:00
columns = append(columns, scope.Quote(foreignField.DBName))
placeholders = append(placeholders, scope.AddToVars(foreignField.Field.Interface()))
2015-07-30 09:26:48 +03:00
}
2015-03-12 12:47:31 +03:00
}
}
2014-01-26 15:34:06 +04:00
}
}
2016-01-19 06:53:53 +03:00
var (
returningColumn = "*"
quotedTableName = scope.QuotedTableName()
primaryField = scope.PrimaryField()
extraOption string
2019-03-10 15:17:21 +03:00
insertModifier string
2016-01-19 06:53:53 +03:00
)
if str, ok := scope.Get("gorm:insert_option"); ok {
extraOption = fmt.Sprint(str)
}
2019-03-10 15:17:21 +03:00
if str, ok := scope.Get("gorm:insert_modifier"); ok {
insertModifier = strings.ToUpper(fmt.Sprint(str))
if insertModifier == "INTO" {
insertModifier = ""
}
}
2015-02-17 15:19:47 +03:00
if primaryField != nil {
2016-01-19 06:53:53 +03:00
returningColumn = scope.Quote(primaryField.DBName)
}
2016-03-07 09:54:20 +03:00
lastInsertIDReturningSuffix := scope.Dialect().LastInsertIDReturningSuffix(quotedTableName, returningColumn)
lastInsertIDOutputInterstitial := scope.Dialect().LastInsertIDOutputInterstitial(quotedTableName, returningColumn, columns)
2016-01-19 06:53:53 +03:00
2014-04-29 13:42:10 +04:00
if len(columns) == 0 {
scope.Raw(fmt.Sprintf(
"INSERT%v INTO %v %v%v%v",
2019-03-10 15:17:21 +03:00
addExtraSpaceIfExist(insertModifier),
quotedTableName,
scope.Dialect().DefaultValueStr(),
addExtraSpaceIfExist(extraOption),
2016-03-07 09:54:20 +03:00
addExtraSpaceIfExist(lastInsertIDReturningSuffix),
))
2014-04-29 13:42:10 +04:00
} else {
scope.Raw(fmt.Sprintf(
"INSERT%v INTO %v (%v)%v VALUES (%v)%v%v",
2019-03-10 15:17:21 +03:00
addExtraSpaceIfExist(insertModifier),
2014-06-03 13:15:05 +04:00
scope.QuotedTableName(),
2014-04-29 13:42:10 +04:00
strings.Join(columns, ","),
addExtraSpaceIfExist(lastInsertIDOutputInterstitial),
2016-01-17 12:46:56 +03:00
strings.Join(placeholders, ","),
addExtraSpaceIfExist(extraOption),
2016-03-07 09:54:20 +03:00
addExtraSpaceIfExist(lastInsertIDReturningSuffix),
2014-04-29 13:42:10 +04:00
))
}
2014-01-26 15:34:06 +04:00
// execute create sql: no primaryField
if primaryField == nil {
2016-03-07 09:54:20 +03:00
if result, err := scope.SQLDB().Exec(scope.SQL, scope.SQLVars...); scope.Err(err) == nil {
2016-01-17 12:46:56 +03:00
// set rows affected count
scope.db.RowsAffected, _ = result.RowsAffected()
// set primary value to primary field
if primaryField != nil && primaryField.IsBlank {
if primaryValue, err := result.LastInsertId(); scope.Err(err) == nil {
scope.Err(primaryField.Set(primaryValue))
2015-02-20 17:06:49 +03:00
}
2014-06-05 13:58:14 +04:00
}
2014-01-26 08:41:37 +04:00
}
return
}
// execute create sql: lastInsertID implemention for majority of dialects
if lastInsertIDReturningSuffix == "" && lastInsertIDOutputInterstitial == "" {
if result, err := scope.SQLDB().Exec(scope.SQL, scope.SQLVars...); scope.Err(err) == nil {
// set rows affected count
scope.db.RowsAffected, _ = result.RowsAffected()
// set primary value to primary field
if primaryField != nil && primaryField.IsBlank {
if primaryValue, err := result.LastInsertId(); scope.Err(err) == nil {
scope.Err(primaryField.Set(primaryValue))
}
}
2014-06-09 04:17:20 +04:00
}
return
}
// execute create sql: dialects with additional lastInsertID requirements (currently postgres & mssql)
if primaryField.Field.CanAddr() {
if err := scope.SQLDB().QueryRow(scope.SQL, scope.SQLVars...).Scan(primaryField.Field.Addr().Interface()); scope.Err(err) == nil {
primaryField.IsBlank = false
scope.db.RowsAffected = 1
}
} else {
scope.Err(ErrUnaddressable)
2014-01-26 08:41:37 +04:00
}
return
2014-01-26 08:41:37 +04:00
}
}
2016-01-17 11:28:32 +03:00
// forceReloadAfterCreateCallback will reload columns that having default value, and set it back to current object
2016-01-17 10:30:42 +03:00
func forceReloadAfterCreateCallback(scope *Scope) {
2016-01-17 12:46:56 +03:00
if blankColumnsWithDefaultValue, ok := scope.InstanceGet("gorm:blank_columns_with_default_value"); ok {
db := scope.DB().New().Table(scope.TableName()).Select(blankColumnsWithDefaultValue.([]string))
for _, field := range scope.Fields() {
if field.IsPrimaryKey && !field.IsBlank {
db = db.Where(fmt.Sprintf("%v = ?", field.DBName), field.Field.Interface())
}
}
db.Scan(scope.Value)
}
}
2016-01-17 13:38:18 +03:00
// afterCreateCallback will invoke `AfterCreate`, `AfterSave` method after creating
2016-01-17 10:30:42 +03:00
func afterCreateCallback(scope *Scope) {
if !scope.HasError() {
scope.CallMethod("AfterCreate")
}
if !scope.HasError() {
scope.CallMethod("AfterSave")
}
2014-01-26 08:41:37 +04:00
}