The sql package provides a generic database connector built on top of database/sql. It is intended for cases where a lightweight query helper is preferred over a full ORM: open a connection, describe how to scan a row into a type, and call Query anywhere.
import "github.com/raykavin/gobox/database/sql"Connector[T]for executing queries and mapping each row to a caller-defined typeScanFunc[T]for describing how a single*sql.Rowscursor maps toTNewSQLfor opening, pinging, and wrapping a database connection
SQLConfig: driver name and DSNScanFunc[T]:func(rows *sql.Rows) (T, error)called once per rowConnector[T]: holds the connection and scan function, exposesQueryandClose
package main
import (
"context"
stdsql "database/sql"
"log"
sqldb "github.com/raykavin/gobox/database/sql"
_ "github.com/lib/pq"
)
type User struct {
ID int
Name string
}
func main() {
conn, err := sqldb.NewSQL(sqldb.SQLConfig{
Driver: "postgres",
DSN: "postgres://user:pass@localhost/mydb?sslmode=disable",
}, func(rows *stdsql.Rows) (User, error) {
var u User
return u, rows.Scan(&u.ID, &u.Name)
})
if err != nil {
log.Fatal(err)
}
defer conn.Close()
users, err := conn.Query(context.Background(),
"SELECT id, name FROM users WHERE active = $1", true)
if err != nil {
log.Fatal(err)
}
for _, u := range users {
log.Printf("%d: %s", u.ID, u.Name)
}
}- the database driver must be imported separately with a blank import (e.g.
_ "github.com/lib/pq") NewSQLcallsPingContextimmediately; a connection failure returns an error before theConnectoris returnedScanFuncmust callrows.Scaninternally and must not advance the cursor;Queryhandles therows.NextloopQueryreturnsnil, nil(not an error) when the result set is emptyClosereleases the underlying connection pool; it should be called when theConnectoris no longer neededNewSQLrejects an emptyDriver, an emptyDSN, and a nilScanFuncbefore opening anything, and closes the connection itself if the ping fails- the alias in the example avoids a collision with the standard library's
database/sql, since both packages are namedsql