Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/wroge/scan
scan sql rows into any type powered by generics
https://github.com/wroge/scan
database db generics go golang mapping rows scan scanner sql
Last synced: 19 days ago
JSON representation
scan sql rows into any type powered by generics
- Host: GitHub
- URL: https://github.com/wroge/scan
- Owner: wroge
- License: mit
- Created: 2022-09-10T16:14:04.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2024-03-08T13:18:34.000Z (8 months ago)
- Last Synced: 2024-10-02T03:03:41.901Z (about 1 month ago)
- Topics: database, db, generics, go, golang, mapping, rows, scan, scanner, sql
- Language: Go
- Homepage:
- Size: 92.8 KB
- Stars: 63
- Watchers: 2
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome - Scan - Scan SQL rows into any type powered by generics (Programming Languages / Golang)
README
Take a look at [github.com/wroge/esquel](https://github.com/wroge/esquel).
[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white)](https://pkg.go.dev/github.com/wroge/scan)
[![Go Report Card](https://goreportcard.com/badge/github.com/wroge/scan)](https://goreportcard.com/report/github.com/wroge/scan)
![golangci-lint](https://github.com/wroge/scan/workflows/golangci-lint/badge.svg)
[![codecov](https://codecov.io/gh/wroge/scan/branch/main/graph/badge.svg?token=SBSedMOGHR)](https://codecov.io/gh/wroge/scan)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/wroge/scan.svg?style=social)](https://github.com/wroge/scan/tags)# Scan
This package offers a convenient and flexible way to scan SQL rows into any type, leveraging the power of generics.
## Features
- **Efficient and Reusable**: Avoid repetitive code and define the column-mapping in one place.
- **Auto Closing**: No need to worry about resource leaks.
- **No Reflection**: Faster than reflection based mappers.
- **Robust Error Handling**: Best practices for managing errors.## Usage
```go
import "github.com/wroge/scan"type Author struct {
ID int64
Name string
}type Post struct {
ID int64
Title string
Authors []Author
}// Define mapping of database columns to struct fields.
var columns = scan.Columns[Post]{
// Map the 'id' column to the 'ID' field in the 'Post' struct.
// Uses the 'scan.Any' function for direct assignment without additional processing.
"id": scan.Any(func(p *Post, id int64) { p.ID = id }),// Map the 'title' column to the 'Title' field in the 'Post' struct.
// The 'scan.Null' function allows handling of nullable database columns.
// If the 'title' column is null, 'default title' is used as the value.
"title": scan.Null("default title", func(p *Post, title string) { p.Title = title }),// Map the 'authors' column, expected to be in JSON format, to the 'Authors' field in the 'Post' struct.
// The 'scan.JSON' function automatically handles unmarshalling of the JSON data into the 'Author' struct slice.
"authors": scan.JSON(func(p *Post, authors []Author) { p.Authors = authors }),// Or you could create a custom scanner with this function.
// "column": scan.Func[Post, V](func(p *Post, value V) error {
// return nil
// }),
}rows, err := db.Query("SELECT ...")
// handle error
```#### Scanning all rows
```go
posts, err := scan.All(rows, columns)
// handle error
```#### Scanning the first row
```go
post, err := scan.First(rows, columns)
if err != nil {
if errors.Is(err, scan.ErrNoRows) {
// handle no rows
}// handle other error
}
```#### Scanning exactly one row
```go
post, err := scan.One(rows, columns)
if err != nil {
if errors.Is(err, scan.ErrTooManyRows) {
// handle too many rows
// post is valid
}if errors.Is(err, scan.ErrNoRows) {
// handle no rows
}// handle other error
}
```#### Scanning a limited number of rows
```go
posts, err := scan.Limit(10, rows, columns)
if err != nil {
if errors.Is(err, scan.ErrTooManyRows) {
// ignore if result set has more than 10 rows
// len(posts) == 10
}// handle other error
}
```#### Using the Iterator directly
```go
iter, err := scan.Iter(rows, columns)
// handle errordefer iter.Close()
for iter.Next() {
var post Posterr = iter.Scan(&post)
// handle error// Or use the Value method:
post, err := iter.Value()
// handle error
}
```