diff --git a/CHANGELOG.md b/CHANGELOG.md index 551c4f35..a7fc57ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -120,6 +120,10 @@ See documentation for `QueryExecMode`. pgx now supports named arguments with the NamedArgs type. This is implemented via the new QueryRewriter interface which allows arbitrary rewriting of query SQL and arguments. + +## RowScanner Interface + +The `RowScanner` interface allows a single argument to Rows.Scan to scan the entire row. ## 3rd Party Logger Integration All integrations with 3rd party loggers have been extracted to separate repositories. This trims the pgx dependency diff --git a/rows.go b/rows.go index b757b1c7..4f9c533d 100644 --- a/rows.go +++ b/rows.go @@ -69,6 +69,12 @@ type Row interface { Scan(dest ...any) error } +// RowScanner scans an entire row at a time into the RowScanner. +type RowScanner interface { + // ScanRows scans the row. + ScanRow(rows Rows) error +} + // connRow implements the Row interface for Conn.QueryRow. type connRow connRows @@ -212,6 +218,13 @@ func (rows *connRows) Scan(dest ...any) error { rows.fatal(err) return err } + + if len(dest) == 1 { + if rc, ok := dest[0].(RowScanner); ok { + return rc.ScanRow(rows) + } + } + if len(fieldDescriptions) != len(dest) { err := fmt.Errorf("number of field descriptions must equal number of destinations, got %d and %d", len(fieldDescriptions), len(dest)) rows.fatal(err) diff --git a/rows_test.go b/rows_test.go new file mode 100644 index 00000000..37f8e1de --- /dev/null +++ b/rows_test.go @@ -0,0 +1,30 @@ +package pgx_test + +import ( + "context" + "testing" + + "github.com/jackc/pgx/v5" + "github.com/stretchr/testify/require" +) + +type testRowScanner struct { + name string + age int32 +} + +func (rs *testRowScanner) ScanRow(rows pgx.Rows) error { + return rows.Scan(&rs.name, &rs.age) +} + +func TestRowScanner(t *testing.T) { + t.Parallel() + + defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) { + var s testRowScanner + err := conn.QueryRow(ctx, "select 'Adam' as name, 72 as height").Scan(&s) + require.NoError(t, err) + require.Equal(t, "Adam", s.name) + require.Equal(t, int32(72), s.age) + }) +}