forked from ddrilling/AsbCloudServer
WellboreService новая логика. Не протестирована.
This commit is contained in:
parent
ce9899b131
commit
b8462253b3
@ -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>
|
||||||
/// Идентификатор
|
/// Идентификатор
|
||||||
|
@ -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!;
|
|
||||||
}
|
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user