sqlz

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Nov 26, 2023 License: MIT Imports: 8 Imported by: 0

README

sqlz

Go Reference build

This package provides a set of helper functions and types to simplify operations with SQL databases in Go. It provides a more flexible and intuitive interface for scanning SQL query results directly into Go structs, slices of structs, or channels of structs. It was inspired by jmoiron/sqlx but it's more lightweight. The core implementation is just the Scan() function.

The package is considered stable and ready for production use.

Examples

Use sqlz to scan a slice of User structs from a query result set.

rows, err := db.QueryContext(ctx, "SELECT * FROM users ORDER BY id LIMIT 10")
if err != nil {
    log.Fatal(err)
}
defer rows.Close()

var records []*User
if err = sqlz.Scan(ctx, rows, &records); err != nil {
    log.Fatal(err)
}
log.Println(records)

It also supports channels:

records := make(chan *User, 8)

go func() {
    defer close(records)
    // ... perform query
    if err = sqlz.Scan(ctx, rows, records); err != nil {
        log.Fatal(err)
    }
}()

for user := range records {
    // Receive all users from the concurrent query.
    fmt.Println("found user:", user.ID)
}
License

MIT License

Documentation

Overview

Package sqlz provides a set of helper functions and types to simplify operations with SQL databases in Go. It provides a more flexible and intuitive interface for scanning SQL query results directly into Go structs, slices of structs, or channels of structs.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func PurgeCache deprecated

func PurgeCache()

PurgeCache purges the internal type cache of the global Scanner.

Deprecated: This is a no-op, use a dedicated Scanner instead.

func Scan

func Scan(ctx context.Context, rows Rows, dest any) error

Scan is for scanning the result set from rows into a destination structure. It uses the global Scanner. See Scanner.Scan for more details.

Example (Chan)
package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	"time"

	"github.com/semrekkers/sqlz"
)

var (
	ctx context.Context
	db  *sql.DB
)

type User struct {
	ID        int
	Name      string
	FirstName string `db:"first_name"`
	LastName  string `db:"last_name"`
	Age       int
	DeletedAt *time.Time `db:"deleted_at"`

	AppValue []byte `db:"-"`
}

func main() {
	records := make(chan *User, 8)

	go func() {
		defer close(records)

		rows, err := db.QueryContext(ctx, "SELECT id FROM users WHERE deleted_at IS NULL ORDER BY id")
		if err != nil {
			log.Fatal(err)
		}
		defer rows.Close()

		if err = sqlz.Scan(ctx, rows, records); err != nil {
			log.Fatal(err)
		}
	}()

	for user := range records {
		fmt.Println("found active user:", user.ID)
	}
}
Output:

Example (Slice)
package main

import (
	"context"
	"database/sql"
	"log"
	"time"

	"github.com/semrekkers/sqlz"
)

var (
	ctx context.Context
	db  *sql.DB
)

type User struct {
	ID        int
	Name      string
	FirstName string `db:"first_name"`
	LastName  string `db:"last_name"`
	Age       int
	DeletedAt *time.Time `db:"deleted_at"`

	AppValue []byte `db:"-"`
}

func main() {
	rows, err := db.QueryContext(ctx, "SELECT * FROM users ORDER BY id LIMIT 10")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	var records []*User
	if err = sqlz.Scan(ctx, rows, &records); err != nil {
		log.Fatal(err)
	}
	log.Println(records)
}
Output:

Example (Struct)
package main

import (
	"context"
	"database/sql"
	"log"
	"time"

	"github.com/semrekkers/sqlz"
)

var (
	ctx context.Context
	db  *sql.DB
)

type User struct {
	ID        int
	Name      string
	FirstName string `db:"first_name"`
	LastName  string `db:"last_name"`
	Age       int
	DeletedAt *time.Time `db:"deleted_at"`

	AppValue []byte `db:"-"`
}

func main() {
	row, err := db.QueryContext(ctx, "SELECT * FROM users WHERE id = 123")
	if err != nil {
		log.Fatal(err)
	}
	defer row.Close()

	var record User
	if err = sqlz.Scan(ctx, row, &record); err != nil {
		log.Fatal(err)
	}
	log.Println(record)
}
Output:

Types

type Rows

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

Rows represents the result set of a database query. It's implemented by sql.Rows.

type Scanner added in v1.1.0

type Scanner struct {

	// IgnoreUnknownColumns controls whether Scan will return an error if a column in the result set has no corresponding struct field.
	// Default is false (return an error).
	IgnoreUnknownColumns bool
	// contains filtered or unexported fields
}

A Scanner is for scanning result sets from rows into a destination structure. It maintains an internal type cache for mapping struct fields to database columns. It's safe for concurrent use by multiple goroutines. The zero value is ready to use.

func (*Scanner) PurgeCache added in v1.1.0

func (s *Scanner) PurgeCache()

PurgeCache purges the internal type cache.

func (*Scanner) Scan added in v1.1.0

func (s *Scanner) Scan(ctx context.Context, rows Rows, dest any) error

Scan is for scanning the result set from rows into a destination structure. It supports scanning into a struct, a slice of structs, or a channel that emits structs.

The destination (dest) must be a pointer to a struct, a pointer to a slice of structs, or a channel of structs. If the destination is a channel, Scan will send a struct for each row in the result set until the context is canceled or the result set is exhausted.

The structure of the destination struct must match the structure of the result set. The field name or its `db` tag must match the column name. The field order does not need to match the column order. If a column has no corresponding struct field, Scan returns an error.

Scan blocks until the context is canceled, the result set is exhausted, or an error occurs.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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