WellboreService новая логика. Не протестирована.

This commit is contained in:
ngfrolov 2023-10-23 18:06:57 +05:00
parent ce9899b131
commit b8462253b3
Signed by untrusted user who does not match committer: ng.frolov
GPG Key ID: E99907A0357B29A7
7 changed files with 137 additions and 150 deletions

View File

@ -10,7 +10,7 @@ public class WellboreDto
/// <summary> /// <summary>
/// Скважина /// Скважина
/// </summary> /// </summary>
public WellWithTimezoneDto Well { get; set; } = null!; public WellDto Well { get; set; } = null!;
/// <summary> /// <summary>
/// Идентификатор /// Идентификатор

View File

@ -1,14 +0,0 @@
using System.Collections.Generic;
namespace AsbCloudApp.Requests;
/// <summary>
/// Параметры запроса для ствола скважины
/// </summary>
public class WellboreRequest : RequestBase
{
/// <summary>
/// Пары идентификаторов скважины и секции
/// </summary>
public IEnumerable<(int idWell, int? idSection)> Ids { get; set; } = null!;
}

View File

@ -42,7 +42,6 @@ namespace AsbCloudApp.Services
/// <param name="idWell"></param> /// <param name="idWell"></param>
/// <param name="start"></param> /// <param name="start"></param>
/// <param name="end"></param> /// <param name="end"></param>
/// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
DatesRangeDto? GetRange(int idWell, DateTimeOffset start, DateTimeOffset end); DatesRangeDto? GetRange(int idWell, DateTimeOffset start, DateTimeOffset end);

View File

@ -2,7 +2,6 @@ using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Services; namespace AsbCloudApp.Services;
@ -11,20 +10,11 @@ namespace AsbCloudApp.Services;
/// </summary> /// </summary>
public interface IWellboreService public interface IWellboreService
{ {
/// <summary> /// <summary>
/// Получение ствола скважины /// Получение стволов скважин
/// </summary> /// </summary>
/// <param name="idWell"></param> /// <param name="idsWells"></param>
/// <param name="idSection"></param> /// <param name="cancellationToken"></param>
/// <param name="cancellationToken"></param> /// <returns></returns>
/// <returns></returns> Task<IEnumerable<WellboreDto>> GetWellboresAsync(IEnumerable<int> idsWells, CancellationToken cancellationToken);
Task<WellboreDto?> GetWellboreAsync(int idWell, int idSection, CancellationToken cancellationToken);
/// <summary>
/// Получение стволов скважин
/// </summary>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<WellboreDto>> GetWellboresAsync(WellboreRequest request, CancellationToken cancellationToken);
} }

View File

