Documentation
¶
Overview ¶
Package litex provides shared SQLite utilities including connection setup, transaction management, and query building helpers.
Index ¶
- Constants
- func BuildComplexQuery(table string, primaryField string, fields string, filter *Filter, ...) (string, []any, error)
- func BuildQuery(table string, primaryField string, fields string, filter *Filter, ...) (string, []any, error)
- func UpdateQuery(table string, fn func(fields []string, args []any) ([]string, []any)) (string, []any, error)
- func Where(field string, operator ...string) string
- type BaseTX
- func (b *BaseTX) Exec(ctx context.Context, stmt string, args ...any) (sql.Result, error)
- func (b *BaseTX) ExecPrepared(ctx context.Context, stmt string, rows [][]any) error
- func (b *BaseTX) Find(ctx context.Context, stmt string, args []any, ...) error
- func (b *BaseTX) Logger() *zerolog.Logger
- func (b *BaseTX) Query(ctx context.Context, stmt string, args ...any) (*sql.Rows, error)
- func (b *BaseTX) QueryRow(ctx context.Context, stmt string, args ...any) *sql.Row
- func (b *BaseTX) TX() *sql.Tx
- type BatchTX
- type Filter
- type Service
- func (s *Service) Close() error
- func (s *Service) CommitBatch(_ context.Context, newTx func(*BatchTX) any, fn func(any) error) error
- func (s *Service) CommitRead(ctx context.Context, newTx func(*BaseTX) any, fn func(any) error) error
- func (s *Service) CommitWrite(ctx context.Context, newTx func(*BaseTX) any, fn func(any) error) error
- func (s *Service) Migrate(ctx context.Context, migrations fs.FS) error
- func (s *Service) OnBatchFlushError(handler func(error))
- func (s *Service) Open() error
Constants ¶
const ( // OpExact matches the column against the whole value, normalized to SQL "=". Use it for IDs, // enums, booleans, and other exact-valued columns. OpExact = "==" // OpSubstring matches a value anywhere in the column, rewritten to "LIKE ?" with the bound value // wrapped in "%" wildcards. On numeric columns this silently over-matches (12 matches 1, 2, 123, // ...), so keep it to free text. OpSubstring = "=~" )
Operators for Where that the query builders treat specially; every other operator passes through verbatim. Matching is per comparison, so one clause can mix both, and neither follows Filter.ExactMatchByDefault, which resolves only a plain "=".
const ( // MemoryDSN is used to define an in-memory-only database. MemoryDSN = ":memory:" // TimeFormat is the default time format for SQLite timestamps. // Source: https://pkg.go.dev/modernc.org/sqlite#Driver.Open. TimeFormat = "2006-01-02 15:04:05.999 -0700 MST" )
Variables ¶
This section is empty.
Functions ¶
func BuildComplexQuery ¶
func BuildComplexQuery(table string, primaryField string, fields string, filter *Filter, joins []string, groupBy []string, fn func(where []string, args []any) ([]string, []any), ) (string, []any, error)
BuildComplexQuery is BuildQuery with JOINs and GROUP BY, for joins or aggregation such as GROUP_CONCAT over a one-to-many. Its operator and identifier rules are the same, except that the groupBy argument is not validated, so it may hold expressions but must be a trusted value.
Example:
BuildComplexQuery(
"participants", "participants.id", "participants.*, GROUP_CONCAT(ases.id) AS asns",
filter,
[]string{"LEFT JOIN ases ON ases.claimee_id = participants.id"},
[]string{"participants.id"},
func(where []string, args []any) ([]string, []any) {
if filter.ID != "" {
where = append(where, litex.Where("participants.id", litex.OpExact))
args = append(args, filter.ID)
}
return where, args
},
)
func BuildQuery ¶
func BuildQuery(table string, primaryField string, fields string, filter *Filter, fn func(where []string, args []any) ([]string, []any)) (string, []any, error)
BuildQuery creates a SELECT statement with filtering and ordering, the fn callback populating the WHERE clauses and their arguments. Pass nil for filter to return all rows ordered by primaryField DESC. See OpSubstring and OpExact for how clause operators are rewritten.
Identifiers are interpolated rather than bound, so table, fields and joins must be trusted values. primaryField, Filter.OrderBy and Filter.GroupBy are validated as simple or dotted identifiers.
func UpdateQuery ¶
func UpdateQuery(table string, fn func(fields []string, args []any) ([]string, []any)) (string, []any, error)
UpdateQuery creates an UPDATE statement of the form "UPDATE table SET a = ?, b = ?", the fn callback populating the fields and their arguments. It deliberately emits no WHERE clause: the caller must append one, otherwise the statement updates every row in the table.
Field names are interpolated, so each is validated as a simple or dotted identifier. table is not, and must be a trusted value.
func Where ¶
Where builds a "field <operator> ?" clause fragment. The operator is optional; omitting it emits a plain "=", read as substring matching unless Filter.ExactMatchByDefault is set. Pass OpSubstring or OpExact to pin the clause regardless of that setting, or any other SQL operator to pass it through verbatim.
Types ¶
type BaseTX ¶
type BaseTX struct {
// contains filtered or unexported fields
}
BaseTX provides common transaction functionality that can be embedded in project-specific transaction types.
func (*BaseTX) Exec ¶
Exec executes a write statement against the transaction. Prefer this over TX().ExecContext() so that logging is consistent across all write operations.
func (*BaseTX) ExecPrepared ¶
ExecPrepared runs stmt once for each row of args against the transaction, reusing a single prepared statement. Use it for bulk writes where the same statement repeats with different values.
func (*BaseTX) Find ¶
func (b *BaseTX) Find(ctx context.Context, stmt string, args []any, scanFn func(rows *sql.Rows) error) error
Find is a convenience wrapper for querying rows. The given scanFn is called on each rows.Next() iteration.
func (*BaseTX) Query ¶
Query executes a query against the transaction and returns the resulting rows. Prefer this over TX().QueryContext() so that logging is consistent across all read operations.
type BatchTX ¶
type BatchTX struct {
// contains filtered or unexported fields
}
BatchTX is provided to project-specific transaction types via CommitBatch. It exposes QueueExec for buffered writes that are flushed to a real transaction by a background timer. It is safe for concurrent use, so a callback may fan QueueExec out across goroutines.
type Filter ¶
type Filter struct {
// Keyset cursor: excludes rows ordered past this value on the OrderBy column. That column should be
// unique, otherwise ties at a page boundary may be skipped.
Offset any `json:"-"`
GroupBy string `json:"-"` // Comma-separated columns to GROUP BY.
OrderBy string `json:"-"` // Column to order by; defaults to the primary field.
Limit int `json:"-"` // Max rows to return; <= 0 omits the LIMIT clause (all rows).
// ExactMatchByDefault decides only what a plain "=" means; clauses pinned with OpSubstring or
// OpExact keep their behaviour either way.
ExactMatchByDefault bool `json:"-"`
OrderAsc bool `json:"-"` // Order ascending; defaults to descending.
}
Filter supplies optional limit, ordering, keyset pagination, and grouping controls to the query builders. Every field is optional: the zero value, or a nil *Filter, returns all matching rows ordered by the primary field descending, with no LIMIT.
Every field is tagged json:"-", so the struct can be embedded in request types without appearing in their JSON.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service represents a SQLite database service.
func (*Service) Close ¶
Close flushes any buffered batch writes and closes the connections, joining any flush failure with the close errors so shutdown data loss is visible. Closing twice is a no-op, and a Service is single-use: construct a new one with NewDB rather than reopening. It blocks for up to twice batchFlushTimeout, since the final flush waits out one the timer had already started.
func (*Service) CommitBatch ¶
func (s *Service) CommitBatch(_ context.Context, newTx func(*BatchTX) any, fn func(any) error) error
CommitBatch provides a BatchTX to the given function for buffered writes. Entries queued via QueueExec reach the service buffer only once fn returns nil, and are flushed roughly every batchFlushInterval and on Close.
The buffer is service-wide, so one failing statement rolls back every entry in that window, including other callers'. Use CommitWrite where failure must be attributable to its own caller.
func (*Service) CommitRead ¶
func (s *Service) CommitRead(ctx context.Context, newTx func(*BaseTX) any, fn func(any) error) error
CommitRead opens a read-only database transaction. The newTx function converts a BaseTX into your project-specific transaction type.
func (*Service) CommitWrite ¶
func (s *Service) CommitWrite(ctx context.Context, newTx func(*BaseTX) any, fn func(any) error) error
CommitWrite opens a read-write database transaction. The newTx function converts a BaseTX into your project-specific transaction type.
func (*Service) Migrate ¶
Migrate applies, in ascending order, every migration newer than the database's PRAGMA user_version, then records the highest applied. Call it after Open.
Files live under migrations/ and are named <version>.sql with an optional _description (1.sql, 1_init.sql, 20260716_add_users.sql). Versions need not be contiguous. Migrations are forward-only and may not exceed 2147483647, the user_version ceiling (YYYYMMDD fits; a full timestamp does not).
func (*Service) OnBatchFlushError ¶
OnBatchFlushError registers a handler invoked when an asynchronous batch flush fails. This handler and Close's error are the only way to observe such failures, since the write runs long after QueueExec returned. When unset, failures are logged.
Directories
¶
| Path | Synopsis |
|---|---|
|
Command example demonstrates a small LiteX-backed user store: connection setup, migrations, typed transactions, and CRUD built on the query helpers.
|
Command example demonstrates a small LiteX-backed user store: connection setup, migrations, typed transactions, and CRUD built on the query helpers. |
|
domain
Package domain declares the application's models and transaction interfaces.
|
Package domain declares the application's models and transaction interfaces. |
|
sqlite
Package sqlite implements the domain transaction interfaces on top of LiteX.
|
Package sqlite implements the domain transaction interfaces on top of LiteX. |