package sql import ( "database/sql" "git.sr.ht/~cco/go-scopes/logging/log" ) type Cfg struct { Driver, Connstr string } type Rows = sql.Rows type rowsProc = func(*sql.Rows) error type Scanner interface{ Scan(*Rows) (Scanner, error) } type Storage struct { *sql.DB } func Open(cfg *Cfg) *Storage { db, err := sql.Open(cfg.Driver, cfg.Connstr) if err != nil { log.Error(err).Msg("sql.Open") return nil } return &Storage{db} } func QueryData[T Scanner](db *Storage, q string, args ...interface{}) []T { var data []T proc := func(r *sql.Rows) error { var rec T r1, err := rec.Scan(r) rec = r1.(T) data = append(data, rec) return err } db.Query(proc, q, args...) // ?? check error return data } func QueryCol[T any](db *Storage, q string, args ...interface{}) []T { var data []T proc := func(r *sql.Rows) error { var rec T err := r.Scan(&rec) data = append(data, rec) return err } db.Query(proc, q, args...) // ?? check error return data } func (db *Storage) Query(process rowsProc, q string, args ...interface{}) error { info := "sql.Storage.Query" //log.Debug().Str("query", q).Msg(info) logErr := func(err error) { log.Error(err).Str("query", q).Msg(info) } rows, err := db.DB.Query(q, args...) if err != nil { logErr(err) return err } for rows.Next() { if err := process(rows); err != nil { logErr(err) return err } } if err := rows.Err(); err != nil { logErr(err) return err } return nil } func (db *Storage) Exec(q string, args ...interface{}) (int64, error) { info := "sql.Storage.Exec" //log.Debug().Str("query", q).Msg(info) res, err := db.DB.Exec(q, args...) if err != nil { log.Error(err).Str("query", q).Msg(info) return 0, err } nrows, _ := res.RowsAffected() return nrows, nil }