@ -20,7 +20,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
{ {
class TelemetryDataCacheItem class TelemetryDataCacheItem
{ {
public TDto? FirstByDate { get; init; } public TDto FirstByDate { get; init; } = default!;
public CyclycArray<TDto> LastData { get; init; } = null!; public CyclycArray<TDto> LastData { get; init; } = null!;
public double TimezoneHours { get; init; } = 5; public double TimezoneHours { get; init; } = 5;
} }
@ -127,7 +127,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
return items; return items;
} }
public TDto? GetLastOrDefault(int idTelemetry) public virtual TDto? GetLastOrDefault(int idTelemetry)
{ {
if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
return default; return default;
@ -150,6 +150,19 @@ namespace AsbCloudInfrastructure.Services.SAUB
return new DatesRangeDto { From = from.Value, To = to }; 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<TEntity>(IAsbCloudDbContext db, Action<string, double?> onProgress, CancellationToken token) private async Task InitializeCacheFromDBAsync<TEntity>(IAsbCloudDbContext db, Action<string, double?> onProgress, CancellationToken token)
where TEntity : class, AsbCloudDb.Model.ITelemetryData where TEntity : class, AsbCloudDb.Model.ITelemetryData
{ {

View File

@ -1,91 +1,135 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.SAUB;
using Mapster;
namespace AsbCloudInfrastructure.Services; namespace AsbCloudInfrastructure.Services;
public class WellboreService : IWellboreService public class WellboreService : IWellboreService
{ {
const string WellboreNameFormat = "Ñòâîë {0}";
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly IWellOperationRepository wellOperationRepository; private readonly IWellOperationRepository wellOperationRepository;
private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;
public WellboreService(IWellService wellService, IWellOperationRepository wellOperationRepository) public WellboreService(
IWellService wellService,
IWellOperationRepository wellOperationRepository,
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
{ {
this.wellService = wellService; this.wellService = wellService;
this.wellOperationRepository = wellOperationRepository; this.wellOperationRepository = wellOperationRepository;
} this.telemetryDataCache = telemetryDataCache;
public async Task<WellboreDto?> 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();
} }
public async Task<IEnumerable<WellboreDto>> GetWellboresAsync(WellboreRequest request, public async Task<IEnumerable<WellboreDto>> GetWellboresAsync(IEnumerable<int> idsWells,
CancellationToken token) CancellationToken token)
{ {
var wellbores = new List<WellboreDto>(request.Ids.Count()); var wellRequest = new WellRequest { Ids = idsWells };
var skip = request.Skip ?? 0; var wells = await wellService.GetAsync(wellRequest, token);
var take = request.Take ?? 10;
var sections = wellOperationRepository.GetSectionTypes() var rowSections = await wellOperationRepository.GetSectionsAsync(idsWells, token);
.ToDictionary(w => w.Id, w => w); 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<WellboreDto> 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) wellbore.DateEnd = dataCache.Value.Last.DateTime;
continue; wellbore.DepthEnd = dataCache.Value.Last.WellDepth!.Value;
}
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<WellWithTimezoneDto>(),
DateStart = section.DateStart.ToOffset(wellTimezoneOffset),
DateEnd = section.DateEnd.ToOffset(wellTimezoneOffset),
DepthStart = section.DepthStart,
DepthEnd = section.DepthEnd,
});
wellbores.AddRange(wellWellbores);
} }
return wellbores return new[] { wellbore };
.OrderBy(w => w.Well.Id).ThenBy(w => w.Id) }
.Skip(skip).Take(take);
} private IEnumerable<WellboreDto> MakeWellboreBySections(IEnumerable<SectionByOperationsDto> sections, WellDto well)
{
var orderedSections = sections.OrderBy(s => s.DateStart);
var wellbores = new List<WellboreDto>();
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;
}
} }

View File

@ -9,6 +9,7 @@ using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Org.BouncyCastle.Asn1.Ocsp;
namespace AsbCloudWebApi.Controllers; namespace AsbCloudWebApi.Controllers;
@ -26,66 +27,20 @@ public class WellboreController : ControllerBase
{ {
this.wellboreService = wellboreService; this.wellboreService = wellboreService;
} }
/// <summary>
/// Получение ствола скважины
/// </summary>
/// <param name="idWell">Id скважины</param>
/// <param name="idSection">Id типа секции скважины</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpGet("{idWell:int}/{idSection:int}")] /// <summary>
[ProducesResponseType(typeof(WellboreDto), StatusCodes.Status200OK)] /// Получение списка стволов скважин
[ProducesResponseType(StatusCodes.Status204NoContent)] /// </summary>
public async Task<IActionResult> GetAsync(int idWell, int idSection, CancellationToken cancellationToken) /// <param name="idsWells">Идентификаторы скважин</param>
{ /// <param name="cancellationToken"></param>
var wellbore = await wellboreService.GetWellboreAsync(idWell, idSection, cancellationToken); /// <returns></returns>
[HttpGet]
if (wellbore is null)
return NoContent();
return Ok(wellbore);
}
/// <summary>
/// Получение списка стволов скважин
/// </summary>
/// <param name="ids">Пары идентификаторов скважины и секции</param>
/// <param name="skip">Опциональный параметр. Количество пропускаемых записей</param>
/// <param name="take">Опциональный параметр. Количество получаемых записей</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<WellboreDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(IEnumerable<WellboreDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetAllAsync([FromQuery] IEnumerable<string> ids, public async Task<IActionResult> GetAllAsync([FromQuery] IEnumerable<int> idsWells,
int? skip,
int? take,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var request = new WellboreRequest var result = await wellboreService.GetWellboresAsync(idsWells, cancellationToken);
{
Ids = ids.Select(id => ParseId(id)),
Skip = skip,
Take = take
};
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);
}
} }