From ad81206cc2259cec9b19b21c54cd97aee5f4c6d5 Mon Sep 17 00:00:00 2001 From: mr-chenguang lcgash Date: Thu, 11 Apr 2024 09:27:40 +0000 Subject: [PATCH 1/4] feat: support reset result as nil when record not found --- gorm.go | 2 ++ scan.go | 4 ++++ tests/query_test.go | 14 ++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/gorm.go b/gorm.go index 775cd3de3b..f07d9daa80 100644 --- a/gorm.go +++ b/gorm.go @@ -50,6 +50,8 @@ type Config struct { CreateBatchSize int // TranslateError enabling error translation TranslateError bool + // NotFoundAsError set result is nil when no record found and result is ptr + NotFoundAsNilWhenPtr bool // ClauseBuilders clause builder ClauseBuilders map[string]clause.ClauseBuilder diff --git a/scan.go b/scan.go index 415b9f0d74..3a2a212c75 100644 --- a/scan.go +++ b/scan.go @@ -342,5 +342,9 @@ func Scan(rows Rows, db *DB, mode ScanMode) { if db.RowsAffected == 0 && db.Statement.RaiseErrorOnNotFound && db.Error == nil { db.AddError(ErrRecordNotFound) + if db.NotFoundAsNilWhenPtr && db.Statement.Dest != nil && reflect.ValueOf(db.Statement.Dest).Kind() == reflect.Ptr { + // reset dest to nil + reflect.ValueOf(db.Statement.Dest).Elem().Set(reflect.Zero(reflect.ValueOf(db.Statement.Dest).Elem().Type())) + } } } diff --git a/tests/query_test.go b/tests/query_test.go index c0259a14a3..bb673f9421 100644 --- a/tests/query_test.go +++ b/tests/query_test.go @@ -206,6 +206,20 @@ func TestFind(t *testing.T) { } }) + t.Run("NotFoundAsNil", func(t *testing.T) { + var first *User + if err := DB.Where("name = ?", "find-not-found").First(&first).Error; err != nil { + AssertEqual(t, err, gorm.ErrRecordNotFound) + AssertEqual(t, first == nil, false) + } + + DB.Config.NotFoundAsNilWhenPtr = true + if err := DB.Where("name = ?", "find-not-found").First(&first).Error; err != nil { + AssertEqual(t, err, gorm.ErrRecordNotFound) + AssertEqual(t, first, nil) + } + }) + var models []User if err := DB.Where("name in (?)", []string{"find"}).Find(&models).Error; err != nil || len(models) != 3 { t.Errorf("errors happened when query find with in clause: %v, length: %v", err, len(models)) From 8ce25a5dd11272527a455a69e8a0c89408f3a5c3 Mon Sep 17 00:00:00 2001 From: mr-chenguang lcgash Date: Mon, 15 Apr 2024 03:08:37 +0000 Subject: [PATCH 2/4] fix: keep nil when dest is ptr & dest is nil[notfound] --- callbacks.go | 3 ++- scan.go | 2 +- statement.go | 1 + tests/query_test.go | 8 +------- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/callbacks.go b/callbacks.go index 50b5b0e937..e97254cf85 100644 --- a/callbacks.go +++ b/callbacks.go @@ -115,7 +115,8 @@ func (p *processor) Execute(db *DB) *DB { if stmt.Dest != nil { stmt.ReflectValue = reflect.ValueOf(stmt.Dest) for stmt.ReflectValue.Kind() == reflect.Ptr { - if stmt.ReflectValue.IsNil() && stmt.ReflectValue.CanAddr() { + stmt.DestIsNil = stmt.ReflectValue.IsNil() + if stmt.DestIsNil && stmt.ReflectValue.CanAddr() { stmt.ReflectValue.Set(reflect.New(stmt.ReflectValue.Type().Elem())) } diff --git a/scan.go b/scan.go index 3a2a212c75..236f405a40 100644 --- a/scan.go +++ b/scan.go @@ -342,7 +342,7 @@ func Scan(rows Rows, db *DB, mode ScanMode) { if db.RowsAffected == 0 && db.Statement.RaiseErrorOnNotFound && db.Error == nil { db.AddError(ErrRecordNotFound) - if db.NotFoundAsNilWhenPtr && db.Statement.Dest != nil && reflect.ValueOf(db.Statement.Dest).Kind() == reflect.Ptr { + if db.Statement.DestIsNil { // reset dest to nil reflect.ValueOf(db.Statement.Dest).Elem().Set(reflect.Zero(reflect.ValueOf(db.Statement.Dest).Elem().Type())) } diff --git a/statement.go b/statement.go index ae79aa3218..b2c187b9e7 100644 --- a/statement.go +++ b/statement.go @@ -26,6 +26,7 @@ type Statement struct { Model interface{} Unscoped bool Dest interface{} + DestIsNil bool ReflectValue reflect.Value Clauses map[string]clause.Clause BuildClauses []string diff --git a/tests/query_test.go b/tests/query_test.go index bb673f9421..f3b00f8b5c 100644 --- a/tests/query_test.go +++ b/tests/query_test.go @@ -208,13 +208,7 @@ func TestFind(t *testing.T) { t.Run("NotFoundAsNil", func(t *testing.T) { var first *User - if err := DB.Where("name = ?", "find-not-found").First(&first).Error; err != nil { - AssertEqual(t, err, gorm.ErrRecordNotFound) - AssertEqual(t, first == nil, false) - } - - DB.Config.NotFoundAsNilWhenPtr = true - if err := DB.Where("name = ?", "find-not-found").First(&first).Error; err != nil { + if err := DB.Where("name = ?", "find not found").First(&first).Error; err != nil { AssertEqual(t, err, gorm.ErrRecordNotFound) AssertEqual(t, first, nil) } From c8ccb9c3ccec6410f7a0924d97468ca76ce5f1a1 Mon Sep 17 00:00:00 2001 From: mr-chenguang lcgash Date: Mon, 15 Apr 2024 03:09:17 +0000 Subject: [PATCH 3/4] remove prop --- gorm.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/gorm.go b/gorm.go index f07d9daa80..775cd3de3b 100644 --- a/gorm.go +++ b/gorm.go @@ -50,8 +50,6 @@ type Config struct { CreateBatchSize int // TranslateError enabling error translation TranslateError bool - // NotFoundAsError set result is nil when no record found and result is ptr - NotFoundAsNilWhenPtr bool // ClauseBuilders clause builder ClauseBuilders map[string]clause.ClauseBuilder From 1c02efdff7622c32cbc8f240216d62aa4ed4c693 Mon Sep 17 00:00:00 2001 From: mr-chenguang lcgash Date: Mon, 15 Apr 2024 03:10:04 +0000 Subject: [PATCH 4/4] fix: change test case name --- tests/query_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/query_test.go b/tests/query_test.go index f3b00f8b5c..2f761d1c76 100644 --- a/tests/query_test.go +++ b/tests/query_test.go @@ -206,7 +206,7 @@ func TestFind(t *testing.T) { } }) - t.Run("NotFoundAsNil", func(t *testing.T) { + t.Run("KeepResultAsNil", func(t *testing.T) { var first *User if err := DB.Where("name = ?", "find not found").First(&first).Error; err != nil { AssertEqual(t, err, gorm.ErrRecordNotFound)