Цикл по базе данных / sql sql.Rows несколько раз? - PullRequest
0 голосов
/ 26 апреля 2018

Мне нужно перебрать возвращенный sql.Rows несколько раз. У меня только два варианта:

  1. для кэширования возвращенных результатов в локальной структуре данных;
  2. повторить запрос к базе данных?

Другими словами, нет способа вернуться в sql.Rows (т. Е. Напротив Rows.Next).

1 Ответ

0 голосов
/ 27 апреля 2018

Другим решением будет использование шаблона декоратора:

// 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
}

Используется так:

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)

С этим шаблоном вы можете написать пользовательскую функцию, которая вызывается при выполнении итерации по коллекции. При использовании безымянного встроенного типа все оригинальные методы (Next, Close и т. Д.) Все еще могут быть вызваны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...