package mysql import ( "context" "errors" "time" "gorm.io/gorm" "wucher/internal/domain/operation" ) type HEMSOperationalDataRepository struct { db *gorm.DB } func NewHEMSOperationalDataRepository(db *gorm.DB) *HEMSOperationalDataRepository { return &HEMSOperationalDataRepository{db: db} } func (r *HEMSOperationalDataRepository) Create(ctx context.Context, row *operation.HEMSOperationalData) error { return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { forcePresents := append([]operation.OperationalDataForcePresent(nil), row.ForcePresents...) files := append([]operation.OperationalFile(nil), row.Files...) row.ForcePresents = nil row.Files = nil if err := tx.Create(row).Error; err != nil { return err } for i := range forcePresents { forcePresents[i].OperationalDataID = row.ID if err := tx.Create(&forcePresents[i]).Error; err != nil { return err } } for i := range files { files[i].OperationalDataID = row.ID if err := tx.Create(&files[i]).Error; err != nil { return err } } row.ForcePresents = forcePresents row.Files = files return nil }) } func (r *HEMSOperationalDataRepository) GetByID(ctx context.Context, id []byte) (*operation.HEMSOperationalData, error) { var row operation.HEMSOperationalData err := r.db.WithContext(ctx). Preload("ForcePresents"). Preload("Files"). Where("id = ? AND deleted_at IS NULL", id). First(&row).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } return &row, err } func (r *HEMSOperationalDataRepository) Update(ctx context.Context, row *operation.HEMSOperationalData) error { return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { forcePresents := append([]operation.OperationalDataForcePresent(nil), row.ForcePresents...) files := append([]operation.OperationalFile(nil), row.Files...) row.ForcePresents = nil row.Files = nil if err := tx.Model(&operation.HEMSOperationalData{}). Where("id = ? AND deleted_at IS NULL", row.ID). Updates(map[string]any{ "time": row.Time, "land_id": nullableBytes(row.LandID), "vocation_id": nullableBytes(row.VocationID), "state_id": nullableBytes(row.StateID), "location": row.Location, "postcode": row.Postcode, "notes": row.Notes, "darkness": row.Darkness, "false_information": row.FalseInformation, "fog": row.Fog, "precipitation": row.Precipitation, "mountain_use": row.MountainUse, "wind": row.Wind, "nfo_search": row.NFOSearch, "landing_site_search": row.LandingSiteSearch, "temperature": row.Temperature, "altitude": row.Altitude, "terrain_index": row.TerrainIndex, "rope_recovery": row.RopeRecovery, "night_flight": row.NightFlight, "instrument_flight": row.InstrumentFlight, "additional_info": row.AdditionalInfo, "updated_by": row.UpdatedBy, "updated_at": time.Now().UTC(), }).Error; err != nil { return err } if err := tx.Where("operational_data_id = ?", row.ID).Delete(&operation.OperationalDataForcePresent{}).Error; err != nil { return err } for i := range forcePresents { forcePresents[i].OperationalDataID = row.ID if err := tx.Create(&forcePresents[i]).Error; err != nil { return err } } if err := tx.Where("operational_data_id = ?", row.ID).Delete(&operation.OperationalFile{}).Error; err != nil { return err } for i := range files { files[i].OperationalDataID = row.ID if err := tx.Create(&files[i]).Error; err != nil { return err } } row.ForcePresents = forcePresents row.Files = files return nil }) } func (r *HEMSOperationalDataRepository) Delete(ctx context.Context, id []byte, deletedBy []byte) error { now := time.Now().UTC() updates := map[string]any{ "deleted_at": now, "deleted_by": deletedBy, "updated_by": deletedBy, "updated_at": now, } return r.db.WithContext(ctx). Model(&operation.HEMSOperationalData{}). Where("id = ? AND deleted_at IS NULL", id). Updates(updates).Error } func (r *HEMSOperationalDataRepository) List(ctx context.Context, filter, sort string, limit, offset int) ([]operation.HEMSOperationalData, int64, error) { var rows []operation.HEMSOperationalData var total int64 base := r.db.WithContext(ctx).Model(&operation.HEMSOperationalData{}).Where("deleted_at IS NULL") if filter != "" { like := "%" + filter + "%" base = base.Where("location LIKE ? OR notes LIKE ? OR additional_info LIKE ? OR terrain_index LIKE ?", like, like, like, like) } query := base.Preload("ForcePresents").Preload("Files") if sort != "" { query = query.Order(sort) } if err := base.Count(&total).Error; err != nil { return nil, 0, err } if limit > 0 { query = query.Limit(limit).Offset(offset) } if err := query.Find(&rows).Error; err != nil { return nil, 0, err } return rows, total, nil } func nullableBytes(raw []byte) any { if len(raw) == 0 { return nil } return raw }