Documentation
¶
Overview ¶
Package concerns holds the shared halves of a connection and a query builder: ManagesTransactions, BuildsQueries, BuildsWhereDateClauses, CompilesJsonPaths, ExplainsQueries and ParsesSearchPath.
Each takes one of two shapes, chosen by what it does:
- one that carries state becomes a struct the user embeds, with the calls it makes back into its user written out as an interface -- ManagesTransactions, which Connection embeds;
- one that carries none becomes functions taking what the receiver was.
An initialism is upper case: ToSQL, ChunkByID, WrapJSONPath.
Every read here carries a Grant ¶
Chunk, Each, First, FirstOrFail, Sole, Lazy and Explain all execute, so they all take an auth.Grant and hand it to the query on every page they fetch. Authorization is not a rule about writes: a chunked export that skipped the Policy is a leak between tenants with a pleasant name, and a chunk loop is exactly where somebody would be tempted to authorize once and then not.
Two of these are declared here for a reason worth reading ¶
DeadlockError and ErrRecordNotFound are declared here rather than in the database package, which imports this one -- Connection embeds ManagesTransactions -- so declaring them there would close an import cycle. The database package re-exports both as aliases, so database.DeadlockException and concerns.DeadlockError are one type, and errors.Is works across the two names because there is only one.
Building a page is not here: hesape/pagination builds a page from rows somebody already fetched, and that is the one way.
Index ¶
- Constants
- Variables
- func Chunk[T any](ctx context.Context, g auth.Grant, query Chunkable[T], count int, ...) (bool, error)
- func ChunkByID[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], count int, ...) (bool, error)
- func ChunkByIDDesc[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], count int, ...) (bool, error)
- func ChunkMap[T, R any](ctx context.Context, g auth.Grant, query Chunkable[T], count int, ...) ([]R, error)
- func Each[T any](ctx context.Context, g auth.Grant, query Chunkable[T], count int, ...) (bool, error)
- func EachByID[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], ...) (bool, error)
- func Explain(ctx context.Context, g auth.Grant, query Explainable) ([]map[string]any, error)
- func First[T any](ctx context.Context, g auth.Grant, query Chunkable[T]) (T, bool, error)
- func FirstOrFail[T any](ctx context.Context, g auth.Grant, query Chunkable[T], message string) (T, error)
- func Lazy[T any](ctx context.Context, g auth.Grant, query Chunkable[T], chunkSize int) func(yield func(T, error) bool)
- func LazyByID[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], chunkSize int, ...) func(yield func(T, error) bool)
- func LazyByIDDesc[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], chunkSize int, ...) func(yield func(T, error) bool)
- func OrWhereAfterToday(b *query.Builder, columns ...any) *query.Builder
- func OrWhereBeforeToday(b *query.Builder, columns ...any) *query.Builder
- func OrWhereFuture(b *query.Builder, columns ...any) *query.Builder
- func OrWhereNowOrFuture(b *query.Builder, columns ...any) *query.Builder
- func OrWhereNowOrPast(b *query.Builder, columns ...any) *query.Builder
- func OrWherePast(b *query.Builder, columns ...any) *query.Builder
- func OrWhereToday(b *query.Builder, columns ...any) *query.Builder
- func OrWhereTodayOrAfter(b *query.Builder, columns ...any) *query.Builder
- func OrWhereTodayOrBefore(b *query.Builder, columns ...any) *query.Builder
- func OrderedChunkByID[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], count int, ...) (bool, error)
- func ParseSearchPath(searchPath any) []string
- func Pipe[Q, R any](query Q, callback func(Q) R) R
- func Sole[T any](ctx context.Context, g auth.Grant, query Chunkable[T]) (T, error)
- func Tap[Q any](query Q, callback func(Q)) Q
- func WhereAfterToday(b *query.Builder, columns ...any) *query.Builder
- func WhereBeforeToday(b *query.Builder, columns ...any) *query.Builder
- func WhereFuture(b *query.Builder, columns ...any) *query.Builder
- func WhereNowOrFuture(b *query.Builder, columns ...any) *query.Builder
- func WhereNowOrPast(b *query.Builder, columns ...any) *query.Builder
- func WherePast(b *query.Builder, columns ...any) *query.Builder
- func WhereToday(b *query.Builder, boolean string, columns ...any) *query.Builder
- func WhereTodayOrAfter(b *query.Builder, columns ...any) *query.Builder
- func WhereTodayOrBefore(b *query.Builder, columns ...any) *query.Builder
- func WrapJSONFieldAndPath(wrap Wrapper, column string) (field, path string)
- func WrapJSONPath(value, delimiter string) string
- func WrapJSONPathSegment(segment string) string
- type Chunkable
- type DeadlockError
- type ExplainConnection
- type Explainable
- type KeyChunkable
- type ManagesTransactions
- func (m *ManagesTransactions) AfterCommit(callback func()) error
- func (m *ManagesTransactions) AfterRollBack(callback func()) error
- func (m *ManagesTransactions) BeforeStartingTransaction(callback func())
- func (m *ManagesTransactions) BeginTransaction() error
- func (m *ManagesTransactions) Commit() error
- func (m *ManagesTransactions) ResetTransactionLevel()
- func (m *ManagesTransactions) RollBack(toLevel *int) error
- func (m *ManagesTransactions) SetTransactionManager(manager TransactionsManager)
- func (m *ManagesTransactions) Transaction(callback func() error, attempts int) error
- func (m *ManagesTransactions) TransactionLevel() int
- func (m *ManagesTransactions) UnsetTransactionManager()
- func (m *ManagesTransactions) UseTransactions(driver TransactionDriver)
- type MultipleRecordsFoundError
- type TransactionDriver
- type TransactionsManager
- type Wrapper
Constants ¶
const DefaultChunkSize = 1000
DefaultChunkSize is the conventional chunk size for ChunkMap, Each, Lazy and LazyByID.
Variables ¶
var ErrNoTransactionsManager = errors.New("Transactions Manager has not been set.")
ErrNoTransactionsManager is the error AfterCommit and AfterRollBack raise when no manager was set.
var ErrRecordNotFound = errors.New("No record found for the given query.")
ErrRecordNotFound is what FirstOrFail returns when nothing matched.
It is declared here rather than in the database package because that package imports this one, and Go refuses the cycle. The database package re-exports it, so database.ErrRecordNotFound and concerns.ErrRecordNotFound are one value under two names.
var ErrRecordsNotFound = errors.New("records not found")
ErrRecordsNotFound is what Sole returns when the query matched no row at all.
Sole is the query that asserts "there is exactly one of these", so both ways of being wrong are errors: none is this one, more than one is MultipleRecordsFoundError. A caller that would rather have a zero value than an error wants First, not Sole.
var Now = time.Now
Now is where BuildsWhereDateClauses reads the clock.
The clock is a variable a test replaces and restores. Everything below reads it, so freezing it freezes all eighteen clauses at once.
Functions ¶
func Chunk ¶
func Chunk[T any](ctx context.Context, g auth.Grant, query Chunkable[T], count int, callback func(results []T, page int) bool) (bool, error)
Chunk walks the result set a page at a time so a large table does not have to fit in memory.
The callback returns false to stop, and Chunk returns false when it was stopped. An unordered query returns the EnforceOrderBy error instead of running, because a chunk that silently repeats rows is the failure the check exists to prevent.
An existing limit and offset on the query are honoured: the offset shifts the first page and the limit bounds the total.
func ChunkByID ¶
func ChunkByID[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], count int, callback func(results []T, page int) bool, column, alias string) (bool, error)
ChunkByID chunks the query by comparing ids rather than by offset.
It is the one to reach for when the rows being walked are also being written to. An offset-based chunk over a table that is having rows inserted into it skips rows, because page two of a list that grew by one row starts where page one already ended.
column empty takes the query's own key; alias empty takes column.
func ChunkByIDDesc ¶
func ChunkByIDDesc[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], count int, callback func(results []T, page int) bool, column, alias string) (bool, error)
ChunkByIDDesc is ChunkByID in descending order.
func ChunkMap ¶
func ChunkMap[T, R any](ctx context.Context, g auth.Grant, query Chunkable[T], count int, callback func(T) R) ([]R, error)
ChunkMap chunks the query, and collects what the callback returns for every row.
Go has no default arguments, so the count is always given -- pass DefaultChunkSize for the conventional default.
func Each ¶
func Each[T any](ctx context.Context, g auth.Grant, query Chunkable[T], count int, callback func(value T, key int) bool) (bool, error)
Each chunks the query, and hands the callback one row at a time with its index.
The index is the position within the chunk, resetting to zero on every page. EachByID numbers across chunks instead, which is a deliberate difference between the two, kept.
func EachByID ¶
func EachByID[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], callback func(value T, key int) bool, count int, column, alias string) (bool, error)
EachByID chunks the query by id, and hands the callback one row at a time.
The index runs across chunks -- ((page - 1) * count) + key -- which is why it differs from Each.
func Explain ¶
Explain asks the engine what it would do with this query, without running it.
It returns the rows and the error the select can fail with. The statement is 'EXPLAIN ' concatenated with the compiled SQL, with the query's own bindings.
func First ¶
First limits the query to one row and returns it.
It returns (zero, false) for an empty result, because a zero-valued struct is indistinguishable from a row of zeroes and a caller that cannot tell them apart writes a bug that only shows up on real data.
func FirstOrFail ¶
func FirstOrFail[T any](ctx context.Context, g auth.Grant, query Chunkable[T], message string) (T, error)
FirstOrFail is First, failing instead of returning false when no row matched.
message empty takes a default sentence. The error wraps ErrRecordNotFound, so errors.Is keeps working when a caller adds context to it and the exception classifier still reports 404.
func Lazy ¶
func Lazy[T any](ctx context.Context, g auth.Grant, query Chunkable[T], chunkSize int) func(yield func(T, error) bool)
Lazy returns an iterator over the whole result set, fetched a chunk at a time.
Go 1.23 has range-over-func, so this returns an iter.Seq2-shaped function: the loop reads
for row, err := range concerns.Lazy(ctx, g, q, 1000) {
and an error ends the iteration after being yielded once, so a caller that forgets to check it still stops rather than looping on a broken query.
func LazyByID ¶
func LazyByID[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], chunkSize int, column, alias string) func(yield func(T, error) bool)
LazyByID is Lazy, chunked by comparing ids rather than by offset.
func LazyByIDDesc ¶
func LazyByIDDesc[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], chunkSize int, column, alias string) func(yield func(T, error) bool)
LazyByIDDesc is LazyByID in descending order.
func OrWhereAfterToday ¶
OrWhereAfterToday is WhereAfterToday, combined with or.
func OrWhereBeforeToday ¶
OrWhereBeforeToday is WhereBeforeToday, combined with or.
func OrWhereFuture ¶
OrWhereFuture is WhereFuture, combined with or.
func OrWhereNowOrFuture ¶
OrWhereNowOrFuture is WhereNowOrFuture, combined with or.
func OrWhereNowOrPast ¶
OrWhereNowOrPast is WhereNowOrPast, combined with or.
func OrWherePast ¶
OrWherePast is WherePast, combined with or.
func OrWhereToday ¶
OrWhereToday is WhereToday, combined with or.
func OrWhereTodayOrAfter ¶
OrWhereTodayOrAfter is WhereTodayOrAfter, combined with or.
func OrWhereTodayOrBefore ¶
OrWhereTodayOrBefore is WhereTodayOrBefore, combined with or.
func OrderedChunkByID ¶
func OrderedChunkByID[T any](ctx context.Context, g auth.Grant, query KeyChunkable[T], count int, callback func(results []T, page int) bool, column, alias string, descending bool) (bool, error)
OrderedChunkByID is the body ChunkByID and ChunkByIDDesc share.
It returns an error when the aliased column is not in the result. It is worth the words it costs: a chunk whose id column was not selected loops on page one forever otherwise.
func ParseSearchPath ¶
ParseSearchPath reads Postgres's search_path option, which arrives as either a string or a list.
"public,reporting" -> ["public", "reporting"]
`"public", 'reporting'` -> ["public", "reporting"]
[]string{"public"} -> ["public"]
It takes any because the value comes out of a configuration file where either shape is legal. A value of any other type answers an empty list.
func Pipe ¶
func Pipe[Q, R any](query Q, callback func(Q) R) R
Pipe hands the query to callback, and gives back what callback returned.
There is no fallback to the original query when callback returns a zero value: a function returning R returns an R, and Go has no null to fall back from. It is not missed -- Tap already covers wanting the query back.
func Sole ¶
Sole returns the one row that matched, and an error when there was none or more than one.
It fetches two rows, not one, which is the whole point: a query for "the invoice for this reference" has to be able to say that two of them exist.
func Tap ¶
func Tap[Q any](query Q, callback func(Q)) Q
Tap hands the query to callback, and gives the query back.
func WhereAfterToday ¶
WhereAfterToday adds a where clause requiring each column to fall after today's date, combined with and.
func WhereBeforeToday ¶
WhereBeforeToday adds a where clause requiring each column to fall before today's date, combined with and.
func WhereFuture ¶
WhereFuture adds a where clause requiring each column to be after now, combined with and.
func WhereNowOrFuture ¶
WhereNowOrFuture adds a where clause requiring each column to be at or after now, combined with and.
func WhereNowOrPast ¶
WhereNowOrPast adds a where clause requiring each column to be at or before now, combined with and.
func WherePast ¶
WherePast adds a where clause requiring each column to be before now, combined with and.
func WhereToday ¶
WhereToday adds a where clause requiring each column to fall on today's date. boolean empty defaults to "and".
func WhereTodayOrAfter ¶
WhereTodayOrAfter adds a where clause requiring each column to fall on or after today's date, combined with and.
func WhereTodayOrBefore ¶
WhereTodayOrBefore adds a where clause requiring each column to fall on or before today's date, combined with and.
func WrapJSONFieldAndPath ¶
WrapJSONFieldAndPath splits `options->language` into the wrapped column and the JSON path, so a grammar can put them either side of whatever its engine spells the extraction function.
The path comes back with a leading ", " already on it, so a grammar concatenating the two gets a ready-made argument list.
func WrapJSONPath ¶
WrapJSONPath turns `language->code` into the quoted '$."language"."code"' a JSON function takes.
func WrapJSONPathSegment ¶
WrapJSONPathSegment quotes the key and leaves the array subscript outside the quotes, because '$."tags"[0]' selects an element and '$."tags[0]"' selects a key that does not exist.
Types ¶
type Chunkable ¶
type Chunkable[T any] interface { // GetOffset returns the query's offset, or nil when none is set. GetOffset() *int // GetLimit returns the query's limit, or nil when none is set. GetLimit() *int // Offset sets the query's offset. Offset(value int) // Limit sets the query's limit. Limit(value int) // ForPage sets the offset and limit for one page of results. ForPage(page, perPage int) // Get runs the query. Get(ctx context.Context, g auth.Grant) ([]T, error) // EnforceOrderBy fails when the query has no order. Chunking an // unordered result set returns rows twice and skips others, and the // database is within its rights. EnforceOrderBy() error }
Chunkable is what the chunking functions ask of the query they walk.
It is an interface rather than a concrete builder, because a function that took *query.Builder would only work for that one builder.
T is the row type. A repository knows what it selects, so the chunk arrives typed.
Get takes an auth.Grant because it executes. Authorization does not bend for a read: List, Find, First, Get, Paginate, an export and a report all pass through a Policy and filter by auth.Tenant(g). The Grant travels from the caller of Chunk down to every page it fetches, so a chunked read is authorized once and stays authorized.
type DeadlockError ¶
type DeadlockError struct {
// Err is the driver error the engine reported.
Err error
}
DeadlockError reports that a nested transaction hit a concurrency error, and the whole transaction is gone.
It is declared here because ManagesTransactions is what raises it and the database package imports this one, so declaring it there would close the cycle. database.DeadlockException is an alias of this type -- one type under two names.
It is not retried, and that is the point of having its own type: on a deadlock the engine has already rolled the whole transaction back, so re-running the statement runs it outside the transaction the caller thinks it is in.
func NewDeadlockError ¶
func NewDeadlockError(err error) *DeadlockError
NewDeadlockError wraps the driver error that reported a deadlock.
func (*DeadlockError) Error ¶
func (e *DeadlockError) Error() string
Error carries the driver's own message through unchanged.
func (*DeadlockError) Unwrap ¶
func (e *DeadlockError) Unwrap() error
Unwrap makes errors.Is and errors.As reach the driver error.
type ExplainConnection ¶
type ExplainConnection interface {
// Select runs a select. The Grant is required because this executes:
// there is no exception for a query plan, and an EXPLAIN that skipped
// the Policy would be a way to learn about rows the caller may not read.
Select(ctx context.Context, g auth.Grant, query string, bindings []any) ([]map[string]any, error)
}
ExplainConnection is the connection Explain runs the EXPLAIN through.
A row is a map because EXPLAIN answers a different shape on every engine -- Postgres one text column, MySQL twelve -- and a struct for it would be a struct for one of the three.
type Explainable ¶
type Explainable interface {
// ToSQL returns the query compiled to SQL.
ToSQL() string
// GetBindings returns the values that go with it.
GetBindings() []any
// GetConnection returns the connection to run EXPLAIN on, narrowed to
// the one call Explain makes on it.
GetConnection() ExplainConnection
}
Explainable is what ExplainsQueries asks of the query it explains.
A query builder reaches for its own compiled SQL, its bindings and its connection; those three are written out here as an interface, because what is a mixin in a dynamic language is an interface in Go.
type KeyChunkable ¶
type KeyChunkable[T any] interface { Chunkable[T] // Clone returns a copy of the query, so the where clause added for the // last id does not accumulate across pages. Clone() KeyChunkable[T] // DefaultKeyName returns the query's own key column. DefaultKeyName() string // ForPageAfterID adds a where clause that reaches perPage rows after // lastID, ordered by column. ForPageAfterID(perPage int, lastID any, column string) // ForPageBeforeID is ForPageAfterID in reverse order. ForPageBeforeID(perPage int, lastID any, column string) // ValueOf reads the value named by alias off the last row of a chunk. A // row here is a T rather than an untyped map, so the builder that // produced it is the only thing that can say which field the alias // names. ValueOf(row T, alias string) (any, bool) }
KeyChunkable is what ChunkByID adds to Chunkable: paging by a comparison against the last id seen rather than by an offset.
It is a separate interface because the id-based methods are the ones a builder can only offer when it knows its key, and because Chunk works without them.
type ManagesTransactions ¶
type ManagesTransactions struct {
// contains filtered or unexported fields
}
ManagesTransactions is the transaction half of a connection: the nesting level, the transactions manager, and the hooks that run before one starts.
It is a struct Connection embeds, so the state it owns is the connection's state.
Savepoints exist here and are not the framework's transaction story ¶
The nested transaction below opens a savepoint. That is not the path an Arandu application takes: database.Transaction joins the outer transaction rather than nesting, on the grounds that partial rollback is a second failure mode for one operation. The generated repository uses database.Transaction.
func (*ManagesTransactions) AfterCommit ¶
func (m *ManagesTransactions) AfterCommit(callback func()) error
AfterCommit runs callback once the outermost transaction commits, or now when there is none open.
func (*ManagesTransactions) AfterRollBack ¶
func (m *ManagesTransactions) AfterRollBack(callback func()) error
AfterRollBack runs callback when the current transaction rolls back.
func (*ManagesTransactions) BeforeStartingTransaction ¶
func (m *ManagesTransactions) BeforeStartingTransaction(callback func())
BeforeStartingTransaction registers a hook to run just before a transaction opens.
It lives here rather than on the connection because the slice it appends to is read by BeginTransaction, which is here too.
func (*ManagesTransactions) BeginTransaction ¶
func (m *ManagesTransactions) BeginTransaction() error
BeginTransaction opens a new transaction, or a nested savepoint if one is already open.
func (*ManagesTransactions) Commit ¶
func (m *ManagesTransactions) Commit() error
Commit commits the current transaction level, for a transaction somebody began by hand rather than through Transaction.
func (*ManagesTransactions) ResetTransactionLevel ¶
func (m *ManagesTransactions) ResetTransactionLevel()
ResetTransactionLevel sets the nesting level back to zero.
Replacing the handle throws away whatever transaction was open on the old one, and a level that outlived its connection is a rollback aimed at nothing.
func (*ManagesTransactions) RollBack ¶
func (m *ManagesTransactions) RollBack(toLevel *int) error
RollBack rolls the transaction back to toLevel, or back one level when toLevel is nil. A level outside the open range is ignored rather than refused: rolling back to a level that does not exist is a no-op, not a failure.
func (*ManagesTransactions) SetTransactionManager ¶
func (m *ManagesTransactions) SetTransactionManager(manager TransactionsManager)
SetTransactionManager sets the manager that records transaction lifecycle events.
func (*ManagesTransactions) Transaction ¶
func (m *ManagesTransactions) Transaction(callback func() error, attempts int) error
Transaction runs callback inside a transaction, committing when it returns nil and rolling back when it returns an error.
attempts bounds the retry count, and it retries only what is worth retrying: a concurrency error at the outermost level. Anything else is returned on the first try, because re-running a statement that failed on a constraint just fails again, slower.
A Go method cannot be generic, so the callback returns only an error and carries its result out through the closure -- which is the shape database.Transaction already has.
func (*ManagesTransactions) TransactionLevel ¶
func (m *ManagesTransactions) TransactionLevel() int
TransactionLevel reports how many transactions are open, counting savepoints.
func (*ManagesTransactions) UnsetTransactionManager ¶
func (m *ManagesTransactions) UnsetTransactionManager()
UnsetTransactionManager clears the transactions manager.
func (*ManagesTransactions) UseTransactions ¶
func (m *ManagesTransactions) UseTransactions(driver TransactionDriver)
UseTransactions wires ManagesTransactions to the connection that embeds it.
A Go struct has to be told which driver it belongs to, so the connection calls this once from its constructor.
type MultipleRecordsFoundError ¶
type MultipleRecordsFoundError struct {
// Count is how many rows the query matched.
Count int
}
MultipleRecordsFoundError is what Sole returns when the query matched more than one row, and it carries how many it saw.
Sole reads two rows and stops, so Count is the number it actually fetched rather than the size of the whole result set -- enough to say "this is not unique", which is the only thing the caller can act on. The uniqueness the query assumed is missing, which is usually a missing unique index or a filter that lost a column.
func NewMultipleRecordsFoundError ¶
func NewMultipleRecordsFoundError(count int) *MultipleRecordsFoundError
NewMultipleRecordsFoundError wraps the count of rows a Sole query matched.
func (*MultipleRecordsFoundError) Error ¶
func (e *MultipleRecordsFoundError) Error() string
Error reports how many records were found.
func (*MultipleRecordsFoundError) GetCount ¶
func (e *MultipleRecordsFoundError) GetCount() int
GetCount returns how many rows the query matched.
type TransactionDriver ¶
type TransactionDriver interface {
// GetName returns the connection's name. The transactions manager keys
// its bookkeeping by it.
GetName() string
// ExecuteBeginTransactionStatement issues a BEGIN, pinning a connection
// for the life of the transaction.
ExecuteBeginTransactionStatement() error
// CommitTransactionStatement issues a COMMIT.
CommitTransactionStatement() error
// RollBackTransactionStatement issues a ROLLBACK, and reports false when
// there was no transaction open to roll back.
RollBackTransactionStatement() (bool, error)
// ExecuteSavepointStatement runs the statement the savepoint paths build.
ExecuteSavepointStatement(sql string) error
// SupportsSavepoints reports whether the query grammar supports
// savepoints.
SupportsSavepoints() bool
// CompileSavepoint returns the statement that creates a savepoint.
CompileSavepoint(name string) string
// CompileSavepointRollBack returns the statement that rolls back to a
// savepoint.
CompileSavepointRollBack(name string) string
// FireConnectionEvent dispatches the transaction event named by event:
// one of "beganTransaction", "committing", "committed" or "rollingBack".
FireConnectionEvent(event string)
// CausedByConcurrencyError reports whether err means a deadlock or a
// serialization failure.
CausedByConcurrencyError(err error) bool
// CausedByLostConnection reports whether err means the connection is
// gone.
CausedByLostConnection(err error) bool
// Reconnect replaces the pool.
Reconnect() error
// ReconnectIfMissingConnection reconnects when the connection has no
// pool yet.
ReconnectIfMissingConnection() error
}
TransactionDriver is what ManagesTransactions drives.
Connection reaches straight for its pool, its query grammar and its own lost-connection detection. Those calls are written out here as an interface, which is the Go spelling of "this embedded type may only be used by a type that has these".
A Connection satisfies it; nothing else is meant to.
type TransactionsManager ¶
type TransactionsManager interface {
// Begin records that a new transaction level opened on connection.
Begin(connection string, level int)
// Commit records that a transaction level committed on connection.
Commit(connection string, levelBeingCommitted, newTransactionLevel int)
// Rollback records that connection rolled back to newTransactionLevel.
Rollback(connection string, newTransactionLevel int)
// AddCallback registers a callback to run after the outermost commit.
AddCallback(callback func())
// AddCallbackForRollback registers a callback to run after a rollback.
AddCallbackForRollback(callback func())
}
TransactionsManager is what ManagesTransactions reports to.
It is narrowed to the five methods this file calls. It is an interface here and a concrete type in the database package for the usual reason: that package imports this one.