Files

125 lines
3.5 KiB
Go

package rule
import (
"context"
"errors"
"strings"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type PageQuery struct {
PageIndex int `form:"pageIndex"`
PageSize int `form:"pageSize"`
Name string `form:"name"`
Enabled *bool `form:"enabled"`
}
type Service struct{ DB *gorm.DB }
func NewService(db *gorm.DB) Service { return Service{DB: db} }
func (s Service) List(ctx context.Context, query PageQuery) ([]Rule, int64, error) {
page, size := pageValues(query.PageIndex, query.PageSize)
db := s.DB.WithContext(ctx).Model(&Rule{})
if name := strings.TrimSpace(query.Name); name != "" {
db = db.Where("name ILIKE ? OR code ILIKE ?", "%"+name+"%", "%"+name+"%")
}
if query.Enabled != nil {
db = db.Where("enabled = ?", *query.Enabled)
}
var count int64
if err := db.Count(&count).Error; err != nil {
return nil, 0, err
}
items := make([]Rule, 0)
err := db.Order("created_at DESC, id DESC").Offset((page - 1) * size).Limit(size).Find(&items).Error
return items, count, err
}
func (s Service) Create(ctx context.Context, input WriteInput, actorID int) (Rule, error) {
normalized, err := Normalize(input, true)
if err != nil {
return Rule{}, err
}
now := time.Now().UTC()
item := Rule{
ID: uuid.NewString(), Code: normalized.Code, Name: normalized.Name, Enabled: true,
EventType: normalized.EventType, MinimumSeverity: normalized.MinimumSeverity,
LocationContains: normalized.LocationContains, Version: 1,
CreatedBy: actorID, UpdatedBy: actorID, CreatedAt: now, UpdatedAt: now,
}
if err = s.DB.WithContext(ctx).Create(&item).Error; err != nil {
return Rule{}, err
}
return item, nil
}
func (s Service) Update(ctx context.Context, id string, input WriteInput, actorID int) (Rule, error) {
if _, err := uuid.Parse(id); err != nil {
return Rule{}, ErrNotFound
}
normalized, err := Normalize(input, false)
if err != nil {
return Rule{}, err
}
var item Rule
err = s.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&item, "id = ?", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrNotFound
}
return err
}
updates := map[string]any{
"name": normalized.Name, "event_type": normalized.EventType,
"minimum_severity": normalized.MinimumSeverity, "location_contains": normalized.LocationContains,
"version": item.Version + 1, "updated_by": actorID, "updated_at": time.Now().UTC(),
}
if err := tx.Model(&item).Updates(updates).Error; err != nil {
return err
}
return tx.First(&item, "id = ?", id).Error
})
return item, err
}
func (s Service) SetEnabled(ctx context.Context, id string, enabled bool, actorID int) (Rule, error) {
if _, err := uuid.Parse(id); err != nil {
return Rule{}, ErrNotFound
}
var item Rule
err := s.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&item, "id = ?", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrNotFound
}
return err
}
if item.Enabled == enabled {
return nil
}
if err := tx.Model(&item).Updates(map[string]any{
"enabled": enabled, "version": item.Version + 1,
"updated_by": actorID, "updated_at": time.Now().UTC(),
}).Error; err != nil {
return err
}
return tx.First(&item, "id = ?", id).Error
})
return item, err
}
func pageValues(page, size int) (int, int) {
if page < 1 {
page = 1
}
if size < 1 || size > 100 {
size = 20
}
return page, size
}