sqldb

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: Apache-2.0 Imports: 3 Imported by: 4

Documentation

Overview

Package sqldb is the provider-agnostic interface to a relational database: RDS, Cloud SQL, Azure Database.

A handle is taken by naming the blueprint resource:

orders := resources.SQLDatabase(app, "ordersDb")

The SDK imports no driver. Which one a build links is a deployment fact, so the build tool writes the import; see the sql-engine flag on celerity-go generate. Implementations are per provider and live in their own modules, such as resources/aws. Typically, implementations will use the database/sql driver, the Conn interface itself is a subset of database/sql.

Index

Constants

View Source
const (
	EnginePostgres = "postgres"
	EngineMySQL    = "mysql"
)

The relational engines Celerity supports, named as the blueprint names them and as the deploy engine records them.

View Source
const (
	// LevelDefault leaves the isolation to the database's own default.
	LevelDefault IsolationLevel = IsolationLevel(sql.LevelDefault)
	// LevelReadCommitted sees only what other transactions have committed, as
	// of each statement.
	LevelReadCommitted = IsolationLevel(sql.LevelReadCommitted)
	// LevelRepeatableRead sees the same rows throughout, so a row read twice
	// reads the same both times.
	LevelRepeatableRead = IsolationLevel(sql.LevelRepeatableRead)
	// LevelSerializable runs as though no other transaction were running, and
	// may be refused rather than allowed to produce a result that could not
	// have happened in some order.
	LevelSerializable = IsolationLevel(sql.LevelSerializable)
)

Variables

View Source
var ErrNoRows = sql.ErrNoRows

ErrNoRows reports a single-row query that matched nothing.

if errors.Is(err, sqldb.ErrNoRows) { ... }

Reported by Row.Scan rather than answered with a zero value, so a missing row and a row whose columns are all zero are told apart.

View Source
var ErrTxDone = sql.ErrTxDone

ErrTxDone reports a transaction that was already committed or rolled back.

if errors.Is(err, sqldb.ErrTxDone) { ... }

What a deferred rollback reports after a commit, which is the one case where it means nothing went wrong.

Functions

func Instrument

func Instrument(hook Instrumentation)

Instrument registers the hook pools are opened through, replacing any already registered.

One rather than many, unlike the hooks a client is handed after it is built: each of these opens the pool, and two of them would open two.

Called from the init of the module holding it, so that linking the module is the whole of the wiring.

func Open

func Open(c driver.Connector, engine string) (*sql.DB, error)

Open returns the pool to query through, instrumented where a module for it is linked, and database/sql's own otherwise.

Called by a provider that has built a connector. Exported because the provider is in another module, and it is the only caller: an application has no reason to.

Types

type Client

type Client interface {
	// Writer returns a connection to the primary, which can read and write.
	Writer(ctx context.Context) (Conn, error)
	// Reader returns a connection for reads, which is a replica where the
	// deployment has one and the primary where it does not.
	Reader(ctx context.Context) (Conn, error)
}

Client is a relational database, handing out separate writer and reader endpoints so that a read replica is used where one exists.

type Conn

type Conn interface {
	// ExecContext runs a statement that answers with an effect rather than rows.
	ExecContext(ctx context.Context, query string, args ...any) (Result, error)
	// QueryContext runs a query and returns its rows, which have to be closed.
	QueryContext(ctx context.Context, query string, args ...any) (Rows, error)
	// QueryRowContext runs a query expected to answer with one row.
	//
	// There is nothing to close: the row holds the result set and releases it
	// when it is scanned. A query that matched nothing reports [ErrNoRows] from
	// Scan, which is the one case where a failure to scan is not a failure.
	QueryRowContext(ctx context.Context, query string, args ...any) Row
	// PingContext checks that the database is reachable and answering.
	//
	// For a health check rather than before a query: a query that is going to
	// run anyway reports the same thing by failing.
	PingContext(ctx context.Context) error
	// PrepareContext prepares a statement on this connection, for running the
	// same query many times.
	//
	// The statement has to be closed, and belongs to this connection: it is
	// prepared on the server at the other end of it, so closing the connection
	// without closing the statement leaves the server holding it until the
	// connection is actually dropped.
	//
	// Worth reaching for only where one connection runs the same statement many
	// times: a backfill, a bulk load, a loop over a result set. What it saves is
	// the parse and plan of the query, so preparing for a single call pays an
	// extra round trip and saves nothing, and on PostgreSQL the driver caches
	// statements for itself regardless.
	PrepareContext(ctx context.Context, query string) (Stmt, error)
	// BeginTx starts a transaction, so that statements which only make sense
	// together either all take effect or none do.
	//
	// The transaction has to be finished with [Tx.Commit] or [Tx.Rollback]: it
	// holds this connection until one of them is called, and a handler that
	// returns without calling either leaves the connection held until the
	// context is cancelled.
	BeginTx(ctx context.Context, opts ...TxOption) (Tx, error)
	// Close gives the connection back to the pool it came from.
	Close() error
}

