Documentation
¶
Overview ¶
Package relica provides a lightweight, type-safe database query builder for Go.
Relica offers a fluent API for building SQL queries with support for:
- Multiple databases (PostgreSQL, MySQL, SQLite)
- Zero production dependencies
- Prepared statement caching
- Transaction management
- Advanced SQL features (JOINs, aggregates, subqueries, CTEs)
Quick Start ¶
Install:
go get github.com/coregx/relica
Basic usage:
db, err := relica.Open("postgres", "user=postgres dbname=myapp")
if err != nil {
log.Fatal(err)
}
defer db.Close()
var users []User
err = db.Select("id", "name").From("users").All(&users)
Features ¶
CRUD Operations:
// SELECT with Expression API
db.Select().From("users").Where(relica.Eq("id", 123)).One(&user)
// INSERT via Model API (recommended)
user := User{Name: "Alice", Email: "alice@example.com"}
db.Model(&user).Insert()
// UPDATE
db.Update("users").
Set(map[string]interface{}{"status": "active"}).
Where(relica.Eq("id", 123)).
Execute()
// DELETE
db.Delete("users").Where(relica.Eq("id", 123)).Execute()
Index ¶
- Variables
- func DetectOperation(query string) string
- func IsCheckViolation(err error) bool
- func IsForeignKeyViolation(err error) bool
- func IsNotNullViolation(err error) bool
- func IsUniqueViolation(err error) bool
- type BatchInsertQuery
- func (biq *BatchInsertQuery) Build() *Query
- func (biq *BatchInsertQuery) Execute() (sql.Result, error)
- func (biq *BatchInsertQuery) ToSQL() (string, []interface{})
- func (biq *BatchInsertQuery) Values(values ...interface{}) *BatchInsertQuery
- func (biq *BatchInsertQuery) ValuesMap(values map[string]interface{}) *BatchInsertQuery
- func (biq *BatchInsertQuery) WithContext(ctx context.Context) *BatchInsertQuery
- type BatchUpdateQuery
- func (buq *BatchUpdateQuery) Build() *Query
- func (buq *BatchUpdateQuery) Execute() (sql.Result, error)
- func (buq *BatchUpdateQuery) Set(keyValue interface{}, values map[string]interface{}) *BatchUpdateQuery
- func (buq *BatchUpdateQuery) ToSQL() (string, []interface{})
- func (buq *BatchUpdateQuery) WithContext(ctx context.Context) *BatchUpdateQuery
- type CaseExp
- type CoalesceExp
- type ConcatExp
- type DB
- func (d *DB) BatchInsert(table string, columns []string) *BatchInsertQuery
- func (d *DB) BatchInsertStruct(table string, data interface{}) *Query
- func (d *DB) BatchUpdate(table, keyColumn string) *BatchUpdateQuery
- func (d *DB) Begin(ctx context.Context) (*Tx, error)
- func (d *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error)
- func (d *DB) Builder() *QueryBuilder
- func (d *DB) Close() error
- func (d *DB) Delete(table string) *DeleteQuery
- func (d *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
- func (d *DB) GenerateParamName(index int) string
- func (d *DB) Insert(table string, data map[string]interface{}) *Query
- func (d *DB) InsertStruct(table string, data interface{}) *Query
- func (d *DB) IsHealthy() bool
- func (d *DB) Model(model interface{}) *ModelQuery
- func (d *DB) NewQuery(query string) *Query
- func (d *DB) PinQuery(query string) bool
- func (d *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
- func (d *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
- func (d *DB) QuoteColumnName(column string) string
- func (d *DB) QuoteTableName(table string) string
- func (d *DB) Select(cols ...string) *SelectQuery
- func (d *DB) Stats() PoolStats
- func (d *DB) Transactional(ctx context.Context, f func(*Tx) error) error
- func (d *DB) TransactionalTx(ctx context.Context, opts *TxOptions, f func(*Tx) error) error
- func (d *DB) UnpinQuery(query string) bool
- func (d *DB) Unwrap() *core.DB
- func (d *DB) Update(table string) *UpdateQuery
- func (d *DB) UpdateStruct(table string, data interface{}) *UpdateQuery
- func (d *DB) Upsert(table string, values map[string]interface{}) *UpsertQuery
- func (d *DB) WarmCache(queries []string) (int, error)
- func (d *DB) WithContext(ctx context.Context) *DB
- type DeleteQuery
- func (dq *DeleteQuery) AndWhere(condition interface{}, params ...interface{}) *DeleteQuery
- func (dq *DeleteQuery) Build() *Query
- func (dq *DeleteQuery) Execute() (sql.Result, error)
- func (dq *DeleteQuery) OrWhere(condition interface{}, params ...interface{}) *DeleteQuery
- func (dq *DeleteQuery) ToSQL() (string, []interface{})
- func (dq *DeleteQuery) Where(condition interface{}, params ...interface{}) *DeleteQuery
- func (dq *DeleteQuery) WithContext(ctx context.Context) *DeleteQuery
- type Expression
- func And(exps ...Expression) Expression
- func Between(col string, from, to interface{}) Expression
- func Eq(col string, value interface{}) Expression
- func EqCol(col1, col2 string) Expression
- func Exists(exp Expression) Expression
- func GreaterOrEqual(col string, value interface{}) Expression
- func GreaterThan(col string, value interface{}) Expression
- func GreaterThanCol(col1, col2 string) Expression
- func In(col string, values ...interface{}) Expression
- func LessOrEqual(col string, value interface{}) Expression
- func LessThan(col string, value interface{}) Expression
- func LessThanCol(col1, col2 string) Expression
- func NewExp(rawSQL string, args ...interface{}) Expression
- func Not(exp Expression) Expression
- func NotBetween(col string, from, to interface{}) Expression
- func NotEq(col string, value interface{}) Expression
- func NotEqCol(col1, col2 string) Expression
- func NotExists(exp Expression) Expression
- func NotIn(col string, values ...interface{}) Expression
- func Or(exps ...Expression) Expression
- type GreatestLeastExp
- type HashExp
- type LikeExp
- type Logger
- type ModelQuery
- func (mq *ModelQuery) Delete() error
- func (mq *ModelQuery) Exclude(attrs ...string) *ModelQuery
- func (mq *ModelQuery) Insert(attrs ...string) error
- func (mq *ModelQuery) Table(name string) *ModelQuery
- func (mq *ModelQuery) Update(attrs ...string) error
- func (mq *ModelQuery) UpdateChanged(original interface{}) error
- func (mq *ModelQuery) Upsert(fields ...string) error
- func (mq *ModelQuery) WithContext(ctx context.Context) *ModelQuery
- type NoopLogger
- type NullIfExp
- type NullStringMap
- type Option
- func WithConnMaxIdleTime(d time.Duration) Option
- func WithConnMaxLifetime(d time.Duration) Option
- func WithHealthCheck(interval time.Duration) Option
- func WithLogger(l Logger) Option
- func WithMaxIdleConns(n int) Option
- func WithMaxOpenConns(n int) Option
- func WithQueryHook(hook QueryHook) Option
- func WithSensitiveFields(fields []string) Option
- func WithStmtCacheCapacity(capacity int) Option
- type Params
- type PoolStats
- type Query
- func (q *Query) All(dest interface{}) error
- func (q *Query) Bind(params ...interface{}) *Query
- func (q *Query) BindParams(params Params) *Query
- func (q *Query) Close() error
- func (q *Query) Column(slice interface{}) error
- func (q *Query) Execute() (sql.Result, error)
- func (q *Query) IsPrepared() bool
- func (q *Query) One(dest interface{}) error
- func (q *Query) Params() []interface{}
- func (q *Query) Prepare() *Query
- func (q *Query) QueryParams() []interface{}deprecated
- func (q *Query) Row(dest ...interface{}) error
- func (q *Query) SQL() string
- type QueryBuilder
- func (qb *QueryBuilder) BatchInsert(table string, columns []string) *BatchInsertQuery
- func (qb *QueryBuilder) BatchInsertStruct(table string, data interface{}) *Query
- func (qb *QueryBuilder) BatchUpdate(table, keyColumn string) *BatchUpdateQuery
- func (qb *QueryBuilder) Delete(table string) *DeleteQuery
- func (qb *QueryBuilder) Insert(table string, values map[string]interface{}) *Query
- func (qb *QueryBuilder) InsertStruct(table string, data interface{}) *Query
- func (qb *QueryBuilder) Select(cols ...string) *SelectQuery
- func (qb *QueryBuilder) Unwrap() *core.QueryBuilder
- func (qb *QueryBuilder) Update(table string) *UpdateQuery
- func (qb *QueryBuilder) UpdateStruct(table string, data interface{}) *UpdateQuery
- func (qb *QueryBuilder) Upsert(table string, values map[string]interface{}) *UpsertQuery
- func (qb *QueryBuilder) WithContext(ctx context.Context) *QueryBuilder
- type QueryEvent
- type QueryHook
- type SelectQuery
- func (sq *SelectQuery) All(dest interface{}) error
- func (sq *SelectQuery) AndSelect(cols ...string) *SelectQuery
- func (sq *SelectQuery) AndWhere(condition interface{}, params ...interface{}) *SelectQuery
- func (sq *SelectQuery) AsExpression() Expression
- func (sq *SelectQuery) Build() *Query
- func (sq *SelectQuery) Column(slice interface{}) error
- func (sq *SelectQuery) Count() (int64, error)
- func (sq *SelectQuery) CrossJoin(table string) *SelectQuery
- func (sq *SelectQuery) Distinct() *SelectQuery
- func (sq *SelectQuery) Except(other *SelectQuery) *SelectQuery
- func (sq *SelectQuery) Exists() (bool, error)
- func (sq *SelectQuery) From(table string) *SelectQuery
- func (sq *SelectQuery) FromSelect(subquery *SelectQuery, alias string) *SelectQuery
- func (sq *SelectQuery) FullJoin(table string, on interface{}) *SelectQuery
- func (sq *SelectQuery) GroupBy(columns ...string) *SelectQuery
- func (sq *SelectQuery) GroupByExpr(expr string, args ...interface{}) *SelectQuery
- func (sq *SelectQuery) GroupBySub(exp Expression) *SelectQuery
- func (sq *SelectQuery) Having(condition interface{}, args ...interface{}) *SelectQuery
- func (sq *SelectQuery) InnerJoin(table string, on interface{}) *SelectQuery
- func (sq *SelectQuery) Intersect(other *SelectQuery) *SelectQuery
- func (sq *SelectQuery) LeftJoin(table string, on interface{}) *SelectQuery
- func (sq *SelectQuery) Limit(limit int64) *SelectQuery
- func (sq *SelectQuery) Offset(offset int64) *SelectQuery
- func (sq *SelectQuery) One(dest interface{}) error
- func (sq *SelectQuery) OrWhere(condition interface{}, params ...interface{}) *SelectQuery
- func (sq *SelectQuery) OrderBy(columns ...string) *SelectQuery
- func (sq *SelectQuery) OrderByExpr(expr string, args ...interface{}) *SelectQuery
- func (sq *SelectQuery) OrderBySub(exp Expression) *SelectQuery
- func (sq *SelectQuery) RightJoin(table string, on interface{}) *SelectQuery
- func (sq *SelectQuery) Row(dest ...interface{}) error
- func (sq *SelectQuery) SelectExpr(expr string, args ...interface{}) *SelectQuery
- func (sq *SelectQuery) SelectSub(exp Expression, alias string) *SelectQuery
- func (sq *SelectQuery) ToSQL() (string, []interface{})
- func (sq *SelectQuery) Union(other *SelectQuery) *SelectQuery
- func (sq *SelectQuery) UnionAll(other *SelectQuery) *SelectQuery
- func (sq *SelectQuery) Unwrap() *core.SelectQuery
- func (sq *SelectQuery) Where(condition interface{}, params ...interface{}) *SelectQuery
- func (sq *SelectQuery) With(name string, query *SelectQuery) *SelectQuery
- func (sq *SelectQuery) WithContext(ctx context.Context) *SelectQuery
- func (sq *SelectQuery) WithRecursive(name string, query *SelectQuery) *SelectQuery
- type SlogAdapter
- type Tx
- func (t *Tx) BatchInsert(table string, columns []string) *BatchInsertQuery
- func (t *Tx) BatchInsertStruct(table string, data interface{}) *Query
- func (t *Tx) BatchUpdate(table, keyColumn string) *BatchUpdateQuery
- func (t *Tx) Builder() *QueryBuilder
- func (t *Tx) Commit() error
- func (t *Tx) Delete(table string) *DeleteQuery
- func (t *Tx) Insert(table string, data map[string]interface{}) *Query
- func (t *Tx) InsertStruct(table string, data interface{}) *Query
- func (t *Tx) Model(model interface{}) *ModelQuery
- func (t *Tx) NewQuery(query string) *Query
- func (t *Tx) Rollback() error
- func (t *Tx) Select(cols ...string) *SelectQuery
- func (t *Tx) Unwrap() *core.Tx
- func (t *Tx) Update(table string) *UpdateQuery
- func (t *Tx) UpdateStruct(table string, data interface{}) *UpdateQuery
- func (t *Tx) Upsert(table string, values map[string]interface{}) *UpsertQuery
- type TxOptions
- type UpdateQuery
- func (uq *UpdateQuery) AndWhere(condition interface{}, params ...interface{}) *UpdateQuery
- func (uq *UpdateQuery) Build() *Query
- func (uq *UpdateQuery) Execute() (sql.Result, error)
- func (uq *UpdateQuery) OrWhere(condition interface{}, params ...interface{}) *UpdateQuery
- func (uq *UpdateQuery) Set(values map[string]interface{}) *UpdateQuery
- func (uq *UpdateQuery) ToSQL() (string, []interface{})
- func (uq *UpdateQuery) Where(condition interface{}, params ...interface{}) *UpdateQuery
- func (uq *UpdateQuery) WithContext(ctx context.Context) *UpdateQuery
- type UpsertQuery
- func (uq *UpsertQuery) Build() *Query
- func (uq *UpsertQuery) DoNothing() *UpsertQuery
- func (uq *UpsertQuery) DoUpdate(columns ...string) *UpsertQuery
- func (uq *UpsertQuery) Execute() (sql.Result, error)
- func (uq *UpsertQuery) OnConflict(columns ...string) *UpsertQuery
- func (uq *UpsertQuery) ToSQL() (string, []interface{})
- func (uq *UpsertQuery) WithContext(ctx context.Context) *UpsertQuery
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = core.ErrNotFound
ErrNotFound is returned by One() when no rows match the query. It wraps sql.ErrNoRows so both errors.Is(err, relica.ErrNotFound) and errors.Is(err, sql.ErrNoRows) return true.
Example:
var user User
err := db.Select().From("users").Where(relica.Eq("id", 999)).One(&user)
if errors.Is(err, relica.ErrNotFound) {
// handle not found
}
Functions ¶
func DetectOperation ¶ added in v0.9.0
DetectOperation detects the SQL operation type (SELECT, INSERT, UPDATE, DELETE, UNKNOWN).
func IsCheckViolation ¶ added in v0.11.0
IsCheckViolation reports whether err represents a CHECK constraint violation. Works with PostgreSQL, MySQL, and SQLite. Returns false for nil errors.
Example:
_, err := db.Model(&product).Insert()
if relica.IsCheckViolation(err) {
// handle check constraint failure
}
func IsForeignKeyViolation ¶ added in v0.11.0
IsForeignKeyViolation reports whether err represents a foreign key constraint violation. Works with PostgreSQL, MySQL, and SQLite. Returns false for nil errors.
Example:
_, err := db.Model(&order).Insert()
if relica.IsForeignKeyViolation(err) {
// handle missing referenced row
}
func IsNotNullViolation ¶ added in v0.11.0
IsNotNullViolation reports whether err represents a NOT NULL constraint violation. Works with PostgreSQL, MySQL, and SQLite. Returns false for nil errors.
Example:
_, err := db.Model(&user).Insert()
if relica.IsNotNullViolation(err) {
// handle missing required field
}
func IsUniqueViolation ¶ added in v0.11.0
IsUniqueViolation reports whether err represents a unique constraint violation. Works with PostgreSQL, MySQL, and SQLite. Returns false for nil errors.
Example:
_, err := db.Model(&user).Insert()
if relica.IsUniqueViolation(err) {
// handle duplicate key
}
Types ¶
type BatchInsertQuery ¶
type BatchInsertQuery struct {
// contains filtered or unexported fields
}
BatchInsertQuery represents a batch INSERT query being built.
func (*BatchInsertQuery) Build ¶
func (biq *BatchInsertQuery) Build() *Query
Build constructs the Query object.
func (*BatchInsertQuery) Execute ¶
func (biq *BatchInsertQuery) Execute() (sql.Result, error)
Execute executes the batch INSERT query.
func (*BatchInsertQuery) ToSQL ¶ added in v0.12.0
func (biq *BatchInsertQuery) ToSQL() (string, []interface{})
ToSQL returns the SQL string and parameters without executing the query. This is useful for debugging, logging, or passing the query to another layer.
Example:
sql, params := db.BatchInsert("users", []string{"name", "email"}).
Values("Alice", "alice@example.com").ToSQL()
func (*BatchInsertQuery) Values ¶
func (biq *BatchInsertQuery) Values(values ...interface{}) *BatchInsertQuery
Values adds a row of values to the batch insert.
Example:
BatchInsert("users", []string{"name", "email"}).
Values("Alice", "alice@example.com").
Values("Bob", "bob@example.com")
func (*BatchInsertQuery) ValuesMap ¶
func (biq *BatchInsertQuery) ValuesMap(values map[string]interface{}) *BatchInsertQuery
ValuesMap adds a row from a map.
Example:
BatchInsert("users", []string{"name", "email"}).
ValuesMap(map[string]interface{}{"name": "Alice", "email": "alice@example.com"})
func (*BatchInsertQuery) WithContext ¶
func (biq *BatchInsertQuery) WithContext(ctx context.Context) *BatchInsertQuery
WithContext sets the context for this batch INSERT query.
type BatchUpdateQuery ¶
type BatchUpdateQuery struct {
// contains filtered or unexported fields
}
BatchUpdateQuery represents a batch UPDATE query being built.
func (*BatchUpdateQuery) Build ¶
func (buq *BatchUpdateQuery) Build() *Query
Build constructs the Query object.
func (*BatchUpdateQuery) Execute ¶
func (buq *BatchUpdateQuery) Execute() (sql.Result, error)
Execute executes the batch UPDATE query.
func (*BatchUpdateQuery) Set ¶
func (buq *BatchUpdateQuery) Set(keyValue interface{}, values map[string]interface{}) *BatchUpdateQuery
Set adds a row update to the batch.
Example:
BatchUpdate("users", "id").
Set(1, map[string]interface{}{"status": 2}).
Set(2, map[string]interface{}{"status": 3})
func (*BatchUpdateQuery) ToSQL ¶ added in v0.12.0
func (buq *BatchUpdateQuery) ToSQL() (string, []interface{})
ToSQL returns the SQL string and parameters without executing the query. This is useful for debugging, logging, or passing the query to another layer.
Example:
sql, params := db.BatchUpdate("users", "id").
Set(1, map[string]interface{}{"status": 2}).ToSQL()
func (*BatchUpdateQuery) WithContext ¶
func (buq *BatchUpdateQuery) WithContext(ctx context.Context) *BatchUpdateQuery
WithContext sets the context for this batch UPDATE query.
type CaseExp ¶ added in v0.9.0
CaseExp represents a SQL CASE expression.
type CoalesceExp ¶ added in v0.9.0
type CoalesceExp = core.CoalesceExp
CoalesceExp represents a SQL COALESCE expression.
func Coalesce ¶ added in v0.9.0
func Coalesce(values ...interface{}) *CoalesceExp
Coalesce creates a COALESCE expression.
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB represents a database connection with query building capabilities.
DB provides a fluent API for constructing and executing SQL queries in a type-safe manner. It wraps the underlying database/sql connection and adds features like:
- Prepared statement caching (LRU eviction, <60ns hit latency)
- Query builder with method chaining
- Transaction management (all isolation levels)
- Multi-database support (PostgreSQL, MySQL, SQLite)
Example:
db, err := relica.Open("postgres", "user=postgres dbname=myapp")
if err != nil {
log.Fatal(err)
}
defer db.Close()
var users []User
err = db.Builder().
Select("id", "name", "email").
From("users").
Where("active = ?", true).
OrderBy("name").
All(&users)
func Open ¶
Open creates a new database connection with optional configuration.
The driverName parameter specifies the database driver:
- "postgres" - PostgreSQL
- "mysql" - MySQL
- "sqlite3" - SQLite
The dsn parameter is the database-specific connection string.
Example:
db, err := relica.Open("postgres", "user=postgres dbname=myapp",
relica.WithMaxOpenConns(100),
relica.WithMaxIdleConns(50))
if err != nil {
log.Fatal(err)
}
defer db.Close()
func WrapDB ¶
WrapDB wraps an existing *sql.DB connection with Relica's query builder.
The caller is responsible for managing the connection lifecycle (including Close()). This is useful when you need to:
- Use Relica with an externally managed connection pool
- Integrate with existing code that already has a *sql.DB instance
- Apply custom connection pool settings before wrapping
Example:
sqlDB, _ := sql.Open("postgres", dsn)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
db := relica.WrapDB(sqlDB, "postgres")
defer sqlDB.Close() // Caller's responsibility
func (*DB) BatchInsert ¶ added in v0.10.0
func (d *DB) BatchInsert(table string, columns []string) *BatchInsertQuery
BatchInsert creates a new batch INSERT query for inserting multiple rows efficiently.
This is a convenience method equivalent to db.Builder().BatchInsert(table, columns).
Example:
result, err := db.BatchInsert("users", []string{"name", "email"}).
Values("Alice", "alice@example.com").
Values("Bob", "bob@example.com").
Execute()
func (*DB) BatchInsertStruct ¶ added in v0.6.0
BatchInsertStruct builds a batch INSERT query from a slice of structs.
This method performs batch insertion of multiple structs in a single query, which is significantly faster than individual inserts. All structs must have the same type and will be inserted with the same column set.
The slice element type must be a struct or pointer to struct. Fields are mapped using the same rules as InsertStruct.
Example:
users := []User{
{Name: "Alice", Email: "alice@example.com"},
{Name: "Bob", Email: "bob@example.com"},
}
result, err := db.BatchInsertStruct("users", users).Execute()
if err != nil {
return err
}
For single struct inserts, use InsertStruct instead.
func (*DB) BatchUpdate ¶ added in v0.10.0
func (d *DB) BatchUpdate(table, keyColumn string) *BatchUpdateQuery
BatchUpdate creates a new batch UPDATE query for updating multiple rows with different values.
This is a convenience method equivalent to db.Builder().BatchUpdate(table, keyColumn).
Example:
result, err := db.BatchUpdate("users", "id").
Set(1, map[string]interface{}{"name": "Alice"}).
Set(2, map[string]interface{}{"name": "Bob"}).
Execute()
func (*DB) Begin ¶
Begin starts a transaction with default options.
The transaction must be committed or rolled back to release resources. It's safe to call Rollback() even after Commit().
Example:
tx, err := db.Begin(ctx)
if err != nil {
return err
}
defer tx.Rollback() // Safe even after Commit
// Use transaction
_, err = tx.Insert("users", data).Execute()
if err != nil {
return err
}
return tx.Commit()
func (*DB) BeginTx ¶
BeginTx starts a transaction with specified options.
Options can specify isolation level and read-only mode:
- Isolation: sql.LevelReadUncommitted, sql.LevelReadCommitted, sql.LevelRepeatableRead, sql.LevelSerializable
- ReadOnly: true for read-only transactions (some databases optimize these)
Example:
opts := &relica.TxOptions{
Isolation: sql.LevelSerializable,
ReadOnly: false,
}
tx, err := db.BeginTx(ctx, opts)
func (*DB) Builder ¶
func (d *DB) Builder() *QueryBuilder
Builder returns a new QueryBuilder for constructing queries.
The query builder provides a fluent interface for building SELECT, INSERT, UPDATE, DELETE, and UPSERT queries.
Example:
db.Builder().
Select("*").
From("users").
Where("id = ?", 123).
One(&user)
func (*DB) Close ¶
Close releases all database resources including the connection pool and statement cache.
After calling Close, the DB instance should not be used.
Example:
db, _ := relica.Open("postgres", dsn)
defer db.Close()
func (*DB) Delete ¶
func (d *DB) Delete(table string) *DeleteQuery
Delete creates a new DELETE query.
This is a convenience method equivalent to db.Builder().Delete(table).
Example:
_, err := db.Delete("users").
Where("id = ?", 123).
Execute()
if err != nil {
return err
}
// Delete multiple rows
_, err := db.Delete("users").
Where("status = ?", "inactive").
Execute()
func (*DB) ExecContext ¶
func (d *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
ExecContext executes a raw SQL query (INSERT/UPDATE/DELETE).
This bypasses the query builder and executes SQL directly. Use this for queries that aren't supported by the query builder or when you need maximum control.
Example:
result, err := db.ExecContext(ctx,
"UPDATE users SET status = ? WHERE id = ?",
1, 123)
if err != nil {
return err
}
rowsAffected, _ := result.RowsAffected()
func (*DB) GenerateParamName ¶
GenerateParamName generates a dialect-specific parameter placeholder for the given index. For PostgreSQL, returns "$1", "$2", etc. For MySQL/SQLite, returns "?".
This is useful when building dynamic SQL queries where you need the correct placeholder syntax for the active database driver.
Example:
ph1 := db.GenerateParamName(1) // PostgreSQL: "$1", MySQL/SQLite: "?" ph2 := db.GenerateParamName(2) // PostgreSQL: "$2", MySQL/SQLite: "?"
func (*DB) Insert ¶
Insert creates a new INSERT query.
This is a convenience method equivalent to db.Builder().Insert(table, data). For batch inserts, use db.Builder().BatchInsert().
Example:
result, err := db.Insert("users", map[string]interface{}{
"name": "Alice",
"email": "alice@example.com",
}).Execute()
if err != nil {
return err
}
rows, _ := result.RowsAffected()
fmt.Printf("Inserted %d row(s)\n", rows)
// For batch operations, use Builder()
result, err := db.Builder().
BatchInsert("users", []string{"name", "email"}).
Values("Alice", "alice@example.com").
Values("Bob", "bob@example.com").
Execute()
func (*DB) InsertStruct ¶ added in v0.6.0
InsertStruct builds an INSERT query from a struct using db tags.
The struct fields are mapped to database columns using the `db` struct tag. Fields without a `db` tag use the field name. Fields tagged with `db:"-"` are ignored. Unexported fields are automatically skipped.
This method provides type-safe struct-based inserts without manually constructing maps. For batch struct inserts, use BatchInsertStruct.
Example:
type User struct {
ID int `db:"id"`
Name string `db:"name"`
Email string `db:"email"`
Skip int `db:"-"` // ignored
}
user := User{Name: "Alice", Email: "alice@example.com"}
result, err := db.InsertStruct("users", &user).Execute()
if err != nil {
return err
}
func (*DB) IsHealthy ¶
IsHealthy returns true if the database connection is healthy. Always returns true if health checks are disabled.
This is a convenience method that calls Stats() internally.
Example:
if !db.IsHealthy() {
log.Error("Database connection unhealthy")
// Attempt reconnection or alert
}
func (*DB) Model ¶ added in v0.6.0
func (d *DB) Model(model interface{}) *ModelQuery
Model creates a ModelQuery for performing CRUD operations on a struct model.
The model must be a pointer to a struct. The table name and primary key are automatically inferred from the struct definition.
Table name resolution:
- If model implements TableName() string, use that value
- Otherwise, use struct name lowercased + 's' (e.g., User → users)
Primary key detection:
- Field with db:"id" tag
- Field with db:"*_id" tag (e.g., db:"user_id")
- Field named "ID"
Example:
type User struct {
ID int `db:"id"`
Name string `db:"name"`
Email string `db:"email"`
}
func (User) TableName() string { return "users" }
// INSERT - auto table name.
user := User{Name: "Alice", Email: "alice@example.com"}
err := db.Model(&user).Insert()
// UPDATE - auto WHERE by primary key.
user.Status = "active"
err = db.Model(&user).Update()
// DELETE - auto WHERE by primary key.
err = db.Model(&user).Delete()
// Field control.
err = db.Model(&user).Exclude("CreatedAt", "UpdatedAt").Insert()
err = db.Model(&user).Table("users_archive").Insert()
func (*DB) NewQuery ¶ added in v0.9.0
NewQuery creates a raw SQL query for execution. Use this for queries that don't fit the query builder pattern, or when you need manual control over prepared statement lifecycle.
Example:
var count int
err := db.NewQuery("SELECT COUNT(*) FROM users").Row(&count)
// With parameters
var user User
err := db.NewQuery("SELECT * FROM users WHERE id = ?").Bind(1).One(&user)
// With Prepare for repeated execution
q := db.NewQuery("SELECT * FROM users WHERE status = ?").Prepare()
defer q.Close()
for _, status := range statuses {
q.Bind(status).All(&users)
}
func (*DB) PinQuery ¶
PinQuery marks a query as pinned in the statement cache, preventing eviction.
Pinned queries remain in cache indefinitely, useful for frequently-used queries. Returns false if the query is not in cache (call WarmCache first).
Example:
// Warm and pin critical queries
queries := []string{"SELECT * FROM users WHERE id = ?"}
db.WarmCache(queries)
db.PinQuery(queries[0]) // Will never be evicted
func (*DB) QueryContext ¶
func (d *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
QueryContext executes a raw SQL query and returns rows.
This bypasses the query builder and executes SQL directly. You are responsible for closing the returned rows.
Example:
rows, err := db.QueryContext(ctx,
"SELECT * FROM users WHERE status = ?", 1)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
// Process rows
}
func (*DB) QueryRowContext ¶
QueryRowContext executes a raw SQL query expected to return at most one row.
This bypasses the query builder and executes SQL directly.
Example:
var count int
err := db.QueryRowContext(ctx,
"SELECT COUNT(*) FROM users").Scan(&count)
func (*DB) QuoteColumnName ¶
QuoteColumnName quotes a column name using the database's identifier quoting style.
This is useful when building dynamic SQL queries.
Example:
quoted := db.QuoteColumnName("user_id")
// PostgreSQL: "user_id"
// MySQL: `user_id`
func (*DB) QuoteTableName ¶
QuoteTableName quotes a table name using the database's identifier quoting style.
This is useful when building dynamic SQL queries.
Example:
quoted := db.QuoteTableName("users")
// PostgreSQL: "users"
// MySQL: `users`
func (*DB) Select ¶
func (d *DB) Select(cols ...string) *SelectQuery
Select creates a new SELECT query.
This is a convenience method equivalent to db.Builder().Select(cols...). For advanced queries (CTEs, subqueries, UNION), use db.Builder() directly.
Example:
var users []User
err := db.Select("id", "name", "email").
From("users").
Where("active = ?", true).
OrderBy("name").
All(&users)
// For wildcard selection
err := db.Select("*").From("users").All(&users)
// For advanced features, use Builder()
err := db.Builder().
With("stats", statsQuery).
Select("*").
From("stats").
All(&results)
func (*DB) Stats ¶
Stats returns database connection pool statistics.
Stats provides insights into connection pool usage including:
- Number of open/idle/in-use connections
- Wait count and duration
- Connections closed due to max lifetime/idle time
- Health check status (if enabled)
Example:
stats := db.Stats()
fmt.Printf("Open: %d, Idle: %d, InUse: %d\n",
stats.OpenConnections, stats.Idle, stats.InUse)
if !stats.Healthy {
log.Warn("Database health check failed")
}
func (*DB) Transactional ¶ added in v0.8.0
Transactional executes f within a transaction with automatic commit/rollback.
If f returns an error, the transaction is rolled back and the error is returned. If f panics, the transaction is rolled back and the panic is re-raised. If f completes successfully, the transaction is committed.
This helper simplifies transaction management and ensures proper cleanup in all code paths, including panics.
Example:
err := db.Transactional(ctx, func(tx *relica.Tx) error {
user := User{Name: "Alice", Email: "alice@example.com"}
if err := tx.Model(&user).Insert(); err != nil {
return err // Auto rollback
}
account := Account{UserID: user.ID, Balance: 100}
if err := tx.Model(&account).Insert(); err != nil {
return err // Auto rollback
}
return nil // Auto commit
})
func (*DB) TransactionalTx ¶ added in v0.8.0
TransactionalTx executes f within a transaction with custom options.
Options can specify isolation level and read-only mode. If f returns an error, the transaction is rolled back and the error is returned. If f panics, the transaction is rolled back and the panic is re-raised. If f completes successfully, the transaction is committed.
Example:
opts := &relica.TxOptions{
Isolation: sql.LevelSerializable,
ReadOnly: false,
}
err := db.TransactionalTx(ctx, opts, func(tx *relica.Tx) error {
// Perform operations within serializable transaction.
return tx.Model(&user).Update()
})
func (*DB) UnpinQuery ¶
UnpinQuery removes the pin from a cached query, allowing normal LRU eviction.
Returns false if the query is not in cache or not pinned.
Example:
db.UnpinQuery("SELECT * FROM users WHERE id = ?")
func (*DB) Unwrap ¶
Unwrap returns the underlying core.DB for advanced use cases.
This method is provided for edge cases where direct access to internal types is needed. Most users should not need this.
Example:
coreDB := db.Unwrap() // Use coreDB for advanced operations
func (*DB) Update ¶
func (d *DB) Update(table string) *UpdateQuery
Update creates a new UPDATE query.
This is a convenience method equivalent to db.Builder().Update(table). For batch updates, use db.Builder().BatchUpdate().
Example:
_, err := db.Update("users").
Set(map[string]interface{}{"status": "active"}).
Where("id = ?", 123).
Execute()
if err != nil {
return err
}
// For batch operations, use Builder()
_, err := db.Builder().
BatchUpdate("users", "id").
Set(1, map[string]interface{}{"status": "active"}).
Set(2, map[string]interface{}{"status": "inactive"}).
Execute()
func (*DB) UpdateStruct ¶ added in v0.6.0
func (d *DB) UpdateStruct(table string, data interface{}) *UpdateQuery
UpdateStruct builds an UPDATE query from a struct using db tags.
Similar to InsertStruct, but for UPDATE operations. The struct fields are converted to SET clauses. You must chain a Where() call to specify which rows to update.
This method provides type-safe struct-based updates without manually constructing maps.
Example:
user := User{Name: "Alice Updated", Status: "active"}
result, err := db.UpdateStruct("users", &user).
Where("id = ?", user.ID).
Execute()
if err != nil {
return err
}
For automatic WHERE clause based on primary key, consider using the Model() API (available in v0.6.0+).
func (*DB) Upsert ¶ added in v0.10.0
func (d *DB) Upsert(table string, values map[string]interface{}) *UpsertQuery
Upsert creates a new UPSERT query (INSERT ... ON CONFLICT).
This is a convenience method equivalent to db.Builder().Upsert(table, values).
Example:
result, err := db.Upsert("users", map[string]interface{}{
"email": "alice@example.com",
"name": "Alice",
}).OnConflict("email").DoUpdate("name").Execute()
func (*DB) WarmCache ¶
WarmCache pre-warms the statement cache by preparing frequently-used queries.
This improves performance at startup by avoiding cache misses for common queries. The queries are prepared synchronously in the order provided. Returns the number of successfully prepared queries and any error encountered.
Example:
n, err := db.WarmCache([]string{
"SELECT * FROM users WHERE id = ?",
"INSERT INTO logs (message, level) VALUES (?, ?)",
"UPDATE users SET last_login = ? WHERE id = ?",
})
if err != nil {
log.Warn("Failed to warm cache", "error", err, "warmed", n)
}
func (*DB) WithContext ¶
WithContext returns a new DB with the given context.
The context will be used for all subsequent query operations unless overridden at the query level.
Example:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
db := db.WithContext(ctx)
db.Builder().Select("*").From("users").All(&users)
type DeleteQuery ¶
type DeleteQuery struct {
// contains filtered or unexported fields
}
DeleteQuery represents a DELETE query being built.
func (*DeleteQuery) AndWhere ¶ added in v0.8.0
func (dq *DeleteQuery) AndWhere(condition interface{}, params ...interface{}) *DeleteQuery
AndWhere adds a WHERE condition with AND logic. If no existing WHERE clause exists, behaves like Where().
Example:
db.Builder().Delete("users").
Where("status = ?", 0).
AndWhere("created_at < ?", "2020-01-01")
func (*DeleteQuery) Build ¶
func (dq *DeleteQuery) Build() *Query
Build constructs the Query object.
func (*DeleteQuery) Execute ¶
func (dq *DeleteQuery) Execute() (sql.Result, error)
Execute executes the DELETE query.
func (*DeleteQuery) OrWhere ¶ added in v0.8.0
func (dq *DeleteQuery) OrWhere(condition interface{}, params ...interface{}) *DeleteQuery
OrWhere adds a WHERE condition with OR logic. If no existing WHERE clause exists, behaves like Where().
Example:
db.Builder().Delete("users").
Where("banned = ?", true).
OrWhere("deleted = ?", true)
func (*DeleteQuery) ToSQL ¶ added in v0.11.0
func (dq *DeleteQuery) ToSQL() (string, []interface{})
ToSQL returns the SQL string and parameters without executing the query. This is useful for debugging, logging, or passing the query to another layer.
Example:
sql, params := db.Delete("users").Where(relica.Eq("id", 1)).ToSQL()
func (*DeleteQuery) Where ¶
func (dq *DeleteQuery) Where(condition interface{}, params ...interface{}) *DeleteQuery
Where adds a WHERE condition to the DELETE query.
Example:
Delete("users").Where("id = ?", 123)
func (*DeleteQuery) WithContext ¶
func (dq *DeleteQuery) WithContext(ctx context.Context) *DeleteQuery
WithContext sets the context for this DELETE query.
type Expression ¶
type Expression = core.Expression
Expression represents a database expression for building complex WHERE clauses.
Expressions provide a type-safe way to construct SQL conditions without writing raw SQL strings. They support nesting and composition.
Example:
expr := relica.And(
relica.Eq("status", 1),
relica.Or(
relica.GreaterThan("age", 18),
relica.Eq("verified", true),
),
)
db.Builder().Select("*").From("users").Where(expr).All(&users)
func Between ¶
func Between(col string, from, to interface{}) Expression
Between creates a BETWEEN expression (column BETWEEN low AND high).
func Eq ¶
func Eq(col string, value interface{}) Expression
Eq creates an equality expression (column = value).
func EqCol ¶ added in v0.13.0
func EqCol(col1, col2 string) Expression
EqCol creates a column-to-column equality expression (col1 = col2). Both identifiers are quoted using the current dialect. Useful for JOIN ON conditions and correlated subquery WHERE clauses.
Example:
relica.EqCol("orders.user_id", "users.id") → "orders"."user_id" = "users"."id"
func GreaterOrEqual ¶
func GreaterOrEqual(col string, value interface{}) Expression
GreaterOrEqual creates a greater-or-equal expression (column >= value).
func GreaterThan ¶
func GreaterThan(col string, value interface{}) Expression
GreaterThan creates a greater-than expression (column > value).
func GreaterThanCol ¶ added in v0.13.0
func GreaterThanCol(col1, col2 string) Expression
GreaterThanCol creates a column-to-column greater-than expression (col1 > col2).
func In ¶
func In(col string, values ...interface{}) Expression
In creates an IN expression (column IN (values...)).
func LessOrEqual ¶
func LessOrEqual(col string, value interface{}) Expression
LessOrEqual creates a less-or-equal expression (column <= value).
func LessThan ¶
func LessThan(col string, value interface{}) Expression
LessThan creates a less-than expression (column < value).
func LessThanCol ¶ added in v0.13.0
func LessThanCol(col1, col2 string) Expression
LessThanCol creates a column-to-column less-than expression (col1 < col2).
func NewExp ¶
func NewExp(rawSQL string, args ...interface{}) Expression
NewExp creates a new raw SQL expression.
func NotBetween ¶
func NotBetween(col string, from, to interface{}) Expression
NotBetween creates a NOT BETWEEN expression.
func NotEq ¶
func NotEq(col string, value interface{}) Expression
NotEq creates a not-equal expression (column != value).
func NotEqCol ¶ added in v0.13.0
func NotEqCol(col1, col2 string) Expression
NotEqCol creates a column-to-column inequality expression (col1 <> col2).
func NotExists ¶
func NotExists(exp Expression) Expression
NotExists creates a NOT EXISTS subquery expression.
func NotIn ¶
func NotIn(col string, values ...interface{}) Expression
NotIn creates a NOT IN expression (column NOT IN (values...)).
type GreatestLeastExp ¶ added in v0.9.0
type GreatestLeastExp = core.GreatestLeastExp
GreatestLeastExp represents a SQL GREATEST or LEAST expression.
func Greatest ¶ added in v0.9.0
func Greatest(values ...interface{}) *GreatestLeastExp
Greatest creates a GREATEST expression.
func Least ¶ added in v0.9.0
func Least(values ...interface{}) *GreatestLeastExp
Least creates a LEAST expression.
type HashExp ¶
HashExp represents a hash-based expression using column-value pairs.
HashExp provides a convenient map syntax for simple equality conditions. Special values are handled automatically:
- nil → "column IS NULL"
- []interface{} → "column IN (...)"
Example:
db.Builder().Select("*").From("users").Where(relica.HashExp{
"status": 1,
"role": []string{"admin", "moderator"},
"deleted_at": nil,
}).All(&users)
type LikeExp ¶
LikeExp represents a LIKE expression with automatic escaping.
LikeExp provides pattern matching with automatic escaping of SQL wildcard characters (%, _).
Example:
db.Builder().Select("*").From("users").Where(
relica.Like("name", "john%"),
).All(&users)
type Logger ¶
Logger defines the logging interface for Relica. Implementations should handle structured logging with key-value pairs.
type ModelQuery ¶ added in v0.6.0
type ModelQuery struct {
// contains filtered or unexported fields
}
ModelQuery provides CRUD operations for struct models.
ModelQuery simplifies database operations by automatically inferring table names and primary keys from struct definitions, similar to ozzo-dbx.
The table name is determined by:
- TableName() method if model implements interface{ TableName() string }
- Otherwise: struct name lowercased with 's' suffix (e.g., User → users)
The primary key is detected from:
- Field with db:"id" tag
- Field with db:"*_id" tag (e.g., db:"user_id")
- Field named "ID"
Example:
type User struct {
ID int `db:"id"`
Name string `db:"name"`
Email string `db:"email"`
}
func (User) TableName() string { return "users" }
user := User{Name: "Alice", Email: "alice@example.com"}
err := db.Model(&user).Insert()
user.Status = "active"
err = db.Model(&user).Update() // Auto WHERE by primary key.
err = db.Model(&user).Delete() // Auto WHERE by primary key.
func (*ModelQuery) Delete ¶ added in v0.6.0
func (mq *ModelQuery) Delete() error
Delete deletes the model from the table.
The WHERE clause is automatically generated using the primary key.
Example:
err := db.Model(&user).Delete() // DELETE FROM users WHERE id=?
func (*ModelQuery) Exclude ¶ added in v0.6.0
func (mq *ModelQuery) Exclude(attrs ...string) *ModelQuery
Exclude excludes the specified fields from the operation.
This is useful for auto-managed fields like timestamps.
Example:
err := db.Model(&user).Exclude("created_at", "updated_at").Insert()
func (*ModelQuery) Insert ¶ added in v0.6.0
func (mq *ModelQuery) Insert(attrs ...string) error
Insert inserts the model into the table.
By default, all public fields are inserted. You can specify which fields to insert by passing their names, or use Exclude() to exclude specific fields.
Example:
// Insert all fields.
err := db.Model(&user).Insert()
// Insert only specific fields.
err := db.Model(&user).Insert("name", "email")
// Exclude fields.
err := db.Model(&user).Exclude("created_at").Insert()
func (*ModelQuery) Table ¶ added in v0.6.0
func (mq *ModelQuery) Table(name string) *ModelQuery
Table overrides the table name for this operation.
This is useful for partitioned tables or archival operations.
Example:
err := db.Model(&user).Table("users_archive").Insert()
func (*ModelQuery) Update ¶ added in v0.6.0
func (mq *ModelQuery) Update(attrs ...string) error
Update updates the model in the table.
The WHERE clause is automatically generated using the primary key. The primary key is detected from:
- Field with db:"id" tag
- Field with db:"*_id" tag (e.g., db:"user_id")
- Field named "ID"
Example:
user.Status = "active"
err := db.Model(&user).Update()
// UPDATE users SET name=?, email=?, status=? WHERE id=?
// Update only specific fields.
err := db.Model(&user).Update("status")
// UPDATE users SET status=? WHERE id=?
func (*ModelQuery) UpdateChanged ¶ added in v0.11.0
func (mq *ModelQuery) UpdateChanged(original interface{}) error
UpdateChanged updates only the fields that differ between the current model and the original snapshot.
It compares each field of the current model against original. Only changed fields are included in the UPDATE SET clause. Primary key fields are never included in the SET clause.
If nothing has changed, no query is executed and nil is returned. The original parameter must be the same type as the model struct.
Example:
var user User
db.Select().From("users").Where(relica.Eq("id", 1)).One(&user)
original := user
user.Name = "Alice Updated"
user.Status = "inactive"
err := db.Model(&user).UpdateChanged(&original)
// UPDATE users SET name=?, status=? WHERE id=?
func (*ModelQuery) Upsert ¶ added in v0.11.0
func (mq *ModelQuery) Upsert(fields ...string) error
Upsert performs an INSERT ... ON CONFLICT DO UPDATE for the model.
Auto-detects the conflict column from the primary key. If fields are specified, only those fields are updated on conflict. If no fields are specified, all non-PK fields are updated on conflict.
For PostgreSQL, the primary key is auto-populated after upsert (using RETURNING). For MySQL/SQLite, LastInsertId() is used when the PK is zero.
Example:
user := User{ID: 1, Name: "Alice", Email: "alice@example.com"}
err := db.Model(&user).Upsert()
// INSERT INTO users (email, id, name) VALUES (?, ?, ?)
// ON CONFLICT (id) DO UPDATE SET email=EXCLUDED.email, name=EXCLUDED.name
// Update only specific fields on conflict:
err = db.Model(&user).Upsert("name")
// ON CONFLICT (id) DO UPDATE SET name=EXCLUDED.name
func (*ModelQuery) WithContext ¶ added in v0.12.0
func (mq *ModelQuery) WithContext(ctx context.Context) *ModelQuery
WithContext sets the context for this model operation.
The context is propagated to the underlying query execution, enabling cancellation and deadline support.
Example:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() err := db.Model(&user).WithContext(ctx).Insert()
type NoopLogger ¶
type NoopLogger = logger.NoopLogger
NoopLogger is a logger that does nothing (zero overhead when logging is disabled).
type NullStringMap ¶ added in v0.9.0
type NullStringMap = core.NullStringMap
NullStringMap represents a map of nullable string values scanned from database rows. Each value is a sql.NullString that can be checked for NULL. This type is useful for dynamic queries where the schema is not known at compile time.
Example:
var result relica.NullStringMap
db.Select("*").From("users").Where("id = ?", 1).One(&result)
name := result.String("name") // returns empty string if NULL
if !result.IsNull("email") {
email := result.String("email")
}
// Multiple rows
var results []relica.NullStringMap
db.Select("*").From("users").All(&results)
type Option ¶
Option is a functional option for configuring DB.
Example:
db, err := relica.Open("postgres", dsn,
relica.WithMaxOpenConns(100),
relica.WithMaxIdleConns(50))
func WithConnMaxIdleTime ¶
WithConnMaxIdleTime sets the maximum amount of time a connection may be idle. Expired connections may be closed lazily before reuse. If duration <= 0, connections are not closed due to a connection's idle time.
Example:
db, err := relica.Open("postgres", dsn,
relica.WithConnMaxIdleTime(1*time.Minute))
func WithConnMaxLifetime ¶
WithConnMaxLifetime sets the maximum amount of time a connection may be reused. Expired connections may be closed lazily before reuse. If duration <= 0, connections are not closed due to a connection's age.
Example:
db, err := relica.Open("postgres", dsn,
relica.WithConnMaxLifetime(5*time.Minute))
func WithHealthCheck ¶
WithHealthCheck enables periodic health checks on database connections. The health checker pings the database at the specified interval to detect dead connections. If interval <= 0, health checks are disabled.
Example:
db, err := relica.Open("postgres", dsn,
relica.WithHealthCheck(30*time.Second))
func WithLogger ¶
WithLogger sets the logger for database query logging. If not set, a NoopLogger is used (zero overhead when logging is disabled).
Example:
import "log/slog"
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
db, err := relica.Open("postgres", dsn,
relica.WithLogger(logger.NewSlogAdapter(logger)))
func WithMaxIdleConns ¶
WithMaxIdleConns sets the maximum number of idle connections.
func WithMaxOpenConns ¶
WithMaxOpenConns sets the maximum number of open connections.
func WithQueryHook ¶ added in v0.9.0
WithQueryHook sets a callback function that is invoked after each query execution. Use this for logging, metrics, distributed tracing, or debugging. If not set, no hook is called (zero overhead).
Example:
db, _ := relica.Open("postgres", dsn,
relica.WithQueryHook(func(ctx context.Context, e relica.QueryEvent) {
slog.Info("query", "sql", e.SQL, "duration", e.Duration, "err", e.Error)
}))
func WithSensitiveFields ¶
WithSensitiveFields sets the list of sensitive field names for parameter masking. If not set, default sensitive field patterns are used.
Example:
db, err := relica.Open("postgres", dsn,
relica.WithSensitiveFields([]string{"password", "token", "api_key"}))
func WithStmtCacheCapacity ¶
WithStmtCacheCapacity sets the prepared statement cache capacity.
type Params ¶ added in v0.9.0
Params represents named parameter values for query binding. Named parameters are specified in SQL using {:name} syntax.
Example:
db.NewQuery("SELECT * FROM users WHERE id={:id} AND status={:status}").
BindParams(relica.Params{"id": 1, "status": "active"}).
All(&users)
type PoolStats ¶
PoolStats represents database connection pool statistics. It provides insights into connection pool health and usage patterns.
type Query ¶
type Query struct {
// contains filtered or unexported fields
}
Query represents a built query ready for execution.
Query encapsulates the SQL string, parameters, and execution context. It provides methods for executing the query and scanning results.
Example:
q := db.Builder().Select("*").From("users").Where("id = ?", 123).Build()
var user User
err := q.One(&user)
func (*Query) Bind ¶ added in v0.9.0
Bind sets positional parameters for the query. Parameters replace ? placeholders in order.
Example:
db.NewQuery("SELECT * FROM users WHERE id = ? AND status = ?").
Bind(1, "active").
One(&user)
func (*Query) BindParams ¶ added in v0.9.0
BindParams binds named parameters using Params map. Named parameters are specified using {:name} syntax.
Example:
db.NewQuery("SELECT * FROM users WHERE id = {:id}").
BindParams(relica.Params{"id": 1}).
One(&user)
func (*Query) Close ¶ added in v0.9.0
Close releases the prepared statement. Safe to call multiple times or on non-prepared queries. Returns nil if query was not prepared or already closed.
func (*Query) Column ¶ added in v0.8.0
Column scans the first column of all rows into a slice. The slice parameter must be a pointer to a slice of the appropriate type.
Example:
var ids []int
err := db.Select("id").From("users").Where("status = ?", "active").Column(&ids)
func (*Query) IsPrepared ¶ added in v0.9.0
IsPrepared returns true if Prepare() was called successfully.
func (*Query) Params ¶ added in v0.12.0
func (q *Query) Params() []interface{}
Params returns the query parameters.
func (*Query) Prepare ¶ added in v0.9.0
Prepare prepares the query for repeated execution. Call Close() when done to release the prepared statement. The prepared statement bypasses the automatic statement cache, giving you full control over the statement lifecycle.
Example:
q := db.NewQuery("SELECT * FROM users WHERE status = ?").Prepare()
defer q.Close()
for _, status := range statuses {
var users []User
q.Bind(status).All(&users)
// process users...
}
func (*Query) QueryParams
deprecated
added in
v0.9.0
func (q *Query) QueryParams() []interface{}
QueryParams returns the query parameters.
Deprecated: Use Params instead.
type QueryBuilder ¶
type QueryBuilder struct {
// contains filtered or unexported fields
}
QueryBuilder constructs type-safe queries.
The query builder provides a fluent interface for building SELECT, INSERT, UPDATE, DELETE, UPSERT, and batch operations. All queries are cached and executed with prepared statements.
Example:
qb := db.Builder()
qb.Select("*").From("users").Where("status = ?", 1).All(&users)
func (*QueryBuilder) BatchInsert ¶
func (qb *QueryBuilder) BatchInsert(table string, columns []string) *BatchInsertQuery
BatchInsert creates a batch INSERT query for multiple rows.
This is 3.3x faster than individual INSERTs for 100 rows. Use Values() or ValuesMap() to add rows.
Example:
db.Builder().BatchInsert("users", []string{"name", "email"}).
Values("Alice", "alice@example.com").
Values("Bob", "bob@example.com").
Execute()
func (*QueryBuilder) BatchInsertStruct ¶ added in v0.6.0
func (qb *QueryBuilder) BatchInsertStruct(table string, data interface{}) *Query
BatchInsertStruct builds a batch INSERT query from a slice of structs.
This is a convenience wrapper that converts each struct in the slice to column values. See DB.BatchInsertStruct for full documentation.
Example:
users := []User{
{Name: "Alice", Email: "alice@example.com"},
{Name: "Bob", Email: "bob@example.com"},
}
result, err := db.Builder().BatchInsertStruct("users", users).Execute()
func (*QueryBuilder) BatchUpdate ¶
func (qb *QueryBuilder) BatchUpdate(table, keyColumn string) *BatchUpdateQuery
BatchUpdate creates a batch UPDATE query for multiple rows.
This is 2.5x faster than individual UPDATEs for 100 rows. Uses CASE-WHEN logic to update multiple rows with different values.
Example:
db.Builder().BatchUpdate("users", "id").
Set(1, map[string]interface{}{"status": 2}).
Set(2, map[string]interface{}{"status": 3}).
Execute()
func (*QueryBuilder) Delete ¶
func (qb *QueryBuilder) Delete(table string) *DeleteQuery
Delete creates a DELETE query for the specified table.
Use Where() to filter rows to delete.
Example:
db.Builder().Delete("users").
Where("id = ?", 123).
Execute()
func (*QueryBuilder) Insert ¶
func (qb *QueryBuilder) Insert(table string, values map[string]interface{}) *Query
Insert builds an INSERT query for a single row.
The values parameter is a map of column names to values. Column order is deterministic (alphabetically sorted) for cache efficiency.
Example:
result, err := db.Builder().Insert("users", map[string]interface{}{
"name": "Alice",
"email": "alice@example.com",
"status": 1,
}).Execute()
func (*QueryBuilder) InsertStruct ¶ added in v0.6.0
func (qb *QueryBuilder) InsertStruct(table string, data interface{}) *Query
InsertStruct builds an INSERT query from a struct using db tags.
This is a convenience wrapper around Insert that converts the struct to a map using reflection. See DB.InsertStruct for full documentation.
Example:
user := User{Name: "Alice", Email: "alice@example.com"}
result, err := db.Builder().InsertStruct("users", &user).Execute()
func (*QueryBuilder) Select ¶
func (qb *QueryBuilder) Select(cols ...string) *SelectQuery
Select starts a SELECT query with the specified columns.
If no columns are provided, defaults to "*" (all columns).
Example:
db.Builder().Select("id", "name", "email").From("users").All(&users)
func (*QueryBuilder) Unwrap ¶
func (qb *QueryBuilder) Unwrap() *core.QueryBuilder
Unwrap returns the underlying core.QueryBuilder for advanced use cases.
This method is provided for edge cases where direct access to internal types is needed. Most users should not need this.
func (*QueryBuilder) Update ¶
func (qb *QueryBuilder) Update(table string) *UpdateQuery
Update creates an UPDATE query for the specified table.
Use Set() to specify column values and Where() to filter rows.
Example:
db.Builder().Update("users").
Set(map[string]interface{}{"status": 2}).
Where("id = ?", 123).
Execute()
func (*QueryBuilder) UpdateStruct ¶ added in v0.6.0
func (qb *QueryBuilder) UpdateStruct(table string, data interface{}) *UpdateQuery
UpdateStruct builds an UPDATE query from a struct using db tags.
This is a convenience wrapper around Update that converts the struct to a map using reflection. See DB.UpdateStruct for full documentation.
Example:
user := User{Name: "Alice Updated", Status: "active"}
result, err := db.Builder().UpdateStruct("users", &user).
Where("id = ?", user.ID).
Execute()
func (*QueryBuilder) Upsert ¶
func (qb *QueryBuilder) Upsert(table string, values map[string]interface{}) *UpsertQuery
Upsert creates an UPSERT query (INSERT with conflict resolution).
Supported strategies:
- PostgreSQL/SQLite: ON CONFLICT ... DO UPDATE
- MySQL: ON DUPLICATE KEY UPDATE
Example:
db.Builder().Upsert("users", map[string]interface{}{
"id": 1,
"name": "Alice",
"email": "alice@example.com",
}).OnConflict("id").DoUpdate("name", "email").Execute()
func (*QueryBuilder) WithContext ¶
func (qb *QueryBuilder) WithContext(ctx context.Context) *QueryBuilder
WithContext sets the context for all queries built by this builder.
The context will be used for all subsequent query operations unless overridden at the query level.
Example:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
qb := db.Builder().WithContext(ctx)
qb.Select("*").From("users").All(&users)
type QueryEvent ¶ added in v0.9.0
type QueryEvent = core.QueryEvent
QueryEvent contains information about an executed query. This is passed to QueryHook callbacks for logging, metrics, or tracing.
type QueryHook ¶ added in v0.9.0
QueryHook is a callback function invoked after each query execution. Use this for logging, metrics, distributed tracing, or debugging.
type SelectQuery ¶
type SelectQuery struct {
// contains filtered or unexported fields
}
SelectQuery represents a SELECT query being built.
SelectQuery supports a wide range of SQL features including:
- JOINs (INNER, LEFT, RIGHT, FULL, CROSS)
- Aggregates (COUNT, SUM, AVG, MIN, MAX)
- GROUP BY and HAVING
- ORDER BY, LIMIT, OFFSET
- Set operations (UNION, INTERSECT, EXCEPT)
- Common Table Expressions (WITH, WITH RECURSIVE)
- Subqueries (in FROM, WHERE, SELECT clauses)
Example:
sq := db.Builder().
Select("u.name", "COUNT(*) as order_count").
From("users u").
InnerJoin("orders o", "o.user_id = u.id").
GroupBy("u.id", "u.name").
Having("COUNT(*) > ?", 10).
OrderBy("order_count DESC")
sq.All(&results)
func (*SelectQuery) All ¶
func (sq *SelectQuery) All(dest interface{}) error
All scans all rows into dest slice.
Example:
var users []User
err := db.Builder().Select("*").From("users").All(&users)
func (*SelectQuery) AndSelect ¶ added in v0.13.1
func (sq *SelectQuery) AndSelect(cols ...string) *SelectQuery
AndSelect appends additional columns to the SELECT clause. Useful for conditional column building where columns are added based on runtime conditions.
Example:
q := db.Select("id", "name").From("users")
if includeEmail {
q = q.AndSelect("email")
}
if includePhone {
q = q.AndSelect("phone")
}
func (*SelectQuery) AndWhere ¶ added in v0.8.0
func (sq *SelectQuery) AndWhere(condition interface{}, params ...interface{}) *SelectQuery
AndWhere adds a WHERE condition with AND logic. If no existing WHERE clause exists, behaves like Where().
Example:
db.Builder().Select("*").From("users").
Where("status = ?", 1).
AndWhere("age > ?", 18)
func (*SelectQuery) AsExpression ¶
func (sq *SelectQuery) AsExpression() Expression
AsExpression converts a SelectQuery to an Expression for subquery use.
Example:
sub := db.Builder().Select("user_id").From("orders").Where("total > ?", 100)
db.Builder().Select("*").From("users").
Where(relica.In("id", sub.AsExpression())).All(&users)
func (*SelectQuery) Build ¶
func (sq *SelectQuery) Build() *Query
Build constructs the Query object from SelectQuery.
Example:
q := db.Builder().Select("*").From("users").Where("id = ?", 123).Build()
sql, params := q.SQL(), q.Params()
func (*SelectQuery) Column ¶ added in v0.8.0
func (sq *SelectQuery) Column(slice interface{}) error
Column scans the first column of all rows into a slice. The slice parameter must be a pointer to a slice of the appropriate type.
Example:
var ids []int
err := db.Builder().Select("id").From("users").
Where("status = ?", "active").Column(&ids)
func (*SelectQuery) Count ¶ added in v0.11.0
func (sq *SelectQuery) Count() (int64, error)
Count executes a COUNT(*) query and returns the number of matching rows. Any columns specified in Select() are ignored; COUNT(*) is always used.
Example:
count, err := db.Select().From("users").Where(relica.Eq("status", 1)).Count()
func (*SelectQuery) CrossJoin ¶
func (sq *SelectQuery) CrossJoin(table string) *SelectQuery
CrossJoin adds a CROSS JOIN clause (Cartesian product).
Example:
db.Builder().Select("*").
From("colors").
CrossJoin("sizes").
All(&results)
func (*SelectQuery) Distinct ¶ added in v0.8.0
func (sq *SelectQuery) Distinct() *SelectQuery
Distinct adds the DISTINCT keyword to the SELECT clause, eliminating duplicate rows.
Example:
db.Builder().Select("category").From("products").Distinct().All(&categories)
// SELECT DISTINCT "category" FROM "products"
func (*SelectQuery) Except ¶
func (sq *SelectQuery) Except(other *SelectQuery) *SelectQuery
Except combines queries using EXCEPT (rows in first but not second).
Database support: PostgreSQL 9.1+, MySQL 8.0.31+, SQLite 3.25+
Example:
q1 := db.Builder().Select("id").From("all_users")
q2 := db.Builder().Select("user_id").From("banned_users")
q1.Except(q2).All(&activeUsers)
func (*SelectQuery) Exists ¶ added in v0.11.0
func (sq *SelectQuery) Exists() (bool, error)
Exists executes the query wrapped in SELECT EXISTS(...) and returns true if any rows match.
Example:
exists, err := db.Select().From("users").Where(relica.Eq("email", email)).Exists()
func (*SelectQuery) From ¶
func (sq *SelectQuery) From(table string) *SelectQuery
From specifies the table to select from.
Supports table aliases: From("users u")
Example:
db.Builder().Select("*").From("users").All(&users)
func (*SelectQuery) FromSelect ¶
func (sq *SelectQuery) FromSelect(subquery *SelectQuery, alias string) *SelectQuery
FromSelect specifies a subquery as the FROM source.
The alias parameter is required for the subquery.
Example:
sub := db.Builder().Select("user_id", "COUNT(*) as cnt").
From("orders").GroupBy("user_id")
db.Builder().Select("*").FromSelect(sub, "order_counts").
Where("cnt > ?", 10).All(&results)
func (*SelectQuery) FullJoin ¶
func (sq *SelectQuery) FullJoin(table string, on interface{}) *SelectQuery
FullJoin adds a FULL OUTER JOIN clause.
Note: Not supported by MySQL.
Example:
db.Builder().Select("u.name", "o.total").
From("users u").
FullJoin("orders o", "o.user_id = u.id").
All(&results)
func (*SelectQuery) GroupBy ¶
func (sq *SelectQuery) GroupBy(columns ...string) *SelectQuery
GroupBy adds GROUP BY clause.
Multiple columns supported. Multiple GroupBy() calls are additive.
Example:
GroupBy("user_id", "status")
func (*SelectQuery) GroupByExpr ¶ added in v0.14.0
func (sq *SelectQuery) GroupByExpr(expr string, args ...interface{}) *SelectQuery
GroupByExpr adds a raw SQL expression to the GROUP BY clause. The expression is used as-is without quoting.
Example:
GroupByExpr("DATE(created_at)")
GroupByExpr("EXTRACT(YEAR FROM order_date)")
func (*SelectQuery) GroupBySub ¶ added in v0.14.1
func (sq *SelectQuery) GroupBySub(exp Expression) *SelectQuery
GroupBySub adds a type-safe expression to the GROUP BY clause.
func (*SelectQuery) Having ¶
func (sq *SelectQuery) Having(condition interface{}, args ...interface{}) *SelectQuery
Having adds HAVING clause (WHERE for aggregates).
Accepts string or Expression. Multiple calls are combined with AND.
Example:
Having("COUNT(*) > ?", 100)
func (*SelectQuery) InnerJoin ¶
func (sq *SelectQuery) InnerJoin(table string, on interface{}) *SelectQuery
InnerJoin adds an INNER JOIN clause.
Example:
db.Builder().Select("u.name", "o.total").
From("users u").
InnerJoin("orders o", "o.user_id = u.id").
All(&results)
func (*SelectQuery) Intersect ¶
func (sq *SelectQuery) Intersect(other *SelectQuery) *SelectQuery
Intersect combines queries using INTERSECT (rows in both).
Database support: PostgreSQL 9.1+, MySQL 8.0.31+, SQLite 3.25+
Example:
q1 := db.Builder().Select("id").From("users")
q2 := db.Builder().Select("user_id").From("orders")
q1.Intersect(q2).All(&ids) // Users who have placed orders
func (*SelectQuery) LeftJoin ¶
func (sq *SelectQuery) LeftJoin(table string, on interface{}) *SelectQuery
LeftJoin adds a LEFT JOIN clause.
Example:
db.Builder().Select("u.name", "o.total").
From("users u").
LeftJoin("orders o", "o.user_id = u.id").
All(&results)
func (*SelectQuery) Limit ¶
func (sq *SelectQuery) Limit(limit int64) *SelectQuery
Limit sets the LIMIT clause.
Example:
Limit(100) // Return at most 100 rows
func (*SelectQuery) Offset ¶
func (sq *SelectQuery) Offset(offset int64) *SelectQuery
Offset sets the OFFSET clause.
Example:
Offset(200) // Skip first 200 rows
func (*SelectQuery) One ¶
func (sq *SelectQuery) One(dest interface{}) error
One scans a single row into dest.
Returns sql.ErrNoRows if no row is found.
Example:
var user User
err := db.Builder().Select("*").From("users").
Where("id = ?", 123).One(&user)
func (*SelectQuery) OrWhere ¶ added in v0.8.0
func (sq *SelectQuery) OrWhere(condition interface{}, params ...interface{}) *SelectQuery
OrWhere adds a WHERE condition with OR logic. If no existing WHERE clause exists, behaves like Where().
Example:
db.Builder().Select("*").From("users").
Where("status = ?", 1).
OrWhere("role = ?", "admin")
func (*SelectQuery) OrderBy ¶
func (sq *SelectQuery) OrderBy(columns ...string) *SelectQuery
OrderBy adds ORDER BY clause with optional direction (ASC/DESC).
Supports multiple columns. Multiple OrderBy() calls are additive.
Example:
OrderBy("age DESC", "name ASC")
func (*SelectQuery) OrderByExpr ¶ added in v0.14.0
func (sq *SelectQuery) OrderByExpr(expr string, args ...interface{}) *SelectQuery
OrderByExpr adds a raw SQL expression to the ORDER BY clause. The expression is used as-is without quoting — useful for CASE WHEN, complex functions, or any expression that shouldn't be treated as a column name.
Example:
OrderByExpr("CASE WHEN status = ? THEN 0 ELSE 1 END", "active")
OrderByExpr("FIELD(id, ?, ?, ?)", 3, 1, 2)
func (*SelectQuery) OrderBySub ¶ added in v0.14.1
func (sq *SelectQuery) OrderBySub(exp Expression) *SelectQuery
OrderBySub adds a type-safe expression to the ORDER BY clause. Use with CaseWhen() or any Expression builder instead of raw SQL strings.
Example:
db.Select("id", "title").From("tasks t").
OrderBySub(relica.CaseWhen().
When("t.due_date < CURRENT_DATE", 0).
When("t.due_date IS NULL", 3).
Else(1)).
OrderBy("t.due_date ASC").
All(&rows)
func (*SelectQuery) RightJoin ¶
func (sq *SelectQuery) RightJoin(table string, on interface{}) *SelectQuery
RightJoin adds a RIGHT JOIN clause.
Example:
db.Builder().Select("u.name", "o.total").
From("users u").
RightJoin("orders o", "o.user_id = u.id").
All(&results)
func (*SelectQuery) Row ¶ added in v0.8.0
func (sq *SelectQuery) Row(dest ...interface{}) error
Row scans a single row into individual variables. Returns sql.ErrNoRows if no rows are found.
Example:
var name string
var age int
err := db.Builder().Select("name", "age").From("users").
Where("id = ?", 1).Row(&name, &age)
func (*SelectQuery) SelectExpr ¶
func (sq *SelectQuery) SelectExpr(expr string, args ...interface{}) *SelectQuery
SelectExpr adds a raw SQL expression to the SELECT clause.
Useful for scalar subqueries, window functions, or complex expressions.
Example:
db.Builder().Select("id", "name").
SelectExpr("(SELECT COUNT(*) FROM orders WHERE orders.user_id = users.id)", "order_count").
From("users").All(&results)
func (*SelectQuery) SelectSub ¶ added in v0.13.0
func (sq *SelectQuery) SelectSub(exp Expression, alias string) *SelectQuery
SelectSub adds a type-safe subquery or computed expression to the SELECT clause with a quoted alias. The expression is built with the correct dialect so identifiers are properly quoted. Prefer SelectSub over SelectExpr when you have an Expression (e.g. a correlated subquery).
Example:
sub := db.Builder().Select("COUNT(*)").From("orders").Where(relica.EqCol("orders.user_id", "users.id"))
db.Builder().Select("id", "name").SelectSub(sub.AsExpression(), "order_count").From("users").All(&results)
Generates (PostgreSQL):
SELECT "id", "name", (SELECT COUNT(*) FROM "orders" WHERE "orders"."user_id" = "users"."id") AS "order_count" FROM "users"
func (*SelectQuery) ToSQL ¶ added in v0.11.0
func (sq *SelectQuery) ToSQL() (string, []interface{})
ToSQL returns the SQL string and parameters without executing the query. This is useful for debugging, logging, or passing the query to another layer.
Example:
sql, params := db.Select().From("users").Where(relica.Eq("id", 1)).ToSQL()
func (*SelectQuery) Union ¶
func (sq *SelectQuery) Union(other *SelectQuery) *SelectQuery
Union combines this query with another using UNION (removes duplicates).
Example:
q1 := db.Builder().Select("name").From("users")
q2 := db.Builder().Select("name").From("archived_users")
q1.Union(q2).All(&names)
func (*SelectQuery) UnionAll ¶
func (sq *SelectQuery) UnionAll(other *SelectQuery) *SelectQuery
UnionAll combines this query with another using UNION ALL (keeps duplicates).
Example:
q1 := db.Builder().Select("id").From("orders_2023")
q2 := db.Builder().Select("id").From("orders_2024")
q1.UnionAll(q2).All(&orderIDs)
func (*SelectQuery) Unwrap ¶
func (sq *SelectQuery) Unwrap() *core.SelectQuery
Unwrap returns the underlying core.SelectQuery for advanced use cases.
This method is provided for edge cases where direct access to internal types is needed. Most users should not need this.
func (*SelectQuery) Where ¶
func (sq *SelectQuery) Where(condition interface{}, params ...interface{}) *SelectQuery
Where adds a WHERE condition.
Accepts either a string with placeholders or an Expression. Multiple Where() calls are combined with AND.
String example:
Where("status = ? AND age > ?", 1, 18)
Expression example:
Where(relica.And(
relica.Eq("status", 1),
relica.GreaterThan("age", 18),
))
func (*SelectQuery) With ¶
func (sq *SelectQuery) With(name string, query *SelectQuery) *SelectQuery
With adds a Common Table Expression (CTE).
Example:
cte := db.Builder().Select("user_id", "SUM(total) as total").
From("orders").GroupBy("user_id")
db.Builder().Select("*").With("order_totals", cte).
From("order_totals").Where("total > ?", 1000).All(&users)
func (*SelectQuery) WithContext ¶
func (sq *SelectQuery) WithContext(ctx context.Context) *SelectQuery
WithContext sets the context for this SELECT query.
This overrides any context set on the QueryBuilder.
Example:
sq.WithContext(ctx).All(&users)
func (*SelectQuery) WithRecursive ¶
func (sq *SelectQuery) WithRecursive(name string, query *SelectQuery) *SelectQuery
WithRecursive adds a recursive Common Table Expression.
The query MUST use UNION or UNION ALL. Database support: PostgreSQL (all), MySQL 8.0+, SQLite 3.25+
Example:
anchor := db.Builder().Select("id", "name", "manager_id", "1 as level").
From("employees").Where("manager_id IS NULL")
recursive := db.Builder().Select("e.id", "e.name", "e.manager_id", "h.level + 1").
From("employees e").InnerJoin("hierarchy h", "e.manager_id = h.id")
cte := anchor.UnionAll(recursive)
db.Builder().Select("*").WithRecursive("hierarchy", cte).
From("hierarchy").OrderBy("level", "name").All(&employees)
type SlogAdapter ¶
type SlogAdapter = logger.SlogAdapter
SlogAdapter wraps log/slog.Logger to implement the Logger interface.
func NewSlogAdapter ¶
func NewSlogAdapter(l *slog.Logger) *SlogAdapter
NewSlogAdapter creates a new logger adapter wrapping an slog.Logger.
type Tx ¶
type Tx struct {
// contains filtered or unexported fields
}
Tx represents a database transaction.
Transactions provide ACID guarantees and support all standard isolation levels. All queries executed through a transaction's builder automatically participate in that transaction.
Example:
tx, err := db.Begin(ctx)
if err != nil {
return err
}
defer tx.Rollback() // Safe to call even after Commit
_, err = tx.Insert("users", data).Execute()
if err != nil {
return err
}
return tx.Commit()
func (*Tx) BatchInsert ¶ added in v0.12.0
func (t *Tx) BatchInsert(table string, columns []string) *BatchInsertQuery
BatchInsert creates a new batch INSERT query within the transaction.
This is a convenience method equivalent to tx.Builder().BatchInsert(table, columns).
Example:
result, err := tx.BatchInsert("users", []string{"name", "email"}).
Values("Alice", "alice@example.com").
Values("Bob", "bob@example.com").
Execute()
func (*Tx) BatchInsertStruct ¶ added in v0.6.0
BatchInsertStruct creates a batch INSERT query from structs within the transaction.
This is a convenience method equivalent to tx.Builder().BatchInsertStruct(table, data). See DB.BatchInsertStruct for full documentation.
Example:
users := []User{
{Name: "Alice", Email: "alice@example.com"},
{Name: "Bob", Email: "bob@example.com"},
}
_, err := tx.BatchInsertStruct("users", users).Execute()
if err != nil {
tx.Rollback()
return err
}
func (*Tx) BatchUpdate ¶ added in v0.12.0
func (t *Tx) BatchUpdate(table, keyColumn string) *BatchUpdateQuery
BatchUpdate creates a new batch UPDATE query within the transaction.
This is a convenience method equivalent to tx.Builder().BatchUpdate(table, keyColumn).
Example:
result, err := tx.BatchUpdate("users", "id").
Set(1, map[string]interface{}{"name": "Alice"}).
Set(2, map[string]interface{}{"name": "Bob"}).
Execute()
func (*Tx) Builder ¶
func (t *Tx) Builder() *QueryBuilder
Builder returns the query builder for this transaction.
All queries built using this builder will execute within the transaction. The builder automatically inherits the transaction's context.
Example:
tx.Builder().Insert("users", data).Execute()
func (*Tx) Commit ¶
Commit commits the transaction.
After calling Commit, the transaction cannot be used for further queries.
Example:
if err := tx.Commit(); err != nil {
return err
}
func (*Tx) Delete ¶
func (t *Tx) Delete(table string) *DeleteQuery
Delete creates a new DELETE query within the transaction.
This is a convenience method equivalent to tx.Builder().Delete(table).
Example:
_, err := tx.Delete("users").Where("id = ?", 123).Execute()
if err != nil {
tx.Rollback()
return err
}
func (*Tx) Insert ¶
Insert creates a new INSERT query within the transaction.
This is a convenience method equivalent to tx.Builder().Insert(table, data).
Example:
_, err := tx.Insert("users", map[string]interface{}{
"name": "Alice",
"email": "alice@example.com",
}).Execute()
if err != nil {
tx.Rollback()
return err
}
func (*Tx) InsertStruct ¶ added in v0.6.0
InsertStruct creates an INSERT query from a struct within the transaction.
This is a convenience method equivalent to tx.Builder().InsertStruct(table, data). See DB.InsertStruct for full documentation.
Example:
user := User{Name: "Alice", Email: "alice@example.com"}
_, err := tx.InsertStruct("users", &user).Execute()
if err != nil {
tx.Rollback()
return err
}
func (*Tx) Model ¶ added in v0.6.0
func (t *Tx) Model(model interface{}) *ModelQuery
Model creates a ModelQuery within transaction context.
All operations performed through this ModelQuery will execute within the transaction.
Example:
tx, _ := db.Begin(ctx)
defer tx.Rollback()
user := User{Name: "Alice"}
err := tx.Model(&user).Insert()
if err != nil {
return err
}
return tx.Commit()
func (*Tx) NewQuery ¶ added in v0.12.0
NewQuery creates a raw SQL query within the transaction.
This is a convenience method equivalent to tx.Builder()-based raw query execution.
Example:
var count int
err := tx.NewQuery("SELECT COUNT(*) FROM users").Row(&count)
func (*Tx) Rollback ¶
Rollback rolls back the transaction.
After calling Rollback, the transaction cannot be used for further queries. It's safe to call Rollback even after Commit (it will be a no-op).
Example:
defer tx.Rollback() // Safe even after Commit
func (*Tx) Select ¶
func (t *Tx) Select(cols ...string) *SelectQuery
Select creates a new SELECT query within the transaction.
This is a convenience method equivalent to tx.Builder().Select(cols...).
Example:
var users []User
err := tx.Select("*").From("users").Where("id = ?", 123).All(&users)
if err != nil {
tx.Rollback()
return err
}
// For advanced features, use Builder()
err := tx.Builder().
With("stats", statsQuery).
Select("*").
From("stats").
All(&results)
func (*Tx) Unwrap ¶
Unwrap returns the underlying core.Tx for advanced use cases.
This method is provided for edge cases where direct access to internal types is needed. Most users should not need this.
func (*Tx) Update ¶
func (t *Tx) Update(table string) *UpdateQuery
Update creates a new UPDATE query within the transaction.
This is a convenience method equivalent to tx.Builder().Update(table).
Example:
_, err := tx.Update("users").
Set(map[string]interface{}{"status": "active"}).
Where("id = ?", 123).
Execute()
if err != nil {
tx.Rollback()
return err
}
func (*Tx) UpdateStruct ¶ added in v0.6.0
func (t *Tx) UpdateStruct(table string, data interface{}) *UpdateQuery
UpdateStruct creates an UPDATE query from a struct within the transaction.
This is a convenience method equivalent to tx.Builder().UpdateStruct(table, data). See DB.UpdateStruct for full documentation.
Example:
user := User{Name: "Alice Updated", Status: "active"}
_, err := tx.UpdateStruct("users", &user).
Where("id = ?", user.ID).
Execute()
if err != nil {
tx.Rollback()
return err
}
func (*Tx) Upsert ¶ added in v0.12.0
func (t *Tx) Upsert(table string, values map[string]interface{}) *UpsertQuery
Upsert creates a new UPSERT query within the transaction.
This is a convenience method equivalent to tx.Builder().Upsert(table, values).
Example:
result, err := tx.Upsert("users", map[string]interface{}{
"email": "alice@example.com",
"name": "Alice",
}).OnConflict("email").DoUpdate("name").Execute()
type TxOptions ¶
TxOptions represents transaction options including isolation level.
Example:
opts := &relica.TxOptions{
Isolation: sql.LevelSerializable,
ReadOnly: true,
}
tx, err := db.BeginTx(ctx, opts)
type UpdateQuery ¶
type UpdateQuery struct {
// contains filtered or unexported fields
}
UpdateQuery represents an UPDATE query being built.
func (*UpdateQuery) AndWhere ¶ added in v0.8.0
func (uq *UpdateQuery) AndWhere(condition interface{}, params ...interface{}) *UpdateQuery
AndWhere adds a WHERE condition with AND logic. If no existing WHERE clause exists, behaves like Where().
Example:
db.Builder().Update("users").
Set(map[string]interface{}{"status": 2}).
Where("id > ?", 100).
AndWhere("active = ?", true)
func (*UpdateQuery) Build ¶
func (uq *UpdateQuery) Build() *Query
Build constructs the Query object.
func (*UpdateQuery) Execute ¶
func (uq *UpdateQuery) Execute() (sql.Result, error)
Execute executes the UPDATE query.
func (*UpdateQuery) OrWhere ¶ added in v0.8.0
func (uq *UpdateQuery) OrWhere(condition interface{}, params ...interface{}) *UpdateQuery
OrWhere adds a WHERE condition with OR logic. If no existing WHERE clause exists, behaves like Where().
Example:
db.Builder().Update("users").
Set(map[string]interface{}{"status": 0}).
Where("banned = ?", true).
OrWhere("deleted = ?", true)
func (*UpdateQuery) Set ¶
func (uq *UpdateQuery) Set(values map[string]interface{}) *UpdateQuery
Set specifies the columns and values to update.
Example:
Update("users").Set(map[string]interface{}{"status": 2})
func (*UpdateQuery) ToSQL ¶ added in v0.11.0
func (uq *UpdateQuery) ToSQL() (string, []interface{})
ToSQL returns the SQL string and parameters without executing the query. This is useful for debugging, logging, or passing the query to another layer.
Example:
sql, params := db.Update("users").Set(map[string]interface{}{"status": 1}).Where(relica.Eq("id", 1)).ToSQL()
func (*UpdateQuery) Where ¶
func (uq *UpdateQuery) Where(condition interface{}, params ...interface{}) *UpdateQuery
Where adds a WHERE condition to the UPDATE query.
Example:
Update("users").Set(...).Where("id = ?", 123)
func (*UpdateQuery) WithContext ¶
func (uq *UpdateQuery) WithContext(ctx context.Context) *UpdateQuery
WithContext sets the context for this UPDATE query.
type UpsertQuery ¶
type UpsertQuery struct {
// contains filtered or unexported fields
}
UpsertQuery represents an UPSERT query being built.
func (*UpsertQuery) Build ¶
func (uq *UpsertQuery) Build() *Query
Build constructs the Query object.
func (*UpsertQuery) DoNothing ¶
func (uq *UpsertQuery) DoNothing() *UpsertQuery
DoNothing ignores conflicts (no update).
Example:
Upsert(...).OnConflict("id").DoNothing()
func (*UpsertQuery) DoUpdate ¶
func (uq *UpsertQuery) DoUpdate(columns ...string) *UpsertQuery
DoUpdate specifies which columns to update on conflict.
Example:
Upsert(...).OnConflict("id").DoUpdate("name", "email")
func (*UpsertQuery) Execute ¶
func (uq *UpsertQuery) Execute() (sql.Result, error)
Execute executes the UPSERT query.
func (*UpsertQuery) OnConflict ¶
func (uq *UpsertQuery) OnConflict(columns ...string) *UpsertQuery
OnConflict specifies the columns that determine a conflict.
Example:
Upsert(...).OnConflict("id", "email")
func (*UpsertQuery) ToSQL ¶ added in v0.12.0
func (uq *UpsertQuery) ToSQL() (string, []interface{})
ToSQL returns the SQL string and parameters without executing the query. This is useful for debugging, logging, or passing the query to another layer.
Example:
sql, params := db.Upsert("users", map[string]interface{}{"id": 1, "name": "Alice"}).
OnConflict("id").DoUpdate("name").ToSQL()
func (*UpsertQuery) WithContext ¶
func (uq *UpsertQuery) WithContext(ctx context.Context) *UpsertQuery
WithContext sets the context for this UPSERT query.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
module
|
|
|
internal
|
|
|
analyzer
Package analyzer provides database query plan analysis using EXPLAIN functionality.
|
Package analyzer provides database query plan analysis using EXPLAIN functionality. |
|
cache
Package cache provides caching utilities for database prepared statements.
|
Package cache provides caching utilities for database prepared statements. |
|
core
Package core provides the core database functionality including connection management, query building, statement caching, and result scanning for Relica.
|
Package core provides the core database functionality including connection management, query building, statement caching, and result scanning for Relica. |
|
dialects
Package dialects provides database-specific SQL dialect implementations for PostgreSQL, MySQL, and SQLite, handling identifier quoting, placeholders, and UPSERT operations.
|
Package dialects provides database-specific SQL dialect implementations for PostgreSQL, MySQL, and SQLite, handling identifier quoting, placeholders, and UPSERT operations. |
|
logger
Package logger provides logging abstractions for Relica.
|
Package logger provides logging abstractions for Relica. |
|
optimizer
Package optimizer provides query optimization analysis and suggestions.
|
Package optimizer provides query optimization analysis and suggestions. |
|
security
Package security provides SQL injection prevention, parameter validation, and query security features for Relica.
|
Package security provides SQL injection prevention, parameter validation, and query security features for Relica. |
|
util
Package util provides utility functions for context handling, string sanitization, and reflection helpers used throughout the Relica library.
|
Package util provides utility functions for context handling, string sanitization, and reflection helpers used throughout the Relica library. |