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

database

package
v2.17.1 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package database provides interface abstractions for interacting with relational data stores

Index

Constants

View Source
const (
	// DefaultConflictBackoffInitial is ConflictBackoffInitial when no
	// ConflictBackoff option sets it. A deadlock's losers need only to fall out
	// of step with each other, which takes milliseconds.
	DefaultConflictBackoffInitial = 5 * time.Millisecond

	// DefaultConflictBackoffMax is ConflictBackoffMax when no ConflictBackoff
	// option sets it. A transaction still conflicting after pauses this long is
	// under contention a longer wait will not clear, and its caller is better
	// served by retry.ErrExhausted soon than by a request that hangs.
	DefaultConflictBackoffMax = 250 * time.Millisecond
)

Variables

View Source
var (
	// ErrUserAlreadyExists indicates that a user with that username has already been created.
	ErrUserAlreadyExists = platformerrors.New("user already exists")

	// ErrTransactionClosed indicates a Tx was used after the callback it was handed to
	// returned. The transaction has already been committed or rolled back, so the
	// statement was not run and never will be. It is returned rather than panicked
	// because the caller is usually a goroutine that outlived its callback, and a panic
	// there takes down a process for a write that was already lost.
	ErrTransactionClosed = platformerrors.New("transaction is closed")
)
View Source
var (
	// ErrDatabaseNotReady indicates the given database is not ready.
	ErrDatabaseNotReady = platformerrors.New("database is not ready yet")
)

Functions

func BlobOrNil

func BlobOrNil(b []byte) any

BlobOrNil maps an empty encoding to a SQL NULL rather than an empty blob.

"No value" and "an empty value" mean the same thing in every column in this module that holds an encoded payload — no request, no failure map, no snapshot — and storing two renderings of it would make the round trip depend on which call site wrote the row: one reader gets nil back and another gets a zero-length slice, from rows that were written to mean the same thing.

func BoolFromNullBool

func BoolFromNullBool(b sql.NullBool) bool

BoolFromNullBool is nullable.BoolFromNullBool.

func CoerceTime

func CoerceTime(v any) (time.Time, bool)

CoerceTime normalizes whatever a driver hands back for a timestamp read as `any`, reporting whether it recognized one.

Timestamps are scanned as `any` rather than sql.NullTime because the drivers disagree. pgx and go-sql-driver return a time.Time, but modernc's SQLite driver stores a bound time.Time as Go's own String() rendering, and an aggregate over such a column loses the declared DATETIME affinity — so it comes back as a plain string that sql.NullTime refuses outright.

A NULL reports false, and callers treat that as "no value" rather than as the zero time: an empty backlog is not a row created at the epoch.

func CursorOrder

func CursorOrder(descending bool) (direction, comparison string)

CursorOrder reports the ORDER BY direction and the comparison operator a keyset-paginated read uses for a given sort direction.

It is one function because the two halves have to agree and nothing checks that they do. A descending page that kept "id > cursor" reads the wrong side of the boundary: the first page comes back, and every page after it skips straight past the rows the caller asked for. That failure produces no error and no empty result — just a listing quietly missing its middle.

func Float32FromNullString

func Float32FromNullString(s sql.NullString) float32

Float32FromNullString is nullable.Float32FromNullString.

func Float32FromString

func Float32FromString(s string) float32

Float32FromString is nullable.Float32FromString.

func Float32PointerFromNullString

func Float32PointerFromNullString(f sql.NullString) *float32

Float32PointerFromNullString is nullable.Float32PointerFromNullString.

func Float64PointerFromNullString

func Float64PointerFromNullString(f sql.NullString) *float64

Float64PointerFromNullString is nullable.Float64PointerFromNullString.

func Int32PointerFromNullInt32

func Int32PointerFromNullInt32(i sql.NullInt32) *int32

Int32PointerFromNullInt32 is nullable.Int32PointerFromNullInt32.

func NullBoolFromBool

func NullBoolFromBool(b bool) sql.NullBool

