Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions callbacks/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package callbacks
import (
"fmt"
"reflect"
"strings"

"gorm.io/gorm"
"gorm.io/gorm/clause"
Expand Down Expand Up @@ -303,8 +302,9 @@ func ConvertToCreateValues(stmt *gorm.Statement) (values clause.Values) {
for _, column := range values.Columns {
if field := stmt.Schema.LookUpField(column.Name); field != nil {
if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
if !field.PrimaryKey && (!field.HasDefaultValue || field.DefaultValueInterface != nil ||
strings.EqualFold(field.DefaultValue, "NULL")) && field.AutoCreateTime == 0 {
// We can confirm the column either has a value or default value,
// so checking HasDefaultValue again will cause some columns to be missed.
if !field.PrimaryKey && field.AutoCreateTime == 0 {
if field.AutoUpdateTime > 0 {
assignment := clause.Assignment{Column: clause.Column{Name: field.DBName}, Value: curTime}
switch field.AutoUpdateTime {
Expand Down
51 changes: 51 additions & 0 deletions tests/associations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tests_test
import (
"testing"

"gorm.io/datatypes"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
Expand Down Expand Up @@ -183,6 +184,56 @@ func TestForeignKeyConstraintsBelongsTo(t *testing.T) {
}
}

func TestFullSaveAssociationsWithJSONDefault(t *testing.T) {
if DB.Dialector.Name() == "mysql" {
t.Skip() // mysql json can't have a default value
}

type ValueDep struct {
ID int
ValueID int
Name string
Params datatypes.JSONMap `gorm:"default:'{}'"`
}
type Value struct {
ID int
Name string
Dep ValueDep
}

if err := DB.Migrator().DropTable(&ValueDep{}, &Value{}); err != nil {
t.Fatalf("failed to drop value table, got err: %v", err)
}
if err := DB.AutoMigrate(&ValueDep{}, &Value{}); err != nil {
t.Fatalf("failed to migrate value table, got err: %v", err)
}

if err := DB.Create(&Value{
Name: "foo",
Dep: ValueDep{Name: "bar", Params: map[string]interface{}{"foo": "bar"}},
}).Error; err != nil {
t.Errorf("failed to create value, got err: %v", err)
}

var value Value
if err := DB.Preload("Dep").First(&value).Error; err != nil {
t.Errorf("failed to find value, got err: %v", err)
}

value.Dep.Params["foo"] = "new bar"
if err := DB.Session(&gorm.Session{FullSaveAssociations: true}).Save(&value).Error; err != nil {
t.Errorf("failed to svae value, got err: %v", err)
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected spelling of 'svae' to 'save'.

Suggested change
t.Errorf("failed to svae value, got err: %v", err)
t.Errorf("failed to save value, got err: %v", err)

Copilot uses AI. Check for mistakes.
}

var result Value
if err := DB.Preload("Dep").First(&result).Error; err != nil {
t.Errorf("failed to find value, got err: %v", err)
}
if result.Dep.Params["foo"] != "new bar" {
t.Errorf("failed to save value dep params, got: %v", result.Dep.Params)
}
}

func TestFullSaveAssociations(t *testing.T) {
coupon := &Coupon{
AppliesToProduct: []*CouponProduct{
Expand Down
61 changes: 47 additions & 14 deletions tests/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/jinzhu/now"
"gorm.io/datatypes"
"gorm.io/gorm"
"gorm.io/gorm/clause"
. "gorm.io/gorm/utils/tests"
Expand Down Expand Up @@ -580,38 +581,70 @@ func TestCreateWithAutoIncrementCompositeKey(t *testing.T) {
}
}

func TestCreateOnConfilctWithDefalutNull(t *testing.T) {
type OnConfilctUser struct {
func TestCreateOnConflictWithDefaultNull(t *testing.T) {
type OnConflictUser struct {
ID string
Name string `gorm:"default:null"`
Email string
Mobile string `gorm:"default:'133xxxx'"`
}

err := DB.Migrator().DropTable(&OnConfilctUser{})
err := DB.Migrator().DropTable(&OnConflictUser{})
AssertEqual(t, err, nil)
err = DB.AutoMigrate(&OnConfilctUser{})
err = DB.AutoMigrate(&OnConflictUser{})
AssertEqual(t, err, nil)

u := OnConfilctUser{
ID: "on-confilct-user-id",
Name: "on-confilct-user-name",
Email: "on-confilct-user-email",
Mobile: "on-confilct-user-mobile",
u := OnConflictUser{
ID: "on-conflict-user-id",
Name: "on-conflict-user-name",
Email: "on-conflict-user-email",
Mobile: "on-conflict-user-mobile",
}
err = DB.Create(&u).Error
AssertEqual(t, err, nil)

u.Name = "on-confilct-user-name-2"
u.Email = "on-confilct-user-email-2"
u.Name = "on-conflict-user-name-2"
u.Email = "on-conflict-user-email-2"
u.Mobile = ""
err = DB.Clauses(clause.OnConflict{UpdateAll: true}).Create(&u).Error
AssertEqual(t, err, nil)

var u2 OnConfilctUser
var u2 OnConflictUser
err = DB.Where("id = ?", u.ID).First(&u2).Error
AssertEqual(t, err, nil)
AssertEqual(t, u2.Name, "on-confilct-user-name-2")
AssertEqual(t, u2.Email, "on-confilct-user-email-2")
AssertEqual(t, u2.Name, "on-conflict-user-name-2")
AssertEqual(t, u2.Email, "on-conflict-user-email-2")
AssertEqual(t, u2.Mobile, "133xxxx")
}

func TestCreateOnConflictWithDefaultJSON(t *testing.T) {
if DB.Dialector.Name() == "mysql" {
t.Skip() // mysql json can't have a default value
}
type OnConflictValue struct {
ID int
Params datatypes.JSONMap `gorm:"default:'{}'"`
}

err := DB.Migrator().DropTable(&OnConflictValue{})
AssertEqual(t, err, nil)
err = DB.AutoMigrate(&OnConflictValue{})
AssertEqual(t, err, nil)

v := OnConflictValue{
Params: datatypes.JSONMap{"foo": "bar"},
}
err = DB.Create(&v).Error
AssertEqual(t, err, nil)

err = DB.Clauses(clause.OnConflict{UpdateAll: true}).Create(&OnConflictValue{
ID: v.ID,
Params: datatypes.JSONMap{"foo": "new-bar"},
}).Error
AssertEqual(t, err, nil)

var v2 OnConflictValue
err = DB.Where("id = ?", v.ID).First(&v2).Error
AssertEqual(t, err, nil)
AssertEqual(t, v2.Params, datatypes.JSONMap{"foo": "new-bar"})
}
1 change: 1 addition & 0 deletions tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/jinzhu/now v1.1.5
github.com/lib/pq v1.10.8
github.com/mattn/go-sqlite3 v1.14.16 // indirect
gorm.io/datatypes v1.2.0
gorm.io/driver/mysql v1.5.0
gorm.io/driver/postgres v1.5.0
gorm.io/driver/sqlite v1.5.0
Expand Down