dbx

package module
v0.0.0-...-f3a27f6 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2026 License: MIT Imports: 4 Imported by: 0

README

dbx

A database-agnostic contract for Go services: Config (a PostgreSQL connection, composable under an env prefix) and Transactor (the interface services depend on to span multiple repositories in one transaction). The root package has no database driver dependency of its own; a driver-specific subpackage provides the actual implementation.

dbx has no gp-system dependency at all: the root package and seed are standard-library only, pg links pgx and its own OTel tracer, and bunx links bun. It works in any Go program. It is also the database layer used by the gp-system backend kit.

Install

go get github.com/gp-system/dbx

Only the subpackage(s) a project actually uses need to be imported:

go get github.com/gp-system/dbx/pg          # pgx-native driver
go get github.com/gp-system/dbx/bunx        # bun query-builder driver
go get github.com/gp-system/dbx/seed        # seeder registry (driver-agnostic)
go get github.com/gp-system/dbx/seed/bunx   # seeder first-or-create helper for bun

Only one driver is ever linked into a given binary; a service depends on dbx.Transactor and dbx.Config, never on the concrete implementation.

Subpackages

  • pg is the pgx-native database stack: NewPool/MustNewPool for pool construction (with an OTel span per query via otelpgx), DBTX/DB as the transaction-aware query executor repositories depend on, and NewTransactor producing a dbx.Transactor backed by pgx.Tx. DB is method-for-method identical to the DBTX interface sqlc generates, so sqlc-based repositories use it unchanged.
  • bunx is the optional adapter for projects that prefer the bun query builder: Open builds a *bun.DB over an existing pgx pool, From/Conn resolve the query surface a repository should use (joining the transaction in context when one is open), and NewTransactor produces a dbx.Transactor backed by bun.Tx. Nothing here links into a binary that does not import it, so pg stays bun-free.
  • seed is the database-agnostic contract of the seeder subsystem: a Registry of named Seeders, each optionally Guarded, run after migrations to load idempotent baseline data. WithTenants runs every seeder once per tenant, with the tenant available via TenantFromContext/OnlyTenants. It has no database driver dependency of its own.
  • seed/bunx provides FirstOrCreate/FirstOrCreateWhere, the idempotency primitive seeders are built around, for projects using the bun query builder. A project that prefers raw SQL writes its own INSERT ... ON CONFLICT DO NOTHING directly against dbx/pg's DBTX instead; the adapter is optional.

Usage

type Config struct {
	DB dbx.Config `envPrefix:"DB_"`
}

pool := pg.MustNewPool(ctx, cfg.DB)
db := pg.NewDB(pool)
tx := pg.NewTransactor(pool)

A service composes repositories inside one transaction:

tx.WithinTransaction(ctx, func(ctx context.Context) error {
	if err := orders.Insert(ctx, o); err != nil {
		return err
	}
	return inventory.Decrement(ctx, o.SKU, o.Qty)
})

Both repositories resolve the same transaction from ctx (via pg.TxFromContext/bunx.TxFromContext); an error from either rolls back everything.

Seeding, wired up after migrations:

reg := &seed.Registry{}
reg.Add(AdminUser(deps))
reg.Add(DefaultRoles(deps))

if err := reg.Run(ctx); err != nil {
	log.Fatal(err)
}

Design rules

  • The root package has zero driver dependency. dbx.Config and dbx.Transactor describe the contract; pg and bunx are the only packages that import a database driver. A service depends on the root package's types, never on pg or bunx directly, so swapping drivers touches only main and the repository layer's constructors.
  • Only one driver is ever linked into a binary. pg and bunx do not import each other, and a project picks exactly one; mixing them is a build-time non-issue (nothing forces it) but a runtime footgun (the two transaction contexts are incompatible), documented on bunx.
  • seed mirrors the same split. The registry and guard model in seed is driver-agnostic; seed/bunx.FirstOrCreate is the only piece that assumes bun, exactly like bunx versus pg for the query layer itself.
  • Transaction failures are plain errors. Both pg.NewTransactor and bunx.NewTransactor wrap the driver error with dbx.ErrBeginTx or dbx.ErrCommitTx (via %w), so a caller distinguishes the failing step with errors.Is without depending on any error-handling package.

