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

libstandard

package module
v0.0.0-...-4e17604 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 26 Imported by: 2

README

libstandard

Shared code for config-handling (lightweight viper-replacement), a pgx-based database pool and utility functions.

test

Database (pgx v5)

NewDatabasePool builds a *pgxpool.Pool from a DatabaseConfig. Two auth modes are supported and picked automatically:

  • Username/password — the classic path. Set User/Password, leave SSLCert/SSLKey empty. The link can still be encrypted via SSLMode (require, verify-full, …) and SSLRootCert.
  • Client certificate (mTLS) — set SSLCert/SSLKey. When they point at a rotating cert (e.g. a cert-manager CSI mount) the keypair is reloaded on every TLS handshake, so certs rotate without a restart, and Password is unused.

MinConns keeps connections warm in the background to avoid cold-handshake latency.

DatabaseConfig uses the same tags as the rest of the config machinery, so every value has a default that env, file or CLI flag can override.

var cfg struct {
    libstandard.DatabaseConfig
}
if err := libstandard.ReadFromEnv(&cfg); err != nil { /* ... */ }

pool, err := libstandard.NewDatabasePool(ctx, cfg.DatabaseConfig)
if err != nil { /* ... */ }
defer pool.Close()

// For ent / database/sql:
db := libstandard.OpenDB(pool)
drv := entsql.OpenDB(dialect.Postgres, db)
client := ent.NewClient(ent.Driver(drv))

To expose the settings as CLI flags, call libstandard.AddDatabaseFlags(cmd).

Note: in pgxpool a connection lifetime/idle-time of 0 means expire immediately, not unlimited. Leave MaxConnLifetime/MaxConnIdleTime empty to inherit pgx's sane defaults (1h / 30m).

Security

When discovering security issues please refer to the Security process.

License

Contributing

Please refer to the Contribution guildelines.

Code of conduct

Please refer to the Conduct guildelines.

Credits

The config-code is mostly ported from the great cleanenv library which is MIT licensed.

Documentation

Index

Constants

View Source
const (
	// Name of the environment variable or a list of names
	TagEnv = "env"
	// Default value
	TagEnvDefault = "env-default"
	// Flag name
	TagFlagName = "flag"
	// Custom list and map separator
	TagEnvSeparator = "env-separator"
	// Flag to mark a field as required
	TagEnvRequired = "env-required"
	// Flag to specify prefix for structure fields
	TagEnvPrefix = "env-prefix"
)

Supported tags

View Source
const (
	DBHost              = "db-host"
	DBPort              = "db-port"
	DBName              = "db-name"
	DBUser              = "db-user"
	DBPassword          = "db-password"
	DBSSLMode           = "db-sslmode"
	DBSSLRootCert       = "db-sslrootcert"
	DBSSLCert           = "db-sslcert"
	DBSSLKey            = "db-sslkey"
	DBMinConns          = "db-min-conns"
	DBMaxConns          = "db-max-conns"
	DBMaxConnLifetime   = "db-max-conn-lifetime"
	DBMaxConnIdleTime   = "db-max-conn-idle-time"
	DBHealthCheckPeriod = "db-health-check-period"
	DBConnectTimeout    = "db-connect-timeout"
)

Flag names registered by AddDatabaseFlags. Exported so applications can look them up on their own command trees if needed.

View Source
const (
	Verbosity = "verbosity"
	Config    = "config"
)
View Source
const (
	// DefaultSeparator is a default list and map separator character
	DefaultSeparator = ","
)

Variables

This section is empty.

Functions

func AddConfigFlag

func AddConfigFlag(cmd *cobra.Command)

func AddDatabaseFlags

func AddDatabaseFlags(cmd *cobra.Command)

AddDatabaseFlags registers the database flags on a cobra command, mirroring AddVerbosityFlag / AddConfigFlag. The defaults here match the env-default tags on DatabaseConfig so that flags, env and file all agree.

func AddVerbosityFlag

func AddVerbosityFlag(cmd *cobra.Command)

func Compress

func Compress(data []byte) ([]byte, error)

func Decompress

func Decompress(data []byte) ([]byte, error)

func DefaultInitializer

func DefaultInitializer(cfg interface{}, cmd *cobra.Command, name string) error

DefaultInitializer loads the config and initializes the logging. This assumes that there are "config" and "verbosity" flags present on the cobra-command.

func FirstOrEmpty

func FirstOrEmpty(slice []string) string