NullBoolFromBool is nullable.NullBoolFromBool.

func NullBoolFromBoolPointer

func NullBoolFromBoolPointer(b *bool) sql.NullBool

NullBoolFromBoolPointer is nullable.NullBoolFromBoolPointer.

func NullInt32FromInt32Pointer

func NullInt32FromInt32Pointer(i *int32) sql.NullInt32

NullInt32FromInt32Pointer is nullable.NullInt32FromInt32Pointer.

func NullInt32FromUint8Pointer

func NullInt32FromUint8Pointer(i *uint8) sql.NullInt32

NullInt32FromUint8Pointer is nullable.NullInt32FromUint8Pointer.

func NullInt32FromUint16

func NullInt32FromUint16(i uint16) sql.NullInt32

NullInt32FromUint16 is nullable.NullInt32FromUint16.

func NullInt32FromUint16Pointer

func NullInt32FromUint16Pointer(i *uint16) sql.NullInt32

NullInt32FromUint16Pointer is nullable.NullInt32FromUint16Pointer.

func NullInt32FromUint32Pointer

func NullInt32FromUint32Pointer(i *uint32) sql.NullInt32

NullInt32FromUint32Pointer is nullable.NullInt32FromUint32Pointer.

func NullInt64FromUint32Pointer

func NullInt64FromUint32Pointer(f *uint32) sql.NullInt64

NullInt64FromUint32Pointer is nullable.NullInt64FromUint32Pointer.

func NullStringFromFloat32

func NullStringFromFloat32(f float32) sql.NullString

NullStringFromFloat32 is nullable.NullStringFromFloat32.

func NullStringFromFloat32Pointer

func NullStringFromFloat32Pointer(f *float32) sql.NullString

NullStringFromFloat32Pointer is nullable.NullStringFromFloat32Pointer.

func NullStringFromFloat64Pointer

func NullStringFromFloat64Pointer(f *float64) sql.NullString

NullStringFromFloat64Pointer is nullable.NullStringFromFloat64Pointer.

func NullStringFromString

func NullStringFromString(s string) sql.NullString

NullStringFromString is nullable.NullStringFromString.

func NullStringFromStringPointer

func NullStringFromStringPointer(s *string) sql.NullString

NullStringFromStringPointer is nullable.NullStringFromStringPointer.

func NullTimeFromTime

func NullTimeFromTime(t time.Time) sql.NullTime

NullTimeFromTime is nullable.NullTimeFromTime.

func NullTimeFromTimePointer

func NullTimeFromTimePointer(t *time.Time) sql.NullTime

NullTimeFromTimePointer is nullable.NullTimeFromTimePointer.

func RunInTransaction

func RunInTransaction(
	ctx context.Context,
	writeDB *sql.DB,
	rollback func(ctx context.Context, tx SQLQueryExecutorAndTransactionManager),
	fn func(tx Tx) error,
) error

RunInTransaction begins a transaction on writeDB, invokes fn with that transaction as the sole query executor, and commits when fn returns nil. It is the shared engine behind each Client's WithTransaction method — application code should prefer Client.WithTransaction, which wraps this with the implementation's observability.

fn receives the transaction as a Tx, not the transaction handle: it cannot commit or roll back, and its statements cannot accidentally target the read replica or another connection. Tx is producible only here, so a parameter typed Tx anywhere in this module is a compile-time claim that the caller is inside one of these. Lifecycle is managed entirely here:

  • rollback is invoked (with the transaction) on any non-nil error from fn, and the error is returned unwrapped.
  • a panic inside fn triggers rollback and is then re-raised, so no connection leaks and the caller still observes the failure.
  • a nil return from fn commits; commit errors are wrapped and returned.

A failed commit has already released the connection back to the pool, so no second rollback is attempted (it would only surface a spurious ErrTxDone).

The Tx is spent the moment fn returns — before the commit or rollback below — so a Tx that escaped into a struct field or a goroutine reports ErrTransactionClosed rather than racing the outcome of a transaction it can no longer affect.

