Dialects & Drivers
Supported SQL dialects, placeholder styles, and database driver setup.
Dew talks to database/sql — it never touches the driver directly. You pick any driver you want, and dew handles the rest. A dialect controls how query placeholders are rendered.
Available dialects
| Dialect | Struct | Placeholders | Example |
|---|---|---|---|
| PostgreSQL | dew.PostgreSQLDialect{} | $1, $2, $3 | WHERE id = $1 |
| MySQL | dew.MySQLDialect{} | ?, ?, ? | WHERE id = ? |
| SQLite | dew.SQLiteDialect{} | ?, ?, ? | WHERE id = ? |
| MSSQL | dew.MSSQLDialect{} | @p1, @p2, @p3 | WHERE id = @p1 |
Usage
Pass a dialect when opening a connection:
db, err := dew.Open("postgres", dsn, dew.PostgreSQLDialect{})And when defining schemas:
var Users = dew.DefineSchema("users", dew.PostgreSQLDialect{}, func(t dew.Table[User]) struct {
// ...
})The Dialect interface
type Dialect interface {
Placeholder(index int) string
}The index is zero-based. PostgreSQL's Placeholder(0) returns "$1", Placeholder(1) returns "$2", etc.
Custom dialects
Implement the Dialect interface to support other databases:
type OracleDialect struct{}
func (d OracleDialect) Placeholder(index int) string {
return fmt.Sprintf(":p%d", index+1)
}Then use it like any built-in dialect:
db, err := dew.Open("oracle", dsn, OracleDialect{})Database drivers
Dew works with any driver that registers itself with database/sql. The driver handles the actual connection; dew only builds and executes queries.
PostgreSQL
import _ "github.com/lib/pq"
db, err := dew.Open("postgres",
"postgres://user:pass@localhost/mydb?sslmode=disable",
dew.PostgreSQLDialect{},
)import _ "github.com/jackc/pgx/v5/stdlib"
db, err := dew.Open("pgx",
"postgres://user:pass@localhost/mydb?sslmode=disable",
dew.PostgreSQLDialect{},
)Or wrap an existing pgx connection pool:
import (
"github.com/jackc/pgx/v5/pgxpool"
"github.com/jackc/pgx/v5/stdlib"
)
pool, err := pgxpool.New(ctx, dsn)
sqlDB := stdlib.OpenDBFromPool(pool)
db := dew.NewDB(sqlDB, dew.PostgreSQLDialect{})MySQL
import _ "github.com/go-sql-driver/mysql"
db, err := dew.Open("mysql",
"user:pass@tcp(localhost:3306)/mydb?parseTime=true",
dew.MySQLDialect{},
)SQLite
import _ "modernc.org/sqlite"
db, err := dew.Open("sqlite", "file.db", dew.SQLiteDialect{})import _ "github.com/mattn/go-sqlite3"
db, err := dew.Open("sqlite3", "file.db", dew.SQLiteDialect{})MSSQL
import _ "github.com/microsoft/go-mssqldb"
db, err := dew.Open("sqlserver",
"sqlserver://user:pass@localhost:1433?database=mydb",
dew.MSSQLDialect{},
)Switching drivers
Since dew only depends on database/sql, switching drivers is a one-line change — swap the import and the driver name. The dialect stays the same:
// Before: lib/pq
import _ "github.com/lib/pq"
db, err := dew.Open("postgres", dsn, dew.PostgreSQLDialect{})
// After: pgx
import _ "github.com/jackc/pgx/v5/stdlib"
db, err := dew.Open("pgx", dsn, dew.PostgreSQLDialect{})All your queries, schemas, and error mappers stay unchanged.
Error mapping per driver
Each driver returns different error types. Your ErrorMapper needs to match the driver you use:
import "github.com/lib/pq"
func pqMapper(err error) error {
var pqErr *pq.Error
if !errors.As(err, &pqErr) {
return err
}
switch pqErr.Code {
case "23505":
return dew.ErrUniqueViolation
case "23503":
return dew.ErrForeignKey
case "23502":
return dew.ErrNotNull
case "23514":
return dew.ErrCheckViolation
default:
return err
}
}import "github.com/jackc/pgx/v5/pgconn"
func pgxMapper(err error) error {
var pgErr *pgconn.PgError
if !errors.As(err, &pgErr) {
return err
}
switch pgErr.Code {
case "23505":
return dew.ErrUniqueViolation
case "23503":
return dew.ErrForeignKey
case "23502":
return dew.ErrNotNull
case "23514":
return dew.ErrCheckViolation
default:
return err
}
}import "github.com/go-sql-driver/mysql"
func mysqlMapper(err error) error {
var mysqlErr *mysql.MySQLError
if !errors.As(err, &mysqlErr) {
return err
}
switch mysqlErr.Number {
case 1062:
return dew.ErrUniqueViolation
case 1452:
return dew.ErrForeignKey
case 1048:
return dew.ErrNotNull
case 3819:
return dew.ErrCheckViolation
default:
return err
}
}Then pass it when creating the DB:
db, err := dew.Open("pgx", dsn, dew.PostgreSQLDialect{},
dew.WithErrorMapper(pgxMapper),
)