FirstOrEmpty returns the first string from the slice.

func NewDatabasePool

func NewDatabasePool(ctx context.Context, cfg DatabaseConfig) (*pgxpool.Pool, error)

NewDatabasePool builds a *pgxpool.Pool from the config and verifies it with a ping. mTLS is wired up automatically when SSLCert and SSLKey are set, with hot-reloading of the client certificate on every handshake.

For ent (or any database/sql consumer) wrap the returned pool:

pool, err := libstandard.NewDatabasePool(ctx, cfg)
...
db := libstandard.OpenDB(pool)
drv := entsql.OpenDB(dialect.Postgres, db)
client := ent.NewClient(ent.Driver(drv))

func OpenDB

func OpenDB(pool *pgxpool.Pool) *sql.DB

OpenDB adapts a pool into a *sql.DB for database/sql consumers such as ent. The pool stays the single source of truth for connection management; closing the returned *sql.DB does not close the pool.

func Read

func Read(cfg interface{}, flags *pflag.FlagSet, file string, defaultCfg DefaultFileConfig) error

Read reads configuration from a file, environment variables and cmd-flags, parses them depending on tags in structure provided. Then it reads and parses

Example:

type ConfigDatabase struct {
	Port     string `flag:"port" yaml:"port" env:"PORT" env-default:"5432"`
	Host     string `flag:"host" yaml:"host" env:"HOST" env-default:"localhost"`
	Name     string `flag:"name" yaml:"name" env:"NAME" env-default:"postgres"`
	User     string `flag:"user" yaml:"user" env:"USER" env-default:"user"`
	Password string `flag:"password" yaml:"password" env:"PASSWORD"`
}

var cfg ConfigDatabase

cmd.Flags().Int32("port", 5432, "Server-Port")
...

err := config.Read(&cfg, cmd.Flags(), "config.yml", , DefaultFileConfig{})
if err != nil {
    ...
}

func ReadFromEnv

func ReadFromEnv(cfg interface{}) error

ReadFromEnv reads configuration from environment variables, parses them depending on tags in structure provided. Then it reads and parses

Example:

type ConfigDatabase struct {
	Port     string `env:"PORT" env-default:"5432"`
	Host     string `env:"HOST" env-default:"localhost"`
	Name     string `env:"NAME" env-default:"postgres"`
	User     string `env:"USER" env-default:"user"`
	Password string `env:"PASSWORD"`
}

var cfg ConfigDatabase

err := config.ReadFromEnv(&cfg)
if err != nil {
    ...
}

func ReadFromFile

func ReadFromFile(cfg interface{}, file string, defaultCfg DefaultFileConfig) error

ReadFromFile reads configuration from a file and environment variables, parses them depending on tags in structure provided. Then it reads and parses

Example:

type ConfigDatabase struct {
	Port     string `yaml:"port" env:"PORT" env-default:"5432"`
	Host     string `yaml:"host" env:"HOST" env-default:"localhost"`
	Name     string `yaml:"name" env:"NAME" env-default:"postgres"`
	User     string `yaml:"user" env:"USER" env-default:"user"`
	Password string `yaml:"password" env:"PASSWORD"`
}

var cfg ConfigDatabase

err := config.ReadFromFile(&cfg, "config.yml", DefaultFileConfig{})
if err != nil {
    ...
}

func ReadFromFlags

func ReadFromFlags(cfg interface{}, flags *pflag.FlagSet) error

ReadFromFlags reads configuration from environment variables and cmd-flags, parses them depending on tags in structure provided. Then it reads and parses

Example:

type ConfigDatabase struct {
	Port     string `flag:"port" env:"PORT" env-default:"5432"`
	Host     string `flag:"host" env:"HOST" env-default:"localhost"`
	Name     string `flag:"name" env:"NAME" env-default:"postgres"`
	User     string `flag:"user" env:"USER" env-default:"user"`
	Password string `flag:"password" env:"PASSWORD"`
}

var cfg ConfigDatabase

cmd.Flags().Int32("port", 5432, "Server-Port")
...

err := config.ReadFromFlags(&cfg, cmd.Flags())
if err != nil {
    ...
}

func SetupLogging

func SetupLogging(out io.Writer, level string) error

SetupLogging set the log output as the log level

func ToMap

func ToMap(slice []string) map[string]string

ToMap converts a string-slice to a map[string]string

func Unescape

func Unescape(s string) string