func ScanAll

func ScanAll[T any](
	ctx context.Context,
	q SQLQueryExecutor,
	subject, query string,
	args []any,
	scan func(Scanner) (T, error),
) (results []T, err error)

ScanAll runs a query and collects one value per row through scan.

It exists because the loop around a *sql.Rows is four separate obligations and every store in this module had written all four by hand, eighteen times: close the rows whatever happens, surface a close failure only when nothing worse already went wrong, check rows.Err() after the loop rather than trusting Next's false, and return the scan error rather than the close error when both occur. Missing the third silently truncates a result set when the connection drops mid-read — the loop simply ends, and the caller gets a short list with no error to say so. Missing the second masks the real cause behind the cleanup's.

subject names the rows in the close failure's message: "outbox id", "dataprivacy request". It is a noun phrase, not a sentence — " rows" is appended.

The named error return is load-bearing. The deferred close writes to it, which is how a close failure on an otherwise-successful read still reaches the caller; a plain `return results, nil` would discard it.

func ScanStrings

func ScanStrings(ctx context.Context, q SQLQueryExecutor, subject, query string, args []any) ([]string, error)

ScanStrings is ScanAll for the single-column reads that collect identifiers, which is what most of them are.

func StringFromFloat32

func StringFromFloat32(f float32) string

StringFromFloat32 is nullable.StringFromFloat32.

func StringFromFloat64

func StringFromFloat64(f float64) string

StringFromFloat64 is nullable.StringFromFloat64.

func StringFromNullString

func StringFromNullString(nt sql.NullString) string

StringFromNullString is nullable.StringFromNullString.

func StringPointerFromNullString

func StringPointerFromNullString(nt sql.NullString) *string

StringPointerFromNullString is nullable.StringPointerFromNullString.

func TimeFromNullTime

func TimeFromNullTime(nt sql.NullTime) time.Time

TimeFromNullTime is nullable.TimeFromNullTime.

func TimePointerFromNullTime

func TimePointerFromNullTime(nt sql.NullTime) *time.Time

TimePointerFromNullTime is nullable.TimePointerFromNullTime.

func Uint16PointerFromNullInt32

func Uint16PointerFromNullInt32(f sql.NullInt32) *uint16

Uint16PointerFromNullInt32 is nullable.Uint16PointerFromNullInt32.

func Uint32PointerFromNullInt32

func Uint32PointerFromNullInt32(f sql.NullInt32) *uint32

Uint32PointerFromNullInt32 is nullable.Uint32PointerFromNullInt32.

func Uint32PointerFromNullInt64

func Uint32PointerFromNullInt64(f sql.NullInt64) *uint32

Uint32PointerFromNullInt64 is nullable.Uint32PointerFromNullInt64.

func WithTransaction added in v2.9.0

func WithTransaction(ctx context.Context, client Client, fn func(querier Tx) error, opts ...TxOption) error

WithTransaction runs fn in a transaction on client, as Client.WithTransaction does, configured by opts. A client with TxOptionsAccess, which every client in this module has, receives the options. One without it, a test double that predates them for instance, runs fn once through Client.WithTransaction and never sees them: every option is a refinement of that single run, never a condition of it being correct, so the fallback is the behavior a caller had before asking for more.

Types

type Client

