Documentation
¶
Overview ¶
Package dbrepo provides composable SQL fragment helpers for building queries.
Functions in this package use @Name placeholders (e.g., @ID, @Name) which rely on database/sql's sql.Named() for driver-level parameter translation. This is distinct from the chuck.Dialect.Placeholder() method which returns engine-specific positional syntax ($1, ?, @p1) for raw SQL composition.
The @Name convention works because database/sql drivers translate sql.NamedArg values into their native parameter syntax at execution time. This means dbrepo output is dialect-agnostic — the same query string works across all engines when paired with sql.Named() arguments.
For identifier quoting, use the Q-suffixed variants (ColumnsQ, SetClauseQ, InsertIntoQ) which accept a chuck.Dialect and quote table/column names via QuoteIdentifier.
Index ¶
- Variables
- func BuildOrderByClause(sortStr string, columnMap map[string]string, defaultSort string) string
- func BuildSearchCondition(search, searchPattern string, fields ...string) string
- func BuildSearchPattern(search string) string
- func ClearArchive(archivedAt *sql.NullTime)
- func ClearExpiry(expiresAt *sql.NullTime)
- func ClearReplacement(replacedByID *sql.NullInt64)
- func Columns(cols ...string) string
- func ColumnsQ(d chuck.Identifier, cols ...string) string
- func GetNow() time.Time
- func IncrementVersion(version *int)
- func InitVersion(version *int)
- func InsertInto(table string, cols ...string) string
- func InsertIntoQ(d chuck.Identifier, table string, cols ...string) string
- func NamedArgs(m map[string]any) []any
- func Placeholders(cols ...string) string
- func SetArchive(archivedAt *time.Time)
- func SetClause(cols ...string) string
- func SetClauseQ(d chuck.Identifier, cols ...string) string
- func SetCreateAudit(createdBy, updatedBy *string, user string)
- func SetCreateTimestamps(createdAt, updatedAt *time.Time)
- func SetDeleteAudit(deletedAt *time.Time, deletedBy *string, user string)
- func SetExpiry(expiresAt *time.Time, t time.Time)
- func SetReplacement(replacedByID *int64, id int64)
- func SetSoftDelete(deletedAt *time.Time)
- func SetSortOrder(sortOrder *int, order int)
- func SetStatus(status *string, value string)
- func SetUpdateAudit(updatedBy *string, user string)
- func SetUpdateTimestamp(updatedAt *time.Time)
- type SelectBuilder
- func (s *SelectBuilder) Build() (query string, args []any)
- func (s *SelectBuilder) CountQuery() (query string, args []any)
- func (s *SelectBuilder) OrderBy(clause string) *SelectBuilder
- func (s *SelectBuilder) OrderByMap(sortStr string, columnMap map[string]string, defaultSort string) *SelectBuilder
- func (s *SelectBuilder) Paginate(limit, offset int) *SelectBuilder
- func (s *SelectBuilder) Where(w *WhereBuilder) *SelectBuilder
- func (s *SelectBuilder) WithDialect(d chuck.Dialect) *SelectBuilder
- type SortField
- type WhereBuilder
- func (w *WhereBuilder) And(condition string, args ...any) *WhereBuilder
- func (w *WhereBuilder) AndIf(ok bool, condition string, args ...any) *WhereBuilder
- func (w *WhereBuilder) Args() []any
- func (w *WhereBuilder) HasConditions() bool
- func (w *WhereBuilder) HasParent(parentID int64, col ...string) *WhereBuilder
- func (w *WhereBuilder) HasStatus(status string, col ...string) *WhereBuilder
- func (w *WhereBuilder) HasVersion(version int, col ...string) *WhereBuilder
- func (w *WhereBuilder) IsRoot(col ...string) *WhereBuilder
- func (w *WhereBuilder) NotArchived(col ...string) *WhereBuilder
- func (w *WhereBuilder) NotArchivedBool(col ...string) *WhereBuilder
- func (w *WhereBuilder) NotDeleted(col ...string) *WhereBuilder
- func (w *WhereBuilder) NotExpired(col ...string) *WhereBuilder
- func (w *WhereBuilder) NotReplaced(col ...string) *WhereBuilder
- func (w *WhereBuilder) Or(condition string, args ...any) *WhereBuilder
- func (w *WhereBuilder) OrIf(ok bool, condition string, args ...any) *WhereBuilder
- func (w *WhereBuilder) ReplacedBy(id int64, col ...string) *WhereBuilder
- func (w *WhereBuilder) Search(search string, fields ...string) *WhereBuilder
- func (w *WhereBuilder) String() string
- func (w *WhereBuilder) WithDialect(d chuck.Dialect) *WhereBuilder
Examples ¶
- BuildOrderByClause
- Columns
- ColumnsQ
- InitVersion
- InsertInto
- InsertIntoQ
- NamedArgs
- NewSelect
- NewWhere
- Placeholders
- SelectBuilder.CountQuery
- SelectBuilder.OrderByMap
- SelectBuilder.WithDialect
- SetClause
- SetClauseQ
- SetCreateTimestamps
- SetStatus
- WhereBuilder (DomainFilters)
- WhereBuilder (TreeQueries)
- WhereBuilder.AndIf
- WhereBuilder.NotDeleted
- WhereBuilder.Search
Constants ¶
This section is empty.
Variables ¶
var NowFunc = time.Now
NowFunc is the function used to get the current time. Override this in tests to freeze or control time:
dbrepo.NowFunc = func() time.Time { return fixedTime }
Functions ¶
func BuildOrderByClause ¶
BuildOrderByClause builds an ORDER BY clause from a sort string. columnMap maps user-friendly column names to SQL column names. defaultSort is used when sortStr is empty or produces no valid columns.
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
columnMap := map[string]string{
"name": "Name",
"created_at": "CreatedAt",
}
fmt.Println(dbrepo.BuildOrderByClause("name:asc", columnMap, "ID ASC"))
fmt.Println(dbrepo.BuildOrderByClause("", columnMap, "ID ASC"))
fmt.Println(dbrepo.BuildOrderByClause("unknown:desc", columnMap, "ID ASC"))
}
Output: ORDER BY Name ASC ORDER BY ID ASC ORDER BY ID ASC
func BuildSearchCondition ¶
BuildSearchCondition builds a search condition for WHERE clauses. Returns "(field1 LIKE @SearchPattern OR field2 LIKE @SearchPattern)".
func BuildSearchPattern ¶
BuildSearchPattern builds a LIKE search pattern from a search string. Returns "%search%" or empty string if search is empty.
func ClearArchive ¶
ClearArchive sets a sql.NullTime to NULL (Valid = false) to unarchive.
func ClearExpiry ¶
ClearExpiry sets a sql.NullTime to NULL (Valid = false) to remove expiry.
func ClearReplacement ¶
ClearReplacement sets a sql.NullInt64 to NULL (Valid = false).
func Columns ¶
Columns joins column names into a comma-separated list.
Columns("ID", "Name", "Email") => "ID, Name, Email"
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
fmt.Println(dbrepo.Columns("ID", "Name", "Email"))
}
Output: ID, Name, Email
func ColumnsQ ¶
func ColumnsQ(d chuck.Identifier, cols ...string) string
ColumnsQ joins column names into a comma-separated list with dialect quoting.
ColumnsQ(d, "ID", "Name", "Email") => `"ID", "Name", "Email"` (Postgres/SQLite)
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
d, _ := chuck.New(chuck.Postgres)
fmt.Println(dbrepo.ColumnsQ(d, "ID", "Name", "Email"))
}
Output: "ID", "Name", "Email"
func IncrementVersion ¶
func IncrementVersion(version *int)
IncrementVersion increments Version by 1.
func InitVersion ¶
func InitVersion(version *int)
InitVersion sets Version to 1 for a new record.
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
var version int
dbrepo.InitVersion(&version)
fmt.Println("Version:", version)
dbrepo.IncrementVersion(&version)
fmt.Println("After increment:", version)
}
Output: Version: 1 After increment: 2
func InsertInto ¶
InsertInto builds a full INSERT INTO … VALUES … statement.
InsertInto("Users", "Name", "Email") =>
"INSERT INTO Users (Name, Email) VALUES (@Name, @Email)"
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
fmt.Println(dbrepo.InsertInto("Users", "Name", "Email"))
}
Output: INSERT INTO Users (Name, Email) VALUES (@Name, @Email)
func InsertIntoQ ¶
func InsertIntoQ(d chuck.Identifier, table string, cols ...string) string
InsertIntoQ builds a full INSERT INTO … VALUES … statement with dialect quoting.
InsertIntoQ(d, "Users", "Name", "Email") =>
`INSERT INTO "Users" ("Name", "Email") VALUES (@Name, @Email)` (Postgres/SQLite)
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
d, _ := chuck.New(chuck.Postgres)
fmt.Println(dbrepo.InsertIntoQ(d, "Users", "Name", "Email"))
}
Output: INSERT INTO "Users" ("Name", "Email") VALUES (@Name, @Email)
func NamedArgs ¶
NamedArgs converts a map to a slice of sql.NamedArg values suitable for passing to database/sql query methods. Keys are sorted for deterministic output.
Example ¶
package main
import (
"database/sql"
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
args := dbrepo.NamedArgs(map[string]any{
"Name": "Alice",
"Email": "alice@test.com",
})
// Keys are sorted for deterministic output
for _, arg := range args {
na := arg.(sql.NamedArg)
fmt.Printf("%s=%v\n", na.Name, na.Value)
}
}
Output: Email=alice@test.com Name=Alice
func Placeholders ¶
Placeholders returns named placeholders for the given columns.
Placeholders("ID", "Name", "Email") => "@ID, @Name, @Email"
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
fmt.Println(dbrepo.Placeholders("ID", "Name", "Email"))
}
Output: @ID, @Name, @Email
func SetArchive ¶
SetArchive sets ArchivedAt to the current time.
func SetClause ¶
SetClause builds a SET fragment for UPDATE statements.
SetClause("Name", "Email") => "Name = @Name, Email = @Email"
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
fmt.Println(dbrepo.SetClause("Name", "Email"))
}
Output: Name = @Name, Email = @Email
func SetClauseQ ¶
func SetClauseQ(d chuck.Identifier, cols ...string) string
SetClauseQ builds a SET fragment for UPDATE statements with dialect quoting.
SetClauseQ(d, "Name", "Email") => `"Name" = @Name, "Email" = @Email` (Postgres/SQLite)
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
d, _ := chuck.New(chuck.Postgres)
fmt.Println(dbrepo.SetClauseQ(d, "Name", "Email"))
}
Output: "Name" = @Name, "Email" = @Email
func SetCreateAudit ¶
SetCreateAudit sets CreatedBy and UpdatedBy for a new record.
func SetCreateTimestamps ¶
SetCreateTimestamps sets CreatedAt and UpdatedAt to current time.
Example ¶
package main
import (
"fmt"
"time"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
// Freeze time for deterministic output
fixed := time.Date(2025, 6, 15, 12, 0, 0, 0, time.UTC)
dbrepo.NowFunc = func() time.Time { return fixed }
defer func() { dbrepo.NowFunc = time.Now }()
type Task struct {
CreatedAt time.Time
UpdatedAt time.Time
}
var t Task
dbrepo.SetCreateTimestamps(&t.CreatedAt, &t.UpdatedAt)
fmt.Println("CreatedAt:", t.CreatedAt.Format(time.RFC3339))
fmt.Println("UpdatedAt:", t.UpdatedAt.Format(time.RFC3339))
}
Output: CreatedAt: 2025-06-15T12:00:00Z UpdatedAt: 2025-06-15T12:00:00Z
func SetDeleteAudit ¶
SetDeleteAudit sets DeletedAt and DeletedBy for a soft-delete with audit trail.
func SetReplacement ¶
SetReplacement sets ReplacedByID to the given ID.
func SetSoftDelete ¶
SetSoftDelete sets DeletedAt to the current time for soft-delete.
func SetSortOrder ¶
SetSortOrder sets the SortOrder value.
func SetStatus ¶
SetStatus sets the Status value.
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
var status string
dbrepo.SetStatus(&status, "published")
fmt.Println(status)
}
Output: published
func SetUpdateAudit ¶
SetUpdateAudit sets UpdatedBy for an updated record.
func SetUpdateTimestamp ¶
SetUpdateTimestamp sets UpdatedAt to current time.
Types ¶
type SelectBuilder ¶
type SelectBuilder struct {
// contains filtered or unexported fields
}
SelectBuilder constructs composable SELECT queries with WHERE, ORDER BY, and pagination.
func NewSelect ¶
func NewSelect(table string, cols ...string) *SelectBuilder
NewSelect creates a new SelectBuilder for the given table and columns.
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
query, _ := dbrepo.NewSelect("Tasks", "ID", "Title", "Status").
Where(
dbrepo.NewWhere().
NotDeleted().
HasStatus("active"),
).
OrderBy("Title ASC").
Paginate(20, 0).
Build()
fmt.Println(query)
}
Output: SELECT ID, Title, Status FROM Tasks WHERE DeletedAt IS NULL AND Status = @Status ORDER BY Title ASC LIMIT @Limit OFFSET @Offset
func (*SelectBuilder) Build ¶
func (s *SelectBuilder) Build() (query string, args []any)
Build returns the complete SQL query string and the collected arguments.
func (*SelectBuilder) CountQuery ¶
func (s *SelectBuilder) CountQuery() (query string, args []any)
CountQuery returns a COUNT(*) query using the same FROM and WHERE clauses.
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
w := dbrepo.NewWhere().HasStatus("active")
sb := dbrepo.NewSelect("Tasks", "ID", "Title").Where(w)
countQuery, _ := sb.CountQuery()
fmt.Println(countQuery)
}
Output: SELECT COUNT(*) FROM Tasks WHERE Status = @Status
func (*SelectBuilder) OrderBy ¶
func (s *SelectBuilder) OrderBy(clause string) *SelectBuilder
OrderBy sets the ORDER BY clause (e.g., "Name ASC" or "CreatedAt DESC, Name ASC").
func (*SelectBuilder) OrderByMap ¶
func (s *SelectBuilder) OrderByMap(sortStr string, columnMap map[string]string, defaultSort string) *SelectBuilder
OrderByMap builds an ORDER BY clause from a sort string and column map, with a default fallback. The sortStr format is "column:direction" (e.g., "name:asc" or "created_at:desc"). Multiple sorts can be separated by commas: "name:asc,created_at:desc".
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
columnMap := map[string]string{
"title": "Title",
"created_at": "CreatedAt",
"status": "Status",
}
query, _ := dbrepo.NewSelect("Tasks", "ID", "Title", "Status").
OrderByMap("title:asc,created_at:desc", columnMap, "ID ASC").
Build()
fmt.Println(query)
}
Output: SELECT ID, Title, Status FROM Tasks ORDER BY Title ASC, CreatedAt DESC
func (*SelectBuilder) Paginate ¶
func (s *SelectBuilder) Paginate(limit, offset int) *SelectBuilder
Paginate sets LIMIT and OFFSET for pagination.
func (*SelectBuilder) Where ¶
func (s *SelectBuilder) Where(w *WhereBuilder) *SelectBuilder
Where sets the WhereBuilder for filtering.
func (*SelectBuilder) WithDialect ¶
func (s *SelectBuilder) WithDialect(d chuck.Dialect) *SelectBuilder
WithDialect sets the dialect for pagination clause generation.
Example ¶
package main
import (
"database/sql"
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
d, _ := chuck.New(chuck.Postgres)
query, _ := dbrepo.NewSelect("tasks", "id", "title").
Where(dbrepo.NewWhere().And("id = @ID", sql.Named("ID", 1))).
WithDialect(d).
Build()
fmt.Println(query)
}
Output: SELECT id, title FROM "tasks" WHERE id = @ID
type SortField ¶
SortField represents a column and sort direction.
func ParseSortString ¶
ParseSortString parses a sort string like "name:asc,created_at:desc" into column/direction pairs.
type WhereBuilder ¶
type WhereBuilder struct {
// contains filtered or unexported fields
}
WhereBuilder constructs composable WHERE clauses with named parameters.
Example (DomainFilters) ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
w := dbrepo.NewWhere().
NotDeleted().
NotExpired().
HasStatus("active").
NotReplaced()
fmt.Println(w.String())
}
Output: WHERE DeletedAt IS NULL AND (ExpiresAt IS NULL OR ExpiresAt > CURRENT_TIMESTAMP) AND Status = @Status AND ReplacedByID IS NULL
Example (TreeQueries) ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
// Find root nodes
roots := dbrepo.NewWhere().IsRoot()
fmt.Println("Roots:", roots.String())
// Find children of a specific node
children := dbrepo.NewWhere().HasParent(42)
fmt.Println("Children:", children.String())
}
Output: Roots: WHERE ParentID IS NULL Children: WHERE ParentID = @ParentID
func NewWhere ¶
func NewWhere() *WhereBuilder
NewWhere creates a new WhereBuilder.
Example ¶
package main
import (
"database/sql"
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
w := dbrepo.NewWhere().
And("DepartmentID = @DeptID", sql.Named("DeptID", 5)).
And("Active = @Active", sql.Named("Active", true))
fmt.Println(w.String())
}
Output: WHERE DepartmentID = @DeptID AND Active = @Active
func (*WhereBuilder) And ¶
func (w *WhereBuilder) And(condition string, args ...any) *WhereBuilder
And adds an AND condition with optional named args.
func (*WhereBuilder) AndIf ¶
func (w *WhereBuilder) AndIf(ok bool, condition string, args ...any) *WhereBuilder
AndIf adds an AND condition only when ok is true.
Example ¶
package main
import (
"database/sql"
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
// AndIf only adds the condition when the first argument is true.
// This is useful for optional filters from user input.
searchTerm := "alice"
minAge := 0 // zero means no filter
w := dbrepo.NewWhere().
And("Active = 1").
AndIf(searchTerm != "", "Name LIKE @Pattern", sql.Named("Pattern", "%"+searchTerm+"%")).
AndIf(minAge > 0, "Age >= @MinAge", sql.Named("MinAge", minAge))
fmt.Println(w.String())
}
Output: WHERE Active = 1 AND Name LIKE @Pattern
func (*WhereBuilder) Args ¶
func (w *WhereBuilder) Args() []any
Args returns the collected named arguments.
func (*WhereBuilder) HasConditions ¶
func (w *WhereBuilder) HasConditions() bool
HasConditions reports whether any conditions have been added.
func (*WhereBuilder) HasParent ¶
func (w *WhereBuilder) HasParent(parentID int64, col ...string) *WhereBuilder
HasParent adds a "ParentID = @ParentID" condition. Pass an optional column name to override the default "ParentID".
func (*WhereBuilder) HasStatus ¶
func (w *WhereBuilder) HasStatus(status string, col ...string) *WhereBuilder
HasStatus adds a "Status = @Status" condition. Pass an optional column name to override the default "Status".
func (*WhereBuilder) HasVersion ¶
func (w *WhereBuilder) HasVersion(version int, col ...string) *WhereBuilder
HasVersion adds a "Version = @Version" condition for optimistic locking. Pass an optional column name to override the default "Version".
func (*WhereBuilder) IsRoot ¶
func (w *WhereBuilder) IsRoot(col ...string) *WhereBuilder
IsRoot adds a "ParentID IS NULL" condition for tree root nodes. Pass an optional column name to override the default "ParentID".
func (*WhereBuilder) NotArchived ¶
func (w *WhereBuilder) NotArchived(col ...string) *WhereBuilder
NotArchived adds an "ArchivedAt IS NULL" condition for archive filtering. Pass an optional column name to override the default "ArchivedAt".
func (*WhereBuilder) NotArchivedBool ¶
func (w *WhereBuilder) NotArchivedBool(col ...string) *WhereBuilder
NotArchivedBool adds a condition for boolean archived columns. Generates "NOT archived" for Postgres/SQLite, "archived = 0" for MSSQL. Pass an optional column name to override the default "archived".
func (*WhereBuilder) NotDeleted ¶
func (w *WhereBuilder) NotDeleted(col ...string) *WhereBuilder
NotDeleted adds a "DeletedAt IS NULL" condition for soft-delete filtering. Pass an optional column name to override the default "DeletedAt".
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
w := dbrepo.NewWhere().NotDeleted()
fmt.Println(w.String())
// With a custom column name for snake_case schemas
w2 := dbrepo.NewWhere().NotDeleted("deleted_at")
fmt.Println(w2.String())
}
Output: WHERE DeletedAt IS NULL WHERE deleted_at IS NULL
func (*WhereBuilder) NotExpired ¶
func (w *WhereBuilder) NotExpired(col ...string) *WhereBuilder
NotExpired adds a condition that filters out expired records. Pass an optional column name to override the default "ExpiresAt".
func (*WhereBuilder) NotReplaced ¶
func (w *WhereBuilder) NotReplaced(col ...string) *WhereBuilder
NotReplaced adds a "ReplacedByID IS NULL" condition for current (non-replaced) records. Pass an optional column name to override the default "ReplacedByID".
func (*WhereBuilder) Or ¶
func (w *WhereBuilder) Or(condition string, args ...any) *WhereBuilder
Or adds an OR branch to the previous condition.
func (*WhereBuilder) OrIf ¶
func (w *WhereBuilder) OrIf(ok bool, condition string, args ...any) *WhereBuilder
OrIf adds an OR condition only when ok is true.
func (*WhereBuilder) ReplacedBy ¶
func (w *WhereBuilder) ReplacedBy(id int64, col ...string) *WhereBuilder
ReplacedBy adds a "ReplacedByID = @ReplacedByID" condition. Pass an optional column name to override the default "ReplacedByID".
func (*WhereBuilder) Search ¶
func (w *WhereBuilder) Search(search string, fields ...string) *WhereBuilder
Search adds a LIKE search condition across the given fields. When a dialect is set via WithDialect, Postgres uses ILIKE for case-insensitive matching. Field names are validated to prevent SQL injection — only alphanumeric characters, underscores, and dots (for qualified names) are allowed.
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/dbrepo"
)
func main() {
d, _ := chuck.New(chuck.Postgres)
w := dbrepo.NewWhere().WithDialect(d).
NotDeleted("deleted_at").
Search("chuck", "name", "bio")
fmt.Println(w.String())
}
Output: WHERE deleted_at IS NULL AND (name ILIKE @SearchPattern OR bio ILIKE @SearchPattern)
func (*WhereBuilder) String ¶
func (w *WhereBuilder) String() string
String returns the full WHERE clause or an empty string when no conditions exist.
func (*WhereBuilder) WithDialect ¶
func (w *WhereBuilder) WithDialect(d chuck.Dialect) *WhereBuilder
WithDialect sets the dialect for dialect-aware operations (e.g. ILIKE on Postgres).