CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/golang-github-com-jackc-pgx-v5

pgx is a pure Go driver and toolkit for PostgreSQL providing a native high-performance interface with PostgreSQL-specific features plus a database/sql compatibility adapter.

Pending
Overview
Eval results
Files

custom-types.mddocs/types/

Custom Types

Working with PostgreSQL enums, composites, domains, and custom types.

Import

import "github.com/jackc/pgx/v5"
import "github.com/jackc/pgx/v5/pgtype"

Loading Types from Database

func (c *Conn) LoadType(ctx context.Context, typeName string) (*pgtype.Type, error)
func (c *Conn) LoadTypes(ctx context.Context, typeNames []string) ([]*pgtype.Type, error)

Supported types: array, composite, domain, enum, range, multirange types. Requires all dependent types to be already registered.

Enums

Load and Register Enum

// Load and register a custom enum type
t, err := conn.LoadType(ctx, "my_status_enum")
if err != nil {
    return err
}
conn.TypeMap().RegisterType(t)

// Load array of the enum
t2, err := conn.LoadType(ctx, "_my_status_enum") // underscore prefix = array type
if err != nil {
    return err
}
conn.TypeMap().RegisterType(t2)

// Now you can use the type
var status string
err = conn.QueryRow(ctx, "SELECT status FROM orders WHERE id = $1", orderID).Scan(&status)

Multiple Types at Once

// Load multiple types (handles dependencies automatically)
types, err := conn.LoadTypes(ctx, []string{"foo", "_foo", "bar", "_bar"})
if err != nil {
    return err
}
for _, t := range types {
    conn.TypeMap().RegisterType(t)
}

Using AfterConnect Hook

For connection pools, register types in the AfterConnect hook:

config, err := pgxpool.ParseConfig(connString)
config.AfterConnect = func(ctx context.Context, conn *pgx.Conn) error {
    t, err := conn.LoadType(ctx, "my_status_enum")
    if err != nil {
        return err
    }
    conn.TypeMap().RegisterType(t)
    
    // Load array type
    arrType, err := conn.LoadType(ctx, "_my_status_enum")
    if err != nil {
        return err
    }
    conn.TypeMap().RegisterType(arrType)
    
    return nil
}
pool, err := pgxpool.NewWithConfig(ctx, config)

Composite Types

Scan into Struct

// Given PostgreSQL composite type:
// CREATE TYPE person AS (name TEXT, age INT);

type Person struct {
    Name string
    Age  int32
}

// Load the type
t, err := conn.LoadType(ctx, "person")
conn.TypeMap().RegisterType(t)

// Query
var p Person
err = conn.QueryRow(ctx, "SELECT person_col FROM people WHERE id = $1", id).Scan(&p)

Insert Composite

person := Person{Name: "Alice", Age: 30}
_, err := conn.Exec(ctx, "INSERT INTO people (person_col) VALUES ($1)", person)

Composite Builders and Scanners

For manual composite encoding/decoding:

func NewCompositeBinaryBuilder(m *Map, buf []byte) *CompositeBinaryBuilder
func (b *CompositeBinaryBuilder) AppendValue(oid uint32, field any)
func (b *CompositeBinaryBuilder) Finish() ([]byte, error)

func NewCompositeBinaryScanner(m *Map, src []byte) *CompositeBinaryScanner
func (cs *CompositeBinaryScanner) Next() bool
func (cs *CompositeBinaryScanner) OID() uint32
func (cs *CompositeBinaryScanner) Bytes() []byte
func (cs *CompositeBinaryScanner) IsNull() bool
func (cs *CompositeBinaryScanner) Err() error

func NewCompositeTextBuilder(m *Map, buf []byte) *CompositeTextBuilder
func (b *CompositeTextBuilder) AppendValue(oid uint32, field any)
func (b *CompositeTextBuilder) Finish() ([]byte, error)

func NewCompositeTextScanner(m *Map, src []byte) *CompositeTextScanner
func (cfs *CompositeTextScanner) Next() bool
func (cfs *CompositeTextScanner) Bytes() []byte
func (cfs *CompositeTextScanner) Err() error

Composite Interfaces

type CompositeCodecField struct {
    Name string
    Type *Type
}

type CompositeIndexGetter interface {
    IsNull() bool
    Index(i int) any
}

type CompositeIndexScanner interface {
    ScanNull() error
    ScanIndex(i int) any
}

Domain Types

Domain types are treated as their base type:

// Given: CREATE DOMAIN email AS TEXT CHECK (VALUE ~ '^.+@.+\..+$');
// Load domain type
t, err := conn.LoadType(ctx, "email")
conn.TypeMap().RegisterType(t)

// Use as string
var email string
err = conn.QueryRow(ctx, "SELECT email FROM users WHERE id = $1", id).Scan(&email)

Custom Type with Scanner/Valuer

Implement Scanner/Valuer interfaces for custom Go types:

type Status string

const (
    StatusPending  Status = "pending"
    StatusApproved Status = "approved"
    StatusRejected Status = "rejected"
)

// Implement TextScanner
func (s *Status) ScanText(v pgtype.Text) error {
    if !v.Valid {
        *s = ""
        return nil
    }
    *s = Status(v.String)
    return nil
}

// Implement TextValuer
func (s Status) TextValue() (pgtype.Text, error) {
    return pgtype.Text{String: string(s), Valid: s != ""}, nil
}

// Now you can scan directly
var status Status
err := conn.QueryRow(ctx, "SELECT status FROM orders WHERE id = $1", id).Scan(&status)

Register Default PgType

For QueryExecModeExec or SimpleProtocol modes where OID is unknown:

conn.TypeMap().RegisterDefaultPgType(Status(""), "my_status_enum")

CompositeCodec

type CompositeCodec struct {
    Fields []CompositeCodecField
}

Used for registering composite type codecs manually.

EnumCodec

type EnumCodec struct{ /* unexported */ }

Caches decoded strings to reduce allocations for types with small cardinality.

RecordCodec

type RecordCodec struct{}

Codec for generic PostgreSQL record type (binary decode only).

SkipUnderlyingTypePlanner

type SkipUnderlyingTypePlanner interface {
    SkipUnderlyingTypePlan()
}

Implement this empty method to prevent pgtype from treating a renamed type as its underlying type.

type MyCustomString string

func (MyCustomString) SkipUnderlyingTypePlan() {}

Utility Types

type CompositeFields []any   // for encoding composite values as slices

Helper Functions

func GetAssignToDstType(dst any) (any, bool)
func NullAssignTo(dst any) error

Performance Note

Custom types loaded via LoadType are only loaded once per connection. Use AfterConnect hooks with pools to ensure all connections have the types registered.

Install with Tessl CLI

npx tessl i tessl/golang-github-com-jackc-pgx-v5

docs

batch.md

common-patterns.md

connection-pool.md

copy.md

database-sql.md

direct-connection.md

index.md

querying.md

testing.md

tracing.md

transactions.md

tile.json