con un clic
sqlex
sqlex is a modern enhancement wrapper for Go database/sql based on jmoiron/sqlx,
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
sqlex is a modern enhancement wrapper for Go database/sql based on jmoiron/sqlx,
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
| name | sqlex |
| description | sqlex is a modern enhancement wrapper for Go database/sql based on jmoiron/sqlx, |
This document is a decision reference for AI programming assistants, focused on "what API to use, how to use it, and what pitfalls to avoid". For full documentation (installation, testing, migration guide, etc.), see README.md.
Positioning: Go database/sql enhancement wrapper (not an ORM), upgraded from jmoiron/sqlx.
Module path: github.com/go-sqlex/sqlex
Go version: 1.21+ | Databases: PostgreSQL, MySQL, SQLite, Oracle, SQL Server
Key Design:
? placeholder; framework auto-Rebinds to $N/@pN/:argNBindExt + NamedExt); function signatures accept anyUnsafe()); can enable strict checkingNeed to query?
├─ Single row → db.Get(&dest, query, args...) or db.NamedGet(&dest, query, arg)
├─ Multiple rows → db.Select(&dest, query, args...) or db.NamedSelect(&dest, query, arg)
└─ Raw rows → db.Queryx / db.QueryRowx or db.NamedQuery
Need to execute?
├─ Normal → db.Exec / db.MustExec or db.NamedExec
└─ In transaction → tx.Exec / tx.CloseWithErr(err) or tx.NamedExec
Need prepared statements?
├─ Positional → db.Preparex / db.PreparexContext
├─ Named → db.PrepareNamed / db.PrepareNamedContext
└─ Note: Prepared stmts do not support IN slice expansion (placeholders fixed at Prepare time)
Need single connection? → db.Connx(ctx) → conn (aligned with DB/Tx interface)
Need JSON column? → types.JSONValue[T] (generic, replaces JSONText)
db, err := sqlex.Connect("postgres", dsn) // with Ping
db, err := sqlex.Open("mysql", dsn) // no Ping
db := sqlex.MustConnect("sqlite3", ":memory:") // panics on failure
? placeholder)// Positional args — framework auto-Rebinds; MySQL/PG/SQLite/SQL Server unified syntax
db.Get(&user, "SELECT * FROM users WHERE id = ?", 1)
db.Select(&users, "SELECT * FROM users WHERE age > ?", 18)
// Named args — supports struct or map[string]any
db.NamedGet(&user, `SELECT * FROM users WHERE name = :name`, map[string]any{"name": "Alice"})
db.NamedSelect(&users, `SELECT * FROM users WHERE age > :min_age`, map[string]any{"min_age": 18})
db.NamedExec(`INSERT INTO users (name, email) VALUES (:name, :email)`, User{Name: "Alice", Email: "a@b.c"})
// Positional args: auto-detects slice + IN list context recognition
db.Select(&users, "SELECT * FROM users WHERE id IN (?)", []int{1, 2, 3})
// Named args: built-in IN expansion
db.NamedSelect(&users, `SELECT * FROM users WHERE id IN (:ids)`, map[string]any{"ids": []int{1, 2, 3}})
IN list context recognition: slice auto-expansion requires both ① strict (?) form (only ? + optional whitespace between ( and )) and ② the complete identifier before ( is IN (case-insensitive, including NOT IN). Other (?) contexts are treated as single values — no AsValue needed.
| SQL pattern | Slice arg | Behavior |
|---|---|---|
IN (?) / NOT IN (?) | slice | Expand |
IN (?, ?, ?) | scalars | No expand |
WHERE x = ? | slice | No expand (single value) |
ANY(?) / ALL(?) / VALUES (?) / func(?) | slice | No expand (correct behavior) |
col_in (?) / t.in (?) | slice | No expand (full token comparison) |
Escape hatches: sqlex.AsValue(v) force no expand (even in IN context) | sqlex.AsList(slice) force expand (even outside IN context, e.g. ANY(?))
Known edge case: IN /* comment */ (?) prevents IN recognition; use AsList as fallback.
tx, err := db.Beginx()
if err != nil {
return err
}
defer func() { tx.CloseWithErr(err) }() // err==nil → Commit, err!=nil → Rollback
_, err = tx.NamedExec(`INSERT INTO users (name) VALUES (:name)`, User{Name: "Bob"})
if err != nil {
return err // auto-Rollback in defer
}
return nil // auto-Commit in defer
conn, err := db.Connx(ctx)
defer conn.Close()
// Conn fully aligned with DB/Tx interface
conn.Get(&user, "SELECT * FROM users WHERE id = ?", 1)
conn.NamedGet(&user, `SELECT * FROM users WHERE name = :name`, map[string]any{"name": "Alice"})
import "github.com/go-sqlex/sqlex/types"
type Config struct {
ID int `db:"id"`
Settings types.JSONValue[Settings] `db:"settings"`
}
cfg := Config{Settings: types.NewJSONValue(Settings{Theme: "dark", FontSize: 14})}
if cfg.Settings.Valid {
theme := cfg.Settings.Val.Theme // "dark"
}
// Val is zero value when !Valid
type MetricsHook struct{}
func (h *MetricsHook) BeforeQuery(ctx context.Context, event *sqlex.QueryEvent) context.Context {
return ctx
}
func (h *MetricsHook) AfterQuery(ctx context.Context, event *sqlex.QueryEvent) {
recordMetric(event.Query, event.Duration, event.Error, event.OperationType, event.RowsAffected)
}
db.AddHook(&MetricsHook{})
// Hooks also apply to Tx/Conn (auto-inherited)
// Multiple Hooks: BeforeQuery forward order, AfterQuery reverse order (onion model)
// Covers full lifecycle: OpQuery/OpExec/OpBegin/OpCommit/OpRollback
Conditional filtering: sqlex does not ship a built-in filter; use decorators:
// Only fire on slow queries
db.AddHook(SlowOnly(&AlertHook{}, 500*time.Millisecond))
// SlowOnly / OnError etc. are trivial to implement yourself
? placeholder — All query methods auto-RebindCloseWithErr for transactions — defer func() { tx.CloseWithErr(err) }()GetContext/SelectContext for timeout controlStmt/NamedStmt hold sql.Stmt, use defer stmt.Close() to avoid resource leaksIn()AsValue needed? operator — Use ?? escapedb.SetStrict(true) for developmentinit() — Use DB.MapperFunc() at runtime instead[A-Za-z_][A-Za-z0-9_.]*; digit-starting :123 not recognizeddb.Select/db.NamedSelect for IN queriessql.Stmt, forgetting Close() causes resource leaks until DB.Close()db.Unsafe() behavior| Feature | Description |
|---|---|
| Hook aspects | AddHook pluggable SQL interceptors (onion model) |
| JSONValue[T] | Generic JSON column type |
| NamedGet/NamedSelect | Convenient named parameter queries (built-in IN expansion) |
| CloseWithErr | Auto Commit/Rollback based on error |
| NamedExt/BindExt | DB/Tx unified programming interface |
| Select/Get auto-IN | Detects slice args + IN list context recognition (only IN (?) expands) |
| StrictMode | Default lenient, can enable strict checking |
| Auto-Rebind | All query methods auto-convert ? |
| Conn enhancement | Fully aligned with DB/Tx interface |
| SQL Server bracket identifiers | scanBracketIdentifier supports [col?name] |
scanSkipSegment, eliminating drift? inside strings/comments/PG double quotes/MySQL backticks/SQL Server brackets/PG dollar quoting[A-Za-z_][A-Za-z0-9_.]*; digit-starting not misidentified| Function | Description |
|---|---|
Connect/ConnectContext/MustConnect | Connect to database (with Ping) |
Open/MustOpen | Open connection (no Ping) |
Select/SelectContext | Query multiple rows (accepts Queryer) |
Get/GetContext | Query single row (accepts Queryer) |
In | Expand IN slice args |
AsValue | Force no expansion (even in IN(?) context) |
AsList | Force expansion (even outside IN(?) context) |
Named | Named parameter binding |
Rebind | Convert bind variable format |
Beginx/BeginTxx, Connx, AddHook, MapperFunc, Preparex/PreparexContext, PrepareNamed/PrepareNamedContext, SetStrict/IsStrict
CloseWithErr(err), Stmtx/StmtxContext, TryStmtx/TryStmtxContext, SetStrict/IsStrict
Get/GetContext, Select/SelectContext, Queryx/QueryxContext, QueryRowx/QueryRowxContext, Exec/ExecContext, MustExec/MustExecContext, NamedGet/NamedGetContext, NamedSelect/NamedSelectContext, NamedExec/NamedExecContext, NamedQuery/NamedQueryContext, Rebind, BindNamed
Context: GetContext, SelectContext, QueryxContext, QueryRowxContext, ExecContext, MustExecContext, NamedGetContext, NamedSelectContext, NamedExecContext, NamedQueryContext
Non-Context (delegate context.Background()): Get, Select, Queryx, QueryRowx, Exec, MustExec, NamedGet, NamedSelect, NamedExec, NamedQuery
Utility: Rebind, BindNamed, DriverName, SetStrict/IsStrict, BeginTxx, PreparexContext, PrepareNamedContext
| Type | Description |
|---|---|
JSONValue[T] | Generic JSON column (Scan/Value + MarshalJSON/UnmarshalJSON; Val/Valid direct access) |
JSONText | json.RawMessage wrapper, supports Scan/Value |
NullJSONText | Nullable JSONText |
GzippedText | Auto gzip compress/decompress []byte |
BitBool | MySQL BIT(1) boolean type |
| Type | Description |
|---|---|
Hook interface | BeforeQuery(ctx, *QueryEvent) ctx + AfterQuery(ctx, *QueryEvent) |
QueryEvent | Contains Query, Args, StartTime, Duration, Error, OperationType, RowsAffected, LastInsertID |
OpType | Operation type enum: OpQuery/OpExec/OpBegin/OpCommit/OpRollback |