dbx

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package dbx provides lightweight, generic helpers for scanning database/sql rows into Go structs. It eliminates repetitive scan boilerplate while keeping full SQL control — no ORM, no query generation, just row mapping.

Struct fields are mapped to result columns via the `db` struct tag. Fields without a `db` tag are ignored. Use `db:"-"` to explicitly skip a field.

Quick Start

Set the default connection once at startup:

dbx.SetDefault(db) // *sql.DB, *sql.Tx, or *sql.Conn

Then use the package-level functions — no connection argument needed:

type User struct {
    ID    int     `db:"id"`
    Name  string  `db:"name"`
    Email *string `db:"email"` // nullable → pointer
}

// Fetch all users
users, err := dbx.QueryAll[User](ctx, "SELECT id, name, email FROM users")

// Fetch one user
user, err := dbx.QueryOne[User](ctx, "SELECT id, name, email FROM users WHERE id = $1", 42)

// Execute a statement
result, err := dbx.Exec(ctx, "DELETE FROM users WHERE id = $1", 42)

Transactions

Use WithTx to run queries inside a transaction. All dbx functions called with the returned context will use the transaction:

tx, _ := db.BeginTx(ctx, nil)
ctx := dbx.WithTx(ctx, tx)

dbx.Exec(ctx, "INSERT INTO users (name) VALUES ($1)", "Alice")
user, err := dbx.QueryOne[User](ctx, "SELECT id, name FROM users WHERE name = $1", "Alice")
tx.Commit()

sqlbuilder Integration

The Q-suffixed variants accept a sqlbuilder.Query directly:

q := sqlbuilder.Select("id", "name", "email").From("users").Where("id = $1", 42).Build()
user, err := dbx.QueryOneQ[User](ctx, q)

NULL Handling

Use pointer types for nullable columns. A NULL value results in nil; a non-NULL value is scanned into the pointed-to type:

type Row struct {
    Name  string  `db:"name"`  // NOT NULL column
    Bio   *string `db:"bio"`   // nullable column
}

Error Handling

SQL and scan errors are wrapped with errors.CodeDatabaseError. QueryOne returns errors.CodeNotFound when no rows match. QueryAll returns an empty slice (not an error) for no rows.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Exec

func Exec(ctx context.Context, query string, args ...any) (sql.Result, error)

Exec executes a non-returning query (INSERT/UPDATE/DELETE without RETURNING).

func ExecQ

func ExecQ(ctx context.Context, q sqlbuilder.Query) (sql.Result, error)

ExecQ is like Exec but accepts a sqlbuilder.Query.

func QueryAll

func QueryAll[T any](ctx context.Context, query string, args ...any) ([]T, error)

QueryAll executes a query and returns all rows scanned into []T. T must be a struct with `db` tags on its fields. Returns an empty slice (not an error) when the query yields no rows.

func QueryAllQ

func QueryAllQ[T any](ctx context.Context, q sqlbuilder.Query) ([]T, error)

QueryAllQ is like QueryAll but accepts a sqlbuilder.Query.

func QueryOne

func QueryOne[T any](ctx context.Context, query string, args ...any) (T, error)

QueryOne executes a query and scans the first row into T. T must be a struct with `db` tags on its fields. Returns errors.CodeNotFound if the query yields no rows.

func QueryOneQ

func QueryOneQ[T any](ctx context.Context, q sqlbuilder.Query) (T, error)

QueryOneQ is like QueryOne but accepts a sqlbuilder.Query.

func SetDefault

func SetDefault(db DB)

SetDefault sets the default database connection used by all package-level functions (QueryAll, QueryOne, Exec, etc.). It must be called once during application startup, before any queries are executed. It is not safe for concurrent use.

dbx.SetDefault(db) // *sql.DB

func WithTx

func WithTx(ctx context.Context, tx *sql.Tx) context.Context

WithTx returns a child context that makes all dbx functions in that context use tx instead of the default connection. This is how you run queries inside a transaction:

tx, _ := db.BeginTx(ctx, nil)
ctx := dbx.WithTx(ctx, tx)
dbx.Exec(ctx, "INSERT INTO users ...") // uses tx
dbx.QueryOne[User](ctx, "SELECT ...")  // uses tx
tx.Commit()

Types

type DB

type DB interface {
	QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
	ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
}

DB combines query and exec capabilities. It is satisfied by *sql.DB, *sql.Tx, and *sql.Conn.

Jump to

Keyboard shortcuts

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