diff --git a/AsbCloudApp/Data/GTR/JsonValue.cs b/AsbCloudApp/Data/GTR/JsonValue.cs index 01b0c6a9..cd37abea 100644 --- a/AsbCloudApp/Data/GTR/JsonValue.cs +++ b/AsbCloudApp/Data/GTR/JsonValue.cs @@ -4,11 +4,11 @@ /// Класс позволяющий хранить значение неопределенного типа. /// Все возможные типы должны быть описаны в JsonValueJsonConverter. /// - /// - public record JsonValue(object value) + /// + public record JsonValue(object Value) { /// public override string ToString() - => value.ToString() ?? string.Empty; + => Value.ToString() ?? string.Empty; } } diff --git a/AsbCloudApp/Data/GTR/WitsRecordDto.cs b/AsbCloudApp/Data/GTR/WitsRecordDto.cs index 763b439b..28e6ba81 100644 --- a/AsbCloudApp/Data/GTR/WitsRecordDto.cs +++ b/AsbCloudApp/Data/GTR/WitsRecordDto.cs @@ -13,11 +13,6 @@ namespace AsbCloudApp.Data.GTR /// public int Id { get; set; } - /// - /// Id телеметрии - /// - public int IdTelemetry { get; set; } - /// /// Дата создания записи /// diff --git a/AsbCloudApp/Repositories/IGtrRepository.cs b/AsbCloudApp/Repositories/IGtrRepository.cs index d982c373..4082a4cc 100644 --- a/AsbCloudApp/Repositories/IGtrRepository.cs +++ b/AsbCloudApp/Repositories/IGtrRepository.cs @@ -32,7 +32,7 @@ namespace AsbCloudApp.Repositories /// /// Task> GetAsync(int idWell, - DateTime dateBegin = default, double intervalSec = 600d, + DateTime? dateBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default); } #nullable disable diff --git a/AsbCloudDb/Migrations/20230417131126_add_tableWits_and_manualHypertable.Designer.cs b/AsbCloudDb/Migrations/20230418055848_Add_GTR.Designer.cs similarity index 99% rename from AsbCloudDb/Migrations/20230417131126_add_tableWits_and_manualHypertable.Designer.cs rename to AsbCloudDb/Migrations/20230418055848_Add_GTR.Designer.cs index 402e612f..b8aea936 100644 --- a/AsbCloudDb/Migrations/20230417131126_add_tableWits_and_manualHypertable.Designer.cs +++ b/AsbCloudDb/Migrations/20230418055848_Add_GTR.Designer.cs @@ -13,8 +13,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace AsbCloudDb.Migrations { [DbContext(typeof(AsbCloudDbContext))] - [Migration("20230417131126_add_tableWits_and_manualHypertable")] - partial class add_tableWits_and_manualHypertable + [Migration("20230418055848_Add_GTR")] + partial class Add_GTR { protected override void BuildTargetModel(ModelBuilder modelBuilder) { @@ -829,7 +829,7 @@ namespace AsbCloudDb.Migrations b.ToTable("t_wits_float"); - b.HasComment("таблица данных ГТИ с типом значения "); + b.HasComment("таблица данных ГТИ с типом значения float"); }); modelBuilder.Entity("AsbCloudDb.Model.GTR.WitsItemInt", b => @@ -858,7 +858,7 @@ namespace AsbCloudDb.Migrations b.ToTable("t_wits_int"); - b.HasComment("таблица данных ГТИ с типом значения int16 int32"); + b.HasComment("таблица данных ГТИ с типом значения int"); }); modelBuilder.Entity("AsbCloudDb.Model.GTR.WitsItemString", b => @@ -4213,6 +4213,21 @@ namespace AsbCloudDb.Migrations .HasColumnName("pressure_sp_slide") .HasComment("Давление. Задание для режима слайда"); + b.Property("Pump0Flow") + .HasColumnType("real") + .HasColumnName("pump0_flow") + .HasComment("Расход. Буровой насос 1"); + + b.Property("Pump1Flow") + .HasColumnType("real") + .HasColumnName("pump1_flow") + .HasComment("Расход. Буровой насос 2"); + + b.Property("Pump2Flow") + .HasColumnType("real") + .HasColumnName("pump2_flow") + .HasComment("Расход. Буровой насос 3"); + b.Property("RotorSpeed") .HasColumnType("real") .HasColumnName("rotor_speed") diff --git a/AsbCloudDb/Migrations/20230417131126_add_tableWits_and_manualHypertable.cs b/AsbCloudDb/Migrations/20230418055848_Add_GTR.cs similarity index 88% rename from AsbCloudDb/Migrations/20230417131126_add_tableWits_and_manualHypertable.cs rename to AsbCloudDb/Migrations/20230418055848_Add_GTR.cs index 2c9220c6..0eafb5c3 100644 --- a/AsbCloudDb/Migrations/20230417131126_add_tableWits_and_manualHypertable.cs +++ b/AsbCloudDb/Migrations/20230418055848_Add_GTR.cs @@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace AsbCloudDb.Migrations { - public partial class add_tableWits_and_manualHypertable : Migration + public partial class Add_GTR : Migration { protected override void Up(MigrationBuilder migrationBuilder) { @@ -29,7 +29,7 @@ namespace AsbCloudDb.Migrations principalColumn: "id", onDelete: ReferentialAction.Cascade); }, - comment: "таблица данных ГТИ с типом значения "); + comment: "таблица данных ГТИ с типом значения float"); migrationBuilder.CreateTable( name: "t_wits_int", @@ -51,7 +51,7 @@ namespace AsbCloudDb.Migrations principalColumn: "id", onDelete: ReferentialAction.Cascade); }, - comment: "таблица данных ГТИ с типом значения int16 int32"); + comment: "таблица данных ГТИ с типом значения int"); migrationBuilder.CreateTable( name: "t_wits_string", @@ -74,6 +74,12 @@ namespace AsbCloudDb.Migrations onDelete: ReferentialAction.Cascade); }, comment: "таблица данных ГТИ с типом значения string"); + + migrationBuilder.Sql + ("SELECT create_hypertable('t_wits_string','date','id_telemetry',2,chunk_time_interval => INTERVAL '5 day'); " + + "SELECT create_hypertable('t_wits_float','date','id_telemetry',2,chunk_time_interval => INTERVAL '5 day'); " + + "SELECT create_hypertable('t_wits_int','date','id_telemetry',2,chunk_time_interval => INTERVAL '5 day'); "); + } protected override void Down(MigrationBuilder migrationBuilder) diff --git a/AsbCloudDb/Migrations/AsbCloudDbContextModelSnapshot.cs b/AsbCloudDb/Migrations/AsbCloudDbContextModelSnapshot.cs index a80d3027..0e7450c4 100644 --- a/AsbCloudDb/Migrations/AsbCloudDbContextModelSnapshot.cs +++ b/AsbCloudDb/Migrations/AsbCloudDbContextModelSnapshot.cs @@ -827,7 +827,7 @@ namespace AsbCloudDb.Migrations b.ToTable("t_wits_float"); - b.HasComment("таблица данных ГТИ с типом значения "); + b.HasComment("таблица данных ГТИ с типом значения float"); }); modelBuilder.Entity("AsbCloudDb.Model.GTR.WitsItemInt", b => @@ -856,7 +856,7 @@ namespace AsbCloudDb.Migrations b.ToTable("t_wits_int"); - b.HasComment("таблица данных ГТИ с типом значения int16 int32"); + b.HasComment("таблица данных ГТИ с типом значения int"); }); modelBuilder.Entity("AsbCloudDb.Model.GTR.WitsItemString", b => diff --git a/AsbCloudDb/Model/GTR/WitsItemBase.cs b/AsbCloudDb/Model/GTR/WitsItemBase.cs index c4259046..7d01b106 100644 --- a/AsbCloudDb/Model/GTR/WitsItemBase.cs +++ b/AsbCloudDb/Model/GTR/WitsItemBase.cs @@ -29,9 +29,9 @@ namespace AsbCloudDb.Model.GTR [Table("t_wits_string"), Comment("таблица данных ГТИ с типом значения string")] public class WitsItemString : WitsItemBase { } - [Table("t_wits_float"), Comment("таблица данных ГТИ с типом значения ")] + [Table("t_wits_float"), Comment("таблица данных ГТИ с типом значения float")] public class WitsItemFloat : WitsItemBase { } - [Table("t_wits_int"), Comment("таблица данных ГТИ с типом значения int16 int32")] + [Table("t_wits_int"), Comment("таблица данных ГТИ с типом значения int")] public class WitsItemInt : WitsItemBase { } } diff --git a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs index ce12d6fe..f3c21918 100644 --- a/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs +++ b/AsbCloudInfrastructure/Repository/GtrWitsRepository.cs @@ -28,7 +28,7 @@ namespace AsbCloudInfrastructure.Repository this.telemetryService = telemetryService; } - public async Task> GetAsync(int idWell, DateTime dateBegin = default, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default) + public async Task> GetAsync(int idWell, DateTime? dateBegin, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default) { var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); if (telemetry is null) @@ -36,91 +36,53 @@ namespace AsbCloudInfrastructure.Repository var timezone = telemetryService.GetTimezone(telemetry.Id); - var filterByDateEnd = dateBegin != default; - DateTimeOffset dateBeginUtc; - if (dateBegin == default) - { - dateBeginUtc = telemetryService.GetLastTelemetryDate(telemetry.Id) - .ToUtcDateTimeOffset(timezone.Hours); - if (dateBeginUtc != default) - dateBeginUtc = dateBeginUtc.AddSeconds(-intervalSec); - } - else - { - dateBeginUtc = dateBegin.ToUtcDateTimeOffset(timezone.Hours); - } + DateTimeOffset? dateBeginUtc = dateBegin?.ToUtcDateTimeOffset(timezone.Hours); + var dateEnd = dateBeginUtc?.AddSeconds(intervalSec); - if (dateBeginUtc == default) - dateBeginUtc = DateTime.UtcNow.AddSeconds(-intervalSec); - var dateEnd = dateBeginUtc.AddSeconds(intervalSec); + var recordAllInt = await GetItemsOrDefaultAsync(telemetry.Id, dateBeginUtc, dateEnd, approxPointsCount, timezone.Hours, token); + var recordAllFloat = await GetItemsOrDefaultAsync(telemetry.Id, dateBeginUtc, dateEnd, approxPointsCount,timezone.Hours, token); + var recordAllString = await GetItemsOrDefaultAsync(telemetry.Id, dateBeginUtc, dateEnd, approxPointsCount, timezone.Hours, token); - var queryWitsInt = db.Set() - .Where(d => d.IdTelemetry == telemetry.Id); - var queryWitsString = db.Set() - .Where(d => d.IdTelemetry == telemetry.Id); - var queryWitsFloat = db.Set() - .Where(d => d.IdTelemetry == telemetry.Id); - - var recordAllInt = await GetItemsOrDefaultAsync(queryWitsInt, dateBeginUtc, dateEnd, filterByDateEnd, approxPointsCount, timezone.Hours, token); - var recordAllFloat = await GetItemsOrDefaultAsync(queryWitsFloat, dateBeginUtc, dateEnd, filterByDateEnd, approxPointsCount,timezone.Hours, token); - var recordAllString = await GetItemsOrDefaultAsync(queryWitsString, dateBeginUtc, dateEnd, filterByDateEnd, approxPointsCount, timezone.Hours, token); - var groupRecordDate = (recordAllFloat.Union(recordAllInt)).Union(recordAllString) + var dtos = (recordAllFloat.Union(recordAllInt)).Union(recordAllString) .GroupBy(g => new { g.IdRecord, g.Date - }).ToList(); - var dtos = groupRecordDate.Select(g => new WitsRecordDto - { - Id = g.Key.IdRecord, - Date = g.Key.Date, - IdTelemetry = g.First().IdTelemetry, - Items = g.Select(r => new { - Key = r.IdItem, - Value = r.Item - }).ToDictionary(x => x.Key, x => x.Value) - }); + }) + .Select(g => new WitsRecordDto + { + Id = g.Key.IdRecord, + Date = g.Key.Date, + Items = g.Select(r => new { + Key = r.IdItem, + Value = r.Item + }).ToDictionary(x => x.Key, x => x.Value) + }); return dtos; } - public async Task SaveDataAsync(int idTelemetry, WitsRecordDto dto, CancellationToken token) + private async Task> GetItemsOrDefaultAsync( + int idTelemetry, + DateTimeOffset? dateBegin, + DateTimeOffset? dateEnd, + int approxPointsCount, + double timezoneHours, + CancellationToken token) + where TEntity: WitsItemBase + where TValue: notnull { - if (dto is null) - return; - var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours; - foreach (var item in dto.Items) - { - var jsonValue = item.Value; - if(jsonValue.value is string valueString) - { - var entity = ConvertToEntity(dto, valueString, timezoneHours); - db.WitsItemString.Add(entity.Adapt()); - } - if (jsonValue.value is float valueFloat) - { - var entity = ConvertToEntity(dto, valueFloat, timezoneHours); - db.WitsItemFloat.Add(entity.Adapt()); - } - if (jsonValue.value is int valueInt) - { - var entity = ConvertToEntity(dto, valueInt, timezoneHours); - db.WitsItemInt.Add(entity.Adapt()); - } - } - await db.SaveChangesAsync(token); - } + var query = db.Set() + .Where(i => i.IdTelemetry == idTelemetry); - private static async Task> GetItemsOrDefaultAsync(IQueryable> query, - DateTimeOffset dateBeginUtc, - DateTimeOffset dateEnd, bool filterByDateEnd, int approxPointsCount, double timezoneHours - , CancellationToken token) - where T: notnull - { - if (filterByDateEnd) - query = query.Where(d => d.DateTime <= dateEnd); + if (dateBegin is not null) + query = query + .Where(d => d.DateTime >= dateBegin); - var fullDataCount = await query.CountAsync(token) - .ConfigureAwait(false); + if (dateEnd is not null) + query = query + .Where(d => d.DateTime <= dateEnd); + + var fullDataCount = await query.CountAsync(token); if (fullDataCount == 0) return Enumerable.Empty(); @@ -133,7 +95,6 @@ namespace AsbCloudInfrastructure.Repository } var entities = await query - .Where(d => d.DateTime >= dateBeginUtc) .OrderBy(d => d.DateTime) .AsNoTracking() .ToListAsync(token) @@ -149,15 +110,43 @@ namespace AsbCloudInfrastructure.Repository }); return items; } - private static WitsItemBase ConvertToEntity(WitsRecordDto record, Tvalue value, double timezoneHours) - where Tvalue: notnull + + public async Task SaveDataAsync(int idTelemetry, WitsRecordDto dto, CancellationToken token) { - var entity = record.Adapt>(); - entity.DateTime = record.Date.ToUtcDateTimeOffset(timezoneHours); - entity.Value = value; - return entity; + var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours; + foreach (var item in dto.Items) + { + var dateTime = dto.Date.ToUtcDateTimeOffset(timezoneHours); + if (item.Value.Value is string valueString) + { + var entity = MakeEntity( dto.Id, item.Key, idTelemetry, dateTime, valueString); + db.WitsItemString.Add(entity); + } + if (item.Value.Value is float valueFloat) + { + var entity = MakeEntity(dto.Id, item.Key, idTelemetry, dateTime, valueFloat); + db.WitsItemFloat.Add(entity); + } + if (item.Value.Value is int valueInt) + { + var entity = MakeEntity(dto.Id, item.Key, idTelemetry, dateTime, valueInt); + db.WitsItemInt.Add(entity); + } + } + await db.SaveChangesAsync(token); } + private static TEntity MakeEntity(int idRecord, int idItem, int idTelemetry, DateTimeOffset dateTime, TValue value) + where TEntity : WitsItemBase, new() + where TValue: notnull + => new TEntity() { + IdRecord = idRecord, + IdItem = idItem, + IdTelemetry = idTelemetry, + DateTime = dateTime, + Value = value, + }; + internal class ItemRecord { public int IdRecord { get; set; } diff --git a/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs b/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs index 094b7319..895d4721 100644 --- a/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/GtrWitsController.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; namespace AsbCloudWebApi.Controllers.SAUB { +#nullable enable [Route("api/[controller]")] [ApiController] public class GtrWitsController : ControllerBase @@ -22,7 +23,7 @@ namespace AsbCloudWebApi.Controllers.SAUB private readonly IGtrRepository gtrRepository; private readonly IHubContext telemetryHubContext; - public string SirnalRMethodGetDataName { get; protected set; } = "ReceiveData"; + public string SignalRMethodGetDataName { get; protected set; } = "ReceiveData"; public GtrWitsController( ITelemetryService telemetryService, @@ -47,7 +48,7 @@ namespace AsbCloudWebApi.Controllers.SAUB /// [HttpGet("{idWell}")] [Permission] - public async Task>> GetDataAsync(int idWell, DateTime begin = default, + public async Task>> GetDataAsync(int idWell, DateTime? begin, int intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default) { int? idCompany = User.GetCompanyId(); @@ -86,8 +87,9 @@ namespace AsbCloudWebApi.Controllers.SAUB var idWell = telemetryService.GetIdWellByTelemetryUid(uid); if (idWell is not null && dto is not null) _ = Task.Run(() => telemetryHubContext.Clients.Group($"well_{idWell}_gtr") - .SendAsync(SirnalRMethodGetDataName, dto), CancellationToken.None); + .SendAsync(SignalRMethodGetDataName, dto), CancellationToken.None); return Ok(); } } +#nullable disable } diff --git a/AsbCloudWebApi/Converters/ValueContainerJsonConverter.cs b/AsbCloudWebApi/Converters/JsonValueJsonConverter.cs similarity index 87% rename from AsbCloudWebApi/Converters/ValueContainerJsonConverter.cs rename to AsbCloudWebApi/Converters/JsonValueJsonConverter.cs index c178d963..386f1234 100644 --- a/AsbCloudWebApi/Converters/ValueContainerJsonConverter.cs +++ b/AsbCloudWebApi/Converters/JsonValueJsonConverter.cs @@ -30,37 +30,37 @@ namespace AsbCloudWebApi.Converters public override void Write(Utf8JsonWriter writer, JsonValue value, JsonSerializerOptions options) { - if (value.value is string strValue) + if (value.Value is string strValue) { writer.WriteStringValue(FormatString(strValue)); return; } - if (value.value is int intValue) + if (value.Value is int intValue) { writer.WriteNumberValue(intValue); return; } - if (value.value is short shortValue) + if (value.Value is short shortValue) { writer.WriteNumberValue(shortValue); return; } - if (value.value is float floatValue) + if (value.Value is float floatValue) { writer.WriteRawValue(floatValue.ToString("#0.0##", CultureInfo.InvariantCulture), true); return; } - if (value.value is double doubleValue) + if (value.Value is double doubleValue) { writer.WriteRawValue(doubleValue.ToString("#0.0##", CultureInfo.InvariantCulture), true); return; } - var typeName = value.value.GetType().Name; + var typeName = value.Value.GetType().Name; throw new NotImplementedException($"{typeName} is not supported type for WITS value"); } diff --git a/AsbCloudWebApi/Rest/Gtr.http b/AsbCloudWebApi/Rest/Gtr.http new file mode 100644 index 00000000..32f6a474 --- /dev/null +++ b/AsbCloudWebApi/Rest/Gtr.http @@ -0,0 +1,31 @@ +@baseUrl = http://127.0.0.1:5000 +@contentType = application/json +@auth = Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2NjI1NDgxNjIsImV4cCI6MTY5NDEwNTc2MiwiaXNzIjoiYSIsImF1ZCI6ImEifQ.OEAlNzxi7Jat6pzDBTAjTbChskc-tdJthJexyWwwUKE + +@uid = 20210910_012752700 +@idCluster = 1 +@idWell = 1 + +# https://marketplace.visualstudio.com/items?itemName=humao.rest-client + +### +GET {{baseUrl}}/api/GtrWits/{{idWell}} +Content-Type: {{contentType}} +accept: */* +Authorization: {{auth}} + +### Post +POST {{baseUrl}}/api/GtrWits/{{uid}} +Content-Type: {{contentType}} +accept: */* +Authorization: {{auth}} + +{ + "id":1, + "date": "2023-04-18T08:41:49.332Z", + "items": { + "1": 1, + "2": 1.1, + "3": "string1" + } +} \ No newline at end of file