Help us shape the future of Go! Take the 2026 Go Developer Survey

database

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package database provides the SQL data layer's dialect-neutral core: a lifecycle-integrated wrapper over a database/sql connection pool and the dialect seam its providers implement. The package is stdlib-plus-config only; every driver lives in a provider sub-module (database/postgres) that constructs the pool and supplies the dialect, so a consumer imports its provider once, at the composition root.

Wrapper

New wraps the provider-constructed *sql.DB with the provider's Dialect and a finalized Config, applying the config's pool settings — the dialect-independent half of construction every provider shares. It performs no I/O: an unfinalized Config, nil conn, or nil dialect panics with the fix named, and everything else waits for Start. DB.Conn exposes the pool; DB.Dialect the seam.

Lifecycle wiring

The package registers no lifecycle hooks of its own. DB.Start and DB.Shutdown carry the lifecycle package's hook signature, so a composition root wires the database as bare method values:

lc.OnStartup(db.Start)
lc.OnShutdown(db.Shutdown)

Start establishes connectivity with a ping bounded by the configured conn_timeout, so a dead database fails the coordinator's startup rather than serving traffic unready. Shutdown closes the pool and returns the close error; after a failed startup the drain passes through it cleanly.

Readiness

DB.Ready satisfies lifecycle.ReadinessChecker structurally and reports live connectivity: false before Start or after Shutdown, and otherwise a ping bounded by conn_timeout. A readiness probe aggregating the database therefore reflects it now — 503 during an outage, healed when the database returns — at the cost of one bounded round trip per probe. DB.Ping is the same verification under the caller's context and bound.

Dialect

Dialect is the whole provider surface the base needs: a name, the bind placeholder renderer, and the driver error mapper. At the connectivity slice MapError is the identity; query surfaces in later slices route SQL rendering and error classification through the seam, which is what keeps them dialect-neutral. Providers are selected by typed construction — a Provider constant and a constructor per sub-module, no registry.

Configuration

Config holds the connection identity, pool sizing, and timeouts, and implements the config package's Merge and Finalize contract, so it loads as part of an application's configuration. The numeric and duration fields are pointers: nil is unset and takes the default, while an explicit zero survives the load and means what it says. Port defaults in the provider, User and Password stay optional (requiredness varies by provider and auth mode), and Options passes dialect-specific connection keys through to the provider. Finalize composes the standard override names from the prefix it receives (via NewEnv, recorded on Env for introspection); an empty prefix disables the overrides.

Errors

ErrNotReady and ErrConnectionFailed are the package's two sentinels, wrapped in the dual form fmt.Errorf("%w: %w", sentinel, err) so errors.Is classifies while the driver's error stays recoverable. sql.ErrNoRows is never mapped; it flows to the boundary unchanged.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotReady reports a call against a [DB] before a successful Start
	// or after Shutdown.
	ErrNotReady = errors.New("database not ready")

	// ErrConnectionFailed classifies a connectivity failure. It is wrapped
	// alongside the driver's error in the dual form
	// fmt.Errorf("%w: %w", ErrConnectionFailed, err), so errors.Is matches
	// the class while the cause stays recoverable.
	ErrConnectionFailed = errors.New("database connection failed")
)

Functions

This section is empty.

Types

type Config

type Config struct {
	Host            string            `json:"host"`
	Name            string            `json:"name"`
	User            string            `json:"user"`
	Password        string            `json:"password"`
	Port            *int              `json:"port"`
	MaxOpenConns    *int              `json:"max_open_conns"`
	MaxIdleConns    *int              `json:"max_idle_conns"`
	ConnMaxLifetime *config.Duration  `json:"conn_max_lifetime"`
	ConnMaxIdleTime *config.Duration  `json:"conn_max_idle_time"`
	ConnTimeout     *config.Duration  `json:"conn_timeout"`
	Options         map[string]string `json:"options"`
	Env             Env               `json:"-"`
}

Config holds the connection identity, pool sizing, and timeouts for a SQL database. The numeric and duration fields are tri-state pointers: nil is unset and takes the default, while an explicit zero survives the load and means what it says — an unlimited pool, or no idle connections. Port has no default here because the default port is a provider fact; each provider supplies its own. User and Password are optional because their requiredness varies by provider and auth mode; the password rides the secrets layer of config.Load rather than a committed file. Options carries dialect-specific connection keys (postgres: sslmode) passed through to the provider. Env records the environment-variable names Finalize composed and read; it is excluded from JSON.

