Models
The models package provides the BaseModelImpl struct that serves as the foundation for all GORM models in a Gofasta application. It includes UUID primary keys, automatic timestamp management, soft delete support, optimistic locking via RecordVersion, and boolean flags IsActive and IsDeletable.
Import
import "github.com/gofastadev/gofasta/pkg/models"Key Types
BaseModel
The interface that all Gofasta models implement.
type BaseModel interface {
gorm.Model
GetID() uuid.UUID
GetCreatedAt() time.Time
GetUpdatedAt() time.Time
GetDeletedAt() time.Time
GetIsActive() bool
GetIsDeletable() bool
GetRecordVersion() int
}BaseModelImpl
The concrete base struct to embed in all your GORM models.
type BaseModelImpl struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;"`
CreatedAt time.Time `gorm:"type:timestamp;not null;"`
UpdatedAt time.Time `gorm:"type:timestamp;not null;"`
DeletedAt time.Time `gorm:"type:timestamp;"`
RecordVersion int `gorm:"type:int;not null;default:1"`
IsActive bool `gorm:"type:bool;not null;default:true"`
IsDeletable bool `gorm:"type:bool;not null;default:true"`
}Key Functions
| Function | Signature | Description |
|---|---|---|
GetID | func (b BaseModelImpl) GetID() uuid.UUID | Returns the model’s UUID |
GetCreatedAt | func (b BaseModelImpl) GetCreatedAt() time.Time | Returns the creation timestamp |
GetUpdatedAt | func (b BaseModelImpl) GetUpdatedAt() time.Time | Returns the last update timestamp |
GetDeletedAt | func (b BaseModelImpl) GetDeletedAt() time.Time | Returns the soft-delete timestamp |
GetIsActive | func (b BaseModelImpl) GetIsActive() bool | Returns whether the record is active |
GetIsDeletable | func (b BaseModelImpl) GetIsDeletable() bool | Returns whether the record can be deleted |
GetRecordVersion | func (b BaseModelImpl) GetRecordVersion() int | Returns the current version for optimistic locking |
BeforeCreate | func (b *BaseModelImpl) BeforeCreate(tx *gorm.DB) error | GORM hook that generates a UUID and sets defaults before insert |
Usage
Defining a Model
Embed BaseModelImpl in your domain models to inherit UUID, timestamps, soft delete, and versioning.
type User struct {
models.BaseModelImpl
Name string `gorm:"type:varchar(255);not null" json:"name"`
Email string `gorm:"type:varchar(255);uniqueIndex;not null" json:"email"`
Password string `gorm:"type:varchar(255);not null" json:"-"`
Role string `gorm:"type:varchar(50);default:'user'" json:"role"`
}
type Post struct {
models.BaseModelImpl
Title string `gorm:"type:varchar(255);not null" json:"title"`
Content string `gorm:"type:text" json:"content"`
AuthorID string `gorm:"type:uuid;not null" json:"author_id"`
Author User `gorm:"foreignKey:AuthorID" json:"author,omitempty"`
}Automatic UUID Generation
The BeforeCreate hook automatically generates a UUID v4 for new records and sets default values for IsActive, IsDeletable, and RecordVersion.
user := User{Name: "Jane", Email: "jane@example.com"}
db.Create(&user)
fmt.Println(user.ID) // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
fmt.Println(user.IsActive) // true
fmt.Println(user.IsDeletable) // true
fmt.Println(user.RecordVersion) // 1Soft Delete
GORM’s soft delete is built in. Calling Delete sets deleted_at instead of removing the row.
// Soft delete
db.Delete(&user)
fmt.Println(user.IsDeleted()) // true
// Query excludes soft-deleted records by default
db.Find(&users) // only returns non-deleted users
// Include soft-deleted records
db.Unscoped().Find(&users) // returns all users
// Permanently delete
db.Unscoped().Delete(&user)Optimistic Locking
Use the RecordVersion field to prevent lost updates in concurrent scenarios. Note that a database trigger automatically increments record_version on update, but you can also check it at the application level.
func (r *UserRepository) Update(ctx context.Context, user *User) error {
result := r.db.Model(user).
Where("record_version = ?", user.RecordVersion).
Updates(map[string]interface{}{
"name": user.Name,
"email": user.Email,
"record_version": user.RecordVersion + 1,
})
if result.RowsAffected == 0 {
return errors.New("CONFLICT", "record was modified by another request", 409)
}
return result.Error
}Auto-Migration
db, err := config.SetupDBWithMigrate(cfg.Database, &User{}, &Post{})