CRUD Operations

Create, Read, Update, and Delete operations on models through database.Get(). Nimbus extends GORM with type-safe generic helpers for common patterns.

Create

// Single record
post := Post{Title: "Hello", Content: "World", Status: "draft"}
result := database.Get().Create(&post)
// post.ID, post.CreatedAt, post.UpdatedAt are automatically set

// Batch create
posts := []Post{
    {Title: "First", Status: "draft"},
    {Title: "Second", Status: "published"},
}
database.Get().Create(&posts)

Read

db := database.Get()

// By primary key
var post Post
db.First(&post, 1)

// By condition
db.First(&post, "slug = ?", "hello-world")

// Find or error (returns gorm.ErrRecordNotFound)
err := db.First(&post, "id = ?", id).Error

// All records
var posts []Post
db.Find(&posts)

// With conditions
db.Where("status = ?", "published").Find(&posts)

// Count
var count int64
db.Model(&Post{}).Where("status = ?", "published").Count(&count)

Update

// Update single field
db.Model(&post).Update("title", "New Title")

// Update multiple fields
db.Model(&post).Updates(map[string]any{
    "title":  "New Title",
    "status": "published",
})

// Update with struct (only non-zero fields)
db.Model(&post).Updates(Post{Title: "New", Status: "published"})

// Save full model (insert or update)
post.Title = "Updated Title"
post.Content = "New content"
db.Save(&post)

Delete

// Soft delete (when model has gorm.DeletedAt field)
db.Delete(&post)

// Hard delete (bypass soft delete)
db.Unscoped().Delete(&post)

// Delete by condition
db.Where("status = ?", "draft").Delete(&Post{})

FirstOrCreate / UpdateOrCreate

// Find by attributes, or create if not found
db.Where(Post{Slug: "unique-post"}).FirstOrCreate(&post)

// With additional attributes on create
db.Where(User{Email: "a@b.com"}).
    Attrs(User{Name: "Default Name"}).
    FirstOrCreate(&user)

// Generic helper (type-safe)
user, err := database.FirstOrCreate[User](db, User{Email: "a@b.com"})

// UpdateOrCreate — upsert (find or create + update)
user, err := database.UpdateOrCreate[User](db,
    User{Email: "a@b.com"},               // search attributes
    map[string]any{"name": "Updated"},     // attributes to update
)

Generic Helpers

FunctionDescription
FirstOrCreate[T](db, attrs)Find or create, returns typed result
UpdateOrCreate[T](db, where, update)Upsert with typed result
Exists(query)Returns true if any record matches
Pluck[T](query, col)Extract column values as typed slice
CountBy(query, col)Group-count into map[string]int64
Chunk[T](db, size, fn)Process records in batches
CachedFind[T](db, id, ttl)Find with in-memory cache
// Check if a slug exists
if database.Exists(db.Model(&Post{}).Where("slug = ?", slug)) {
    return c.JSON(409, map[string]string{"error": "slug taken"})
}

// Get all emails
emails, _ := database.Pluck[string](db.Model(&User{}), "email")

// Count posts by status
stats := database.CountBy(db.Model(&Post{}), "status")
// map[string]int64{"draft": 3, "published": 10, "archived": 2}

// Process 50,000 users in batches of 100
database.Chunk[User](db, 100, func(users []User) error {
    for _, u := range users {
        sendNewsletter(u)
    }
    return nil
})

Transactions

err := database.Transaction(func(tx *gorm.DB) error {
    if err := tx.Create(&order).Error; err != nil {
        return err // auto-rollback
    }
    if err := tx.Create(&payment).Error; err != nil {
        return err // auto-rollback
    }
    return nil // auto-commit
})