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.Builder().Select("*").From("users").All(&users)
Features ¶
CRUD Operations:
// SELECT
db.Builder().Select("*").From("users").Where("id = ?", 123).One(&user)
// INSERT
db.Builder().Insert("users", map[string]interface{}{
"name": "Alice",
"email": "alice@example.com",
}).Execute()
// UPDATE
db.Builder().Update("users").
Set(map[string]interface{}{"status": "active"}).
Where("id = ?", 123).
Execute()
// DELETE
db.Builder().Delete("users").Where("id = ?", 123).Execute()
Index ¶
- Variables
- type BatchInsertQuery
- func (biq *BatchInsertQuery) Build() *Query
- func (biq *BatchInsertQuery) Execute() (sql.Result, error)
- 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
- type CaseExp
- type CoalesceExp
- type ConcatExp
- type DB
- func (d *DB) BatchInsertStruct(table string, data interface{}) *Query
- 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() 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) 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) Where(condition interface{}, params ...interface{}) *DeleteQuery
- func (dq *DeleteQuery) WithContext(ctx context.Context) *DeleteQuery
- type Expression
- type GreatestLeastExp
- type HashExp
- type LikeExp
- type Logger
- type ModelQuery
- type NoopLogger
- type NullIfExp
- type NullStringMap
- type 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) Prepare() *Query
- func (q *Query) QueryParams() []interface{}
- 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) 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) CrossJoin(table string) *SelectQuery
- func (sq *SelectQuery) Distinct(v bool) *SelectQuery
- func (sq *SelectQuery) Except(other *SelectQuery) *SelectQuery
- 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) 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) 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) 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) BatchInsertStruct(table string, data interface{}) *Query
- 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) 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
- 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) 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) WithContext(ctx context.Context) *UpsertQuery
Constants ¶
This section is empty.
Variables ¶
var And = core.And
And combines expressions with AND.
var Between = core.Between
Between creates a BETWEEN expression (column BETWEEN low AND high).
var Case = core.Case
Case creates a simple CASE expression.
var CaseWhen = core.CaseWhen
CaseWhen creates a searched CASE expression (without column).
var Coalesce = core.Coalesce
Coalesce creates a COALESCE expression.
var Concat = core.Concat
Concat creates a string concatenation expression.
var DetectOperation = core.DetectOperation
DetectOperation detects the SQL operation type (SELECT, INSERT, UPDATE, DELETE, UNKNOWN).
var Eq = core.Eq
Eq creates an equality expression (column = value).
var Exists = core.Exists
Exists creates an EXISTS subquery expression.
var GreaterOrEqual = core.GreaterOrEqual
GreaterOrEqual creates a greater-or-equal expression (column >= value).
var GreaterThan = core.GreaterThan
GreaterThan creates a greater-than expression (column > value).
var Greatest = core.Greatest
Greatest creates a GREATEST expression.
var In = core.In
In creates an IN expression (column IN (values...)).
var Least = core.Least
Least creates a LEAST expression.
var LessOrEqual = core.LessOrEqual
LessOrEqual creates a less-or-equal expression (column <= value).
var LessThan = core.LessThan
LessThan creates a less-than expression (column < value).
var Like = core.Like
Like creates a LIKE expression with automatic escaping.
var NewExp = core.NewExp
NewExp creates a new raw SQL expression.
var NewSlogAdapter = logger.NewSlogAdapter
NewSlogAdapter creates a new logger adapter wrapping an slog.Logger.
var Not = core.Not
Not negates an expression.
var NotBetween = core.NotBetween
NotBetween creates a NOT BETWEEN expression.
var NotEq = core.NotEq
NotEq creates a not-equal expression (column != value).
var NotExists = core.NotExists
NotExists creates a NOT EXISTS subquery expression.
var NotIn = core.NotIn
NotIn creates a NOT IN expression (column NOT IN (values...)).
var NotLike = core.NotLike
NotLike creates a NOT LIKE expression.
var NullIf = core.NullIf
NullIf creates a NULLIF expression.
var Or = core.Or
Or combines expressions with OR.
var OrLike = core.OrLike
OrLike creates a LIKE expression combined with OR.
var OrNotLike = core.OrNotLike
OrNotLike creates a NOT LIKE expression combined with OR.
var WithConnMaxIdleTime = core.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))
var WithConnMaxLifetime = core.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))
var WithHealthCheck = core.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))
var WithLogger = core.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)))
var WithMaxIdleConns = core.WithMaxIdleConns
WithMaxIdleConns sets the maximum number of idle connections.
var WithMaxOpenConns = core.WithMaxOpenConns
WithMaxOpenConns sets the maximum number of open connections.
var WithQueryHook = core.WithQueryHook
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)
}))
var WithSensitiveFields = core.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"}))
var WithStmtCacheCapacity = core.WithStmtCacheCapacity
WithStmtCacheCapacity sets the prepared statement cache capacity.
Functions ¶
This section is empty.
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) 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) WithContext ¶
func (buq *BatchUpdateQuery) WithContext(ctx context.Context) *BatchUpdateQuery
WithContext sets the context for this batch UPDATE query.
type CoalesceExp ¶ added in v0.9.0
type CoalesceExp = core.CoalesceExp
CoalesceExp represents a SQL 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 NewDB ¶
NewDB creates a database connection (deprecated: use Open).
This function exists for backward compatibility. New code should use Open.
Example:
db, err := relica.NewDB("postgres", dsn)
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) 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) 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.Builder().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 unique parameter placeholder name.
This is useful when building dynamic SQL queries.
Example:
ph := db.GenerateParamName() // Returns: p1, p2, p3, etc.
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) 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) 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)
type GreatestLeastExp ¶ added in v0.9.0
type GreatestLeastExp = core.GreatestLeastExp
GreatestLeastExp represents a SQL GREATEST or 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=?
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))
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) 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 ¶ added in v0.9.0
func (q *Query) QueryParams() []interface{}
QueryParams returns the query parameters.
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) 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) 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(v bool) *SelectQuery
Distinct sets whether to select distinct rows. When enabled, adds DISTINCT keyword to the SELECT clause to eliminate duplicate rows. Multiple calls to Distinct() override previous settings.
Example:
db.Builder().Select("category").From("products").Distinct(true).All(&categories)
// SELECT DISTINCT "category" FROM "products"
db.Builder().Select("*").From("users").Distinct(false).All(&users)
// SELECT * FROM "users"
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) 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) 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) 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) 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.
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.Builder().Insert("users", data).Execute()
if err != nil {
return err
}
return tx.Commit()
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) 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) 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
}
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) 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) WithContext ¶
func (uq *UpsertQuery) WithContext(ctx context.Context) *UpsertQuery
WithContext sets the context for this UPSERT query.
Directories
¶
| Path | Synopsis |
|---|---|
|
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. |