Unescape removes backslashes and double-quotes from strings

func Unique

func Unique(stringSlice []string) []string

Unique removes all duplicate values from the given slice

Types

type DatabaseConfig

type DatabaseConfig struct {
	Host string `yaml:"host" env:"DB_HOST" env-default:"localhost" flag:"db-host"`
	Port uint16 `yaml:"port" env:"DB_PORT" env-default:"5432" flag:"db-port"`
	Name string `yaml:"name" env:"DB_NAME" env-default:"postgres" flag:"db-name"`
	User string `yaml:"user" env:"DB_USER" env-default:"postgres" flag:"db-user"`

	// Password drives the classic username/password path. Set it for password
	// auth; it is ignored once client-certificate auth is active (see below).
	Password string `yaml:"password" env:"DB_PASSWORD" flag:"db-password"`

	// TLS. Two mutually exclusive auth modes are supported:
	//
	//   - Password auth: leave SSLCert/SSLKey empty. The connection can still be
	//     encrypted via SSLMode (e.g. require or verify-full) plus SSLRootCert.
	//   - Client-certificate (mTLS) auth: set SSLCert and SSLKey. The files are
	//     reloaded on every TLS handshake, so short-lived rotating certs (e.g. a
	//     cert-manager CSI mount) work without a restart, and Password is unused.
	//
	// SSLMode follows libpq semantics (disable, allow, prefer, require,
	// verify-ca, verify-full).
	SSLMode     string `yaml:"sslMode" env:"DB_SSLMODE" env-default:"prefer" flag:"db-sslmode"`
	SSLRootCert string `yaml:"sslRootCert" env:"DB_SSLROOTCERT" flag:"db-sslrootcert"`
	SSLCert     string `yaml:"sslCert" env:"DB_SSLCERT" flag:"db-sslcert"`
	SSLKey      string `yaml:"sslKey" env:"DB_SSLKEY" flag:"db-sslkey"`

	// Pool sizing. MinConns keeps that many connections warm in the background,
	// so callers rarely pay a cold TCP+TLS handshake. MaxConns caps the pool;
	// when 0 pgx picks max(4, NumCPU).
	MinConns int32 `yaml:"minConns" env:"DB_MIN_CONNS" env-default:"2" flag:"db-min-conns"`
	MaxConns int32 `yaml:"maxConns" env:"DB_MAX_CONNS" env-default:"10" flag:"db-max-conns"`

	// WARNING: in pgxpool a duration of 0 means "expire immediately", NOT
	// "unlimited" (the opposite of database/sql). Leave these empty to inherit
	// pgx's sane defaults (lifetime 1h, idle 30m, health-check 1m) rather than
	// setting them to 0.
	MaxConnLifetime   string `yaml:"maxConnLifetime" env:"DB_MAX_CONN_LIFETIME" flag:"db-max-conn-lifetime"`
	MaxConnIdleTime   string `yaml:"maxConnIdleTime" env:"DB_MAX_CONN_IDLE_TIME" flag:"db-max-conn-idle-time"`
	HealthCheckPeriod string `yaml:"healthCheckPeriod" env:"DB_HEALTH_CHECK_PERIOD" flag:"db-health-check-period"`

	// ConnectTimeout bounds a single connection attempt. 0 means no timeout, so
	// it defaults to something finite.
	ConnectTimeout string `yaml:"connectTimeout" env:"DB_CONNECT_TIMEOUT" env-default:"10s" flag:"db-connect-timeout"`
}

DatabaseConfig holds everything needed to build a pgx connection pool. The struct tags plug into this package's own config machinery (ReadFromEnv / ReadFromFile / ReadFromFlags), so every field carries a default that an application can override via config-file, environment variable or CLI flag without touching code.

Durations are Go duration strings ("30s", "5m", "1h"). They intentionally default to the empty string, which means "keep pgx's own default" - see the warning on the pool fields below.

type DefaultFileConfig

type DefaultFileConfig struct {
	Name       string
	Extensions []string
	Paths      []string
}

type Setter

type Setter interface {
	SetValue(string) error
}

Setter is an interface for a custom value setter.

To implement a custom value setter you need to add a SetValue function to your type that will receive a string raw value:

type MyField string

func (f *MyField) SetValue(s string) error {
	if s == "" {
		return fmt.Errorf("field value can't be empty")
	}
	*f = MyField("my field is: " + s)
	return nil
}

Jump to

Keyboard shortcuts

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