Model Query Builder
Every model can use the query builder via db.Model(&Model{}) or the typed database.QueryFor helper. Chain Where, Order, Limit, Preload, and other methods to build complex queries.
Starting a Query
db := database.Get()
// GORM-style
q := db.Model(&Post{})
// Nimbus Query helper
q := database.QueryFor(db, &Post{})
Chaining Conditions
var posts []Post
db.Model(&Post{}).
Where("status", "published").
Where("created_at > ?", time.Now().AddDate(0, 0, -7)).
Order("created_at desc").
Limit(10).
Find(&posts)
database.QueryFor
The QueryFor helper provides a chainable query builder with a cleaner API:
database.QueryFor(db, &Post{}).
Where("status", "published").
OrWhere("featured", true).
WhereNotNull("published_at").
Select("id", "title", "created_at").
OrderBy("created_at desc").
Limit(10).
Offset(20).
Get(&posts)
Query Methods
| Method | Description |
|---|---|
Where(col, val) | AND condition |
OrWhere(col, val) | OR condition |
WhereNull(col) | WHERE col IS NULL |
WhereNotNull(col) | WHERE col IS NOT NULL |
Select(cols...) | Select specific columns |
OrderBy(expr) | ORDER BY clause |
Limit(n) | Limit results |
Offset(n) | Skip rows |
Get(dest) | Execute query into dest |
Eager Loading
db.Model(&Post{}).
Preload("User").
Preload("Comments").
Preload("Comments.User").
Where("status", "published").
Find(&posts)
Pagination
Built-in pagination with metadata:
var posts []Post
page, _ := strconv.Atoi(c.Query("page", "1"))
// Simple paginate
paginator := database.Paginate(db, &posts, page, 15)
// With custom query
paginator := database.PaginateQuery(
db.Where("status = ?", "published").Order("created_at desc"),
&posts, page, 15,
)
// With base URL for link generation
paginator := database.PaginateWithBaseURL(db, &posts, page, 15, "/api/posts")
// Use in response
return c.JSON(200, map[string]any{
"data": posts,
"meta": paginator.Meta(), // { current_page, per_page, total, last_page }
})
Generic Helpers
Type-safe generic query helpers:
// FirstOrCreate — find by attrs or create
user, err := database.FirstOrCreate[User](db, User{Email: "a@b.com"})
// UpdateOrCreate — upsert
user, err := database.UpdateOrCreate[User](db,
User{Email: "a@b.com"},
map[string]any{"name": "Updated"},
)
// Check existence
exists := database.Exists(db.Model(&Post{}).Where("slug = ?", slug))
// Pluck column values
emails, err := database.Pluck[string](db.Model(&User{}), "email")
// Count with group
counts := database.CountBy(db.Model(&Post{}), "status")
// map[string]int64{"draft": 3, "published": 10}
// Chunk processing (batches of 100)
database.Chunk[Post](db, 100, func(posts []Post) error {
for _, p := range posts {
// process each post
}
return nil
})
// Cached find (with in-memory cache)
post, err := database.CachedFind[Post](db, postID, 5*time.Minute)
Transactions
// Auto-commit/rollback
err := database.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&order).Error; err != nil {
return err // auto-rollback
}
tx.Create(&payment)
return nil // auto-commit
})