Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix lack of error passing for nested preload #19

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions callback_query_preload.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,14 @@ func preloadCallback(scope *Scope) {
scope.Err(errors.New("unsupported relation"))
}

preloadedMap[preloadKey] = true
if currentScope.DB().Error == nil {
preloadedMap[preloadKey] = true
}
break
}

if !preloadedMap[preloadKey] {
scope.Err(fmt.Errorf("can't preload field %s for %s", preloadField, currentScope.GetModelStruct().ModelType))
scope.Err(fmt.Errorf("can't preload field %s for %s: %s", preloadField, currentScope.GetModelStruct().ModelType, currentScope.DB().Error))
return
}
}
Expand Down
104 changes: 104 additions & 0 deletions preload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package gorm_test
import (
"database/sql"
"encoding/json"
"errors"
"os"
"reflect"
"strings"
"testing"

"github.com/jinzhu/gorm"
Expand Down Expand Up @@ -192,6 +194,108 @@ func TestNestedPreload1(t *testing.T) {
}
}

type SQLCommonMock struct {
db *sql.DB
errorQuery string
}

func (s *SQLCommonMock) Exec(query string, args ...interface{}) (sql.Result, error) {
return s.db.Exec(query, args...)
}

func (s *SQLCommonMock) Prepare(query string) (*sql.Stmt, error) {
return s.db.Prepare(query)
}

func (s *SQLCommonMock) Query(query string, args ...interface{}) (*sql.Rows, error) {
if query == s.errorQuery {
return nil, errors.New("faked database error")
}
return s.db.Query(query, args...)
}

func (s *SQLCommonMock) QueryRow(query string, args ...interface{}) *sql.Row {
return s.db.QueryRow(query, args...)
}

func TestNestedPreload1FirstLevelError(t *testing.T) {
var err error
sqlDB := DB.DB()

// will not preload Level2 due to faked database error
sqlMock := &SQLCommonMock{db: sqlDB, errorQuery: `SELECT * FROM "level2" WHERE ("level3_id" IN (?))`}
localDB, err := gorm.Open(DB.Dialect().GetName(), sqlMock)
if err != nil {
t.Error(err)
}

type (
Level1 struct {
ID uint
Value string
Level2ID uint
}
Level2 struct {
ID uint
Level1 Level1
Level3ID uint
}
Level3 struct {
ID uint
Name string
Level2 Level2
}
)
localDB.DropTableIfExists(&Level3{})
localDB.DropTableIfExists(&Level2{})
localDB.DropTableIfExists(&Level1{})
if err := localDB.AutoMigrate(&Level3{}, &Level2{}, &Level1{}).Error; err != nil {
t.Error(err)
}

savedToDb := Level3{Level2: Level2{Level1: Level1{Value: "value"}}}
if err = localDB.Create(&savedToDb).Error; err != nil {
t.Error(err)
}

want := savedToDb
want.Level2 = Level2{}

var got Level3
if err = localDB.Preload("Level2").Find(&got).Error; errors.Is(err, nil) {
t.Error("expecting error on preload failue")
}

if err != nil && !strings.Contains(err.Error(), "faked database error") {
t.Error(err)
}

if !reflect.DeepEqual(got, want) {
t.Errorf("got %s; want %s", toJSONString(got), toJSONString(want))
}

// will not preload Level1 due to faked database error
sqlMock = &SQLCommonMock{db: sqlDB, errorQuery: `SELECT * FROM "level1" WHERE ("level2_id" IN (?))`}
localDB, err = gorm.Open(DB.Dialect().GetName(), sqlMock)
if err != nil {
t.Error(err)
}

want = savedToDb
want.Level2.Level1 = Level1{}
if err = localDB.Preload("Level2.Level1").Find(&got).Error; errors.Is(err, nil) {
t.Error("expecting error on nested preload failue")
}

if err != nil && !strings.Contains(err.Error(), "faked database error") {
t.Error(err)
}

if !reflect.DeepEqual(got, want) {
t.Errorf("got %s; want %s", toJSONString(got), toJSONString(want))
}
}

func TestNestedPreload2(t *testing.T) {
type (
Level1 struct {
Expand Down