Skip to Content

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

FunctionSignatureDescription
GetIDfunc (b BaseModelImpl) GetID() uuid.UUIDReturns the model’s UUID
GetCreatedAtfunc (b BaseModelImpl) GetCreatedAt() time.TimeReturns the creation timestamp
GetUpdatedAtfunc (b BaseModelImpl) GetUpdatedAt() time.TimeReturns the last update timestamp
GetDeletedAtfunc (b BaseModelImpl) GetDeletedAt() time.TimeReturns the soft-delete timestamp
GetIsActivefunc (b BaseModelImpl) GetIsActive() boolReturns whether the record is active
GetIsDeletablefunc (b BaseModelImpl) GetIsDeletable() boolReturns whether the record can be deleted
GetRecordVersionfunc (b BaseModelImpl) GetRecordVersion() intReturns the current version for optimistic locking
BeforeCreatefunc (b *BaseModelImpl) BeforeCreate(tx *gorm.DB) errorGORM 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) // 1

Soft 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{})
  • Config — Database setup and connection
  • Seeds — Seed initial data for models
  • Types — Shared type definitions
Last updated on