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

sqltest

package
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2026 License: Apache-2.0 Imports: 14 Imported by: 1

Documentation

Overview

Package sqltest is the scripted database/sql driver a consumer's hermetic tests run over: its connections consume scripted responses in call order and record every statement, prepare, and transaction call they receive. It supports prepare, so prepare-based verification has a harness, and it accepts any argument value unconverted, so tests see the exact Go values a runner bound. It is public because every consumer's unit tier runs over it, the library's own packages included.

It is strict where a real driver is, so a test cannot pass on a path production would reject; each refusal is one of its own errors. The one leniency it keeps is the argument set: a real driver rejects a value it cannot encode, and this one records it.

The package exports:

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrUnscripted = errors.New("sqltest: unscripted call")
	ErrScript     = errors.New("sqltest: response does not fit the call")
	ErrArguments  = errors.New("sqltest: argument count does not match the placeholders")
)

The driver's own failures, each the counterpart of a failure a real driver or engine raises. A statement no response was scripted for is a statement the test did not expect to run; a response whose shape does not fit the call is a script defect. An argument count that does not match the statement's placeholders is what the engine rejects at bind time.

View Source
var ErrLockNotHeld = errors.New("sqltest: lock not held")

ErrLockNotHeld is LockingDialect's Unlock of a name the script reports was not held, the counterpart of an engine that answers false to an unlock rather than failing.

Functions

This section is empty.

Types

type Call

type Call struct {
	Op        Op
	SQL       string
	Args      []any
	TxOptions driver.TxOptions
}

Call is one recorded driver call. SQL and Args are set for exec, query, and prepare; TxOptions for begin.

type Dialect

type Dialect struct{}

Dialect is the stub dialect: $N placeholders and a MapError that wraps every non-nil error in a *MappedError, so a test proves an error crossed the mapping boundary with one errors.As.

func (Dialect) MapError

func (Dialect) MapError(err error) error

MapError wraps err in a *MappedError; nil stays nil. An already mapped error is returned as is, so double mapping is visible as absence of nesting rather than a crash.

func (Dialect) Name

func (Dialect) Name() string

func (Dialect) Placeholder

func (Dialect) Placeholder(n int) string

type LockingDialect added in v0.6.0

type LockingDialect struct{ Dialect }

LockingDialect is the stub dialect with the sqlate.TryLocker capability, and so sqlate.Locker: each call runs one statement on the pinned connection, so the lock calls are part of the recorded script and a test scripts their outcomes like any other call.

  • Lock executes "SELECT lock($1)" with the name; script an exec response, or an error for a lock that fails.
  • TryLock queries "SELECT try_lock($1)" with the name and reports the one boolean row; script true for a granted lock, false for one another session holds.
  • Unlock queries "SELECT unlock($1)" with the name; script true for a held lock, false for one that was not, which is ErrLockNotHeld.

It lets a consumer's unit suite cover a protocol that takes a lock, where Dialect covers a provider without the capability.

func (LockingDialect) Lock added in v0.6.0

func (LockingDialect) Lock(ctx context.Context, conn *sql.Conn, name string) error

Lock executes the scripted lock statement for name on conn.

func (LockingDialect) TryLock added in v0.6.0

func (LockingDialect) TryLock(ctx context.Context, conn *sql.Conn, name string) (bool, error)

TryLock queries the scripted try-lock statement for name on conn and reports its boolean.

func (LockingDialect) Unlock added in v0.6.0

func (LockingDialect) Unlock(ctx context.Context, conn *sql.Conn, name string) error

Unlock queries the scripted unlock statement for name on conn; a false row is ErrLockNotHeld.

type MappedError

type MappedError struct{ Err error }

MappedError marks an error that passed through Dialect.MapError.

func (*MappedError) Error

func (e *MappedError) Error() string

func (*MappedError) Unwrap

func (e *MappedError) Unwrap() error

type Op

type Op string

Op names a recorded driver call.

const (
	OpExec     Op = "exec"
	OpQuery    Op = "query"
	OpPrepare  Op = "prepare"
	OpBegin    Op = "begin"
	OpCommit   Op = "commit"
	OpRollback Op = "rollback"
)

type Recorder

type Recorder struct {

	// FailPrepare, when set, decides whether a prepare of the given text
	// fails; nil means every prepare succeeds.
	FailPrepare func(query string) error
	// FailBegin, FailCommit, FailRollback, FailPing inject failures into the
	// transaction and ping calls.
	FailBegin, FailCommit, FailRollback, FailPing error
	// contains filtered or unexported fields
}

Recorder is the shared state behind every connection a connector hands out: the response queue, the call log, and the failure switches.

func Open

func Open(t testing.TB, responses ...Response) (*sql.DB, *Recorder)

Open returns a pool over a fresh Recorder, closed when the test ends.

func (*Recorder) Calls

func (r *Recorder) Calls() []Call

Calls returns a copy of the call log in order.

func (*Recorder) Ops

func (r *Recorder) Ops() []Op

Ops returns the sequence of operations recorded.

func (*Recorder) Pending

func (r *Recorder) Pending() int

Pending reports how many scripted responses remain unconsumed; a test asserts zero to prove every scripted call happened.

func (*Recorder) Queue

func (r *Recorder) Queue(responses ...Response)

Queue appends responses for later exec and query calls.

func (*Recorder) RowsLeaked

func (r *Recorder) RowsLeaked() int

RowsLeaked reports row sets opened and never closed.

func (*Recorder) SQL

func (r *Recorder) SQL(op Op) []string

SQL returns the statement texts recorded for op, in order.

type Response

type Response struct {
	Err      error
	Affected int64
	Columns  []string
	Rows     [][]driver.Value
}

Response scripts the outcome of the next exec or query call: an error, or the affected count (exec) or the columns and rows (query). An exec response has no columns or rows and a query response no affected count; every row is as wide as Columns and contains driver.Value types only, as a real driver returns them. Prepare, begin, commit, and rollback do not consume responses; their failures are set on the Recorder directly.

func WithTotal added in v0.4.0

func WithTotal(r Response, n int64) Response

WithTotal returns r as a counted collection page returns it: with a trailing count column holding n in every row, from which a query.Projection reads its exact total and which it hides from the scan. A unit suite uses it to script a List or Continue under query.TotalExact without spelling the library's reserved column name. WithTotal leaves r unchanged. An empty r still gains the column, as an empty counted page declares it.

type ReturningDialect added in v0.3.0

type ReturningDialect struct{ Dialect }

ReturningDialect is the stub dialect with the query.Returner capability: it appends "RETURNING <columns>" to an INSERT or UPDATE, as an engine with the clause renders it, and declines any other verb. It lets a consumer's unit suite cover a returning command's single-statement form, where Dialect covers the fallback.

func (ReturningDialect) Returning added in v0.3.0

func (ReturningDialect) Returning(verb query.Verb, body string, columns []string) (string, bool)

Returning appends the RETURNING clause to body for query.Insert and query.Update and declines every other verb.

Jump to

Keyboard shortcuts

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