From 76f890137a0bfed3d7508cd21451e5f4d73c10e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20-=20=E3=82=A2=E3=83=AC=E3=83=83=E3=82=AF=E3=82=B9?= Date: Tue, 7 Apr 2026 12:38:58 +0200 Subject: [PATCH] fix: Iter yields all rows instead of only the first ScanOne closes the underlying pgx.Rows after scanning, which caused the iterator to stop after the first row. Switch to ScanRow which scans the current row without closing the cursor. --- table.go | 6 ++---- tests/table_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/table.go b/table.go index e0d591e..3e96fd5 100644 --- a/table.go +++ b/table.go @@ -417,10 +417,8 @@ func (t *Table[T, P, I]) Iter(ctx context.Context, where sq.Sqlizer, orderBy []s defer rows.Close() for rows.Next() { var record T - if err := t.Query.Scan.ScanOne(&record, rows); err != nil { - if !errors.Is(err, pgx.ErrNoRows) { - yield(nil, err) - } + if err := t.Query.Scan.ScanRow(&record, rows); err != nil { + yield(nil, err) return } if !yield(&record, nil) { diff --git a/tests/table_test.go b/tests/table_test.go index 52f0a77..b3356a6 100644 --- a/tests/table_test.go +++ b/tests/table_test.go @@ -619,6 +619,34 @@ func TestHardDeleteByID(t *testing.T) { }) } +func TestIter(t *testing.T) { + truncateAllTables(t) + + ctx := t.Context() + db := initDB(DB) + + account := &Account{Name: "Iter Account"} + err := db.Accounts.Insert(ctx, account) + require.NoError(t, err) + + const total = 100 + for i := range total { + err := db.Articles.Insert(ctx, &Article{AccountID: account.ID, Author: fmt.Sprintf("Author %03d", i)}) + require.NoError(t, err) + } + + iter, err := db.Articles.Iter(ctx, sq.Eq{"account_id": account.ID}, []string{"id"}) + require.NoError(t, err) + + var count int + for article, err := range iter { + require.NoError(t, err) + require.NotNil(t, article) + count++ + } + require.Equal(t, total, count, "Iter should yield all rows") +} + func TestLockForUpdates(t *testing.T) { truncateAllTables(t)