package mysql import ( "context" "errors" "time" "gorm.io/gorm" filemanager "wucher/internal/domain/file_manager" helicopterfile "wucher/internal/domain/helicopter_file" takeover "wucher/internal/domain/takeover" ) type TakeoverRepository struct { db *gorm.DB } func NewTakeoverRepository(db *gorm.DB) *TakeoverRepository { return &TakeoverRepository{db: db} } func (r *TakeoverRepository) Create(ctx context.Context, row *takeover.TakeoverAc) error { return r.db.WithContext(ctx).Create(row).Error } func (r *TakeoverRepository) Update(ctx context.Context, row *takeover.TakeoverAc) error { return r.db.WithContext(ctx).Save(row).Error } func (r *TakeoverRepository) Delete(ctx context.Context, id []byte, deletedBy []byte) error { now := time.Now().UTC() return r.db.WithContext(ctx).Model(&takeover.TakeoverAc{}). Where("id = ? AND deleted_at IS NULL", id). Updates(map[string]any{"deleted_at": now, "deleted_by": deletedBy, "updated_by": deletedBy}).Error } // ListActiveEditedTemplateUUIDs returns template UUIDs for takeover-linked files // that are still active. Trashed or lifecycle-deleted files are ignored. func (r *TakeoverRepository) ListActiveEditedTemplateUUIDs(tx *gorm.DB, takeoverID []byte) ([][]byte, error) { if len(takeoverID) != 16 { return nil, nil } db := tx if db == nil { db = r.db } var editedTemplateUUIDs [][]byte if err := db.Table("file_files"). Where( "takeover_id = ? AND template_uuid IS NOT NULL AND deleted_at IS NULL AND lifecycle_deleted_at IS NULL AND status <> ?", takeoverID, filemanager.FileStatusTrashed, ). Distinct(). Pluck("template_uuid", &editedTemplateUUIDs).Error; err != nil { return nil, err } return editedTemplateUUIDs, nil } // ListChecklistTemplateFiles returns the helicopter files that make up a section's // inspection checklist. Documents created from a template (via create-from-template) // are stored as helicopter_files rows for takeover/WOPI editing but are not checklist // items, so they are excluded here. Pass the active transaction handle to run within // an ongoing transaction; when tx is nil the repository's own connection is used. func (r *TakeoverRepository) ListChecklistTemplateFiles(tx *gorm.DB, helicopterID []byte, section string) ([]helicopterfile.HelicopterFile, error) { db := tx if db == nil { db = r.db } var rows []helicopterfile.HelicopterFile if err := db. Model(&helicopterfile.HelicopterFile{}). Preload("SourceFile"). Preload("FileAttachment"). Preload("FileAttachment.File"). Where("helicopter_id = ? AND section = ?", helicopterID, section). Order("position ASC, id ASC"). Find(&rows).Error; err != nil { return nil, err } filtered := rows[:0] for i := range rows { if helicopterFileRowCreatedFromTemplate(&rows[i]) { continue } filtered = append(filtered, rows[i]) } return filtered, nil } // helicopterFileRowCreatedFromTemplate reports whether a helicopter file row points to a // document instantiated from a template (non-empty template_uuid on the underlying file). func helicopterFileRowCreatedFromTemplate(row *helicopterfile.HelicopterFile) bool { if row == nil { return false } if row.SourceFile != nil { return len(row.SourceFile.TemplateUUID) == 16 } if row.FileAttachment != nil && row.FileAttachment.File != nil { return len(row.FileAttachment.File.TemplateUUID) == 16 } return false } func (r *TakeoverRepository) GetByID(ctx context.Context, id []byte) (*takeover.TakeoverAc, error) { var row takeover.TakeoverAc err := r.db.WithContext(ctx). Preload("Base"). Preload("ReserveAc"). Preload("ReserveAc.Aircraft"). Preload("ReserveAc.Inspection"). Preload("RosterCrews"). Preload("OtherPeople"). Preload("Files"). Preload("Files.FileAttachment"). Preload("Files.FileAttachment.File"). 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 *TakeoverRepository) List(ctx context.Context, limit, offset int) ([]takeover.TakeoverAc, int64, error) { rows := make([]takeover.TakeoverAc, 0) var total int64 base := r.db.WithContext(ctx). Model(&takeover.TakeoverAc{}). Preload("Base"). Preload("ReserveAc"). Preload("ReserveAc.Aircraft"). Preload("ReserveAc.Inspection"). Preload("RosterCrews"). Preload("OtherPeople"). Preload("Files"). Preload("Files.FileAttachment"). Preload("Files.FileAttachment.File"). Where("deleted_at IS NULL") if err := base.Count(&total).Error; err != nil { return nil, 0, err } q := base.Order("created_at DESC") if limit > 0 { q = q.Limit(limit).Offset(offset) } if err := q.Find(&rows).Error; err != nil { return nil, 0, err } return rows, total, nil }