Query Scopes

Scopes are reusable query fragments. Nimbus provides built-in scopes for common patterns, and you can define custom scopes as functions that accept *gorm.DB and return *gorm.DB.

Custom Scopes

func Published(db *gorm.DB) *gorm.DB {
    return db.Where("status = ?", "published")
}

func Recent(db *gorm.DB) *gorm.DB {
    return db.Where("created_at > ?", time.Now().AddDate(0, 0, -30))
}

// Usage
var posts []Post
db.Model(&Post{}).Scopes(Published, Recent).Find(&posts)

Scopes with Arguments

func Status(status string) func(*gorm.DB) *gorm.DB {
    return func(db *gorm.DB) *gorm.DB {
        return db.Where("status = ?", status)
    }
}

func OlderThan(days int) func(*gorm.DB) *gorm.DB {
    return func(db *gorm.DB) *gorm.DB {
        return db.Where("created_at < ?", time.Now().AddDate(0, 0, -days))
    }
}

db.Model(&Post{}).Scopes(Status("draft"), OlderThan(7)).Find(&posts)

Built-in Scopes

Nimbus includes pre-built scopes in the database package:

ScopeSQLDescription
WhereScope(col, val)WHERE col = valSimple equality filter
OrderScope(expr)ORDER BY exprOrder results
LatestScope(col)ORDER BY col DESCNewest first
OldestScope(col)ORDER BY col ASCOldest first
LimitScope(n)LIMIT nLimit results
WhenScope(cond, scope)ConditionalApply scope only when condition is true
import "github.com/CodeSyncr/nimbus/database"

// Latest posts
db.Scopes(database.LatestScope("created_at"), database.LimitScope(10)).Find(&posts)

// Conditional scope (filter by status only if parameter provided)
status := c.Query("status", "")
db.Scopes(
    database.WhenScope(status != "", database.WhereScope("status", status)),
    database.LatestScope("created_at"),
).Find(&posts)

Soft Delete Scopes

When models use gorm.DeletedAt, soft-deleted records are auto-excluded. Use these scopes to include them:

// Include soft-deleted records
db.Scopes(database.WithTrashed).Find(&posts)

// Only soft-deleted records
db.Scopes(database.OnlyTrashed).Find(&posts)

// Restore a soft-deleted record
database.Restore(db, &post)

// Permanently delete (bypass soft delete)
database.ForceDelete(db, &post)

// Check if model is soft-deleted
if database.IsTrashed(&post) {
    // ...
}

Combining Scopes

// Build queries dynamically
scopes := []func(*gorm.DB) *gorm.DB{
    database.LatestScope("created_at"),
}

if filterStatus != "" {
    scopes = append(scopes, Status(filterStatus))
}
if onlyRecent {
    scopes = append(scopes, Recent)
}

db.Model(&Post{}).Scopes(scopes...).Find(&posts)