diff --git a/AsbCloudApp/Data/WellboreDto.cs b/AsbCloudApp/Data/WellboreDto.cs index c153b14f..68c5695b 100644 --- a/AsbCloudApp/Data/WellboreDto.cs +++ b/AsbCloudApp/Data/WellboreDto.cs @@ -10,7 +10,7 @@ public class WellboreDto /// /// Скважина /// - public WellWithTimezoneDto Well { get; set; } = null!; + public WellDto Well { get; set; } = null!; /// /// Идентификатор diff --git a/AsbCloudApp/Requests/WellboreRequest.cs b/AsbCloudApp/Requests/WellboreRequest.cs deleted file mode 100644 index 32b4cbe2..00000000 --- a/AsbCloudApp/Requests/WellboreRequest.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace AsbCloudApp.Requests; - -/// -/// Параметры запроса для ствола скважины -/// -public class WellboreRequest : RequestBase -{ - /// - /// Пары идентификаторов скважины и секции - /// - public IEnumerable<(int idWell, int? idSection)> Ids { get; set; } = null!; -} \ No newline at end of file diff --git a/AsbCloudApp/Services/ITelemetryDataService.cs b/AsbCloudApp/Services/ITelemetryDataService.cs index 58eeeb70..154986b4 100644 --- a/AsbCloudApp/Services/ITelemetryDataService.cs +++ b/AsbCloudApp/Services/ITelemetryDataService.cs @@ -42,7 +42,6 @@ namespace AsbCloudApp.Services /// /// /// - /// /// DatesRangeDto? GetRange(int idWell, DateTimeOffset start, DateTimeOffset end); diff --git a/AsbCloudApp/Services/IWellboreService.cs b/AsbCloudApp/Services/IWellboreService.cs index f42485ae..0b577ba5 100644 --- a/AsbCloudApp/Services/IWellboreService.cs +++ b/AsbCloudApp/Services/IWellboreService.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; -using AsbCloudApp.Requests; namespace AsbCloudApp.Services; @@ -11,20 +10,11 @@ namespace AsbCloudApp.Services; /// public interface IWellboreService { - /// - /// Получение ствола скважины - /// - /// - /// - /// - /// - Task GetWellboreAsync(int idWell, int idSection, CancellationToken cancellationToken); - - /// - /// Получение стволов скважин - /// - /// - /// - /// - Task> GetWellboresAsync(WellboreRequest request, CancellationToken cancellationToken); + /// + /// Получение стволов скважин + /// + /// + /// + /// + Task> GetWellboresAsync(IEnumerable idsWells, CancellationToken cancellationToken); } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index b579c876..531ab8d9 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -20,7 +20,7 @@ namespace AsbCloudInfrastructure.Services.SAUB { class TelemetryDataCacheItem { - public TDto? FirstByDate { get; init; } + public TDto FirstByDate { get; init; } = default!; public CyclycArray LastData { get; init; } = null!; public double TimezoneHours { get; init; } = 5; } @@ -127,7 +127,7 @@ namespace AsbCloudInfrastructure.Services.SAUB return items; } - public TDto? GetLastOrDefault(int idTelemetry) + public virtual TDto? GetLastOrDefault(int idTelemetry) { if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) return default; @@ -150,6 +150,19 @@ namespace AsbCloudInfrastructure.Services.SAUB return new DatesRangeDto { From = from.Value, To = to }; } + public (TDto First, TDto Last)? GetOrDefaultFirstLast(int idTelemetry) + { + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + return null; + + if (!cacheItem.LastData.Any()) + return null; + + var last = cacheItem.LastData[^1]; + var first = cacheItem.FirstByDate; + return (first, last); + } + private async Task InitializeCacheFromDBAsync(IAsbCloudDbContext db, Action onProgress, CancellationToken token) where TEntity : class, AsbCloudDb.Model.ITelemetryData { diff --git a/AsbCloudInfrastructure/Services/WellboreService.cs b/AsbCloudInfrastructure/Services/WellboreService.cs index 396243d6..9fd4080d 100644 --- a/AsbCloudInfrastructure/Services/WellboreService.cs +++ b/AsbCloudInfrastructure/Services/WellboreService.cs @@ -1,91 +1,135 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; +using AsbCloudApp.Data.SAUB; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; -using AsbCloudDb.Model; -using Mapster; +using AsbCloudInfrastructure.Services.SAUB; namespace AsbCloudInfrastructure.Services; public class WellboreService : IWellboreService { + const string WellboreNameFormat = " {0}"; private readonly IWellService wellService; private readonly IWellOperationRepository wellOperationRepository; + private readonly TelemetryDataCache telemetryDataCache; - public WellboreService(IWellService wellService, IWellOperationRepository wellOperationRepository) + public WellboreService( + IWellService wellService, + IWellOperationRepository wellOperationRepository, + TelemetryDataCache telemetryDataCache) { this.wellService = wellService; this.wellOperationRepository = wellOperationRepository; - } - - public async Task GetWellboreAsync(int idWell, int idSection, CancellationToken cancellationToken) - { - var request = new WellboreRequest - { - Ids = new (int, int?)[] { (idWell, idSection) }, - Take = 1, - }; - var data = await GetWellboresAsync(request, cancellationToken); - return data.FirstOrDefault(); + this.telemetryDataCache = telemetryDataCache; } - public async Task> GetWellboresAsync(WellboreRequest request, + public async Task> GetWellboresAsync(IEnumerable idsWells, CancellationToken token) { - var wellbores = new List(request.Ids.Count()); - var skip = request.Skip ?? 0; - var take = request.Take ?? 10; + var wellRequest = new WellRequest { Ids = idsWells }; + var wells = await wellService.GetAsync(wellRequest, token); - var sections = wellOperationRepository.GetSectionTypes() - .ToDictionary(w => w.Id, w => w); + var rowSections = await wellOperationRepository.GetSectionsAsync(idsWells, token); + var groupedSections = rowSections + .GroupBy(s => s.IdWell); - var ids = request.Ids.GroupBy(i => i.idWell, i => i.idSection); + var wellbores = wells + .SelectMany(well => { + var wellSections = groupedSections.FirstOrDefault(group => group.Key == well.Id); + if (wellSections is not null) + return MakeWellboreBySections(wellSections, well); + else + return MakeWellboreDefault(well); + }) + .OrderBy(w => w.Well.Id) + .ThenBy(w => w.Id); - var idsWells = request.Ids.Select(i => i.idWell); + return wellbores; + } - var allSections = await wellOperationRepository.GetSectionsAsync(idsWells, token); + private IEnumerable MakeWellboreDefault(WellDto well) + { + var wellbore = new WellboreDto { + Id = 1, + Name = string.Format(WellboreNameFormat, 1), + Well = well, + }; - foreach (var id in ids) + if(well.IdTelemetry is not null) { - var well = await wellService.GetOrDefaultAsync(id.Key, token); + var dataCache = telemetryDataCache.GetOrDefaultFirstLast(well.IdTelemetry.Value); + if (dataCache is not null) + { + wellbore.DateStart = dataCache.Value.First.DateTime; + wellbore.DepthStart = dataCache.Value.First.WellDepth!.Value; - if (well is null) - continue; - - var wellTimezoneOffset = TimeSpan.FromHours(well.Timezone.Hours); - - var wellFactSections = allSections - .Where(section => section.IdWell == id.Key) - .Where(section => section.IdType == WellOperation.IdOperationTypeFact); - - var idsSections = id - .Where(i => i.HasValue) - .Select(i => i!.Value); - - if (idsSections.Any()) - wellFactSections = wellFactSections - .Where(section => idsSections.Contains(section.IdWellSectionType)); - - var wellWellbores = wellFactSections.Select(section => new WellboreDto { - Id = section.IdWellSectionType, - Name = sections[section.IdWellSectionType].Caption, - Well = well.Adapt(), - DateStart = section.DateStart.ToOffset(wellTimezoneOffset), - DateEnd = section.DateEnd.ToOffset(wellTimezoneOffset), - DepthStart = section.DepthStart, - DepthEnd = section.DepthEnd, - }); - - wellbores.AddRange(wellWellbores); + wellbore.DateEnd = dataCache.Value.Last.DateTime; + wellbore.DepthEnd = dataCache.Value.Last.WellDepth!.Value; + } } - return wellbores - .OrderBy(w => w.Well.Id).ThenBy(w => w.Id) - .Skip(skip).Take(take); - } + return new[] { wellbore }; + } + + private IEnumerable MakeWellboreBySections(IEnumerable sections, WellDto well) + { + var orderedSections = sections.OrderBy(s => s.DateStart); + var wellbores = new List(); + int wellboreId = 1; + + SectionByOperationsDto? preSection = null; + WellboreDto? wellbore = null; + + foreach (var section in orderedSections) + { + if (wellbore is null || wellbore.DepthEnd > section.DepthStart) + { + wellbore = new WellboreDto + { + Name = string.Format(WellboreNameFormat, wellboreId), + Id = wellboreId, + Well = well, + + DateStart = section.DateStart, + DateEnd = section.DateEnd, + DepthStart = section.DepthStart, + DepthEnd = section.DepthEnd, + }; + + wellbores.Add(wellbore); + wellboreId++; + + } + else + { + wellbore.DepthEnd = section.DepthEnd; + wellbore.DateEnd = section.DateEnd; + } + + preSection = section; + } + + if (wellbore is not null) + { + if (well.IdTelemetry is not null) + { + var dataCache = telemetryDataCache.GetOrDefaultFirstLast(well.IdTelemetry.Value); + if (dataCache is not null) + { + wellbore.DateStart = dataCache.Value.First.DateTime; + wellbore.DepthStart = dataCache.Value.First.WellDepth!.Value; + + wellbore.DateEnd = dataCache.Value.Last.DateTime; + wellbore.DepthEnd = dataCache.Value.Last.WellDepth!.Value; + } + } + } + + return wellbores; + } } \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/WellboreController.cs b/AsbCloudWebApi/Controllers/WellboreController.cs index ba3a27cb..8b0a94bf 100644 --- a/AsbCloudWebApi/Controllers/WellboreController.cs +++ b/AsbCloudWebApi/Controllers/WellboreController.cs @@ -9,6 +9,7 @@ using AsbCloudApp.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Org.BouncyCastle.Asn1.Ocsp; namespace AsbCloudWebApi.Controllers; @@ -26,66 +27,20 @@ public class WellboreController : ControllerBase { this.wellboreService = wellboreService; } - - /// - /// Получение ствола скважины - /// - /// Id скважины - /// Id типа секции скважины - /// - /// - [HttpGet("{idWell:int}/{idSection:int}")] - [ProducesResponseType(typeof(WellboreDto), StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task GetAsync(int idWell, int idSection, CancellationToken cancellationToken) - { - var wellbore = await wellboreService.GetWellboreAsync(idWell, idSection, cancellationToken); - - if (wellbore is null) - return NoContent(); - - return Ok(wellbore); - } - - /// - /// Получение списка стволов скважин - /// - /// Пары идентификаторов скважины и секции - /// Опциональный параметр. Количество пропускаемых записей - /// Опциональный параметр. Количество получаемых записей - /// - /// - [HttpGet] + /// + /// Получение списка стволов скважин + /// + /// Идентификаторы скважин + /// + /// + [HttpGet] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public async Task GetAllAsync([FromQuery] IEnumerable ids, - int? skip, - int? take, + public async Task GetAllAsync([FromQuery] IEnumerable idsWells, CancellationToken cancellationToken) - { - var request = new WellboreRequest - { - Ids = ids.Select(id => ParseId(id)), - Skip = skip, - Take = take - }; + { + var result = await wellboreService.GetWellboresAsync(idsWells, cancellationToken); - return Ok(await wellboreService.GetWellboresAsync(request, cancellationToken)); + return Ok(result); } - - private static (int, int?) ParseId(string id) - { - var idPair = id.Split(','); - if (!int.TryParse(idPair[0], out var idWell)) - throw new ArgumentInvalidException(nameof(id), $"Не удалось получить Id скважины \"{idPair[0]}\""); - - if (idPair.Length > 1) - { - if (int.TryParse(idPair[1], out int idWellSectionType)) - return (idWell, idWellSectionType); - else - throw new ArgumentInvalidException(nameof(id), $"Не удалось получить Id ствола \"{idPair[1]}\""); - } - return (idWell, null); - } } \ No newline at end of file