func (*Config) Finalize

func (c *Config) Finalize(envPrefix string) error

Finalize composes the environment override names from envPrefix (an empty prefix disables overrides), applies defaults, applies the overrides, and validates. Name is the one required field; a malformed override fails with an error naming its variable.

func (*Config) Merge

func (c *Config) Merge(src *Config)

Merge overlays src's set fields onto the receiver. Options merges key-wise, so an overlay can set one connection option without dropping the rest.

type DB

type DB struct {
	// contains filtered or unexported fields
}

DB wraps a provider-constructed connection pool with lifecycle integration and the provider's dialect. It owns one pool for the process: construction performs no I/O, Start establishes connectivity, and Ready reports it live. Start and Shutdown carry the lifecycle hook signature, so the composition root registers the bare method values, and Ready satisfies lifecycle.ReadinessChecker structurally; the package registers no hooks of its own.

func New

func New(conn *sql.DB, dialect Dialect, cfg Config) *DB

New wraps a provider-constructed pool with dialect and applies cfg's pool settings — the dialect-independent half of construction every provider shares. It panics if cfg was not finalized, or on a nil conn or dialect: each is a wiring defect at the composition root, not a runtime condition.

func (*DB) Conn

func (d *DB) Conn() *sql.DB

Conn returns the underlying connection pool.

func (*DB) Dialect

func (d *DB) Dialect() Dialect

Dialect returns the dialect the provider constructed this database with.

func (*DB) Ping

func (d *DB) Ping(ctx context.Context) error

Ping verifies connectivity under the caller's context: ErrNotReady before Start or after Shutdown, and otherwise a ping whose failure wraps ErrConnectionFailed. Unlike DB.Ready it applies no timeout of its own.

func (*DB) Ready

func (d *DB) Ready() bool

Ready reports live connectivity: false before Start or after Shutdown, and otherwise the result of a ping bounded by the configured conn_timeout. The probe reflects the database now — readiness drops during an outage and recovers with it, at the cost of one bounded round trip per call.

func (*DB) Shutdown

func (d *DB) Shutdown(ctx context.Context) error

Shutdown clears readiness and closes the pool, returning the close error. Closing a pool that never connected is a clean no-op, so the drain-after-failed-startup path is safe. The context exists for the lifecycle hook signature; sql.DB.Close is synchronous.

func (*DB) Start

func (d *DB) Start(ctx context.Context) error

Start establishes connectivity with a ping bounded by the configured conn_timeout and marks the database started. A failure wraps ErrConnectionFailed around the driver's error. There is no started guard: a repeat Start just pings again.

type Dialect

type Dialect interface {
	// Name identifies the dialect; it matches the provider's Provider
	// constant.
	Name() string

	// Placeholder renders the 1-based nth bind parameter ("$1" for
	// postgres, "@p1" for a future mssql).
	Placeholder(n int) string

	// MapError translates a driver error into the package's sentinels. At
	// the connectivity slice it is the identity: nothing is classified and
	// sql.ErrNoRows always flows through unchanged.
	MapError(err error) error
}

Dialect is the seam a provider implements: the whole surface the base package needs from an engine. Query surfaces in later slices route SQL rendering and driver errors through it, so consumers import their provider only at the composition root.

type Env

type Env struct {
	Host            string
	Name            string
	User            string
	Password        string
	Port            string
	MaxOpenConns    string
	MaxIdleConns    string
	ConnMaxLifetime string
	ConnMaxIdleTime string
	ConnTimeout     string
}

Env names the environment variables Config.Finalize reads, composed from the prefix it receives under the "database" segment: DATABASE_HOST, DATABASE_PORT, and the rest, prefixed by whatever config.EnvName produces. An empty name disables that one override; the zero value — an empty prefix — disables all of them. Populated by Finalize and exposed for introspection.

func NewEnv

func NewEnv(prefix string) Env

NewEnv composes the standard override names from a prefix under the "database" segment: DATABASE_HOST, DATABASE_PORT, and the rest, prefixed by whatever config.EnvName produces. An empty prefix returns the zero Env, disabling the overrides.

type Provider

type Provider string

Provider types the constant each provider sub-module declares for typed selection at the composition root; database/postgres declares postgres.Provider.

Directories

Path Synopsis
postgres module

Jump to

Keyboard shortcuts

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