Skip to content

Commit

Permalink
Fix nested preload with duplicate ptr belongs to (#365)
Browse files Browse the repository at this point in the history
  • Loading branch information
Fs02 committed Mar 4, 2024
1 parent 3b36085 commit d65f8e1
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 1 deletion.
8 changes: 7 additions & 1 deletion cursor.go
Expand Up @@ -92,8 +92,14 @@ func scanMulti(cur Cursor, keyField string, keyType reflect.Type, cols map[any][
key, found := doc.Value(keyField)
mustTrue(found, "rel: key field not found")

needCopy := false
for _, col := range cols[key] {
col.Append(doc)
if needCopy {
col.Append(doc.Copy())
} else {
col.Append(doc)
needCopy = true
}
}

// create new doc for next scan
Expand Down
7 changes: 7 additions & 0 deletions document.go
Expand Up @@ -266,6 +266,13 @@ func (d Document) NewDocument() *Document {
return newZeroDocument(d.rt)
}

// Copy returns copy of this document
func (d Document) Copy() *Document {
rv := reflect.New(d.rt)
rv.Elem().Set(d.rv)
return NewDocument(rv)
}

// Append is alias for Assign for compatibility with internal slice interface
func (d *Document) Append(o *Document) {
d.Assign(o)
Expand Down
88 changes: 88 additions & 0 deletions repository_test.go
Expand Up @@ -4025,6 +4025,94 @@ func TestRepository_Preload_scanErrors(t *testing.T) {
cur.AssertExpectations(t)
}

type ScheduledQuestion struct {
ID int
QuestionID int
Question *Question
}

type Question struct {
ID int
Answers []Answers
}

type Answers struct {
ID int
QuestionID int
}

func TestRepository_Preload_nestedWithDuplicatePtrBelongsTo(t *testing.T) {
var (
adapter = &testAdapter{}
repo = New(adapter)
scheduledQuestions = []ScheduledQuestion{}
cur = &testCursor{}
)

{
adapter.On("Query", From("scheduled_questions")).Return(cur, nil).Once()
cur.On("Close").Return(nil).Once()
cur.On("Fields").Return([]string{"id", "question_id"}, nil).Once()
cur.On("Next").Return(true).Times(2)
cur.MockScan(1, 1).Once()
cur.MockScan(2, 1).Once()
cur.On("Next").Return(false).Once()

assert.Nil(t, repo.FindAll(context.TODO(), &scheduledQuestions))
}

{
adapter.On("Query", From("questions").Where(In("id", 1))).Return(cur, nil).Once()
cur.On("Close").Return(nil).Once()
cur.On("Fields").Return([]string{"id"}, nil).Once()
cur.On("Next").Return(true).Times(1)
cur.MockScan(1).Once()
cur.On("Next").Return(false).Once()

assert.Nil(t, repo.Preload(context.TODO(), &scheduledQuestions, "question"))
}

{
adapter.On("Query", From("answers").Where(In("question_id", 1))).Return(cur, nil).Once()
cur.On("Close").Return(nil).Once()
cur.On("Fields").Return([]string{"id", "question_id"}, nil).Once()
cur.On("Next").Return(true).Times(1)
cur.MockScan(1, 1).Once()
cur.On("Next").Return(false).Once()

assert.Nil(t, repo.Preload(context.TODO(), &scheduledQuestions, "question.answers"))
}

assert.Equal(t, []ScheduledQuestion{
{
ID: 1,
QuestionID: 1,
Question: &Question{
ID: 1,
Answers: []Answers{
{
ID: 1,
QuestionID: 1,
},
},
},
},
{
ID: 2,
QuestionID: 1,
Question: &Question{
ID: 1,
Answers: []Answers{
{
ID: 1,
QuestionID: 1,
},
},
},
},
}, scheduledQuestions)
}

func TestRepository_MustPreload(t *testing.T) {
var (
adapter = &testAdapter{}
Expand Down

0 comments on commit d65f8e1

Please sign in to comment.