scan

package module
v0.0.17 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 4, 2024 License: MIT Imports: 2 Imported by: 1

README

go.dev reference Go Report Card golangci-lint codecov GitHub tag (latest SemVer)

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

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
posts, err := scan.All(rows, columns)
// handle error
Scanning the first row
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
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
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
iter, err := scan.Iter(rows, columns)
// handle error

defer iter.Close()

for iter.Next() {
	var post Post

	err = iter.Scan(&post)
	// handle error

	// Or use the Value method:
	post, err := iter.Value()
	// handle error
}

Documentation

Overview

Scan sql rows into any type powered by generics with proper error handling and automatic resource cleanup.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoRows = errors.New("sql: no rows in result set")

ErrNoRows represents the error indicating no rows in the result set.

View Source
var ErrTooManyRows = errors.New("sql: too many rows in result set")

ErrTooManyRows represents the error indicating too many rows in the result set.

Functions

func All

func All[T any](rows Rows, columns Columns[T]) ([]T, error)

All retrieves all rows, scans them into a slice, and closes the iterator.

func First added in v0.0.8

func First[T any](rows Rows, columns Columns[T]) (T, error)

First retrieves the first row, scans it, and closes the iterator.

func Limit added in v0.0.12

func Limit[T any](limit int, rows Rows, columns Columns[T]) ([]T, error)

Limit retrieves up to a specified number of rows, scans them, and closes the iterator.

func One

func One[T any](rows Rows, columns Columns[T]) (T, error)

One retrieves a single row, scans it, and closes the iterator.

Types

type Columns added in v0.0.10

type Columns[T any] map[string]Scanner[T]

Columns are used by the utility functions.

type Func added in v0.0.8

type Func[T, V any] func(*T, V) error

Func is a function type that defines a custom scanner for a column.

func Any

func Any[T, V any](scan func(*T, V)) Func[T, V]

Any creates a custom scanner for a column with a specified scan function.

func JSON

func JSON[T, V any](scan func(*T, V)) Func[T, []byte]

JSON creates a custom scanner for a column containing JSON data with a specified scan function.

func Null

func Null[T, V any](def V, scan func(*T, V)) Func[T, *V]

Null creates a custom scanner for a nullable column with a specified default value and scan function.

func (Func[T, V]) Scan added in v0.0.8

func (f Func[T, V]) Scan() (any, func(*T) error)

Scan implements the Scan method for the Func type.

type Iterator added in v0.0.8

type Iterator[T any] struct {
	// contains filtered or unexported fields
}

Iterator for scanning SQL rows.

func Iter added in v0.0.8

func Iter[T any](rows Rows, columns Columns[T]) (Iterator[T], error)

Iter creates a new iterator.

func (Iterator[T]) Close added in v0.0.8

func (i Iterator[T]) Close() error

Close releases resources of the iterator.

func (Iterator[T]) Err added in v0.0.8

func (i Iterator[T]) Err() error

Err returns any error from iteration process.

func (Iterator[T]) Next added in v0.0.8

func (i Iterator[T]) Next() bool

Next advances the iterator to the next row.

func (Iterator[T]) Scan added in v0.0.8

func (i Iterator[T]) Scan(t *T) error

Scan scans the current row into a value of type T.

func (Iterator[T]) Value added in v0.0.11

func (i Iterator[T]) Value() (T, error)

Value retrieves the current row value.

type Rows

type Rows interface {
	Next() bool
	Scan(dest ...any) error
	Columns() ([]string, error)
	Err() error
	Close() error
}

Rows defines the interface for a SQL result set, including methods for iterating, scanning, and error handling.

type Scanner added in v0.0.8

type Scanner[T any] interface {
	Scan() (any, func(*T) error)
}

Scanner defines the interface for a custom column scanner. It returns a pair: destination for scan and a function to process the scan result.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL