Skip to content

Commit

Permalink
Close rows early to avoid panics and early errors
Browse files Browse the repository at this point in the history
fix #52
  • Loading branch information
blockloop committed Mar 31, 2023
1 parent a59dd0d commit 4dd2896
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 6 deletions.
20 changes: 16 additions & 4 deletions scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,20 @@ var (
// defers returning err until Scan is called, which is an unnecessary
// optimization for this library.
func Row(v interface{}, r RowsScanner) error {
if AutoClose {
defer closeRows(r)
}

return row(v, r, false)
}

// RowStrict scans a single row into a single variable. It is identical to
// Row, but it ignores fields that do not have a db tag
func RowStrict(v interface{}, r RowsScanner) error {
if AutoClose {
defer closeRows(r)
}

return row(v, r, true)
}

Expand Down Expand Up @@ -75,19 +83,23 @@ func row(v interface{}, r RowsScanner, strict bool) error {

// Rows scans sql rows into a slice (v)
func Rows(v interface{}, r RowsScanner) (outerr error) {
if AutoClose {
defer closeRows(r)
}

return rows(v, r, false)
}

// RowsStrict scans sql rows into a slice (v) only using db tags
func RowsStrict(v interface{}, r RowsScanner) (outerr error) {
return rows(v, r, true)
}

func rows(v interface{}, r RowsScanner, strict bool) (outerr error) {
if AutoClose {
defer closeRows(r)
}

return rows(v, r, true)
}

func rows(v interface{}, r RowsScanner, strict bool) (outerr error) {
vType := reflect.TypeOf(v)
if k := vType.Kind(); k != reflect.Ptr {
return fmt.Errorf("%q must be a pointer: %w", k.String(), ErrNotAPointer)
Expand Down
5 changes: 3 additions & 2 deletions scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,14 @@ func TestRowsStrictIgnoresFieldsWithoutDBTag(t *testing.T) {
assert.Equal(t, "", items[1].Last)
}

func TestRowCloses(t *testing.T) {
func TestRowClosesEarly(t *testing.T) {
rows := fakeRowsWithRecords(t, []string{"name"},
[]interface{}{"Bob"},
)

var name string
assert.NoError(t, scan.Row(&name, rows))
// dont' pass a pointer to cause an early error
assert.Error(t, scan.Row(name, rows))
assert.EqualValues(t, 1, rows.CloseCallCount())
}

Expand Down

0 comments on commit 4dd2896

Please sign in to comment.