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/Repositories/ITelemetryDataCache.cs b/AsbCloudApp/Repositories/ITelemetryDataCache.cs
new file mode 100644
index 00000000..0bc73275
--- /dev/null
+++ b/AsbCloudApp/Repositories/ITelemetryDataCache.cs
@@ -0,0 +1,62 @@
+using AsbCloudApp.Data;
+using AsbCloudApp.Requests;
+using System;
+using System.Collections.Generic;
+
+namespace AsbCloudApp.Repositories
+{
+ ///
+ /// Хранилище кеша
+ ///
+ ///
+ public interface ITelemetryDataCache where TDto : ITelemetryData
+ {
+ ///
+ /// добавить в кеш чанк записей по телеметрии
+ ///
+ ///
+ ///
+ void AddRange(int idTelemetry, IEnumerable range);
+
+ ///
+ /// вернуть последнюю записть
+ ///
+ ///
+ ///
+ TDto? GetLastOrDefault(int idTelemetry);
+
+ ///
+ /// Получить кешированые записи
+ ///
+ ///
+ ///
+ ///
+ /// приблизительное кол-во возвращаемых записей после их прореживания
+ ///
+ IEnumerable? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600, int approxPointsCount = 1024);
+
+ ///
+ /// Получить кешированые записи
+ ///
+ ///
+ ///
+ ///
+ IEnumerable? GetOrDefault(int idTelemetry, TelemetryDataRequest request);
+
+ ///
+ /// Получить диапазон дат телеметрии.
+ /// Дата первой записи телеметрии храниться отдельно и запоняется при инициализации
+ ///
+ ///
+ ///
+ DatesRangeDto? GetOrDefaultDataDateRange(int idTelemetry);
+
+ ///
+ /// Получение первой и последней записи телеметрии.
+ /// Первая запись телеметрии храниться отдельно и запоняется при инициализации
+ ///
+ ///
+ ///
+ (TDto First, TDto Last)? GetOrDefaultFirstLast(int idTelemetry);
+ }
+}
\ No newline at end of file
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/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs
index 0ce35409..93c6575e 100644
--- a/AsbCloudInfrastructure/DependencyInjection.cs
+++ b/AsbCloudInfrastructure/DependencyInjection.cs
@@ -161,13 +161,13 @@ namespace AsbCloudInfrastructure
services.AddMemoryCache();
services.AddScoped(provider => provider.GetRequiredService());
- services.AddSingleton(new WitsInfoService());
- services.AddSingleton(provider => TelemetryDataCache.GetInstance(provider));
- services.AddSingleton(provider => TelemetryDataCache.GetInstance(provider));
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton(provider => ReduceSamplingService.GetInstance(configuration));
+ services.AddSingleton(new WitsInfoService());
+ services.AddSingleton>(provider => TelemetryDataCache.GetInstance(provider));
+ services.AddSingleton>(provider => TelemetryDataCache.GetInstance(provider));
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton(provider => ReduceSamplingService.GetInstance(configuration));
services.AddTransient();
services.AddTransient, ProcessMapPlanRepository>();
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs
index 32fc88a2..649f03de 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs
@@ -1,4 +1,5 @@
using AsbCloudApp.Data;
+using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb;
using AsbCloudDb.Model;
@@ -18,12 +19,12 @@ namespace AsbCloudInfrastructure.Services.SAUB
{
protected readonly IAsbCloudDbContext db;
protected readonly ITelemetryService telemetryService;
- protected readonly TelemetryDataCache telemetryDataCache;
+ protected readonly ITelemetryDataCache telemetryDataCache;
public TelemetryDataBaseService(
IAsbCloudDbContext db,
ITelemetryService telemetryService,
- TelemetryDataCache telemetryDataCache)
+ ITelemetryDataCache telemetryDataCache)
{
this.db = db;
this.telemetryService = telemetryService;
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
index dd602a1a..154b70d2 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
@@ -11,15 +11,15 @@ using AsbCloudInfrastructure.Background;
using System.Threading;
using AsbCloudApp.Data;
using AsbCloudApp.Requests;
+using AsbCloudApp.Repositories;
namespace AsbCloudInfrastructure.Services.SAUB
{
- public class TelemetryDataCache
- where TDto : AsbCloudApp.Data.ITelemetryData
+ public class TelemetryDataCache : ITelemetryDataCache where TDto : AsbCloudApp.Data.ITelemetryData
{
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;
}
@@ -48,7 +48,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
instance = new TelemetryDataCache();
var worker = provider.GetRequiredService();
var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}";
- var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) => {
+ var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) =>
+ {
var db = provider.GetRequiredService();
await instance.InitializeCacheFromDBAsync(db, onProgress, token);
});
@@ -105,14 +106,14 @@ namespace AsbCloudInfrastructure.Services.SAUB
///
public IEnumerable? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600d, int approxPointsCount = 1024)
{
- if(!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
+ if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
return null;
var cacheLastData = cacheItem.LastData;
if (!cacheLastData.Any() || cacheLastData[0].DateTime > dateBegin)
return null;
-
+
var dateEnd = dateBegin.AddSeconds(intervalSec);
var items = cacheLastData
.Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd);
@@ -125,7 +126,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;
@@ -139,7 +140,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
return null;
var from = cacheItem.FirstByDate?.DateTime;
- if(!cacheItem.LastData.Any())
+ if (!cacheItem.LastData.Any())
return null;
var to = cacheItem.LastData[^1].DateTime;
@@ -148,6 +149,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
{
@@ -176,10 +190,10 @@ namespace AsbCloudInfrastructure.Services.SAUB
var idTelemetry = well.IdTelemetry!.Value;
var hoursOffset = well.Timezone.Hours;
-
- onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++/count);
+
+ onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++ / count);
var cacheItem = await GetOrDefaultCacheDataFromDbAsync(db, idTelemetry, capacity, hoursOffset, token);
- if(cacheItem is not null)
+ if (cacheItem is not null)
caches.TryAdd(idTelemetry, cacheItem);
}
}
@@ -215,7 +229,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
var dtos = entities
.AsEnumerable()
.Reverse()
- .Select(entity => {
+ .Select(entity =>
+ {
var dto = entity.Adapt();
dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset);
return dto;
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs
index afe89528..b9ce8d6c 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs
@@ -1,6 +1,7 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Exceptions;
+using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Mapster;
@@ -26,7 +27,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
IAsbCloudDbContext db,
ITelemetryService telemetryService,
ITelemetryUserService telemetryUserService,
- TelemetryDataCache telemetryDataCache)
+ ITelemetryDataCache telemetryDataCache)
: base(db, telemetryService, telemetryDataCache)
{
this.telemetryUserService = telemetryUserService;
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs
index 78119d6b..dab1e851 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs
@@ -1,4 +1,5 @@
using AsbCloudApp.Data.SAUB;
+using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Mapster;
@@ -11,7 +12,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
public TelemetryDataSpinService(
IAsbCloudDbContext db,
ITelemetryService telemetryService,
- TelemetryDataCache telemetryDataCache)
+ ITelemetryDataCache telemetryDataCache)
: base(db, telemetryService, telemetryDataCache)
{ }
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs
index 7aa4f6c5..a084e687 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs
@@ -1,5 +1,6 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.SAUB;
+using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb;
using AsbCloudDb.Model;
@@ -18,7 +19,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
{
private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache;
- private readonly TelemetryDataCache dataSaubCache;
+ //TODO: методы использующие ITelemetryDataCache, скорее всего, тут не нужны
+ private readonly ITelemetryDataCache dataSaubCache;
private readonly ITimezoneService timezoneService;
public ITimezoneService TimeZoneService => timezoneService;
@@ -26,7 +28,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
public TelemetryService(
IAsbCloudDbContext db,
IMemoryCache memoryCache,
- TelemetryDataCache dataSaubCache,
+ ITelemetryDataCache dataSaubCache,
ITimezoneService timezoneService)
{
this.db = db;
diff --git a/AsbCloudInfrastructure/Services/WellInfoService.cs b/AsbCloudInfrastructure/Services/WellInfoService.cs
index 70c6afdd..60693eeb 100644
--- a/AsbCloudInfrastructure/Services/WellInfoService.cs
+++ b/AsbCloudInfrastructure/Services/WellInfoService.cs
@@ -36,7 +36,7 @@ public class WellInfoService
var operationsStatService = services.GetRequiredService();
var processMapPlanWellDrillingRepository = services.GetRequiredService>();
var subsystemOperationTimeService = services.GetRequiredService();
- var telemetryDataSaubCache = services.GetRequiredService>();
+ var telemetryDataSaubCache = services.GetRequiredService>();
var messageHub = services.GetRequiredService>();
var wells = await wellService.GetAllAsync(token);
@@ -180,16 +180,16 @@ public class WellInfoService
public IEnumerable IdsCompanies { get; set; } = null!;
}
- private readonly TelemetryDataCache telemetryDataSaubCache;
- private readonly TelemetryDataCache telemetryDataSpinCache;
+ private readonly ITelemetryDataCache telemetryDataSaubCache;
+ private readonly ITelemetryDataCache telemetryDataSpinCache;
private readonly IWitsRecordRepository witsRecord7Repository;
private readonly IWitsRecordRepository witsRecord1Repository;
private readonly IGtrRepository gtrRepository;
private static IEnumerable WellMapInfo = Enumerable.Empty();
public WellInfoService(
- TelemetryDataCache telemetryDataSaubCache,
- TelemetryDataCache telemetryDataSpinCache,
+ ITelemetryDataCache telemetryDataSaubCache,
+ ITelemetryDataCache telemetryDataSpinCache,
IWitsRecordRepository witsRecord7Repository,
IWitsRecordRepository witsRecord1Repository,
IGtrRepository gtrRepository)
diff --git a/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs b/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs
index 004ce863..a93dc50b 100644
--- a/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs
+++ b/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs
@@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.SAUB;
using AsbCloudInfrastructure.Services.SAUB;
+using AsbCloudApp.Repositories;
namespace AsbCloudInfrastructure.Services.WellOperationService;
@@ -19,10 +20,10 @@ public class OperationsStatService : IOperationsStatService
private readonly IAsbCloudDbContext db;
private readonly IMemoryCache memoryCache;
private readonly IWellService wellService;
- private readonly TelemetryDataCache telemetryDataCache;
+ private readonly ITelemetryDataCache telemetryDataCache;
- public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService,
- TelemetryDataCache telemetryDataCache)
+ public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService,
+ ITelemetryDataCache telemetryDataCache)
{
this.db = db;
this.memoryCache = memoryCache;
diff --git a/AsbCloudInfrastructure/Services/WellboreService.cs b/AsbCloudInfrastructure/Services/WellboreService.cs
index 396243d6..4417dd49 100644
--- a/AsbCloudInfrastructure/Services/WellboreService.cs
+++ b/AsbCloudInfrastructure/Services/WellboreService.cs
@@ -1,91 +1,134 @@
-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 ITelemetryDataCache telemetryDataCache;
- public WellboreService(IWellService wellService, IWellOperationRepository wellOperationRepository)
+ public WellboreService(
+ IWellService wellService,
+ IWellOperationRepository wellOperationRepository,
+ ITelemetryDataCache 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
+ .Where(section => section.IdType == 1)
+ .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,
+ };
+ //if(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.DateEnd = dataCache.Value.Last.DateTime;
+ wellbore.DepthEnd = dataCache.Value.Last.WellDepth!.Value;
+ }
+ }
+ }
+
+ return wellbores;
+ }
}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Startup.cs b/AsbCloudInfrastructure/Startup.cs
index 240c8892..cef6745b 100644
--- a/AsbCloudInfrastructure/Startup.cs
+++ b/AsbCloudInfrastructure/Startup.cs
@@ -15,6 +15,7 @@ using AsbCloudInfrastructure.Services.Subsystems;
using System.Linq;
using DocumentFormat.OpenXml.InkML;
using AsbCloudDb;
+using AsbCloudApp.Repositories;
namespace AsbCloudInfrastructure
{
@@ -29,8 +30,8 @@ namespace AsbCloudInfrastructure
context.Database.EnshureCreatedAndMigrated();
// TODO: Сделать инициализацию кеша телеметрии более явной.
- _ = provider.GetRequiredService>();
- _ = provider.GetRequiredService>();
+ _ = provider.GetRequiredService>();
+ _ = provider.GetRequiredService>();
var backgroundWorker = provider.GetRequiredService();
backgroundWorker.WorkStore.AddPeriodic(TimeSpan.FromMinutes(30));
diff --git a/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs
index 77f94b84..1a802054 100644
--- a/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs
+++ b/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs
@@ -3,14 +3,11 @@ using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
-using AsbCloudInfrastructure.Repository;
-using AsbCloudInfrastructure.Services.SAUB;
+using AsbCloudInfrastructure.Services;
using NSubstitute;
-using Org.BouncyCastle.Asn1.Ocsp;
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -19,25 +16,207 @@ namespace AsbCloudWebApi.Tests.ServicesTests
{
public class WellboreServiceTest
{
+ private IWellService wellService;
+ private IWellOperationRepository wellOperationRepository;
+ private ITelemetryDataCache telemetryDataCache;
+ private WellboreService wellboreService;
+
+ private WellDto well1 = new WellDto
+ {
+ Id = 1,
+ IdState = 1,
+ IdTelemetry = 1,
+ LastTelemetryDate = DateTime.Now,
+ Caption = "well 1"
+ };
+
+ private WellDto well2 = new WellDto
+ {
+ Id = 2,
+ IdState = 1,
+ IdTelemetry = 100,
+ LastTelemetryDate = DateTime.Now,
+ Caption = "well 2"
+ };
public WellboreServiceTest()
{
- var wellService = Substitute.For();
- wellService.GetAsync(Arg.Any(), Arg.Any())
- .Returns(Enumerable.Empty());
+ wellService = Substitute.For();
- var wellOperationRepository = Substitute.For();
- wellOperationRepository.GetSectionsAsync(Arg.Any>(), Arg.Any())
- .Returns(Enumerable.Empty());
+ wellOperationRepository = Substitute.For();
+
+ telemetryDataCache = Substitute.For>();
- var telemetryDataCache = Substitute.For>();
- telemetryDataCache.GetOrDefaultFirstLast(Arg.Any());
+ wellboreService = new WellboreService(wellService, wellOperationRepository, telemetryDataCache);
}
[Fact]
- public async Task GetWellboresAsync()
+ public async Task GetWellboresAsync_returns_empty_collection()
{
+ var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None);
+ Assert.NotNull(result);
+ Assert.False(result.Any());
+ }
+
+ [Fact]
+ public async Task GetWellboresAsync_returns_one_bore_by_well_only()
+ {
+ wellService.GetAsync(Arg.Any(), Arg.Any())
+ .Returns(new WellDto[] { well1 });
+
+ var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None);
+
+ Assert.Single(result);
+ var wellbore0 = result.ElementAt(0);
+ Assert.Equal(well1.Caption, wellbore0.Well.Caption);
+ Assert.Equal(well1.Id, wellbore0.Well.Id);
+
+ Assert.Equal("Ствол 1", wellbore0.Name);
+ Assert.Equal(1, wellbore0.Id);
+
+ Assert.Equal(default, wellbore0.DateStart);
+ Assert.Equal(default, wellbore0.DateEnd);
+ Assert.Equal(default, wellbore0.DepthStart);
+ Assert.Equal(default, wellbore0.DepthEnd);
+ }
+
+ [Fact]
+ public async Task GetWellboresAsync_returns_two_bore_by_two_wells_only()
+ {
+ wellService.GetAsync(Arg.Any(), Arg.Any())
+ .Returns(new WellDto[] { well1, well2 });
+
+ var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None);
+
+ Assert.Equal(2, result.Count());
+ }
+
+ [Fact]
+ public async Task GetWellboresAsync_returns_two_bore_by_well_with_sections()
+ {
+ wellService.GetAsync(Arg.Any(), Arg.Any())
+ .Returns(new WellDto[] { well1 });
+
+ var section0 = new SectionByOperationsDto()
+ { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 01), DateEnd = new DateTime(2023, 01, 02), DepthStart = 000, DepthEnd = 100 };
+ var section1 = new SectionByOperationsDto()
+ { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 02), DateEnd = new DateTime(2023, 01, 03), DepthStart = 100, DepthEnd = 300 };
+ var section2 = new SectionByOperationsDto()
+ { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 03), DateEnd = new DateTime(2023, 01, 04), DepthStart = 200, DepthEnd = 210 };
+ var section3 = new SectionByOperationsDto()
+ { IdWell = int.MaxValue, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 03), DateEnd = new DateTime(2023, 01, 04), DepthStart = 200, DepthEnd = 220 };
+ var section4 = new SectionByOperationsDto()
+ { IdWell = well1.Id, IdWellSectionType = 0, IdType = 0, DateStart = new DateTime(2023, 01, 05), DateEnd = new DateTime(2023, 01, 06), DepthStart = 150, DepthEnd = 220 };
+
+ wellOperationRepository.GetSectionsAsync(Arg.Any>(), Arg.Any())
+ .Returns(new SectionByOperationsDto[]{section0, section1, section2, section3, section4, });
+
+ var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None);
+
+ Assert.Equal(2, result.Count());
+ var wellbore0 = result.ElementAt(0);
+ Assert.Equal(well1.Caption, wellbore0.Well.Caption);
+ Assert.Equal(well1.Id, wellbore0.Well.Id);
+
+ Assert.Equal("Ствол 1", wellbore0.Name);
+ Assert.Equal(1, wellbore0.Id);
+
+ Assert.Equal(section0.DateStart, wellbore0.DateStart);
+ Assert.Equal(section0.DepthStart, wellbore0.DepthStart);
+ Assert.Equal(section1.DateEnd, wellbore0.DateEnd);
+ Assert.Equal(section1.DepthEnd, wellbore0.DepthEnd);
+
+ var wellbore1 = result.ElementAt(1);
+ Assert.Equal(well1.Caption, wellbore1.Well.Caption);
+ Assert.Equal(well1.Id, wellbore1.Well.Id);
+
+ Assert.Equal("Ствол 2", wellbore1.Name);
+ Assert.Equal(2, wellbore1.Id);
+
+ Assert.Equal(section2.DateStart, wellbore1.DateStart);
+ Assert.Equal(section2.DepthStart, wellbore1.DepthStart);
+ Assert.Equal(section2.DateEnd, wellbore1.DateEnd);
+ Assert.Equal(section2.DepthEnd, wellbore1.DepthEnd);
+ }
+
+
+ [Fact]
+ public async Task GetWellboresAsync_returns_one_bore_by_well_with_telemetry()
+ {
+ wellService.GetAsync(Arg.Any(), Arg.Any())
+ .Returns(new WellDto[] { well1 });
+
+ var firstCacheItem = new TelemetryDataSaubDto { DateTime = new DateTime(2000, 01, 01), WellDepth = 0, };
+ var lastCacheItem = new TelemetryDataSaubDto { DateTime = new DateTime(2023, 01, 05), WellDepth = 321, };
+
+ telemetryDataCache.GetOrDefaultFirstLast(Arg.Any())
+ .Returns((firstCacheItem, lastCacheItem));
+
+ var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None);
+
+ Assert.Single(result);
+ var wellbore0 = result.ElementAt(0);
+ Assert.Equal(well1.Caption, wellbore0.Well.Caption);
+ Assert.Equal(well1.Id, wellbore0.Well.Id);
+
+ Assert.Equal("Ствол 1", wellbore0.Name);
+ Assert.Equal(1, wellbore0.Id);
+
+ Assert.Equal(firstCacheItem.DateTime, wellbore0.DateStart);
+ Assert.Equal(firstCacheItem.WellDepth!.Value, wellbore0.DepthStart);
+ Assert.Equal(lastCacheItem.DateTime, wellbore0.DateEnd);
+ Assert.Equal(lastCacheItem.WellDepth!.Value, wellbore0.DepthEnd);
+ }
+
+ [Fact]
+ public async Task GetWellboresAsync_returns_two_bore_by_well_with_all()
+ {
+ wellService.GetAsync(Arg.Any(), Arg.Any())
+ .Returns(new WellDto[] { well1 });
+
+ var section0 = new SectionByOperationsDto()
+ { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 01), DateEnd = new DateTime(2023, 01, 02), DepthStart = 000, DepthEnd = 100 };
+ var section1 = new SectionByOperationsDto()
+ { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 02), DateEnd = new DateTime(2023, 01, 03), DepthStart = 100, DepthEnd = 300 };
+ var section2 = new SectionByOperationsDto()
+ { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 03), DateEnd = new DateTime(2023, 01, 04), DepthStart = 200, DepthEnd = 210 };
+
+ wellOperationRepository.GetSectionsAsync(Arg.Any>(), Arg.Any())
+ .Returns(new SectionByOperationsDto[] { section0, section1, section2});
+
+ var firstCacheItem = new TelemetryDataSaubDto { DateTime = new DateTime(2000, 01, 01), WellDepth = 0, };
+ var lastCacheItem = new TelemetryDataSaubDto { DateTime = new DateTime(2023, 01, 05), WellDepth = 321, };
+
+ telemetryDataCache.GetOrDefaultFirstLast(Arg.Any())
+ .Returns((firstCacheItem, lastCacheItem));
+
+ var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None);
+
+ Assert.Equal(2, result.Count());
+ var wellbore0 = result.ElementAt(0);
+ Assert.Equal(well1.Caption, wellbore0.Well.Caption);
+ Assert.Equal(well1.Id, wellbore0.Well.Id);
+
+ Assert.Equal("Ствол 1", wellbore0.Name);
+ Assert.Equal(1, wellbore0.Id);
+
+ Assert.Equal(section0.DateStart, wellbore0.DateStart);
+ Assert.Equal(section0.DepthStart, wellbore0.DepthStart);
+ Assert.Equal(section1.DateEnd, wellbore0.DateEnd);
+ Assert.Equal(section1.DepthEnd, wellbore0.DepthEnd);
+
+ var wellbore1 = result.ElementAt(1);
+ Assert.Equal(well1.Caption, wellbore1.Well.Caption);
+ Assert.Equal(well1.Id, wellbore1.Well.Id);
+
+ Assert.Equal("Ствол 2", wellbore1.Name);
+ Assert.Equal(2, wellbore1.Id);
+
+ Assert.Equal(section2.DateStart, wellbore1.DateStart);
+ Assert.Equal(section2.DepthStart, wellbore1.DepthStart);
+ Assert.Equal(lastCacheItem.DateTime, wellbore1.DateEnd);
+ Assert.Equal(lastCacheItem.WellDepth!.Value, wellbore1.DepthEnd);
}
}
}
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
diff --git a/AsbCloudWebApi/Rest/Auth.http b/AsbCloudWebApi/Rest/Auth.http
new file mode 100644
index 00000000..36097c0e
--- /dev/null
+++ b/AsbCloudWebApi/Rest/Auth.http
@@ -0,0 +1,12 @@
+@baseUrl = http://127.0.0.1:5000
+@contentType = application/json
+
+## Auth
+POST {{baseUrl}}/auth/login
+Content-Type: {{contentType}}
+accept: */*
+
+{
+ "login": "dev",
+ "password": "Rp7gsNMk"
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Rest/wellbore.http b/AsbCloudWebApi/Rest/wellbore.http
index 9a7918ac..e00c6687 100644
--- a/AsbCloudWebApi/Rest/wellbore.http
+++ b/AsbCloudWebApi/Rest/wellbore.http
@@ -1,15 +1,13 @@
@baseUrl = http://127.0.0.1:5000
@contentType = application/json
-@auth = Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2NjI1NDgxNjIsImV4cCI6MTY5NDEwNTc2MiwiaXNzIjoiYSIsImF1ZCI6ImEifQ.OEAlNzxi7Jat6pzDBTAjTbChskc-tdJthJexyWwwUKE
+@auth = Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2OTgxMjY1MTUsImV4cCI6MTcyOTY4NDExNSwiaXNzIjoiYSIsImF1ZCI6ImEifQ.3Lq256cYtHnKlGWChPhZv2rUJPjbJEHU-18xdyJlYDE
-@uid = 20210101_000000000
-@idCluster = 1
-@idWell = 1
+@idWell = 2
# https://marketplace.visualstudio.com/items?itemName=humao.rest-client
###
-GET {{baseUrl}}/api/well/wellbore?ids=1,2
+GET {{baseUrl}}/api/wellbore?idsWells=1
Content-Type: {{contentType}}
accept: */*
Authorization: {{auth}}