type Client interface {
	// Dialect reports the SQL dialect this client speaks.
	//
	// It is on the client because the two always travel together: every package in
	// this module that emits SQL holds a Client and a dialect.Dialect side by side,
	// and nothing previously stopped the pair disagreeing — a caller could hand
	// dialect.MySQL to a store backed by a Postgres client and get syntactically
	// valid SQL that the server rejects at runtime. Sourcing the dialect from the
	// client makes that mismatch unrepresentable rather than merely unlikely.
	Dialect() dialect.Dialect
	// Reader returns an executor for the read database. It exposes no transaction
	// control by design; use WithTransaction for anything transactional.
	Reader() SQLQueryExecutor
	// Writer returns an executor for the write database, for single, non-transactional
	// statements. Multi-statement work belongs in WithTransaction.
	Writer() SQLQueryExecutor
	// WithTransaction begins a transaction on the write database, invokes fn with it as
	// the sole executor, commits on a nil return, and rolls back on error or panic.
	//
	// fn receives only an executor, not the transaction handle: it cannot commit or
	// roll back. Returning an error (or panicking) is the sole way to abort, and drives
	// exactly one rollback — so fn can't roll back and then also return an error, which
	// would otherwise trigger a redundant second rollback.
	//
	// This is the one way into a transaction for application code, and specifically for
	// a caller of a store whose writes take a Tx and who has no transaction of their own
	// to join. A free function — database.Atomic(ctx, client, fn) — was proposed for that
	// caller and rejected: it is this method with its receiver moved into an argument, so
	// it is a second exported name that can do nothing this one cannot, in a module whose
	// rule is to extract what can be got wrong twice rather than what is merely written
	// twice. A delegating alias cannot drift from its delegate, so there is nothing for
	// the second name to protect. Per-store WithTransaction wrappers are rejected on the
	// same ground, and RunInTransaction is the engine rather than the entry point: it
	// takes a raw *sql.DB and a rollback function, and skips this method's observability.
	//
	// A transaction that takes options, RetryOnConflict among them, goes through the
	// package-level WithTransaction instead. That one is not an alias: it carries the
	// options this method cannot take without breaking every implementer, and runs fn
	// through TxOptionsAccess where the client has it.
	WithTransaction(ctx context.Context, fn func(querier Tx) error) error
	Close() error
	CurrentTime() time.Time
}

Client is the safe surface for database access. It deliberately does not expose a raw *sql.DB: reads and single-statement writes go through the narrow executors returned by Reader and Writer (which cannot begin a transaction), and all transactional work goes through WithTransaction. A transaction is therefore unreachable except via WithTransaction, so statements cannot accidentally run outside a transaction or against the read replica.

Callers that genuinely need the concrete pool (migrations, session-pinned advisory locks, driver features off this seam) can obtain it via the RawAccess capability.

type ClientConfig

type ClientConfig interface {
	GetReadConnectionString() string
	GetWriteConnectionString() string
	GetMaxPingAttempts() uint64
	GetPingWaitPeriod() time.Duration
	GetMaxIdleConns() int
	GetMaxOpenConns() int
	GetConnMaxLifetime() time.Duration
}

ClientConfig provides the configuration needed by database clients. This interface allows the config package to provide configuration without creating an import cycle.

type Manager

type Manager interface {
	CreateUser(ctx context.Context, username, password string) error
	DeleteUser(ctx context.Context, username string) error

	CreateDatabase(ctx context.Context, dbName, owner string) error
	DeleteDatabase(ctx context.Context, dbName string) error

	UserExists(ctx context.Context, username string) (bool, error)
	DatabaseExists(ctx context.Context, dbName string) (bool, error)

	GrantUserAccessToTable(ctx context.Context, username, schema, table, privilege string) error
	UserCanAccessDatabase(ctx context.Context, username, dbName string) (bool, error)
}

type Migrator

type Migrator interface {
	Migrate(ctx context.Context, db *sql.DB) error
}

Migrator is an interface for running database migrations. Implementations handle the specifics of migration execution (e.g., darwin, goose, etc.)

type RawAccess

type RawAccess interface {
	ReadDB() *sql.DB
	WriteDB() *sql.DB
}

RawAccess is an optional capability exposing the concrete *sql.DB pools for callers that genuinely need them — schema migrations, session-pinned advisory locks, or driver features outside the executor seam. A caller obtains it by asserting on a Client:

raw, ok := client.(database.RawAccess)

Reaching for RawAccess is a deliberate step outside the safe Client surface; prefer Reader, Writer, and WithTransaction wherever they suffice. Providers may expose further, provider-specific capabilities the same way — e.g. the postgres package's PgxAccess, which exposes the native pgx pools backing these handles.

