From 7593bc4254c0d724c082d991a2685fd3051ed934 Mon Sep 17 00:00:00 2001 From: Wenbo han Date: Sat, 8 Apr 2023 18:18:17 +0800 Subject: [PATCH] Support model events --- contracts/database/orm/events.go | 45 ++ database/gorm/gorm.go | 441 +++++++++++-- database/gorm/gorm_test.go | 1005 +++++++++++++++++++++++------- 3 files changed, 1203 insertions(+), 288 deletions(-) create mode 100644 contracts/database/orm/events.go diff --git a/contracts/database/orm/events.go b/contracts/database/orm/events.go new file mode 100644 index 000000000..4a4688049 --- /dev/null +++ b/contracts/database/orm/events.go @@ -0,0 +1,45 @@ +package orm + +type Retrieved interface { + Retrieved(Query) error +} + +type Creating interface { + Creating(Query) error +} + +type Created interface { + Created(Query) error +} + +type Updating interface { + Updating(Query) error +} + +type Updated interface { + Updated(Query) error +} + +type Saving interface { + Saving(Query) error +} + +type Saved interface { + Saved(Query) error +} + +type Deleting interface { + Deleting(Query) error +} + +type Deleted interface { + Deleted(Query) error +} + +type ForceDeleting interface { + ForceDeleting(Query) error +} + +type ForceDeleted interface { + ForceDeleted(Query) error +} diff --git a/database/gorm/gorm.go b/database/gorm/gorm.go index b004bd58a..da97129fc 100644 --- a/database/gorm/gorm.go +++ b/database/gorm/gorm.go @@ -184,43 +184,37 @@ func (r *Query) Create(value any) error { } if len(r.instance.Statement.Selects) > 0 { - if len(r.instance.Statement.Selects) == 1 && r.instance.Statement.Selects[0] == orm.Associations { - r.instance.Statement.Selects = []string{} - return r.instance.Create(value).Error - } - - for _, val := range r.instance.Statement.Selects { - if val == orm.Associations { - return errors.New("cannot set orm.Associations and other fields at the same time") - } - } - - return r.instance.Create(value).Error + return r.selectCreate(value) } if len(r.instance.Statement.Omits) > 0 { - if len(r.instance.Statement.Omits) == 1 && r.instance.Statement.Omits[0] == orm.Associations { - r.instance.Statement.Selects = []string{} - return r.instance.Omit(orm.Associations).Create(value).Error - } + return r.omitCreate(value) + } - for _, val := range r.instance.Statement.Omits { - if val == orm.Associations { - return errors.New("cannot set orm.Associations and other fields at the same time") - } + return r.create(value) +} + +func (r *Query) Delete(dest any, conds ...any) (*contractsorm.Result, error) { + if deletingModel, ok := dest.(contractsorm.Deleting); ok { + if err := deletingModel.Deleting(r); err != nil { + return nil, err } + } - return r.instance.Create(value).Error + res := r.instance.Delete(dest, conds...) + if res.Error != nil { + return nil, res.Error } - return r.instance.Omit(orm.Associations).Create(value).Error -} + if deletedModel, ok := dest.(contractsorm.Deleted); ok { + if err := deletedModel.Deleted(r); err != nil { + return nil, err + } + } -func (r *Query) Delete(value any, conds ...any) (*contractsorm.Result, error) { - result := r.instance.Delete(value, conds...) return &contractsorm.Result{ - RowsAffected: result.RowsAffected, - }, result.Error + RowsAffected: res.RowsAffected, + }, nil } func (r *Query) Distinct(args ...any) contractsorm.Query { @@ -238,7 +232,7 @@ func (r *Query) Exec(sql string, values ...any) (*contractsorm.Result, error) { } func (r *Query) Find(dest any, conds ...any) error { - if len(conds) == 1 { + if len(conds) > 0 { switch cond := conds[0].(type) { case string: if cond == "" { @@ -255,57 +249,111 @@ func (r *Query) Find(dest any, conds ...any) error { } } - return r.instance.Find(dest, conds...).Error + if err := r.instance.Find(dest, conds...).Error; err != nil { + return err + } + + return retrieved(r, dest) } func (r *Query) First(dest any) error { - err := r.instance.First(dest).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil + res := r.instance.First(dest) + if res.Error != nil { + if errors.Is(res.Error, gorm.ErrRecordNotFound) { + return nil + } + + return res.Error } - return err + return retrieved(r, dest) } func (r *Query) FirstOr(dest any, callback func() error) error { err := r.instance.First(dest).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - return callback() + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return callback() + } + + return err } - return nil + return retrieved(r, dest) +} + +func (r *Query) FirstOrCreate(dest any, conds ...any) error { + if len(conds) == 0 { + return errors.New("query condition is require") + } + + var res *gorm.DB + if len(conds) > 1 { + res = r.instance.Attrs(conds[1]).FirstOrInit(dest, conds[0]) + } else { + res = r.instance.FirstOrInit(dest, conds[0]) + } + + if res.Error != nil { + return res.Error + } + if res.RowsAffected > 0 { + return retrieved(r, dest) + } + + return r.Create(dest) } func (r *Query) FirstOrFail(dest any) error { err := r.instance.First(dest).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - return orm.ErrRecordNotFound + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return orm.ErrRecordNotFound + } + + return err } - return err + return retrieved(r, dest) } func (r *Query) FirstOrNew(dest any, attributes any, values ...any) error { + var res *gorm.DB if len(values) > 0 { - return r.instance.Attrs(values[0]).FirstOrInit(dest, attributes).Error + res = r.instance.Attrs(values[0]).FirstOrInit(dest, attributes) } else { - return r.instance.FirstOrInit(dest, attributes).Error + res = r.instance.FirstOrInit(dest, attributes) } -} -func (r *Query) FirstOrCreate(dest any, conds ...any) error { - var err error - if len(conds) > 1 { - err = r.instance.Attrs(conds[1]).FirstOrCreate(dest, conds[0]).Error - } else { - err = r.instance.FirstOrCreate(dest, conds...).Error + if res.Error != nil { + return res.Error + } + if res.RowsAffected > 0 { + return retrieved(r, dest) } - return err + return nil } func (r *Query) ForceDelete(value any, conds ...any) (*contractsorm.Result, error) { + if forceDeletingModel, ok := value.(contractsorm.ForceDeleting); ok { + if err := forceDeletingModel.ForceDeleting(r); err != nil { + return nil, err + } + } + res := r.instance.Unscoped().Delete(value, conds...) + if res.Error != nil { + return nil, res.Error + } + + if res.RowsAffected > 0 { + if forceDeletedModel, ok := value.(contractsorm.ForceDeleted); ok { + if err := forceDeletedModel.ForceDeleted(r); err != nil { + return nil, err + } + } + } return &contractsorm.Result{ RowsAffected: res.RowsAffected, @@ -313,7 +361,7 @@ func (r *Query) ForceDelete(value any, conds ...any) (*contractsorm.Result, erro } func (r *Query) Get(dest any) error { - return r.instance.Find(dest).Error + return r.Find(dest) } func (r *Query) Group(name string) contractsorm.Query { @@ -467,26 +515,14 @@ func (r *Query) Save(value any) error { } if len(r.instance.Statement.Selects) > 0 { - for _, val := range r.instance.Statement.Selects { - if val == orm.Associations { - return r.instance.Session(&gorm.Session{FullSaveAssociations: true}).Save(value).Error - } - } - - return r.instance.Save(value).Error + return r.selectSave(value) } if len(r.instance.Statement.Omits) > 0 { - for _, val := range r.instance.Statement.Omits { - if val == orm.Associations { - return r.instance.Omit(orm.Associations).Save(value).Error - } - } - - return r.instance.Save(value).Error + return r.omitSave(value) } - return r.instance.Omit(orm.Associations).Save(value).Error + return r.save(value) } func (r *Query) Scan(dest any) error { @@ -555,7 +591,15 @@ func (r *Query) Updates(values any) (*contractsorm.Result, error) { } func (r *Query) UpdateOrCreate(dest any, attributes any, values any) error { - return r.instance.Assign(values).FirstOrCreate(dest, attributes).Error + res := r.instance.Assign(values).FirstOrInit(dest, attributes) + if res.Error != nil { + return res.Error + } + if res.RowsAffected > 0 { + return r.Save(dest) + } + + return r.Create(dest) } func (r *Query) Where(query any, args ...any) contractsorm.Query { @@ -607,3 +651,268 @@ func (r *Query) Scopes(funcs ...func(contractsorm.Query) contractsorm.Query) con return NewQueryInstance(tx) } + +func (r *Query) selectCreate(value any) error { + if len(r.instance.Statement.Selects) == 1 && r.instance.Statement.Selects[0] == orm.Associations { + r.instance.Statement.Selects = []string{} + + return create(r, value) + } + + for _, val := range r.instance.Statement.Selects { + if val == orm.Associations { + return errors.New("cannot set orm.Associations and other fields at the same time") + } + } + + return create(r, value) +} + +func (r *Query) omitCreate(value any) error { + if len(r.instance.Statement.Omits) == 1 && r.instance.Statement.Omits[0] == orm.Associations { + r.instance.Statement.Selects = []string{} + if err := saving(r, value); err != nil { + return err + } + if err := creating(r, value); err != nil { + return err + } + if err := r.instance.Omit(orm.Associations).Create(value).Error; err != nil { + return err + } + if err := created(r, value); err != nil { + return err + } + if err := saved(r, value); err != nil { + return err + } + + return nil + } + + for _, val := range r.instance.Statement.Omits { + if val == orm.Associations { + return errors.New("cannot set orm.Associations and other fields at the same time") + } + } + + return create(r, value) +} + +func (r *Query) create(value any) error { + if err := saving(r, value); err != nil { + return err + } + if err := creating(r, value); err != nil { + return err + } + + if err := r.instance.Omit(orm.Associations).Create(value).Error; err != nil { + return err + } + + if err := created(r, value); err != nil { + return err + } + if err := saved(r, value); err != nil { + return err + } + + return nil +} + +func (r *Query) selectSave(value any) error { + for _, val := range r.instance.Statement.Selects { + if val == orm.Associations { + if err := saving(r, value); err != nil { + return err + } + if err := updating(r, value); err != nil { + return err + } + if err := r.instance.Session(&gorm.Session{FullSaveAssociations: true}).Save(value).Error; err != nil { + return err + } + if err := updated(r, value); err != nil { + return err + } + if err := saved(r, value); err != nil { + return err + } + + return nil + } + } + + if err := saving(r, value); err != nil { + return err + } + if err := updating(r, value); err != nil { + return err + } + if err := r.instance.Save(value).Error; err != nil { + return err + } + if err := updated(r, value); err != nil { + return err + } + if err := saved(r, value); err != nil { + return err + } + + return nil +} + +func (r *Query) omitSave(value any) error { + for _, val := range r.instance.Statement.Omits { + if val == orm.Associations { + if err := saving(r, value); err != nil { + return err + } + if err := updating(r, value); err != nil { + return err + } + if err := r.instance.Omit(orm.Associations).Save(value).Error; err != nil { + return err + } + if err := updated(r, value); err != nil { + return err + } + if err := saved(r, value); err != nil { + return err + } + + return nil + } + } + + if err := saving(r, value); err != nil { + return err + } + if err := updating(r, value); err != nil { + return err + } + if err := r.instance.Save(value).Error; err != nil { + return err + } + if err := updated(r, value); err != nil { + return err + } + if err := saved(r, value); err != nil { + return err + } + + return nil +} + +func (r *Query) save(value any) error { + if err := saving(r, value); err != nil { + return err + } + if err := updating(r, value); err != nil { + return err + } + if err := r.instance.Omit(orm.Associations).Save(value).Error; err != nil { + return err + } + if err := updated(r, value); err != nil { + return err + } + if err := saved(r, value); err != nil { + return err + } + + return nil +} + +func retrieved(query *Query, dest any) error { + if retrievedModel, ok := dest.(contractsorm.Retrieved); ok { + if err := retrievedModel.Retrieved(query); err != nil { + return err + } + } + + return nil +} + +func updating(query *Query, dest any) error { + if updatingModel, ok := dest.(contractsorm.Updating); ok { + if err := updatingModel.Updating(query); err != nil { + return err + } + } + + return nil +} + +func updated(query *Query, dest any) error { + if updatedModel, ok := dest.(contractsorm.Updated); ok { + if err := updatedModel.Updated(query); err != nil { + return err + } + } + + return nil +} + +func saving(query *Query, dest any) error { + if savingModel, ok := dest.(contractsorm.Saving); ok { + if err := savingModel.Saving(query); err != nil { + return err + } + } + + return nil +} + +func saved(query *Query, dest any) error { + if savedModel, ok := dest.(contractsorm.Saved); ok { + if err := savedModel.Saved(query); err != nil { + return err + } + } + + return nil +} + +func creating(query *Query, dest any) error { + if creatingModel, ok := dest.(contractsorm.Creating); ok { + if err := creatingModel.Creating(query); err != nil { + return err + } + } + + return nil +} + +func created(query *Query, dest any) error { + if createdModel, ok := dest.(contractsorm.Created); ok { + if err := createdModel.Created(query); err != nil { + return err + } + } + + return nil +} + +func create(query *Query, dest any) error { + if err := saving(query, dest); err != nil { + return err + } + if err := creating(query, dest); err != nil { + return err + } + + if err := query.instance.Create(dest).Error; err != nil { + return err + } + + if err := created(query, dest); err != nil { + return err + } + if err := saved(query, dest); err != nil { + return err + } + + return nil +} diff --git a/database/gorm/gorm_test.go b/database/gorm/gorm_test.go index a29eb3546..54b5c6c52 100644 --- a/database/gorm/gorm_test.go +++ b/database/gorm/gorm_test.go @@ -1,7 +1,6 @@ package gorm import ( - "errors" "fmt" "log" "strconv" @@ -29,6 +28,130 @@ type User struct { Roles []*Role `gorm:"many2many:role_user"` } +func (u *User) Creating(query contractsorm.Query) error { + if u.Name == "event_create_name" { + u.Avatar = "event_create_avatar" + } + if u.Name == "event_save_create_name" { + u.Avatar = "event_create_avatar" + } + if u.Name == "event_create_first_or_create_name" { + u.Avatar = "event_create_first_or_create_avatar" + } + + return nil +} + +func (u *User) Created(query contractsorm.Query) error { + if u.Name == "event_create_name" { + u.Avatar = "event_created_avatar" + } + if u.Name == "event_create_first_or_create_name" { + u.Avatar = "event_created_first_or_create_avatar" + } + + return nil +} + +func (u *User) Saving(query contractsorm.Query) error { + if u.Name == "event_save_create_name" { + u.Avatar = "event_save_create_avatar" + } + if u.Name == "event_save_update_save_name" { + u.Avatar = "event_save_update_save_avatar" + } + + return nil +} + +func (u *User) Saved(query contractsorm.Query) error { + if u.Name == "event_save_create_name" { + u.Avatar = "event_saved_avatar" + } + if u.Name == "event_save_update_save_name" { + u.Avatar = u.Avatar + "1" + } + + return nil +} + +func (u *User) Updating(query contractsorm.Query) error { + if u.Name == "event_update_save_name" { + u.Avatar = "event_update_save_avatar" + } + if u.Name == "event_save_update_save_name" { + u.Avatar = u.Avatar + "1" + } + + return nil +} + +func (u *User) Updated(query contractsorm.Query) error { + if u.Name == "event_update_save_name" { + u.Avatar = "event_updated_save_avatar" + } + if u.Name == "event_save_update_save_name" { + u.Avatar = "event_saved_updated_save_avatar" + } + + return nil +} + +func (u *User) Deleting(query contractsorm.Query) error { + if u.Name == "event_delete_name" { + u.Avatar = "event_delete_avatar" + } + + return nil +} + +func (u *User) Deleted(query contractsorm.Query) error { + if u.Name == "event_delete_name" { + u.Avatar = "event_deleted_avatar" + } + + return nil +} + +func (u *User) Retrieved(query contractsorm.Query) error { + if u.Name == "event_retrieve_find_name" { + u.Name = "event_retrieved_find_name" + } + if u.Name == "event_retrieve_first_name" { + u.Name = "event_retrieved_first_name" + } + if u.Name == "event_retrieve_first_or_name" { + u.Name = "event_retrieved_first_or_name" + } + if u.Name == "event_retrieve_first_or_create_name" { + u.Name = "event_retrieved_first_or_create_name" + } + if u.Name == "event_retrieve_first_or_fail_name" { + u.Name = "event_retrieved_first_or_fail_name" + } + if u.Name == "event_retrieve_first_or_new_name" { + u.Name = "event_retrieved_first_or_new_name" + } + + return nil +} + +func (u *User) ForceDeleting(query contractsorm.Query) error { + if u.Name == "event_force_delete_name" { + u.Name = "event_force_delete_name1" + } + + return nil +} + +func (u *User) ForceDeleted(query contractsorm.Query) error { + if u.Name == "event_force_delete_name1" { + u.Name = "event_force_deleted_name" + } + + return nil +} + type Role struct { orm.Model Name string @@ -369,160 +492,223 @@ func (s *GormQueryTestSuite) TestCount() { } func (s *GormQueryTestSuite) TestCreate() { - for driver, query := range s.queries { - s.Run(driver.String(), func() { - tests := []struct { - description string - setup func(description string) - }{ - { - description: "success when create with no relationships", - setup: func(description string) { - user := User{Name: "create_user", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} - user.Address.Name = "create_address" - user.Books[0].Name = "create_book0" - user.Books[1].Name = "create_book1" - s.Nil(query.Create(&user), description) - s.True(user.ID > 0, description) - s.True(user.Address.ID == 0, description) - s.True(user.Books[0].ID == 0, description) - s.True(user.Books[1].ID == 0, description) - }, + for _, query := range s.queries { + tests := []struct { + name string + setup func() + }{ + { + name: "success when create with no relationships", + setup: func() { + user := User{Name: "create_user", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} + user.Address.Name = "create_address" + user.Books[0].Name = "create_book0" + user.Books[1].Name = "create_book1" + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + s.True(user.Address.ID == 0) + s.True(user.Books[0].ID == 0) + s.True(user.Books[1].ID == 0) }, - { - description: "success when create with select orm.Associations", - setup: func(description string) { - user := User{Name: "create_user", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} - user.Address.Name = "create_address" - user.Books[0].Name = "create_book0" - user.Books[1].Name = "create_book1" - s.Nil(query.Select(orm.Associations).Create(&user), description) - s.True(user.ID > 0, description) - s.True(user.Address.ID > 0, description) - s.True(user.Books[0].ID > 0, description) - s.True(user.Books[1].ID > 0, description) - }, + }, + { + name: "success when create with select orm.Associations", + setup: func() { + user := User{Name: "create_user", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} + user.Address.Name = "create_address" + user.Books[0].Name = "create_book0" + user.Books[1].Name = "create_book1" + s.Nil(query.Select(orm.Associations).Create(&user)) + s.True(user.ID > 0) + s.True(user.Address.ID > 0) + s.True(user.Books[0].ID > 0) + s.True(user.Books[1].ID > 0) }, - { - description: "success when create with select fields", - setup: func(description string) { - user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} - user.Address.Name = "create_address" - user.Books[0].Name = "create_book0" - user.Books[1].Name = "create_book1" - s.Nil(query.Select("Name", "Avatar", "Address").Create(&user), description) - s.True(user.ID > 0, description) - s.True(user.Address.ID > 0, description) - s.True(user.Books[0].ID == 0, description) - s.True(user.Books[1].ID == 0, description) - }, + }, + { + name: "success when create with select fields", + setup: func() { + user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} + user.Address.Name = "create_address" + user.Books[0].Name = "create_book0" + user.Books[1].Name = "create_book1" + s.Nil(query.Select("Name", "Avatar", "Address").Create(&user)) + s.True(user.ID > 0) + s.True(user.Address.ID > 0) + s.True(user.Books[0].ID == 0) + s.True(user.Books[1].ID == 0) }, - { - description: "success when create with omit fields", - setup: func(description string) { - user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} - user.Address.Name = "create_address" - user.Books[0].Name = "create_book0" - user.Books[1].Name = "create_book1" - s.Nil(query.Omit("Address").Create(&user), description) - s.True(user.ID > 0, description) - s.True(user.Address.ID == 0, description) - s.True(user.Books[0].ID > 0, description) - s.True(user.Books[1].ID > 0, description) - }, + }, + { + name: "success when create with omit fields", + setup: func() { + user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} + user.Address.Name = "create_address" + user.Books[0].Name = "create_book0" + user.Books[1].Name = "create_book1" + s.Nil(query.Omit("Address").Create(&user)) + s.True(user.ID > 0) + s.True(user.Address.ID == 0) + s.True(user.Books[0].ID > 0) + s.True(user.Books[1].ID > 0) }, - { - description: "success create with omit orm.Associations", - setup: func(description string) { - user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} - user.Address.Name = "create_address" - user.Books[0].Name = "create_book0" - user.Books[1].Name = "create_book1" - s.Nil(query.Omit(orm.Associations).Create(&user), description) - s.True(user.ID > 0, description) - s.True(user.Address.ID == 0, description) - s.True(user.Books[0].ID == 0, description) - s.True(user.Books[1].ID == 0, description) - }, + }, + { + name: "success create with omit orm.Associations", + setup: func() { + user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} + user.Address.Name = "create_address" + user.Books[0].Name = "create_book0" + user.Books[1].Name = "create_book1" + s.Nil(query.Omit(orm.Associations).Create(&user)) + s.True(user.ID > 0) + s.True(user.Address.ID == 0) + s.True(user.Books[0].ID == 0) + s.True(user.Books[1].ID == 0) }, - { - description: "error when set select and omit at the same time", - setup: func(description string) { - user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} - user.Address.Name = "create_address" - user.Books[0].Name = "create_book0" - user.Books[1].Name = "create_book1" - s.EqualError(query.Omit(orm.Associations).Select("Name").Create(&user), "cannot set Select and Omits at the same time", description) - }, + }, + { + name: "error when set select and omit at the same time", + setup: func() { + user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} + user.Address.Name = "create_address" + user.Books[0].Name = "create_book0" + user.Books[1].Name = "create_book1" + s.EqualError(query.Omit(orm.Associations).Select("Name").Create(&user), "cannot set Select and Omits at the same time") }, - { - description: "error when select that set fields and orm.Associations at the same time", - setup: func(description string) { - user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} - user.Address.Name = "create_address" - user.Books[0].Name = "create_book0" - user.Books[1].Name = "create_book1" - s.EqualError(query.Select("Name", orm.Associations).Create(&user), "cannot set orm.Associations and other fields at the same time", description) - }, + }, + { + name: "error when select that set fields and orm.Associations at the same time", + setup: func() { + user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} + user.Address.Name = "create_address" + user.Books[0].Name = "create_book0" + user.Books[1].Name = "create_book1" + s.EqualError(query.Select("Name", orm.Associations).Create(&user), "cannot set orm.Associations and other fields at the same time") }, - { - description: "error when omit that set fields and orm.Associations at the same time", - setup: func(description string) { - user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} - user.Address.Name = "create_address" - user.Books[0].Name = "create_book0" - user.Books[1].Name = "create_book1" - s.EqualError(query.Omit("Name", orm.Associations).Create(&user), "cannot set orm.Associations and other fields at the same time", description) - }, + }, + { + name: "error when omit that set fields and orm.Associations at the same time", + setup: func() { + user := User{Name: "create_user", Avatar: "create_avatar", Address: &Address{}, Books: []*Book{&Book{}, &Book{}}} + user.Address.Name = "create_address" + user.Books[0].Name = "create_book0" + user.Books[1].Name = "create_book1" + s.EqualError(query.Omit("Name", orm.Associations).Create(&user), "cannot set orm.Associations and other fields at the same time") }, - } - for _, test := range tests { - test.setup(test.description) - } - }) + }, + { + name: "success with create event", + setup: func() { + user := User{Name: "event_create_name"} + s.Nil(query.Create(&user)) + s.Equal("event_created_avatar", user.Avatar) + + var user1 User + s.Nil(query.Where("name", "event_create_name").First(&user1)) + s.Equal("event_create_avatar", user1.Avatar) + }, + }, + { + name: "success with save event", + setup: func() { + user := User{Name: "event_save_create_name"} + s.Nil(query.Create(&user)) + s.Equal("event_saved_avatar", user.Avatar) + + var user1 User + s.Nil(query.Where("name", "event_save_create_name").First(&user1)) + s.Equal("event_create_avatar", user1.Avatar) + }, + }, + } + for _, test := range tests { + s.Run(test.name, func() { + test.setup() + }) + } } } func (s *GormQueryTestSuite) TestDelete() { - for driver, query := range s.queries { - s.Run(driver.String(), func() { - user := User{Name: "delete_user", Avatar: "delete_avatar"} - s.Nil(query.Create(&user)) - s.True(user.ID > 0) - - res, err := query.Delete(&user) - s.Equal(int64(1), res.RowsAffected) - s.Nil(err) - - var user1 User - s.Nil(query.Find(&user1, user.ID)) - s.Equal(uint(0), user1.ID) - - user2 := User{Name: "delete_user", Avatar: "delete_avatar"} - s.Nil(query.Create(&user2)) - s.True(user2.ID > 0) - - res, err = query.Delete(&User{}, user2.ID) - s.Equal(int64(1), res.RowsAffected) - s.Nil(err) - - var user3 User - s.Nil(query.Find(&user3, user2.ID)) - s.Equal(uint(0), user3.ID) - - users := []User{{Name: "delete_user", Avatar: "delete_avatar"}, {Name: "delete_user1", Avatar: "delete_avatar1"}} - s.Nil(query.Create(&users)) - s.True(users[0].ID > 0) - s.True(users[1].ID > 0) - - res, err = query.Delete(&User{}, []uint{users[0].ID, users[1].ID}) - s.Equal(int64(2), res.RowsAffected) - s.Nil(err) - - var count int64 - s.Nil(query.Model(&User{}).Where("name", "delete_user").OrWhere("name", "delete_user1").Count(&count)) - s.True(count == 0) - }) + for _, query := range s.queries { + tests := []struct { + name string + setup func() + }{ + { + name: "success", + setup: func() { + user := User{Name: "delete_user", Avatar: "delete_avatar"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + res, err := query.Delete(&user) + s.Equal(int64(1), res.RowsAffected) + s.Nil(err) + + var user1 User + s.Nil(query.Find(&user1, user.ID)) + s.Equal(uint(0), user1.ID) + }, + }, + { + name: "success by id", + setup: func() { + user := User{Name: "delete_user", Avatar: "delete_avatar"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + res, err := query.Delete(&User{}, user.ID) + s.Equal(int64(1), res.RowsAffected) + s.Nil(err) + + var user1 User + s.Nil(query.Find(&user1, user.ID)) + s.Equal(uint(0), user1.ID) + }, + }, + { + name: "success by multiple", + setup: func() { + users := []User{{Name: "delete_user", Avatar: "delete_avatar"}, {Name: "delete_user1", Avatar: "delete_avatar1"}} + s.Nil(query.Create(&users)) + s.True(users[0].ID > 0) + s.True(users[1].ID > 0) + + res, err := query.Delete(&User{}, []uint{users[0].ID, users[1].ID}) + s.Equal(int64(2), res.RowsAffected) + s.Nil(err) + + var count int64 + s.Nil(query.Model(&User{}).Where("name", "delete_user").OrWhere("name", "delete_user1").Count(&count)) + s.True(count == 0) + }, + }, + { + name: "delete with event", + setup: func() { + user := User{Name: "event_delete_name", Avatar: "event_delete_avatar"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + user.Avatar = "event_delete_avatar1" + res, err := query.Delete(&user) + s.Equal(int64(1), res.RowsAffected) + s.Equal("event_deleted_avatar", user.Avatar) + s.Nil(err) + + var user1 User + s.Nil(query.Find(&user1, user.ID)) + s.Equal(uint(0), user1.ID) + }, + }, + } + for _, test := range tests { + s.Run(test.name, func() { + test.setup() + }) + } } } @@ -568,102 +754,409 @@ func (s *GormQueryTestSuite) TestExec() { } func (s *GormQueryTestSuite) TestFind() { - for driver, query := range s.queries { - s.Run(driver.String(), func() { - user := User{Name: "find_user"} - s.Nil(query.Create(&user)) - s.True(user.ID > 0) - - var user2 User - s.Nil(query.Find(&user2, user.ID)) - s.True(user2.ID > 0) - - var user3 []User - s.Nil(query.Find(&user3, []uint{user.ID})) - s.Equal(1, len(user3)) - - var user4 []User - s.Nil(query.Where("id in ?", []uint{user.ID}).Find(&user4)) - s.Equal(1, len(user4)) - }) + for _, query := range s.queries { + tests := []struct { + name string + setup func() + }{ + { + name: "success", + setup: func() { + user := User{Name: "find_user"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + var user2 User + s.Nil(query.Find(&user2, user.ID)) + s.True(user2.ID > 0) + + var user3 []User + s.Nil(query.Find(&user3, []uint{user.ID})) + s.Equal(1, len(user3)) + + var user4 []User + s.Nil(query.Where("id in ?", []uint{user.ID}).Find(&user4)) + s.Equal(1, len(user4)) + }, + }, + { + name: "success with event", + setup: func() { + user := User{Name: "event_retrieve_find_name"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + var user1 User + s.Nil(query.Where("name", "event_retrieve_find_name").Find(&user1)) + s.True(user1.ID > 0) + s.Equal("event_retrieved_find_name", user1.Name) + }, + }, + } + for _, test := range tests { + s.Run(test.name, func() { + test.setup() + }) + } } } func (s *GormQueryTestSuite) TestFirst() { - for driver, query := range s.queries { - s.Run(driver.String(), func() { - user := User{Name: "first_user"} - s.Nil(query.Create(&user)) - s.True(user.ID > 0) - - var user1 User - s.Nil(query.Where("name", "first_user").First(&user1)) - s.True(user1.ID > 0) - }) + for _, query := range s.queries { + tests := []struct { + name string + setup func() + }{ + { + name: "success", + setup: func() { + user := User{Name: "first_user"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + var user1 User + s.Nil(query.Where("name", "first_user").First(&user1)) + s.True(user1.ID > 0) + }, + }, + { + name: "success with event", + setup: func() { + user := User{Name: "event_retrieve_first_name"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + var user1 User + s.Nil(query.Where("name", "event_retrieve_first_name").First(&user1)) + s.True(user1.ID > 0) + s.Equal("event_retrieved_first_name", user1.Name) + + var user2 User + s.Nil(query.Where("name", "event_retrieve_first_name1").First(&user2)) + s.True(user2.ID == 0) + s.Equal("", user2.Name) + }, + }, + } + for _, test := range tests { + s.Run(test.name, func() { + test.setup() + }) + } } } -func (s *GormQueryTestSuite) TestFirstOrCreate() { - for driver, query := range s.queries { - s.Run(driver.String(), func() { - var user User - s.Nil(query.Where("avatar", "first_or_create_avatar").FirstOrCreate(&user, User{Name: "first_or_create_user"})) - s.True(user.ID > 0) +func (s *GormQueryTestSuite) TestFirstOr() { + for _, query := range s.queries { + tests := []struct { + name string + setup func() + }{ + { + name: "not found, new one", + setup: func() { + var user User + s.Nil(query.Where("name", "first_or_user").FirstOr(&user, func() error { + user.Name = "goravel" + + return nil + })) + s.Equal(uint(0), user.ID) + s.Equal("goravel", user.Name) - var user1 User - s.Nil(query.Where("avatar", "first_or_create_avatar").FirstOrCreate(&user1, User{Name: "user"}, User{Avatar: "first_or_create_avatar1"})) - s.True(user1.ID > 0) - s.True(user1.Avatar == "first_or_create_avatar1") - }) + }, + }, + { + name: "not found, new one with event", + setup: func() { + var user User + s.Nil(query.Where("name", "event_retrieve_first_or_name").FirstOr(&user, func() error { + user.Name = "goravel" + + return nil + })) + s.Equal(uint(0), user.ID) + s.Equal("goravel", user.Name) + + }, + }, + { + name: "found", + setup: func() { + user := User{Name: "first_or_name"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + var user1 User + s.Nil(query.Where("name", "first_or_name").Find(&user1)) + s.True(user1.ID > 0) + }, + }, + { + name: "found with event", + setup: func() { + user := User{Name: "event_retrieve_first_or_name"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + var user1 User + s.Nil(query.Where("name", "event_retrieve_first_or_name").Find(&user1)) + s.True(user1.ID > 0) + s.Equal("event_retrieved_first_or_name", user1.Name) + }, + }, + } + for _, test := range tests { + s.Run(test.name, func() { + test.setup() + }) + } } } -func (s *GormQueryTestSuite) TestFirstOr() { - for driver, query := range s.queries { - s.Run(driver.String(), func() { - var user User - s.Nil(query.Where("name", "first_or_user").FirstOr(&user, func() error { - user.Name = "goravel" - - return nil - })) - s.Equal(uint(0), user.ID) - s.Equal("goravel", user.Name) - - var user1 User - s.EqualError(query.Where("name", "first_or_user").FirstOr(&user1, func() error { - return errors.New("error") - }), "error") - s.Equal(uint(0), user1.ID) - }) +func (s *GormQueryTestSuite) TestFirstOrCreate() { + for _, query := range s.queries { + tests := []struct { + name string + setup func() + }{ + { + name: "error when empty conditions", + setup: func() { + var user User + s.EqualError(query.FirstOrCreate(&user), "query condition is require") + s.True(user.ID == 0) + }, + }, + { + name: "success", + setup: func() { + var user User + s.Nil(query.FirstOrCreate(&user, User{Name: "first_or_create_user"})) + s.True(user.ID > 0) + s.Equal("first_or_create_user", user.Name) + + var user1 User + s.Nil(query.FirstOrCreate(&user1, User{Name: "first_or_create_user"})) + s.Equal(user.ID, user1.ID) + + var user2 User + s.Nil(query.Where("avatar", "first_or_create_avatar").FirstOrCreate(&user2, User{Name: "user"}, User{Avatar: "first_or_create_avatar2"})) + s.True(user2.ID > 0) + s.True(user2.Avatar == "first_or_create_avatar2") + }, + }, + { + name: "success with retrieved event", + setup: func() { + user := User{Name: "event_retrieve_first_or_create_name"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + var user1 User + s.Nil(query.FirstOrCreate(&user1, User{Name: "event_retrieve_first_or_create_name"})) + s.True(user1.ID > 0) + s.Equal("event_retrieved_first_or_create_name", user1.Name) + }, + }, + { + name: "success with create event", + setup: func() { + var user User + s.Nil(query.FirstOrCreate(&user, User{Name: "event_create_first_or_create_name"})) + s.True(user.ID > 0) + s.Equal("event_create_first_or_create_name", user.Name) + s.Equal("event_created_first_or_create_avatar", user.Avatar) + + var user1 User + s.Nil(query.Where("name", "event_create_first_or_create_name").First(&user1)) + s.Equal("event_create_first_or_create_avatar", user1.Avatar) + }, + }, + } + for _, test := range tests { + s.Run(test.name, func() { + test.setup() + }) + } } } func (s *GormQueryTestSuite) TestFirstOrFail() { - for driver, query := range s.queries { - s.Run(driver.String(), func() { - var user User - s.Equal(orm.ErrRecordNotFound, query.Where("name", "first_or_fail_user").FirstOrFail(&user)) - s.Equal(uint(0), user.ID) - }) + for _, query := range s.queries { + tests := []struct { + name string + setup func() + }{ + { + name: "fail", + setup: func() { + var user User + s.Equal(orm.ErrRecordNotFound, query.Where("name", "first_or_fail_user").FirstOrFail(&user)) + s.Equal(uint(0), user.ID) + }, + }, + { + name: "success", + setup: func() { + user := User{Name: "first_or_fail_name"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + s.Equal("first_or_fail_name", user.Name) + + var user1 User + s.Nil(query.Where("name", "first_or_fail_name").FirstOrFail(&user1)) + s.True(user1.ID > 0) + }, + }, + { + name: "success with event", + setup: func() { + var user User + s.Equal(orm.ErrRecordNotFound, query.Where("name", "event_retrieve_first_or_fail_name").FirstOrFail(&user)) + s.Equal(uint(0), user.ID) + + user1 := User{Name: "event_retrieve_first_or_fail_name"} + s.Nil(query.Create(&user1)) + s.True(user1.ID > 0) + s.Equal("event_retrieve_first_or_fail_name", user1.Name) + + var user2 User + s.Nil(query.Where("name", "event_retrieve_first_or_fail_name").FirstOrFail(&user2)) + s.True(user2.ID > 0) + s.Equal("event_retrieved_first_or_fail_name", user2.Name) + }, + }, + } + for _, test := range tests { + s.Run(test.name, func() { + test.setup() + }) + } } } func (s *GormQueryTestSuite) TestFirstOrNew() { - for driver, query := range s.queries { - s.Run(driver.String(), func() { - var user User - s.Nil(query.FirstOrNew(&user, User{Name: "first_or_new_name"})) - s.Equal(uint(0), user.ID) - s.Equal("first_or_new_name", user.Name) - s.Equal("", user.Avatar) + for _, query := range s.queries { + tests := []struct { + name string + setup func() + }{ + { + name: "not found, new one", + setup: func() { + var user User + s.Nil(query.FirstOrNew(&user, User{Name: "first_or_new_name"})) + s.Equal(uint(0), user.ID) + s.Equal("first_or_new_name", user.Name) + s.Equal("", user.Avatar) + + var user1 User + s.Nil(query.FirstOrNew(&user1, User{Name: "first_or_new_name"}, User{Avatar: "first_or_new_avatar"})) + s.Equal(uint(0), user1.ID) + s.Equal("first_or_new_name", user1.Name) + s.Equal("first_or_new_avatar", user1.Avatar) + }, + }, + { + name: "not found, new one with event", + setup: func() { + var user User + s.Nil(query.FirstOrNew(&user, User{Name: "event_retrieve_first_or_new_name"})) + s.Equal(uint(0), user.ID) + s.Equal("event_retrieve_first_or_new_name", user.Name) + s.Equal("", user.Avatar) + }, + }, + { + name: "found", + setup: func() { + user := User{Name: "first_or_new_name"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + s.Equal("first_or_new_name", user.Name) + + var user1 User + s.Nil(query.FirstOrNew(&user1, User{Name: "first_or_new_name"})) + s.True(user1.ID > 0) + s.Equal("first_or_new_name", user1.Name) + }, + }, + { + name: "found with event", + setup: func() { + user := User{Name: "event_retrieve_first_or_new_name"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + s.Equal("event_retrieve_first_or_new_name", user.Name) + + var user1 User + s.Nil(query.FirstOrNew(&user1, User{Name: "event_retrieve_first_or_new_name"})) + s.True(user1.ID > 0) + s.Equal("event_retrieved_first_or_new_name", user1.Name) + }, + }, + } + for _, test := range tests { + s.Run(test.name, func() { + test.setup() + }) + } + } +} - var user1 User - s.Nil(query.FirstOrNew(&user1, User{Name: "first_or_new_name"}, User{Avatar: "first_or_new_avatar"})) - s.Equal(uint(0), user1.ID) - s.Equal("first_or_new_name", user1.Name) - s.Equal("first_or_new_avatar", user1.Avatar) - }) +func (s *GormQueryTestSuite) TestForceDelete() { + for _, query := range s.queries { + tests := []struct { + name string + setup func() + }{ + { + name: "success", + setup: func() { + user := User{Name: "force_delete_name"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + s.Equal("force_delete_name", user.Name) + + res, err := query.Where("name = ?", "force_delete_name").ForceDelete(&User{}) + s.Equal(int64(1), res.RowsAffected) + s.Nil(err) + s.Equal("force_delete_name", user.Name) + + var user1 User + s.Nil(query.WithTrashed().Find(&user1, user.ID)) + s.Equal(uint(0), user1.ID) + }, + }, + { + name: "success with event", + setup: func() { + user := User{Name: "event_force_delete_name"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + s.Equal("event_force_delete_name", user.Name) + + user1 := User{ + Name: "event_force_delete_name", + } + res, err := query.Where("name", "event_force_delete_name1").ForceDelete(&user1) + s.Equal(int64(0), res.RowsAffected) + s.Nil(err) + s.Equal("event_force_delete_name1", user1.Name) + + res, err = query.ForceDelete(&user) + s.Equal(int64(1), res.RowsAffected) + s.Nil(err) + s.Equal("event_force_deleted_name", user.Name) + }, + }, + } + for _, test := range tests { + s.Run(test.name, func() { + test.setup() + }) + } } } @@ -1143,6 +1636,77 @@ func (s *GormQueryTestSuite) TestRaw() { } } +func (s *GormQueryTestSuite) TestSave() { + for _, query := range s.queries { + tests := []struct { + name string + setup func() + }{ + { + name: "success when create", + setup: func() { + user := User{Name: "save_create_user", Avatar: "save_create_avatar"} + s.Nil(query.Save(&user)) + s.True(user.ID > 0) + + var user1 User + s.Nil(query.Find(&user1, user.ID)) + s.Equal("save_create_user", user1.Name) + }, + }, + { + name: "success when update", + setup: func() { + user := User{Name: "save_update_user", Avatar: "save_update_avatar"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + + user.Name = "save_update_user1" + s.Nil(query.Save(&user)) + + var user1 User + s.Nil(query.Find(&user1, user.ID)) + s.Equal("save_update_user1", user1.Name) + }, + }, + { + name: "success with update event", + setup: func() { + user := User{Name: "event_update_save_name"} + s.Nil(query.Save(&user)) + s.True(user.ID > 0) + s.Equal("event_update_save_name", user.Name) + s.Equal("event_updated_save_avatar", user.Avatar) + + var user1 User + s.Nil(query.Find(&user1, user.ID)) + s.Equal("event_update_save_avatar", user1.Avatar) + }, + }, + { + name: "success with update and save event", + setup: func() { + user := User{Name: "event_save_update_save_name"} + s.Nil(query.Save(&user)) + s.True(user.ID > 0) + s.Equal("event_save_update_save_name", user.Name) + s.Equal("event_saved_updated_save_avatar1", user.Avatar) + + var user1 User + s.Nil(query.Find(&user1, user.ID)) + s.Equal("event_save_update_save_avatar1", user1.Avatar) + }, + }, + } + for _, test := range tests { + s.Run(test.name, func() { + test.setup() + }) + } + + } +} + func (s *GormQueryTestSuite) TestScope() { for driver, query := range s.queries { s.Run(driver.String(), func() { @@ -1270,13 +1834,10 @@ func (s *GormQueryTestSuite) TestUpdate() { s.Nil(query.Create(&user)) s.True(user.ID > 0) - user.Name = "update_user1" - s.Nil(query.Save(&user)) s.Nil(query.Model(&User{}).Where("id = ?", user.ID).Update("avatar", "update_avatar1")) var user1 User s.Nil(query.Find(&user1, user.ID)) - s.Equal("update_user1", user1.Name) s.Equal("update_avatar1", user1.Avatar) }) }