pgxscan

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 17, 2021 License: MIT Imports: 6 Imported by: 0

README

pgxscan

Struct scanning for pgx.

Go Reference

This package adds simple scanning into structs using query results from pgx. Therefore it is bound to pgx and Postgresql. That's what it is meant for.

Documentation

Overview

Package pgxscan adds the ability to directly scan into structs from pgx query results.

Supported data types

The following Go data types are supported as destinations in a struct:

  • int64
  • int32
  • int16
  • string
  • []byte
  • float64
  • float32

The data types have to match exactly. No extension or truncation is done.

For example:

A struct field of int32 has to be matched with a SQL result field of int. Neither int64 nor int16 are allowed as destination types for an int result.

This applies to all supported types!

TODO: decide if larger int types should be allowed to hold smaller results. Does only make sense for ints, floating point values would be hit by rounding/representation problems.

pgxscan also supports some slice types directly:

[]int64
[]int32
[]int16
[]float32
[]float64
[]string
[][]byte

Only 1 dimensional arrays are supported for now. The slices in the struct are overwritten by newly allocated slices. So it does not make sense to pre-allocate anything in there.

Embedded structs are supported. If there are duplicate field names, the highest level name is used. Which is the Go rule for access.

Default name matching

A match is found when the following conditions are met:

  • both names are not empty (length > 0)
  • the name of the struct field matches the name from the result set (EqualFold)
Example
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/guidog/pgxscan"
	"github.com/jackc/pgx/v4"
)

type testRecord struct {
	// order of fields does not matter
	String string
	X      []byte
	Bigid  int64
	N      float32
	R      float64
	Xx     [][]byte
	A      []string
	Xa     []int64
}

func setupDB() *pgx.Conn {
	// do DB connect
	return &pgx.Conn{}
}

func main() {
	const testTable = `CREATE TABLE IF NOT EXISTS scantest (
  bigid bigint DEFAULT 7,
  string text DEFAULT 'xy',
  n real DEFAULT 42.1,
  r double precision DEFAULT -0.000001,
  a text[] DEFAULT '{"AA","BB"}',
  x bytea DEFAULT '\x010203',
  xx bytea[] DEFAULT '{"0102", "x"}',
  xa int[] DEFAULT '{11,22}'
)`

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	db := setupDB()
	defer db.Close(ctx)

	rows, err := db.Query(ctx, "SELECT * FROM scantest")
	if err != nil {
		panic(err)
	}
	defer rows.Close()

	for rows.Next() {
		var dest testRecord

		fmt.Printf("data before: %+v\n", dest)

		err = pgxscan.ReadStruct(&dest, rows)
		if err != nil {
			panic(err)
		}

		fmt.Printf("data after: %+v\n", dest)
	}
}
Output:

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotPointer is returend when the destination is not a pointer.
	ErrNotPointer = errors.New("arg not a pointer")
	// ErrNotStruct is returned when the dereferenced destination pointer does not point to a struct.
	ErrNotStruct = errors.New("arg not a struct")
	// ErrDestNil is returned when the destination is nil or points to nothing.
	ErrDestNil = errors.New("destination is nil")
	// ErrNotSimpleSlice is returned if the destination field is a slice
	ErrNotSimpleSlice = errors.New("db field not a simple slice")
	// ErrEmptyStruct is returned if the destination struct has no fields
	ErrEmptyStruct = errors.New("destination struct has no fields")
	// ErrInvalidDestination is returned when the destination field does not match the DB type
	ErrInvalidDestination = errors.New("destination has incompatible type")

	// DefaultNameMatcher is the matching function used by ReadStruct.
	// If not set, the internal matching is used.
	DefaultNameMatcher NameMatcherFnc = nil
)

Functions

func ReadStruct

func ReadStruct(dest interface{}, rows PgxRows) error

ReadStruct scans the current record in rows into the given destination.

The destination has to be a pointer to a struct type. If a struct field is exported and the name matches a returned column name the value of the db column is assigned to the struct field.

If a struct field cannot be modified it is silently ignored.

If a DB value can not be assigned to the destination field an ErrInvalidDestination error or an error wrapping ErrInvalidDestination is returned.

Error checking is best done w/ errors.Is().

ReadStruct uses DefaultNameMatcher to match struct fields to result columns. If it is not set, the internal matching is used.

Types

type NameMatcherFnc added in v0.0.4

type NameMatcherFnc func(fieldName, resultName string) bool

NameMatcherFnc is the signature for a function doing the name matching for fields. fieldName is the name of the struct field and resultName the column name returned from the query. If the names match true is returned, false otherwise.

type PgxRows added in v0.0.8

type PgxRows interface {
	FieldDescriptions() []pgproto3.FieldDescription
	Values() ([]interface{}, error)
	Err() error
}

PgxRows is a subset of the pgx.Rows interface.

Used to create a smaller API to implement for tests.

Jump to

Keyboard shortcuts

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