type ResultIterator

type ResultIterator interface {
	Next() bool
	Err() error
	Scanner
	io.Closer
}

ResultIterator represents any iterable database response (i.e. sql.Rows).

type SQLQueryExecutor

type SQLQueryExecutor interface {
	ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
	PrepareContext(context.Context, string) (*sql.Stmt, error)
	QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
	QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
}

SQLQueryExecutor is a subset interface for sql.{DB|Tx} objects.

type SQLQueryExecutorAndTransactionManager

type SQLQueryExecutorAndTransactionManager interface {
	SQLQueryExecutor
	SQLTransactionManager
}

SQLQueryExecutorAndTransactionManager is a subset interface for sql.{DB|Tx} objects.

type SQLTransactionManager

type SQLTransactionManager interface {
	Rollback() error
}

SQLTransactionManager is a subset interface for sql.{DB|Tx} objects.

type Scanner

type Scanner interface {
	Scan(dest ...any) error
}

Scanner represents any database response (i.e. sql.Row[s]).

type Tx

type Tx interface {
	SQLQueryExecutor
	// contains filtered or unexported methods
}

Tx is the executor a transaction hands to its callback. It is a SQLQueryExecutor plus one unexported marker method, which is the whole point: only this package can produce a Tx, and the only thing in this package that produces one is RunInTransaction. So a parameter typed Tx says "this runs in a transaction" in a way the compiler enforces, where a SQLQueryExecutor parameter said it in prose and accepted Client.Writer() without complaint.

That distinction is why several exported entry points in this module take a Tx rather than a SQLQueryExecutor — identity's Registrar trio, identity's AcceptInvitation and EraseUser, outbox's Enqueue and SideEffect. Each writes rows that are only meaningful together, and each previously carried the obligation as a doc comment that a caller holding Writer() could satisfy by not reading it.

Unexported helpers that are correct in either context keep SQLQueryExecutor. A helper called both from inside a WithTransaction and from a single-statement write genuinely does not care, and narrowing it to Tx would force its non-transactional callers to open a transaction they do not need.

What this does not catch

Three misuses survive the type, and naming them here is cheaper than letting a reader discover them:

Escape. A callback can store its Tx in a struct field, a package variable, or a closure that outlives the callback. The type cannot stop that. Use after the callback returns is caught at runtime instead: the Tx is marked spent the instant the callback returns, and every method on a spent Tx fails with ErrTransactionClosed rather than reaching a transaction that has already been committed or rolled back.

Lifetime. A goroutine started inside the callback can outlive it and reach for the Tx while the transaction is being committed. The spent flag is atomic precisely so that this is a clean ErrTransactionClosed under the race detector rather than a data race, but the write it was trying to make is still lost. *sql.Tx is not safe for concurrent use by design; a Tx inherits that, and the flag only makes the failure legible.

Nesting. Client.WithTransaction takes no executor, so calling it from inside a callback opens a second, independent transaction on the write pool rather than a savepoint. The two commit separately and can deadlock against each other. Nothing in the type system says so, because the inner call does not mention the outer Tx.

A fourth is worth stating even though it is not a misuse of Tx: holding a Tx does not stop the same code from also calling Client.Writer(). Statements sent through the writer are outside the transaction and commit on their own.

func NewTxForTesting

func NewTxForTesting(exec SQLQueryExecutor) Tx

NewTxForTesting presents exec as a Tx without a transaction behind it. It is an escape hatch for tests, and it is the one hole in the guarantee Tx exists to make: whatever this is handed — a mock, a bare *sql.DB, a Client's Writer — becomes assignable to every parameter in this module that says "must run in a transaction".

It exists because the alternative is worse. Fifteen hand-written Client doubles in this module implement WithTransaction by invoking the callback with an executor they made up, and without a constructor each of them would either reimplement Tx (they cannot; the marker is unexported) or the doubles would have to become real database connections. Consumers writing their own doubles are in the same position.