Documentation

Overview

Package dbx is the database-agnostic contract of the kit: Config describes a PostgreSQL connection and Transactor is the interface services depend on to span multiple repositories in one transaction. It has no database driver dependency of its own.

Two implementations exist, selected by which one a project imports:

  • dbx/pg — the pgx-native stack (pool construction, a DBTX query executor, and a Transactor backed by pgx.Tx).
  • dbx/bunx — an optional adapter for projects that prefer the bun query builder, backed by bun.Tx.

Only one is ever linked into a given binary; a service depends on dbx.Transactor and dbx.Config, never on the concrete implementation.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrBeginTx  = errors.New("dbx: begin transaction")
	ErrCommitTx = errors.New("dbx: commit transaction")
)

ErrBeginTx and ErrCommitTx identify which transaction lifecycle step failed, regardless of which Transactor implementation (dbx/pg or dbx/bunx) is in use. Both implementations wrap the driver error with one of these via errors.Is-compatible %w; a caller that needs to distinguish "the database is unreachable" from "a constraint failed at commit" matches on these instead of the underlying driver error type.

Functions

This section is empty.

Types

type Config

type Config struct {
	Host     string `env:"HOST" envDefault:"localhost"`
	Port     int    `env:"PORT" envDefault:"5432"`
	User     string `env:"USER,required"`
	Password string `env:"PASSWORD,required"`
	Database string `env:"NAME,required"`
	SSLMode  string `env:"SSLMODE" envDefault:"disable"`
	MaxConns int32  `env:"MAX_CONNS" envDefault:"10"`
}

Config describes a PostgreSQL connection. Compose it under a prefix:

type Config struct {
	DB dbx.Config `envPrefix:"DB_"`
}

which maps to DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME, DB_SSLMODE, DB_MAX_CONNS. A second, independent connection composes under its own prefix the same way (the kit's `add db` generator does this for named connections):

type Config struct {
	DB          dbx.Config `envPrefix:"DB_"`
	DBAnalytics dbx.Config `envPrefix:"DB_ANALYTICS_"`
}

func (Config) DSN

func (c Config) DSN() string

DSN renders the config as a postgres:// connection URL.

type Transactor

type Transactor interface {
	WithinTransaction(ctx context.Context, fn func(ctx context.Context) error) error
}

Transactor runs a function within a database transaction. The transaction is carried by the context, so every DB call made through the kit's executors — dbx/pg's DB or dbx/bunx's resolvers — inside fn joins it automatically.

Directories

Path Synopsis
Package bunx is the optional bun adapter for the kit's transaction model.
Package bunx is the optional bun adapter for the kit's transaction model.
Package pg is the pgx-native database stack: pool construction, a transaction-aware query executor (DB), and a Transactor (satisfying dbx.Transactor) that lets a service span multiple repositories with one transaction.
Package pg is the pgx-native database stack: pool construction, a transaction-aware query executor (DB), and a Transactor (satisfying dbx.Transactor) that lets a service span multiple repositories with one transaction.
Package seed is the database-agnostic contract of the kit's seeder subsystem: a Registry of named Seeders, each optionally guarded, run after migrations to load idempotent baseline data (an admin user, roles, lookup tables).
Package seed is the database-agnostic contract of the kit's seeder subsystem: a Registry of named Seeders, each optionally guarded, run after migrations to load idempotent baseline data (an admin user, roles, lookup tables).
bunx
Package bunx is the seed subsystem's optional bun adapter: FirstOrCreate, the idempotent primitive seeders are built around.
Package bunx is the seed subsystem's optional bun adapter: FirstOrCreate, the idempotent primitive seeders are built around.

Jump to

Keyboard shortcuts

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