https://github.com/bsm/dbx
Useful extensions to stdlib's database/sql
https://github.com/bsm/dbx
Last synced: about 1 year ago
JSON representation
Useful extensions to stdlib's database/sql
- Host: GitHub
- URL: https://github.com/bsm/dbx
- Owner: bsm
- License: apache-2.0
- Created: 2017-11-08T10:30:13.000Z (over 8 years ago)
- Default Branch: main
- Last Pushed: 2021-06-24T16:14:03.000Z (almost 5 years ago)
- Last Synced: 2025-04-13T05:54:52.751Z (about 1 year ago)
- Language: Go
- Size: 17.6 KB
- Stars: 2
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# DBx
[](https://github.com/bsm/dbx/actions/workflows/test.yml)
[](http://godoc.org/github.com/bsm/dbx)
[](https://opensource.org/licenses/Apache-2.0)
Useful extensions to stdlib's [database/sql](https://golang.org/pkg/database/sql).
## Iterators
A simple wrapper for [sql.Rows](https://golang.org/pkg/database/sql/#Rows) to iterate
over structs:
```go
import (
"fmt"
"github.com/bsm/dbx"
)
func main() {
// Init a temp dir
dir, err := os.MkdirTemp("", "dbx-example")
if err != nil {
panic(err)
}
// Create tables, seed some test data
db, err := setupTestDB(dir)
if err != nil {
panic(err)
}
defer db.Close()
// Query rows
rows, err := db.Query(`SELECT id, title FROM posts ORDER BY id`)
if err != nil {
panic(err)
}
// Wrap rows in an iterator AND defer Close()
iter := dbx.NewIterator(rows, func(rs dbx.RowScanner) (interface{}, error) {
post := new(Post)
if err := rs.Scan(&post.ID, &post.Title); err != nil {
return nil, err
}
return post, nil
})
defer iter.Close()
// Iterate over records, print a few
n := 0
for iter.Next() {
post := iter.Record().(*Post)
if n++; n%321 == 0 {
fmt.Printf("%+v\n", post)
}
}
// Check for iterator errors
if err := iter.Err(); err != nil {
panic(err)
}
}
```
Like above, just batching and with the ability to resolve (1:n) associations:
```go
import (
"fmt"
"strings"
"github.com/bsm/dbx"
)
func main() {
// Init a temp dir
dir, err := os.MkdirTemp("", "dbx-example")
if err != nil {
panic(err)
}
// Create tables, seed some test data
db, err := setupTestDB(dir)
if err != nil {
panic(err)
}
defer db.Close()
// Scan each Post row into a struct (callback)
scanPost := func(rs dbx.RowScanner) (interface{}, error) {
post := new(Post)
if err := rs.Scan(&post.ID, &post.Title); err != nil {
return nil, err
}
return post, nil
}
// Scan each Comment row into a struct (callback)
scanComment := func(rs dbx.RowScanner) (interface{}, error) {
comment := new(Comment)
if err := rs.Scan(&comment.ID, &comment.PostID, &comment.Message); err != nil {
return nil, err
}
return comment, nil
}
// For every batch of Posts, fetch all the associated comments (callback)
transformBatch := func(recs []interface{}) error {
postMap := make(map[int64]*Post, len(recs))
postIDs := make([]interface{}, 0, len(recs))
for _, rec := range recs {
post := rec.(*Post)
postMap[post.ID] = post
postIDs = append(postIDs, post.ID)
}
rows, err := db.Query(`SELECT id, post_id, message FROM comments WHERE post_id IN (?`+strings.Repeat(",?", len(postIDs)-1)+`)`, postIDs...)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
v, err := scanComment(rows)
if err != nil {
return err
}
comment := v.(*Comment)
post := postMap[comment.PostID]
post.Comments = append(post.Comments, *comment)
}
return rows.Err()
}
// Query rows
rows, err := db.Query(`SELECT id, title FROM posts ORDER BY id`)
if err != nil {
panic(err)
}
// Wrap rows in an iterator AND defer Close()
iter := dbx.NewBatchIterator(rows, 100, scanPost, transformBatch)
defer iter.Close()
// Iterate over records, print a few
n := 0
for iter.Next() {
post := iter.Record().(*Post)
if n++; n%321 == 0 {
fmt.Printf("%+v\n", post)
}
}
// Check for iterator errors
if err := iter.Err(); err != nil {
panic(err)
}
}
```