package mysql import ( "context" "errors" "gorm.io/gorm" "wucher/internal/domain/mcf" ) type MCFRepository struct{ db *gorm.DB } func NewMCFRepository(db *gorm.DB) *MCFRepository { return &MCFRepository{db: db} } func (r *MCFRepository) Create(ctx context.Context, row *mcf.MaintenanceCheckFlight) error { return r.db.WithContext(ctx).Create(row).Error } func (r *MCFRepository) Update(ctx context.Context, row *mcf.MaintenanceCheckFlight) error { return r.db.WithContext(ctx).Save(row).Error } func (r *MCFRepository) Delete(ctx context.Context, id []byte, deletedBy []byte) error { return r.db.WithContext(ctx).Model(&mcf.MaintenanceCheckFlight{}). Where("id = ? AND deleted_at IS NULL", id). Updates(map[string]any{"deleted_at": gorm.Expr("NOW(3)"), "deleted_by": deletedBy, "updated_by": deletedBy}).Error } func (r *MCFRepository) GetByID(ctx context.Context, id []byte) (*mcf.MaintenanceCheckFlight, error) { var row mcf.MaintenanceCheckFlight err := r.db.WithContext(ctx). 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 *MCFRepository) GetLatestByHelicopter(ctx context.Context, helicopterID []byte) (*mcf.MaintenanceCheckFlight, error) { var row mcf.MaintenanceCheckFlight err := r.db.WithContext(ctx). Where("helicopter_id = ? AND deleted_at IS NULL", helicopterID). Order("created_at DESC"). First(&row).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } return &row, err } func (r *MCFRepository) ListByHelicopter(ctx context.Context, helicopterID []byte) ([]mcf.MaintenanceCheckFlight, error) { rows := make([]mcf.MaintenanceCheckFlight, 0) err := r.db.WithContext(ctx). Where("helicopter_id = ? AND deleted_at IS NULL", helicopterID). Order("created_at DESC"). Find(&rows).Error return rows, err } // LatestByHelicopterIDs returns the latest (non-deleted) MCF per helicopter, keyed by // helicopter id (raw bytes as string). Helicopters without an MCF are simply absent. func (r *MCFRepository) LatestByHelicopterIDs(ctx context.Context, helicopterIDs [][]byte) (map[string]*mcf.MaintenanceCheckFlight, error) { out := make(map[string]*mcf.MaintenanceCheckFlight, len(helicopterIDs)) if len(helicopterIDs) == 0 { return out, nil } rows := make([]mcf.MaintenanceCheckFlight, 0) err := r.db.WithContext(ctx). Where("helicopter_id IN ? AND deleted_at IS NULL AND id = (SELECT m2.id FROM maintenance_check_flights m2 WHERE m2.helicopter_id = maintenance_check_flights.helicopter_id AND m2.deleted_at IS NULL ORDER BY m2.created_at DESC, m2.id DESC LIMIT 1)", helicopterIDs). Find(&rows).Error if err != nil { return out, err } for i := range rows { out[string(rows[i].HelicopterID)] = &rows[i] } return out, nil } // HelicopterHasOpenMCF reports whether the helicopter has a draft MCF (created but not // yet completed/signed). Enforces one open MCF per helicopter. func (r *MCFRepository) HelicopterHasOpenMCF(ctx context.Context, helicopterID []byte) (bool, error) { var count int64 err := r.db.WithContext(ctx).Model(&mcf.MaintenanceCheckFlight{}). Where("helicopter_id = ? AND deleted_at IS NULL AND completed_at IS NULL AND cancelled_at IS NULL", helicopterID). Count(&count).Error if err != nil { return false, err } return count > 0, nil } func (r *MCFRepository) PendingHelicopterIDs(ctx context.Context, helicopterIDs [][]byte) (map[string]bool, error) { out := make(map[string]bool) if len(helicopterIDs) == 0 { return out, nil } type rowT struct { HelicopterID []byte `gorm:"column:helicopter_id"` } rows := make([]rowT, 0) err := r.db.WithContext(ctx). Table("maintenance_check_flights m"). Select("m.helicopter_id"). Where("m.deleted_at IS NULL AND m.cancelled_at IS NULL AND m.helicopter_id IN ? AND m.id = (SELECT m2.id FROM maintenance_check_flights m2 WHERE m2.helicopter_id = m.helicopter_id AND m2.deleted_at IS NULL AND m2.cancelled_at IS NULL ORDER BY m2.created_at DESC, m2.id DESC LIMIT 1) AND m.completed_at IS NULL", helicopterIDs). Scan(&rows).Error if err != nil { return out, err } for i := range rows { out[string(rows[i].HelicopterID)] = true } return out, nil }