Skip to content

v0.6.0: Struct Operations

Choose a tag to compare

@kolkov kolkov released this 23 Nov 22:42
· 201 commits to main since this release

Type-safe database operations using Go structs

We're excited to announce Relica v0.6.0 with comprehensive struct-based operations! This release eliminates manual map construction and provides two complementary approaches for working with structs.


✨ What's New

🏗️ Phase 1: InsertStruct/UpdateStruct

Explicit struct operations with full control:

type User struct {
    ID    int    `db:"id"`
    Name  string `db:"name"`
    Email string `db:"email"`
}

// Single insert
user := User{Name: "Alice", Email: "alice@example.com"}
result, err := db.InsertStruct("users", &user).Execute()

// Batch insert (multiple rows)
users := []User{
    {Name: "Alice", Email: "alice@example.com"},
    {Name: "Bob", Email: "bob@example.com"},
}
result, err := db.BatchInsertStruct("users", users).Execute()

// Update with explicit WHERE
user.Status = "active"
result, err := db.UpdateStruct("users", &user).Where("id = ?", user.ID).Execute()

🎯 Phase 2: Model() API

Elegant domain model operations with auto table/PK detection:

type User struct {
    ID    int    `db:"id"`
    Name  string `db:"name"`
    Email string `db:"email"`
}

// Implement TableName() interface
func (User) TableName() string { return "users" }

// INSERT - auto table name
user := User{Name: "Alice", Email: "alice@example.com"}
err := db.Model(&user).Insert()

// UPDATE - auto WHERE by primary key
user.Status = "active"
err = db.Model(&user).Update()
// SQL: UPDATE users SET name=?, email=?, status=? WHERE id=?

// DELETE - auto WHERE by primary key
err = db.Model(&user).Delete()
// SQL: DELETE FROM users WHERE id=?

🎁 Key Features

✅ Type safety - Compile-time struct validation
✅ Zero manual maps - No more map[string]interface{}
✅ db tag support - Uses existing struct tags
✅ Auto table name - Via TableName() interface
✅ Auto primary key - Detects db:"id" or ID field
✅ Field control - Exclude() and selective inserts
✅ Table override - .Table("custom_table")
✅ Transaction support - Works with db.Transact()
✅ Context support - Works with WithContext()
✅ Batch operations - BatchInsertStruct()


📊 When to Use Each?

Feature InsertStruct() Model().Insert()
Table name Manual Auto-detected
Primary key Manual WHERE Auto WHERE
Best for Ad-hoc data, DTOs Domain models
Boilerplate More explicit Minimal

Recommendation:

  • Use Model() for your domain models (User, Order, Product)
  • Use InsertStruct() for DTOs and temporary data structures

📖 Documentation


📦 Installation

go get github.com/coregx/relica@v0.6.0

Upgrade from v0.5.0

Zero breaking changes! All existing code continues to work.

go get -u github.com/coregx/relica
go mod tidy

🧪 Quality Metrics

  • 48 tests (27 integration + 21 unit)
  • 86% test coverage (exceeds 80% target)
  • 0 linter issues (golangci-lint clean)
  • Zero breaking changes (fully backward compatible)
  • 8.5 hours implementation (within 8-11 hour estimate)

🙏 Credits

This feature was implemented in response to real production user feedback (PubSub-Go team). Thank you for helping make Relica better!

Special thanks to:

  • PubSub-Go team for the feature request
  • All community contributors
  • Early adopters providing feedback

📝 Migration Example

Before (v0.5.0)

result, err := db.Insert("users", map[string]interface{}{
    "name":  user.Name,
    "email": user.Email,
    "age":   user.Age,
}).Execute()

After (v0.6.0) - Option 1: InsertStruct

result, err := db.InsertStruct("users", &user).Execute()

After (v0.6.0) - Option 2: Model()

err := db.Model(&user).Insert()

🔗 Links


Full Changelog: https://github.com/coregx/relica/blob/main/CHANGELOG.md#060---2025-11-24