Conn is the subset of database/sql a handler needs, kept as an interface so that a driver is never forced on a caller.

type Instrumentation

type Instrumentation func(c driver.Connector, engine string) (*sql.DB, error)

Instrumentation opens the pool a provider will query through, from the connector it would have opened one from.

It takes a connector rather than an open pool because instrumenting database/sql means wrapping the driver: there is nothing to set on a pool that is already open, so a hook has to be given what the pool would be built from. Which is why a provider calls Open instead of database/sql's own OpenDB.

Declared here rather than in a provider module because a connector is database/sql's whoever built it, so one hook serves every provider. What fills it is a module linked for the purpose, since core depends on no tracing library.

type IsolationLevel

type IsolationLevel int

IsolationLevel is how much of what other transactions are doing a transaction can see.

Only the levels every supported engine implements as itself. Read uncommitted is absent: Postgres accepts it and runs read committed anyway, so asking for it would mean one thing on one engine and another on the next.

type Result

type Result interface {
	// RowsAffected is how many rows the statement changed.
	RowsAffected() (int64, error)
	// LastInsertId is the id the statement generated, where the engine reports
	// one. MySQL does; PostgreSQL answers a RETURNING clause instead.
	LastInsertId() (int64, error)
}

Result reports the effect of a statement.

type Row

type Row interface {
	// Scan copies the row's columns into dest, and reports [ErrNoRows] where
	// the query matched nothing.
	Scan(dest ...any) error
	// Err reports a failure that happened before there was a row to scan.
	Err() error
}

Row is a result expected to hold one row.

type Rows

type Rows interface {
	// Next advances to the next row, and is false at the end of the set or on a
	// failure, which [Rows.Err] tells apart.
	Next() bool
	// Scan copies the current row's columns into dest.
	Scan(dest ...any) error
	// Err reports what stopped the iteration, where anything did.
	Err() error
	// Close gives the result set back.
	Close() error
}

Rows iterates a result set, and has to be closed.

type Stmt

type Stmt interface {
	// ExecContext runs the statement with these arguments.
	ExecContext(ctx context.Context, args ...any) (Result, error)
	// QueryContext runs the statement and returns its rows, which have to be
	// closed.
	QueryContext(ctx context.Context, args ...any) (Rows, error)
	// QueryRowContext runs the statement expecting one row. See
	// [Conn.QueryRowContext].
	QueryRowContext(ctx context.Context, args ...any) Row
	// Close gives the statement back. A statement left open is held by the
	// server as well as by this process.
	Close() error
}

Stmt is a statement the database has already parsed and planned, for running the same query many times without paying for that again.

Takes no query: the statement is the query, and the arguments are what changes between calls.

type Tx

type Tx interface {
	// ExecContext runs a statement within the transaction.
	ExecContext(ctx context.Context, query string, args ...any) (Result, error)
	// QueryContext runs a query within the transaction. The rows have to be
	// closed, and before the transaction is finished.
	QueryContext(ctx context.Context, query string, args ...any) (Rows, error)
	// QueryRowContext runs a query expected to answer with one row, within the
	// transaction. See [Conn.QueryRowContext].
	QueryRowContext(ctx context.Context, query string, args ...any) Row
	// PrepareContext prepares a statement for use inside this transaction.
	//
	// The statement is the transaction's: it cannot be used after a commit or a
	// rollback, and it is closed with the transaction whether or not the caller
	// closes it.
	PrepareContext(ctx context.Context, query string) (Stmt, error)
	// Commit makes everything the transaction did take effect.
	Commit() error
	// Rollback undoes everything the transaction did.
	//
	// Safe to call after a commit, where it reports [ErrTxDone] and does
	// nothing, which is what makes a deferred rollback the way to be sure a
	// transaction is always finished:
	//
	//	tx, err := conn.BeginTx(ctx)
	//	if err != nil {
	//	    return err
	//	}
	//	defer tx.Rollback()
	//	...
	//	return tx.Commit()
	Rollback() error
}

Tx is a transaction, statements that take effect together or not at all.

Nothing a transaction does is visible to anything else until it is committed, and a rollback reverts all of it.

type TxOption

type TxOption func(*TxOptions)

TxOption configures a transaction.

type TxOptions

type TxOptions struct {
	// Isolation is how much of what other transactions are doing this one can
	// see. Zero leaves it to the database's own default.
	Isolation IsolationLevel
	// ReadOnly declares that the transaction writes nothing, which lets a
	// database answer it from a replica and skip the bookkeeping a write needs.
	ReadOnly bool
}

TxOptions is the resolved configuration for a transaction.

func ResolveTxOptions

func ResolveTxOptions(opts []TxOption) TxOptions

ResolveTxOptions applies options in order and returns what they amount to.

For provider modules, which read the options to start a transaction. An application has no reason to call it.

Directories

Path Synopsis
otel module

Jump to

Keyboard shortcuts

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