Production code must not call it. forbidigo enforces that in this repository — the rule is relaxed for _test.go files and nothing else — and a consumer that wants the same guarantee can add the same three lines to its own .golangci.yml.

The Tx it returns is spent-checked like any other, but nothing ever spends it: there is no callback to return from. A test that wants to observe ErrTransactionClosed needs a real WithTransaction.

type TxConfig added in v2.9.0

type TxConfig struct {

	// ConflictAttempts bounds how many times fn runs in total, the first
	// included, while the client reports a retryable conflict. A value below 2
	// runs fn once.
	ConflictAttempts uint

	// ConflictBackoffInitial is the ceiling on the pause before the second
	// attempt. Each later ceiling doubles, up to ConflictBackoffMax.
	ConflictBackoffInitial time.Duration

	// ConflictBackoffMax caps the ceiling on every pause, however many
	// attempts were asked for.
	ConflictBackoffMax time.Duration
	// contains filtered or unexported fields
}

TxConfig is what a WithTransaction call's options resolve to. It is exported so a Client implementation outside this module, a test double included, can implement TxOptionsAccess and read the options it was handed.

func NewTxConfig added in v2.9.0

func NewTxConfig(opts ...TxOption) TxConfig

NewTxConfig resolves opts, in order, into the configuration for one transaction, with defaults in place of the backoff an option left unset: the config a Client reads is the one that runs.

type TxOption added in v2.9.0

type TxOption func(*TxConfig)

TxOption configures a single WithTransaction call.

func ConflictBackoff added in v2.9.0

func ConflictBackoff(initial, maxDelay time.Duration) TxOption

ConflictBackoff sets the pause between the attempts RetryOnConflict allows. The ceiling on the first pause is initial, each one after it doubles, and none exceeds maxDelay; the pause itself is drawn at random below its ceiling, so transactions that lost the same deadlock do not start over in lockstep.

A zero or negative argument keeps that half's default, DefaultConflictBackoffInitial or DefaultConflictBackoffMax, and a maxDelay below initial pauses at most maxDelay every time. Without RetryOnConflict it has nothing to pace.

func RetryOnConflict added in v2.9.0

func RetryOnConflict(attempts uint) TxOption

RetryOnConflict re-runs the whole transaction, up to attempts times in total, when the database aborts it with a conflict its engine resolves by asking the caller to start over: a deadlock or a serialization failure. Which errors qualify is the client's decision, not the caller's; postgres and mysql each recognize their own, and sqlite, a single writer, recognizes none. Every other error returns on the first attempt, as does a canceled context. When every attempt conflicts, the error wraps retry.ErrExhausted around the last conflict.

err := database.WithTransaction(ctx, client, fn, database.RetryOnConflict(3))

The contract on fn

Opting in is a claim that fn is safe to run more than once. Each run starts from a rolled-back transaction, so anything fn does through tx is undone before the next one. Nothing else is:

  • fn must act only through tx. A mail sent, a message published, or a statement run on Client.Writer() from inside fn happens once per attempt. Side effects belong in the outbox, whose writes take the same Tx and roll back with it.
  • fn must not accumulate into state it captured. Assigning a result to a captured variable is fine, since the final attempt overwrites it; appending to a captured slice or incrementing a captured counter is not.

A caller who cannot make that claim leaves the option off and keeps a single attempt, which is the default.

type TxOptionsAccess added in v2.9.0

type TxOptionsAccess interface {
	WithTransactionOptions(ctx context.Context, fn func(querier Tx) error, opts ...TxOption) error
}

TxOptionsAccess is an optional capability: a Client whose transactions take TxOptions. The postgres, mysql, and sqlite clients have it. It is a capability rather than a parameter on Client.WithTransaction because adding one there breaks every Client implementation, test doubles included, for a feature none of them has to support.

Callers reach it through the package-level WithTransaction rather than by asserting for it, so the fallback for a client without it is decided once.

Directories

