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

MethodDescription
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
})