Repository navigation
Getting Started
This page takes you from go get to running your first queries.
On this page: Install · Choose a mode · Build only · Build and run · Options · Your first queries · Next steps
go get github.com/akfaiz/quillimport "github.com/akfaiz/quill/db"quill has no third-party runtime dependencies. You bring your own database/sql driver (pgx, go-sql-driver/mysql, a SQLite driver, ...). It requires Go 1.25 or newer.
There are two entry points. Both return a *db.DB.
| Function | Needs a connection | Use it to | |
|---|---|---|---|
| Build only | db.Use(dialect, opts...) |
No | Produce (sql, args) for your own driver, tests or logging |
| Build and run | db.New(conn, dialect, opts...) |
Yes | Build and execute |
From a *db.DB you start a statement:
| Start with | Returns | Purpose |
|---|---|---|
Select(cols...).From("t") |
*db.SelectBuilder |
Read rows |
Insert("t") |
*db.InsertBuilder |
Insert rows |
Update("t") |
*db.UpdateBuilder |
Update rows |
Delete("t") |
*db.DeleteBuilder |
Delete rows |
Each builder exposes only the methods that are valid for its statement. An insert has no Where, and only a select has GroupBy.
Set the dialect once and reuse it:
pg := db.Use(db.Postgres)
sql, args, err := pg.Select().From("users").Where("id", 7).ToSQL()
// SELECT * FROM "users" WHERE "id" = $1 args: [7]
sql, args, err = pg.Update("users").Set("name", "Anna").Where("id", 7).ToSQL()
// UPDATE "users" SET "name" = $1 WHERE "id" = $2 args: [Anna 7]Running a query on a build-only DB returns db.ErrNotBound. It never panics.
db.New accepts anything with QueryContext and ExecContext (the db.Conn interface): *sql.DB, *sql.Tx and *sql.Conn all qualify.
import (
"database/sql"
"github.com/akfaiz/quill/db"
_ "github.com/jackc/pgx/v5/stdlib" // any database/sql driver
)
sqlDB, err := sql.Open("pgx", dsn) // load dsn from config or a secret store, never hard-code it
if err != nil {
return err
}
conn := db.New(sqlDB, db.Postgres)Dialect constants: db.Postgres, db.MySQL, db.MariaDB, db.SQLite. The dialect decides quoting ("x" or `x`), placeholders ($1 or ?) and dialect-specific clauses. See Dialect Differences.
Tip: call the variable
conn, notdb. A variable nameddbhides the package inside its scope.
Both constructors accept the same options.
| Option | Effect |
|---|---|
db.WithPrefix("app_") |
Prefixes table names, aliases and qualified columns. From("users as u") becomes "app_users" AS "app_u"
|
db.WithHook(fn) |
Calls fn(ctx, db.QueryEvent) after every statement (logging, metrics, tracing) |
db.WithLogArgs() |
Includes bind values in QueryEvent.Args. Off by default because arguments can be personal data |
conn := db.New(sqlDB, db.Postgres,
db.WithPrefix("app_"),
db.WithHook(func(ctx context.Context, e db.QueryEvent) {
log.Printf("%s args=%d took=%s err=%v", e.SQL, e.NumArgs, e.Duration, e.Err)
}),
)More in Hooks and Options.
ctx := context.Background()
type User struct {
ID int64
Name string
Email *string // pointer: NULL becomes nil
Active bool
}
// Read many
var users []User
err := conn.Select().From("users").Where("active", true).OrderBy("id").Get(ctx, &users)
// Read one by id (db.ErrNotFound when missing)
var u User
err = conn.Select().From("users").Find(ctx, 7, &u)
// Insert and get the new id
id, err := conn.Insert("users").Values(map[string]any{"name": "Ann"}).ExecGetID(ctx)
// Update, returns rows affected
n, err := conn.Update("users").Set("name", "Anna").Where("id", id).Exec(ctx)
// Delete
n, err = conn.Delete("users").Where("id", id).Exec(ctx)Every method that touches the database takes a context.Context first and honours cancellation.
Give the struct a TableName() and use the Typed API:
type User struct {
ID int64 `db:"id,omitempty"`
Name string `db:"name"`
Email *string `db:"email"`
}
func (User) TableName() string { return "users" }
users, err := db.From[User](conn).Where("active", true).OrderBy("id").Get(ctx) // []Usererr := conn.Transaction(ctx, func(tx *db.DB) error {
if _, err := tx.Update("accounts").Decrement("balance", 50).Where("id", 1).Exec(ctx); err != nil {
return err // rolls back
}
_, err := tx.Update("accounts").Increment("balance", 50).Where("id", 2).Exec(ctx)
return err // nil commits
})- Core Concepts: understand how builders and errors behave.
- Select Queries and Where Clauses: build real queries.
- Cookbook: ready-made recipes.
quill wiki · v0.2.0 · Repository · pkg.go.dev · Report an issue · MIT License
Basics
Building queries
Data access
- Writing Data
- Reading Data
- Pagination and Chunking
- Transactions
- Typed API
- Struct Mapping
- Hooks and Options
Reference
Guides