Path Synopsis
Package databasecfg selects and builds a database.Client — Postgres, MySQL, or SQLite — and owns the connection strings each of them wants.
Package databasecfg selects and builds a database.Client — Postgres, MySQL, or SQLite — and owns the connection strings each of them wants.
Package ddl renders a package's embedded schema against a dialect and a table prefix, and vets the prefix against every identifier the schema would create.
Package ddl renders a package's embedded schema against a dialect and a table prefix, and vets the prefix against every identifier the schema would create.
Package dialect names the SQL dialects the module's SQL-emitting packages support, and carries the small helpers every one of them otherwise reimplements: bind-marker rendering, identifier vetting, and DDL statement splitting.
Package dialect names the SQL dialects the module's SQL-emitting packages support, and carries the small helpers every one of them otherwise reimplements: bind-marker rendering, identifier vetting, and DDL statement splitting.
internal
sqlclient
Package sqlclient holds the parts of a database.Client that do not vary by SQL driver.
Package sqlclient holds the parts of a database.Client that do not vary by SQL driver.
Package migrate provides the platform's standard database.Migrator: embedded SQL migrations with the operational discipline consumers otherwise hand-roll — an instance-based provider (no global goose state, so parallel tests never race), and on Postgres a session advisory lock that serializes concurrently booting replicas, with probe timeouts tightened so a waiting replica notices the winner promptly instead of goose's leisurely default.
Package migrate provides the platform's standard database.Migrator: embedded SQL migrations with the operational discipline consumers otherwise hand-roll — an instance-based provider (no global goose state, so parallel tests never race), and on Postgres a session advisory lock that serializes concurrently booting replicas, with probe timeouts tightened so a waiting replica notices the winner promptly instead of goose's leisurely default.
Package databasemock provides moq-generated mocks for the database package.
Package databasemock provides moq-generated mocks for the database package.
Package mysql provides an interface for writing to a MySQL instance.
Package mysql provides an interface for writing to a MySQL instance.
tableaccess
Package tableaccess is the MySQL database.Manager: the administrative surface that creates users and databases and grants table privileges, as distinct from the query path a database.Client serves.
Package tableaccess is the MySQL database.Manager: the administrative surface that creates users and databases and grants table privileges, as distinct from the query path a database.Client serves.
Package nullable converts between Go values and the database/sql Null types.
Package nullable converts between Go values and the database/sql Null types.
Package postgres provides an interface for writing to a Postgres instance.
Package postgres provides an interface for writing to a Postgres instance.
pgnotify
Package pgnotify turns Postgres LISTEN/NOTIFY into a wake-up signal for a poller.
Package pgnotify turns Postgres LISTEN/NOTIFY into a wake-up signal for a poller.
pgretry
Package pgretry re-runs a Postgres write that failed for one of the two reasons Postgres resolves by asking the caller to run it again.
Package pgretry re-runs a Postgres write that failed for one of the two reasons Postgres resolves by asking the caller to run it again.
tableaccess
Package tableaccess is the PostgreSQL database.Manager: the administrative surface that creates roles and databases and grants table privileges, as distinct from the query path a database.Client serves.
Package tableaccess is the PostgreSQL database.Manager: the administrative surface that creates roles and databases and grants table privileges, as distinct from the query path a database.Client serves.
Package querygen emits sqlc input for tables shaped the way this module's row conventions expect, in the dialect of whichever of the three databases this module supports will run it.
Package querygen emits sqlc input for tables shaped the way this module's row conventions expect, in the dialect of whichever of the three databases this module supports will run it.
Package sqlguard runs the guarded write four durable-state packages in this module are built on, and says what it means when the guard matches nothing.
Package sqlguard runs the guarded write four durable-state packages in this module are built on, and says what it means when the guard matches nothing.
Package sqlite provides an interface for writing to a SQLite database.
Package sqlite provides an interface for writing to a SQLite database.
tableaccess
Package tableaccess is the SQLite database.Manager, and every one of its operations refuses.
Package tableaccess is the SQLite database.Manager, and every one of its operations refuses.

Jump to

Keyboard shortcuts

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