Files
2026-09-07 19:28:31 +01:00

41 lines
1.2 KiB
Go

package db
import (
"context"
"database/sql"
"github.com/jmoiron/sqlx"
)
// Rebinder is implemented by sqlx.DB and sqlx.Tx. Queries remain in the
// common question-mark form until they reach the final database boundary.
type Rebinder interface {
Rebind(string) string
}
// ContextExecer is the final writer boundary used by ExecContext.
type ContextExecer interface {
Rebinder
ExecContext(context.Context, string, ...any) (sql.Result, error)
}
// Bind expands sqlx.In arguments and then rebinds placeholders exactly once.
// Callers must pass the returned query directly to the same database or
// transaction boundary; do not call Rebind on it again.
func Bind(rebinder Rebinder, query string, args ...any) (string, []any, error) {
expanded, expandedArgs, err := sqlx.In(query, args...)
if err != nil {
return "", nil, err
}
return rebinder.Rebind(expanded), expandedArgs, nil
}
// ExecContext expands, rebinds, and executes a query at its final boundary.
func ExecContext(ctx context.Context, execer ContextExecer, query string, args ...any) (sql.Result, error) {
bound, boundArgs, err := Bind(execer, query, args...)
if err != nil {
return nil, err
}
return execer.ExecContext(ctx, bound, boundArgs...)
}