using AutoMapper; using ECMJobRunner.Application.Common.Dtos; using ECMJobRunner.Domain.Interfaces; using MediatR; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace ECMJobRunner.Application.Profiles.Queries { /// /// Query to retrieve profiles with flexible filtering options /// All query options are nullable - when no filters are specified, returns all profiles /// public class GetProfileQuery : IRequest> { /// /// Profile ID to retrieve (optional) /// When specified, returns only the profile with this ID /// public long? Id { get; set; } /// /// Filter by active status (optional) /// When null, returns both active and inactive profiles /// When true, returns only active profiles /// When false, returns only inactive profiles /// public bool? Active { get; set; } /// /// Filter by profile type (optional) /// When specified, returns only profiles with this type /// Type: 0 = ADSync; 1 = GraphQL; 2 = SQL-Job; 3 = SQL and REST-Job /// public byte? TypeId { get; set; } /// /// Filter by profile name (optional) /// When specified, returns profiles with matching name (case-insensitive contains) /// public string? ProfileName { get; set; } /// /// Include associated SQL jobs in the result (optional) /// Default: true /// public bool IncludeSqlJobs { get; set; } = true; } /// /// Handler for GetProfileQuery /// Retrieves profiles with optional filtering and uses AutoMapper for DTO mapping /// public class GetProfileQueryHandler : IRequestHandler> { private readonly ICfgProfileRepository _profileRepository; private readonly IMapper _mapper; /// /// Constructor /// /// Repository for profile data access /// AutoMapper instance for entity-to-DTO mapping public GetProfileQueryHandler(ICfgProfileRepository profileRepository, IMapper mapper) { _profileRepository = profileRepository; _mapper = mapper; } /// /// Handles the by retrieving and mapping profiles /// /// The query containing optional filter parameters /// Cancellation token /// List of matched profiles mapped to public async Task> Handle(GetProfileQuery request, CancellationToken cancellationToken) { IEnumerable profiles; // If ID is specified, get single profile by ID if (request.Id.HasValue) { var profile = request.IncludeSqlJobs ? await _profileRepository.GetByIdWithSqlJobsAsync(request.Id.Value, cancellationToken) : await _profileRepository.GetByIdAsync(request.Id.Value, cancellationToken); profiles = profile != null ? new[] { profile } : []; } // Otherwise, get profiles with filters else { // Get all profiles with SQL jobs if requested if (request.IncludeSqlJobs) { // If Active filter is specified and true, use optimized method if (request.Active.HasValue && request.Active.Value) { profiles = await _profileRepository.GetAllActiveWithSqlJobsAsync(cancellationToken); } else { // Generic query with filters profiles = await _profileRepository.FindAsync(p => true, cancellationToken); } } else { profiles = await _profileRepository.GetAllAsync(cancellationToken); } // Apply filters if (request.Active.HasValue) { profiles = profiles.Where(p => p.Active == request.Active.Value); } if (request.TypeId.HasValue) { profiles = profiles.Where(p => p.TypeId == request.TypeId.Value); } if (!string.IsNullOrWhiteSpace(request.ProfileName)) { #if NET profiles = profiles.Where(p => p.ProfileName.Contains(request.ProfileName, StringComparison.OrdinalIgnoreCase)); #else profiles = profiles.Where(p => p.ProfileName.IndexOf(request.ProfileName!, StringComparison.OrdinalIgnoreCase) >= 0); #endif } } // Use AutoMapper to map entities to DTOs return _mapper.Map>(profiles.ToList()); } } }