Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loop through database/sql sql.Rows multiple times?

Tags:

go

I need to loop through returned sql.Rows multiple times. Are my only two options:

  1. to cache the returned results in a local data structure;
  2. redo the database query?

In other words, there is no way to go back in sql.Rows (i.e., opposite of Rows.Next).

like image 863
thebitguru Avatar asked Apr 26 '18 14:04

thebitguru


People also ask

Can I iterate in SQL?

The ITERATE statement is used to cause the flow of control to return to the beginning of a labeled LOOP statement.


1 Answers

Another solution would be to use the decorator pattern:

// A RowsDecorator wraps sql.Rows and allows a callback to be called whenever Scan is called
type RowsDecorator struct {
    *sql.Rows
    OnScan func([]interface{}, error)
}

func Wrap(rows *sql.Rows, onScan func([]interface{}, error)) *RowsDecorator {
    return &RowsDecorator{Rows: rows, OnScan: onScan}
}

// Scan calls Rows.Scan and an optional callback
func (rows *RowsDecorator) Scan(dest ...interface{}) error {
    err := rows.Rows.Scan(dest...)
    if rows.OnScan != nil {
        rows.OnScan(dest, err)
    }
    return err
}

Used like this:

db.Exec(`CREATE TABLE example (id INTEGER, txt TEXT)`)
db.Exec(`INSERT INTO example (id, txt) VALUES (1, 'test-1'), (2, 'test-2'), (3, 'test-3') `)

rawrows, err := db.Query("SELECT id, txt FROM example")
if err != nil {
    log.Fatal(err)
}
defer rawrows.Close()

sum := 0
rows := Wrap(rawrows, func(dest []interface{}, err error) {
    if err == nil {
        sum += *dest[0].(*int)
    }
})
for rows.Next() {
    var id int
    var txt string
    err := rows.Scan(&id, &txt)
    if err != nil {
        log.Fatal(err)
    }
    log.Println(id, txt)
}
log.Println("sum", sum)

With this pattern you can write a custom function that is called as you iterate over the collection. By using an unnamed, embedded type all of the original methods (Next, Close, etc) can still be called.

like image 60
Caleb Avatar answered Oct 03 '22 19:10

Caleb