Documentation
¶
Index ¶
- func CatalogSearchRank(sku string, cs CatalogSearch) int32
- func ConnRetryConfig() *retry.Config
- func EscapeLike(s string) string
- func Int64FromInterface(v any) (int64, bool)
- func IsDeadlock(err error) bool
- func IsDuplicateEntry(err error) bool
- func IsRetryableConnectionError(err error) bool
- func IsRetryableLockConflict(err error) bool
- func MapSQLError(err error) *apierror.APIError
- func MapSQLErrorWithDuplicateKeys(err error, mapping DuplicateKeyMapping) *apierror.APIError
- func NewDbPool(config *Config) (*sql.DB, error)
- func NullInt64Ptr(i *int64) sql.NullInt64
- func NullString(s string) sql.NullString
- func NullStringFulltextPtr(s *string) sql.NullString
- func NullStringLikePtr(s *string) sql.NullString
- func NullStringPtr(s *string) sql.NullString
- func NullTierInt64Param(t *int) sql.NullInt64
- func NullTime(t time.Time) sql.NullTime
- func NullTimePtr(t *time.Time) sql.NullTime
- func SanitizeFulltextBoolean(s string) string
- func StringFromInterface(v any) string
- func StringFromNullString(ns sql.NullString) *string
- func TimeFromNullTime(nt sql.NullTime) *time.Time
- func TrimDecimal(s string) string
- func WithConnRetry(ctx context.Context, cfg *retry.Config, operation string, fn func() error) error
- type CatalogSearch
- type Config
- type DuplicateKeyMapping
- type FulltextSearch
- type NullableRawMessage
- type SavepointRunner
- type TransactionManager
- type TxQuerier
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CatalogSearchRank ¶
func CatalogSearchRank(sku string, cs CatalogSearch) int32
CatalogSearchRank returns the SKU tier used for search ordering (0 exact, 1 token, 2 prefix, 3 substring-only). It mirrors the CASE expression in catalog list SQL.
func ConnRetryConfig ¶
ConnRetryConfig returns the short retry policy used by WithConnRetry. The waits are deliberately small: a dropped database connection (e.g. a Vitess tablet failover) is either recovered by the next pooled connection almost immediately or not at all, and callers sit on hot request paths.
func EscapeLike ¶
EscapeLike escapes MySQL LIKE metacharacters in user-provided search terms.
func Int64FromInterface ¶
Int64FromInterface extracts an int64 from an interface{} value. MySQL CASE expressions are typed as interface{} by sqlc and may arrive as int64, int, or []byte depending on the driver. Returns (0, false) for nil.
func IsDeadlock ¶
IsDeadlock reports whether err is a MySQL 1213 (deadlock) or PostgreSQL 40P01 (deadlock_detected) / 40001 (serialization_failure) error.
func IsDuplicateEntry ¶
IsDuplicateEntry reports whether err is a MySQL 1062 (duplicate entry) error.
func IsRetryableConnectionError ¶
IsRetryableConnectionError reports whether err is a transient connection-level failure (connection refused, server gone away, connection killed, or lost mid-query — e.g. a Vitess tablet failover) that is safe to retry for an idempotent operation. It returns false when the caller's own context is canceled or past its deadline, since retrying then is pointless.
func IsRetryableLockConflict ¶
IsRetryableLockConflict reports whether err is a transient database lock conflict that is safe to retry around a small, idempotent database operation.
func MapSQLError ¶
MapSQLError converts common SQL/driver errors into an APIError so callers can differentiate expected cases (e.g. not found) from infrastructural failures (timeouts, connection issues, unknown errors).
func MapSQLErrorWithDuplicateKeys ¶
func MapSQLErrorWithDuplicateKeys(err error, mapping DuplicateKeyMapping) *apierror.APIError
MapSQLErrorWithDuplicateKeys works like MapSQLError but, for MySQL 1062 errors, looks up the violated constraint name in the provided mapping to return a domain-specific error. If no mapping matches, it falls through to the generic ResourceExistsError from MapSQLError.
func NewDbPool ¶
NewDbPool creates a new instrumented SQL database connection pool for MySQL with default parameters and tracing.
Example ¶
ExampleNewDbPool shows the minimal configuration for creating a connection pool: only DBURI is required; all other fields receive production defaults.
package main
import (
"github.com/open-mrp/api/shared/db"
)
func main() {
pool, err := db.NewDbPool(&db.Config{
DBURI: "user:pass@tcp(localhost:3306)/app",
})
if err != nil {
panic(err)
}
defer pool.Close()
}
Output:
func NullInt64Ptr ¶
func NullString ¶
func NullString(s string) sql.NullString
func NullStringFulltextPtr ¶
func NullStringFulltextPtr(s *string) sql.NullString
NullStringFulltextPtr returns a NullString formatted for MySQL FULLTEXT BOOLEAN MODE search. It appends a wildcard (*) so the term matches any word that starts with the given value (e.g. "kilo" → "kilo*").
func NullStringLikePtr ¶
func NullStringLikePtr(s *string) sql.NullString
NullStringLikePtr returns a NullString with the value wrapped in % wildcards for LIKE queries.
func NullStringPtr ¶
func NullStringPtr(s *string) sql.NullString
func NullTierInt64Param ¶
NullTierInt64Param binds cursor_match_tier for sqlc (nullable integer tier 0–3).
func SanitizeFulltextBoolean ¶
SanitizeFulltextBoolean strips MySQL BOOLEAN MODE operators from user input.
func StringFromInterface ¶
StringFromInterface extracts a string from an interface{} value. MySQL CASE expressions are typed as interface{} by sqlc and may arrive as []byte or string depending on the driver. Returns "" for nil.
func StringFromNullString ¶
func StringFromNullString(ns sql.NullString) *string
func TrimDecimal ¶
TrimDecimal removes unnecessary trailing zeros from a MySQL DECIMAL string. "1.000000000000000000000000000000" → "1", "10.500000..." → "10.5".
func WithConnRetry ¶
WithConnRetry retries operation only for transient connection failures (see IsRetryableConnectionError). Callers must only use it for idempotent operations — typically pure reads — because a connection lost mid-write leaves the write's outcome unknown. A nil cfg uses ConnRetryConfig.
Types ¶
type CatalogSearch ¶
type CatalogSearch struct {
// Contains is a LIKE pattern "%escaped_query%" for substring matches.
Contains sql.NullString
// Exact is the raw query string for SKU equality (tier 0) and token / MATCH expressions.
Exact sql.NullString
// Prefix is a LIKE pattern "escaped_query%" for prefix SKU matches (tier 2).
Prefix sql.NullString
}
CatalogSearch binds parameters for catalog list queries that filter by item SKU and description and rank exact / token / prefix SKU matches ahead of plain substring matches.
func NewCatalogSearch ¶
func NewCatalogSearch(q *string) CatalogSearch
NewCatalogSearch builds bind args for catalog search. If q is nil or empty, all fields are invalid (no search).
type Config ¶
type Config struct {
// DBURI (required) is the database connection URI.
DBURI string
// TracingEnabled (optional; default: true) specifies whether tracing is enabled. The zero value (false) is treated as "unset" by WithDefaults and replaced with true, so tracing cannot be disabled via this config.
TracingEnabled bool
// ConnectionMaxLifetime (optional; default: 30m) is the maximum lifetime of a connection.
ConnectionMaxLifetime time.Duration
// ConnectionMaxIdleTime (optional; default: 10m) is the maximum idle time of a connection.
ConnectionMaxIdleTime time.Duration
// MaxOpenConnections (optional; default: 50) is the maximum number of open connections.
MaxOpenConnections int
// MaxIdleConnections (optional; default: 50) is the maximum number of idle connections.
MaxIdleConnections int
}
Config represents the configuration for the database connection pool.
func (*Config) WithDefaults ¶
WithDefaults returns a new Config with all zero-value optional fields replaced by production defaults. It is safe to call on a nil receiver. The original Config is not mutated; a copy is always returned.
type DuplicateKeyMapping ¶
DuplicateKeyMapping maps MySQL unique constraint names to custom APIError constructors.
type FulltextSearch ¶
type FulltextSearch struct {
// Fulltext is the value for the FULLTEXT IS NULL guard and AGAINST clause.
Fulltext sql.NullString
// Fulltext2 is a duplicate of Fulltext required by a sqlc dedup bug.
Fulltext2 sql.NullString
// Like is the value for the LIKE fallback (set for short queries).
Like sql.NullString
}
FulltextSearch holds parameters for a SQL clause that supports both FULLTEXT (MATCH/AGAINST) and LIKE search. Queries with at least innoDBMinTokenSize characters use FULLTEXT; shorter queries fall back to LIKE so that short abbreviations (e.g. "pr") are still matched.
The SQL clause should be structured as:
AND (
(sqlc.narg('search_query') IS NULL AND sqlc.narg('like_query') IS NULL)
OR MATCH(...) AGAINST(sqlc.narg('search_query') IN BOOLEAN MODE)
OR col LIKE sqlc.narg('like_query')
)
Due to a sqlc bug, MATCH/AGAINST generates a duplicate parameter (SearchQuery_2). This helper populates both so callers don't need to know about the dedup issue.
Usage:
ft := db.NewFulltextSearch(params.Query)
sqlc.ListFooParams{ SearchQuery: ft.Fulltext, SearchQuery_2: ft.Fulltext2, LikeQuery: ft.Like, ... }
func NewFulltextSearch ¶
func NewFulltextSearch(s *string) FulltextSearch
type NullableRawMessage ¶
type NullableRawMessage []byte
func (*NullableRawMessage) Scan ¶
func (n *NullableRawMessage) Scan(value any) error
type SavepointRunner ¶
type SavepointRunner interface {
Run(ctx context.Context, fn func(ctx context.Context) *apierror.APIError) *apierror.APIError
}
SavepointRunner brackets a unit of work in a SAVEPOINT within an open transaction. Run releases the savepoint on success and rolls back to it on error — undoing only that unit's writes while the surrounding transaction stays alive — so a batch can let one item fail without discarding the rest. Obtain one from WithTxSavepoint.
type TransactionManager ¶
type TransactionManager[Q TxQuerier[Q], F any] interface { WithTx(ctx context.Context, fn func(ctx context.Context, f F) *apierror.APIError) *apierror.APIError // WithTxSavepoint is WithTx plus a SavepointRunner over the same transaction, for // partial-success batches: successful items and whatever the callback commits still // commit together at the end, and a mid-batch crash rolls the whole thing back. WithTxSavepoint(ctx context.Context, fn func(ctx context.Context, f F, sp SavepointRunner) *apierror.APIError) *apierror.APIError }
TransactionManager runs a unit of work in a database transaction.
A transaction that InnoDB picks as a deadlock victim is re-run, so callbacks must be safe to execute more than once. In practice that means a callback may only write to the database: its writes are rolled back with the transaction, so a second run starts from the same state the first one did. Anything that escapes the database does not get undone — an HTTP call to a payment provider, a message published straight to the broker, a value appended to a slice declared outside the callback — and would happen twice.
That is why events are written to the outbox rather than published inline, and why results are assembled inside the callback and handed out at the end. `make tx-audit` checks these rules across the codebase.
func NewTransactionManager ¶
func NewTransactionManager[Q TxQuerier[Q], F any]( db *sql.DB, queries Q, factoryCreate func(Q) F, ) TransactionManager[Q, F]