Database & ORM
Nimbus provides a full-featured ORM built on GORM, inspired by Laravel-style model workflows. Configure connections, use the query builder, models, migrations, relationships, pagination, transactions, hooks, serialization, and factories.
Documentation
Detailed guides for each topic:
Configuration
Set DB_DRIVER and DB_DSN in .env. Supported drivers: sqlite, postgres, mysql.
// bin/server.go
db, err := database.Connect(config.Database.Driver, config.Database.DSN)
// With debug (pretty-print SQL in development)
db, err := database.ConnectWithConfig(database.ConnectConfig{
Driver: config.Database.Driver,
DSN: config.Database.DSN,
Debug: config.App.Env == "development",
})
| Driver | DSN example |
|---|---|
sqlite | database.sqlite |
postgres | host=localhost user=gorm password=gorm dbname=gorm port=5432 sslmode=disable |
mysql | user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True |
Query builder
Use database.From(db, "posts") for raw table queries or db.Model(&Post{}) for model queries.
// Table query (returns plain objects)
var posts []map[string]any
database.From(database.Get(), "posts").
Where("status", "published").
OrderBy("created_at desc").
Limit(10).
Get(&posts)
// Model query (returns model instances)
var posts []Post
database.Get().Model(&Post{}).
Where("status", "published").
Order("created_at desc").
Find(&posts)
Models
Embed database.Model for ID, CreatedAt, UpdatedAt, DeletedAt (soft delete),
and optionally declare metadata with Table() and Fillable().
type Post struct {
database.Model
Title string
Content string
Status string
}
// Optional: override table name for Nimbus helpers.
func (Post) Table() string { return "posts" }
// Optional: control mass-assignable fields.
func (Post) Fillable() []string {
return []string{"Title", "Content", "Status"}
}
CRUD
// Create
post := Post{Title: "Hello", Content: "World", Status: "draft"}
database.Get().Create(&post)
// Read
var p Post
database.Get().First(&p, id)
database.Get().Where("status", "published").Find(&posts)
// Update
database.Get().Model(&p).Updates(map[string]any{"title": "New Title"})
// Delete (soft delete when Model has DeletedAt)
database.Get().Delete(&p)
Pagination
database.Paginate returns a Lucid-style paginator with meta and URLs.
q := database.Get().Model(&Post{}).Where("status", "published").Order("created_at desc")
paginator, err := database.Paginate(q, &posts, page, 20)
paginator.BaseUrl("/posts")
// paginator.Data, paginator.Total, paginator.CurrentPage, paginator.LastPage
// paginator.FirstPageURL, paginator.NextPageURL, paginator.PrevPageURL
Transactions
Nimbus provides first-class support for database transactions via the nimbus.Transaction helper. This ensures data integrity by automatically committing if the function succeeds, or rolling back if an error occurs.
Managed Transactions
The following example demonstrates a bank transfer where money is debited from one account and credited to another. Both operations must succeed together.
func TransferFunds(fromID, toID uint, amount float64) error {
return nimbus.Transaction(func(tx *nimbus.DB) error {
// 1. Debit from source account
if err := tx.Model(&Account{}).Where("id = ?", fromID).
Update("balance", gorm.Expr("balance - ?", amount)).Error; err != nil {
return err // Automatically rolls back
}
// 2. Credit to destination account
if err := tx.Model(&Account{}).Where("id = ?", toID).
Update("balance", gorm.Expr("balance + ?", amount)).Error; err != nil {
return err // Automatically rolls back
}
return nil // Automatically commits
})
}
Manual Transactions
If you need more control, you can use nimbus.Begin() to start a transaction manually.
tx := nimbus.Begin()
if err := tx.Create(&Account{Name: "Savings", Balance: 1000}).Error; err != nil {
tx.Rollback()
return err
}
tx.Commit()
Relationships & eager loading
Define relations with Nimbus tags (framework-agnostic) and use
database.Preload or
database.AutoPreload to avoid N+1.
type Post struct {
database.Model
UserID uint
User User ` + "`nimbus:\"belongsTo:User,foreignKey:UserID\"`" + `
}
type User struct {
database.Model
Posts []Post ` + "`nimbus:\"hasMany:Post,foreignKey:UserID\"`" + `
}
// Eager load
database.AutoPreload(database.Get(), &Post{}).Find(&posts)
Model hooks
Register lifecycle hooks with database.RegisterHooks.
database.RegisterHooks(database.Get(), "users", database.Hooks{
BeforeCreate: func(db *gorm.DB) {
// e.g. hash password
},
AfterCreate: func(db *gorm.DB) {
// e.g. send welcome email
},
})
Serialization
Exclude sensitive fields when returning JSON with database.Serialize.
m, _ := database.Serialize(user, database.SerializeOptions{
Omit: []string{"password", "remember_token"},
})
return c.JSON(200, m)
Factories
Generate fake data for tests and seeders.
PostFactory := database.Define("posts", func(f *database.Faker) map[string]any {
return map[string]any{
"title": f.Sentence(),
"content": f.Paragraph(),
"status": "draft",
}
})
PostFactory.Create(db)
PostFactory.CreateMany(db, 10)
PostFactory.Merge(map[string]any{"status": "published"}).Create(db)
Migrations
Use database.Migration (Name, Up, Down) and database/schema for schema changes. See Migrations.
Seeders
Implement database.Seeder or use database.SeedFunc. See Seeders.