postgres

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: May 20, 2026 License: AGPL-3.0 Imports: 21 Imported by: 0

Documentation

Overview

Package postgres provides a Postgres-backed implementation of service.Repository for the identity service.

This is an alternative to the EntDB-backed repository. The two are interchangeable from the AuthService's point of view: both implement the same service.Repository interface.

Why Postgres

Postgres is well understood, ubiquitous in production environments, and ships with a mature ops toolkit (pg_dump, pg_basebackup, replicas, PITR via WAL archiving). It is the right default for teams that want to run identity without taking a dependency on the tenant-shard-db stack.

Driver choice

The implementation uses pgx/v5 directly (not via database/sql). pgxpool.Pool gives us a tuneable connection pool; pgx is also faster than database/sql and exposes Postgres-specific features (LISTEN / NOTIFY, COPY, JSONB native typing) that we may want later.

Migrations

Schema DDL lives under migrations/ and is applied via golang-migrate/migrate using the embed.FS source. By default New() does NOT run pending migrations on connect — production deploys run migrations out-of-band as a separate Job, so a rolling rollout never races two replicas to apply the same change. Set Config.AutoMigrate to true (or GATEWAY_POSTGRES_AUTO_MIGRATE=true) only for local dev and single-replica environments.

Multi-tenancy

Every table carries a tenant_id text not null column and uniqueness constraints are scoped to (tenant_id, ...). A pgRepository instance is constructed with a single tenant_id and writes/reads only that tenant's rows.

Error mapping

Postgres unique-violation errors (SQLSTATE 23505) are mapped to service.ErrAlreadyExists by errors.go::wrapPgErr. ErrNoRows is surfaced as a nil result (not an error), matching the existing in-memory and EntDB drivers.

Index

Constants

View Source
const DefaultConnTimeout = 5 * time.Second

DefaultConnTimeout is used when Config.ConnTimeout is zero.

View Source
const DefaultMaxConns int32 = 25

DefaultMaxConns is used when Config.MaxConns is zero.

Variables

This section is empty.

Functions

func New

func New(ctx context.Context, cfg Config) (*pgRepository, error)

New constructs a Postgres-backed repository:

  1. Parse / validate cfg.
  2. Open a pgxpool with cfg.MaxConns, cfg.ConnTimeout.
  3. Optionally run pending migrations (cfg.AutoMigrate=true).
  4. Ping to fail fast on a misconfigured DSN.

The returned store implements both service.Repository and service.DB. The caller is responsible for keeping the *pgRepository alive for the lifetime of the service; pool resources are released by Close().

Types

type Config

type Config struct {
	DSN         string
	MaxConns    int32
	ConnTimeout time.Duration
	AutoMigrate bool
	TenantID    string
}

Config controls how the postgres repository connects to its database.

DSN is the libpq-style connection string, e.g.

postgres://user:pass@host:5432/dbname?sslmode=disable

MaxConns caps the underlying pgxpool. A zero value means "use the pgxpool default" (currently 4 + GOMAXPROCS-ish). 25 is the suggested default for an identity service node (see DefaultMaxConns).

ConnTimeout is the per-acquire timeout used when checking a connection out of the pool. It does NOT bound the total query time — callers are still responsible for passing a context with the appropriate deadline.

AutoMigrate controls whether New() applies pending schema migrations on first connect. In CI / dev / test we want true (the default); in strict production deploys teams may flip it to false and run `migrate ... up` from a deploy pipeline instead.

TenantID is the tenant whose rows this repository instance writes and reads. Multi-tenant deployments construct one repository per tenant; the most common single-tenant config plumbs cfg.DefaultTenantID straight through.

func ConfigFromEnv

func ConfigFromEnv(tenantID string) Config

ConfigFromEnv reads Config values from GATEWAY_POSTGRES_* env vars. It is a convenience for callers that don't want to plumb each field through their own config struct. tenantID is passed in (rather than read from env) because identity already plumbs cfg.DefaultTenantID.

Jump to

Keyboard shortcuts

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