using Microsoft.EntityFrameworkCore; using Solicitors.Core; using Solicitors.Core.Data; using Solicitors.Core.Models; using Solicitors.Core.Models.Imports; using Solicitors.Data.RepositorySetup; namespace Solicitors.Data; internal class SolicitorsRepository : DbContext, ISolicitorRepository, IReadOnlyCitiesRepository, IRatingsProviderRepository { private readonly IRepoSetupService _setup; public SolicitorsRepository(IRepoSetupService setup) { _setup = setup; } public DbSet Solicitors { get; set; } public DbSet SolicitorRatings { get; set; } public DbSet SolicitorLocations { get; set; } public DbSet SolicitorLocationRatings { get; set; } public DbSet Cities { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => _setup.OnConfiguring(optionsBuilder); public IAsyncEnumerable GetAllSolicitorsAsync() => Solicitors .Include(solicitor => solicitor.Cities) .Include(solicitor => solicitor.Locations) .ThenInclude(location => location.LocationRatings) .Include(solicitor => solicitor.Ratings) .AsAsyncEnumerable(); public Task GetSolicitorByIdAsync(Guid id, CancellationToken cancellationToken = default) => Solicitors .Include(solicitor => solicitor.Cities) .Include(solicitor => solicitor.Locations) .ThenInclude(location => location.LocationRatings) .Include(solicitor => solicitor.Ratings) .FirstOrDefaultAsync(x => x.SolicitorId == id, cancellationToken); public async Task AddOrUpdateSolicitorAsync(SolicitorData solicitor, CancellationToken cancellationToken) { var matchingSolicitor = await Solicitors .FirstOrDefaultAsync( item => item.Name == solicitor.Name, cancellationToken: cancellationToken); if (matchingSolicitor is null) await AddNewSolicitor(solicitor, cancellationToken); else await UpdateExistingSolicitor(solicitor, matchingSolicitor, cancellationToken); } private async Task AddNewSolicitor( SolicitorData solicitor, CancellationToken cancellationToken) { var newSol = new Solicitor() { Name = solicitor.Name, RelativeUrl = solicitor.UrlPath, Phone = solicitor.Phone, Email = solicitor.Email, Website = solicitor.Website, ShortDescription = solicitor.ShortDescription }; Solicitors.Add(newSol); var cityTasks = solicitor.Cities .Distinct() .Select(async (city) => { var matchingCity = await Cities.FirstOrDefaultAsync( item => item.Name == city, cancellationToken: cancellationToken); if (matchingCity is null) { matchingCity = new City() { Name = city }; Cities.Add(matchingCity); newSol.Cities.Add(matchingCity); } matchingCity.Solicitors.Add(newSol); }); await Task.WhenAll(cityTasks); foreach (var rating in solicitor.Ratings) { var newRating = new SolicitorRating() { Value = rating.Value, Maximum = rating.MaxValue, Provider = rating.RatingProvider, Solicitor = newSol }; SolicitorRatings.Add(newRating); newSol.Ratings.Add(newRating); } foreach (var location in solicitor.Offices) { var newLocation = new SolicitorLocation() { Address = location.Address, Phone = location.Phone, Solicitor = newSol }; SolicitorLocations.Add(newLocation); newSol.Locations.Add(newLocation); foreach (var rating in location.LocationRatings) { var newLocRating = new SolicitorLocationRating() { Value = rating.value, Maximum = rating.MaxValue, Provider = rating.RatingProvider, SolicitorLocation = newLocation }; SolicitorLocationRatings.Add(newLocRating); newLocation.LocationRatings.Add(newLocRating); } } await SaveChangesAsync(cancellationToken); } private Task UpdateExistingSolicitor( SolicitorData solicitor, Solicitor matchingSolicitor, CancellationToken cancellationToken) { // TODO return Task.CompletedTask; } public IAsyncEnumerable GetCitiesAsync(CancellationToken cancellationToken) { return Cities .Select(city => city.Name) .AsAsyncEnumerable(); } public IAsyncEnumerable GetAllRatingsProvidersAsync() { return SolicitorRatings .Select(rating => rating.Provider) .Distinct() .OrderBy(x => x == "Solicitors.com" ? 0 : 1) .ThenBy(x => x) .AsAsyncEnumerable(); } }