From 3a1ea55be27041b8cd7ada723829c14fe760a843 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 20 Nov 2024 16:08:16 +0500 Subject: [PATCH 1/5] =?UTF-8?q?=D0=90=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B2=D0=BD=D1=83=D1=82=D1=80=D0=B8?= =?UTF-8?q?=20=D0=B8=D0=BD=D1=82=D0=B5=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=BE?= =?UTF-8?q?=D0=BD=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=82=D0=B5=D1=81=D1=82=D0=B0?= =?UTF-8?q?=20(=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TimeSeriesBaseControllerTest.cs | 3 +- .../WebAppFactoryFixture.cs | 33 ++++++++++--------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Persistence.IntegrationTests/Controllers/TimeSeriesBaseControllerTest.cs b/Persistence.IntegrationTests/Controllers/TimeSeriesBaseControllerTest.cs index 2119bf7..c63f094 100644 --- a/Persistence.IntegrationTests/Controllers/TimeSeriesBaseControllerTest.cs +++ b/Persistence.IntegrationTests/Controllers/TimeSeriesBaseControllerTest.cs @@ -22,7 +22,8 @@ public abstract class TimeSeriesBaseControllerTest : BaseIntegrat public TimeSeriesBaseControllerTest(WebAppFactoryFixture factory) : base(factory) { dbContext.CleanupDbSet(); - client = factory.GetHttpClient>(string.Empty); + + client = factory.GetAuthorizedHttpClient>(string.Empty); } public async Task InsertRangeSuccess(TDto dto) diff --git a/Persistence.IntegrationTests/WebAppFactoryFixture.cs b/Persistence.IntegrationTests/WebAppFactoryFixture.cs index d1cedf8..62489e3 100644 --- a/Persistence.IntegrationTests/WebAppFactoryFixture.cs +++ b/Persistence.IntegrationTests/WebAppFactoryFixture.cs @@ -8,6 +8,7 @@ using Persistence.Database.Postgres; using Persistence.API; using Refit; using System.Text.Json; +using System.Net.Http.Headers; namespace Persistence.IntegrationTests; public class WebAppFactoryFixture : WebApplicationFactory @@ -79,23 +80,23 @@ public class WebAppFactoryFixture : WebApplicationFactory return RestService.For(httpClient, RefitSettings); } - //public T GetAuthorizedHttpClient(string uriSuffix) - //{ - // var httpClient = GetAuthorizedHttpClient(); - // if (string.IsNullOrEmpty(uriSuffix)) - // return RestService.For(httpClient, RefitSettings); + public T GetAuthorizedHttpClient(string uriSuffix) + { + var httpClient = GetAuthorizedHttpClient(); + if (string.IsNullOrEmpty(uriSuffix)) + return RestService.For(httpClient, RefitSettings); - // if (httpClient.BaseAddress is not null) - // httpClient.BaseAddress = new Uri(httpClient.BaseAddress, uriSuffix); + if (httpClient.BaseAddress is not null) + httpClient.BaseAddress = new Uri(httpClient.BaseAddress, uriSuffix); - // return RestService.For(httpClient, RefitSettings); - //} + return RestService.For(httpClient, RefitSettings); + } - //private HttpClient GetAuthorizedHttpClient() - //{ - // var httpClient = CreateClient(); - // var jwtToken = ApiTokenHelper.GetAdminUserToken(); - // httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken); - // return httpClient; - //} + private HttpClient GetAuthorizedHttpClient() + { + var httpClient = CreateClient(); + ////var jwtToken = ApiTokenHelper.GetAdminUserToken(); + //httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken); + return httpClient; + } } From 098c180b12b0881f910035d34d4cdf4347af8d9d Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 21 Nov 2024 11:41:53 +0500 Subject: [PATCH 2/5] =?UTF-8?q?=D0=90=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B2=20=D0=B8=D0=BD=D1=82=D0=B5?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=BE=D0=BD=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Persistence.API/appsettings.Tests.json | 9 +++- Persistence.API/appsettings.json | 6 +-- .../Controllers/DataSaubControllerTest.cs | 2 +- .../TimeSeriesBaseControllerTest.cs | 5 ++- Persistence.IntegrationTests/JwtToken.cs | 8 ++++ Persistence.IntegrationTests/KeyCloakUser.cs | 27 ++++++++++++ .../Persistence.IntegrationTests.csproj | 1 + .../WebAppFactoryFixture.cs | 43 +++++++++++++++---- 8 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 Persistence.IntegrationTests/JwtToken.cs create mode 100644 Persistence.IntegrationTests/KeyCloakUser.cs diff --git a/Persistence.API/appsettings.Tests.json b/Persistence.API/appsettings.Tests.json index c1329f9..033464f 100644 --- a/Persistence.API/appsettings.Tests.json +++ b/Persistence.API/appsettings.Tests.json @@ -4,5 +4,12 @@ "Port": 5432, "Username": "postgres", "Password": "q" - } + }, + "KeycloakTestUser": { + "username": "myuser", + "password": 12345, + "clientId": "webapi", + "grantType": "password" + }, + "KeycloakGetTokenUrl": "http://192.168.0.10:8321/realms/Persistence/protocol/openid-connect/token" } diff --git a/Persistence.API/appsettings.json b/Persistence.API/appsettings.json index 2e0033b..3e1eea7 100644 --- a/Persistence.API/appsettings.json +++ b/Persistence.API/appsettings.json @@ -10,9 +10,9 @@ }, "AllowedHosts": "*", "Authentication": { - "MetadataAddress": "http://localhost:8080/realms/TestRealm/.well-known/openid-configuration", + "MetadataAddress": "http://192.168.0.10:8321/realms/Persistence/.well-known/openid-configuration", "Audience": "account", - "ValidIssuer": "http://localhost:8080/realms/TestRealm", - "AuthorizationUrl": "http://localhost:8080/realms/TestRealm/protocol/openid-connect/auth" + "ValidIssuer": "http://192.168.0.10:8321/realms/Persistence", + "AuthorizationUrl": "http://192.168.0.10:8321/realms/Persistence/protocol/openid-connect/auth" } } diff --git a/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs b/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs index 025492a..0e15a60 100644 --- a/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs +++ b/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs @@ -11,7 +11,7 @@ public class DataSaubControllerTest : TimeSeriesBaseControllerTest : BaseIntegrat { dbContext.CleanupDbSet(); - client = factory.GetAuthorizedHttpClient>(string.Empty); + Task.Run(async () => + { + client = await factory.GetAuthorizedHttpClient>(string.Empty); + }).Wait(); } public async Task InsertRangeSuccess(TDto dto) diff --git a/Persistence.IntegrationTests/JwtToken.cs b/Persistence.IntegrationTests/JwtToken.cs new file mode 100644 index 0000000..38bf315 --- /dev/null +++ b/Persistence.IntegrationTests/JwtToken.cs @@ -0,0 +1,8 @@ +using System.Text.Json.Serialization; + +namespace Persistence.IntegrationTests; +public class JwtToken +{ + [JsonPropertyName("access_token")] + public required string AccessToken { get; set; } +} diff --git a/Persistence.IntegrationTests/KeyCloakUser.cs b/Persistence.IntegrationTests/KeyCloakUser.cs new file mode 100644 index 0000000..aa4d335 --- /dev/null +++ b/Persistence.IntegrationTests/KeyCloakUser.cs @@ -0,0 +1,27 @@ +namespace Persistence.IntegrationTests; + +/// +/// настройки credentials для пользователя в KeyCloak +/// +public class KeyCloakUser +{ + /// + /// + /// + public required string Username { get; set; } + + /// + /// + /// + public required string Password { get; set; } + + /// + /// + /// + public required string ClientId { get; set; } + + /// + /// + /// + public required string GrantType { get; set; } +} diff --git a/Persistence.IntegrationTests/Persistence.IntegrationTests.csproj b/Persistence.IntegrationTests/Persistence.IntegrationTests.csproj index 912eeda..f36e78d 100644 --- a/Persistence.IntegrationTests/Persistence.IntegrationTests.csproj +++ b/Persistence.IntegrationTests/Persistence.IntegrationTests.csproj @@ -15,6 +15,7 @@ + all diff --git a/Persistence.IntegrationTests/WebAppFactoryFixture.cs b/Persistence.IntegrationTests/WebAppFactoryFixture.cs index 62489e3..8ac7bf2 100644 --- a/Persistence.IntegrationTests/WebAppFactoryFixture.cs +++ b/Persistence.IntegrationTests/WebAppFactoryFixture.cs @@ -3,12 +3,13 @@ using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Persistence.API; using Persistence.Database.Model; using Persistence.Database.Postgres; -using Persistence.API; using Refit; -using System.Text.Json; +using RestSharp; using System.Net.Http.Headers; +using System.Text.Json; namespace Persistence.IntegrationTests; public class WebAppFactoryFixture : WebApplicationFactory @@ -23,6 +24,8 @@ public class WebAppFactoryFixture : WebApplicationFactory private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions)); private readonly string connectionString; + private readonly KeyCloakUser keycloakTestUser; + public readonly string KeycloakGetTokenUrl; public WebAppFactoryFixture() { @@ -32,6 +35,10 @@ public class WebAppFactoryFixture : WebApplicationFactory var dbConnection = configuration.GetSection("DbConnection").Get()!; connectionString = dbConnection.GetConnectionString(); + + keycloakTestUser = configuration.GetSection("KeycloakTestUser").Get()!; + + KeycloakGetTokenUrl = configuration.GetSection("KeycloakGetTokenUrl").Value!; } protected override void ConfigureWebHost(IWebHostBuilder builder) @@ -53,7 +60,6 @@ public class WebAppFactoryFixture : WebApplicationFactory var dbContext = scopedServices.GetRequiredService(); dbContext.Database.EnsureCreatedAndMigrated(); - //dbContext.Deposits.AddRange(Data.Defaults.Deposits); dbContext.SaveChanges(); }); } @@ -80,9 +86,9 @@ public class WebAppFactoryFixture : WebApplicationFactory return RestService.For(httpClient, RefitSettings); } - public T GetAuthorizedHttpClient(string uriSuffix) + public async Task GetAuthorizedHttpClient(string uriSuffix) { - var httpClient = GetAuthorizedHttpClient(); + var httpClient = await GetAuthorizedHttpClient(); if (string.IsNullOrEmpty(uriSuffix)) return RestService.For(httpClient, RefitSettings); @@ -92,11 +98,32 @@ public class WebAppFactoryFixture : WebApplicationFactory return RestService.For(httpClient, RefitSettings); } - private HttpClient GetAuthorizedHttpClient() + private async Task GetAuthorizedHttpClient() { var httpClient = CreateClient(); - ////var jwtToken = ApiTokenHelper.GetAdminUserToken(); - //httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken); + var token = await GetTokenAsync(); + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + return httpClient; } + + private async Task GetTokenAsync() + { + var restClient = new RestClient(); + + var request = new RestRequest(KeycloakGetTokenUrl, Method.Post); + request.AddParameter("username", keycloakTestUser.Username); + request.AddParameter("password", keycloakTestUser.Password); + request.AddParameter("client_id", keycloakTestUser.ClientId); + request.AddParameter("grant_type", keycloakTestUser.GrantType); + + var keyCloackResponse = await restClient.PostAsync(request); + if (keyCloackResponse.IsSuccessful && !String.IsNullOrEmpty(keyCloackResponse.Content)) + { + var token = JsonSerializer.Deserialize(keyCloackResponse.Content)!; + return token.AccessToken; + } + + return String.Empty; + } } From c751f74b35e05f1aa09b9fdf4f24542ea3b83a75 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 21 Nov 2024 17:02:36 +0500 Subject: [PATCH 3/5] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BD=20=D1=81?= =?UTF-8?q?=D1=83=D1=84=D1=84=D0=B8=D0=BA=D1=81=20"Async"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/TimeSeriesController.cs | 18 +++++++---- Persistence.API/Program.cs | 3 ++ .../TimeSeriesDataCachedRepository.cs | 27 ++++++++++++---- .../Repositories/TimeSeriesDataRepository.cs | 30 +++++++++-------- Persistence/API/IChangeLogApi.cs | 12 +++---- Persistence/API/IDictionaryElementApi.cs | 8 ++--- Persistence/API/ISetpointApi.cs | 8 ++--- Persistence/API/ISyncApi.cs | 2 +- Persistence/API/ITableDataApi.cs | 2 +- ...phDataApi.cs => ITimeSeriesBaseDataApi.cs} | 10 +++--- Persistence/API/ITimeSeriesDataApi.cs | 14 ++------ Persistence/Models/ChangeLogDto.cs | 2 +- .../Repositories/ISetpointRepository.cs | 6 ++-- .../Repositories/ITableDataRepository.cs | 2 +- ...sitory.cs => ITimeSeriesBaseRepository.cs} | 6 ++-- .../Repositories/ITimeSeriesDataRepository.cs | 32 +------------------ 16 files changed, 85 insertions(+), 97 deletions(-) rename Persistence/API/{IGraphDataApi.cs => ITimeSeriesBaseDataApi.cs} (61%) rename Persistence/Repositories/{IGraphDataRepository.cs => ITimeSeriesBaseRepository.cs} (76%) diff --git a/Persistence.API/Controllers/TimeSeriesController.cs b/Persistence.API/Controllers/TimeSeriesController.cs index e6c74ef..d4491cc 100644 --- a/Persistence.API/Controllers/TimeSeriesController.cs +++ b/Persistence.API/Controllers/TimeSeriesController.cs @@ -19,24 +19,30 @@ public class TimeSeriesController : ControllerBase, ITimeSeriesDataApi GetAsync(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token) + public async Task Get(DateTimeOffset dateBegin, CancellationToken token) { - var result = await this.timeSeriesDataRepository.GetAsync(dateBegin, dateEnd, token); + var result = await this.timeSeriesDataRepository.GetGtDate(dateBegin, token); return Ok(result); - } [HttpGet("datesRange")] - public async Task GetDatesRangeAsync(CancellationToken token) + public async Task GetDatesRange(CancellationToken token) { - var result = await this.timeSeriesDataRepository.GetDatesRangeAsync(token); + var result = await this.timeSeriesDataRepository.GetDatesRange(token); return Ok(result); } + public Task GetResampledData(DateTimeOffset dateBegin, DateTimeOffset dateEnd, int approxPointsCount = 1024) + { + throw new NotImplementedException(); + } + [HttpPost] - public async Task InsertRangeAsync(IEnumerable dtos, CancellationToken token) + public async Task InsertRange(IEnumerable dtos, CancellationToken token) { var result = await this.timeSeriesDataRepository.InsertRange(dtos, token); return Ok(result); } + + } diff --git a/Persistence.API/Program.cs b/Persistence.API/Program.cs index 93e62a1..bc54d92 100644 --- a/Persistence.API/Program.cs +++ b/Persistence.API/Program.cs @@ -1,10 +1,13 @@ +using Persistence.Models; + namespace Persistence.API; public class Program { public static void Main(string[] args) { + var host = CreateHostBuilder(args).Build(); Startup.BeforeRunHandler(host); host.Run(); diff --git a/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs b/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs index 4a553ac..7c9d06e 100644 --- a/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs +++ b/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs @@ -10,8 +10,8 @@ public class TimeSeriesDataCachedRepository : TimeSeriesDataRepos where TEntity : class, ITimestampedData, new() where TDto : class, ITimeSeriesAbstractDto, new() { - public static TDto FirstByDate { get; set; } = default!; - public static CyclicArray LastData { get; set; } = null!; + public static TDto? FirstByDate { get; private set; } + public static CyclicArray LastData { get; } = new CyclicArray(CacheItemsCount); private const int CacheItemsCount = 3600; @@ -19,8 +19,6 @@ public class TimeSeriesDataCachedRepository : TimeSeriesDataRepos { Task.Run(async () => { - LastData = new CyclicArray(CacheItemsCount); - var firstDateItem = await base.GetFirstAsync(CancellationToken.None); if (firstDateItem == null) { @@ -35,17 +33,17 @@ public class TimeSeriesDataCachedRepository : TimeSeriesDataRepos }).Wait(); } - public override async Task> GetAsync(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token) + public override async Task> GetGtDate(DateTimeOffset dateBegin, CancellationToken token) { if (LastData.Count() == 0 || LastData[0].Date > dateBegin) { - var dtos = await base.GetAsync(dateBegin, dateEnd, token); + var dtos = await base.GetGtDate(dateBegin, token); return dtos; } var items = LastData - .Where(i => i.Date >= dateBegin && i.Date <= dateEnd); + .Where(i => i.Date >= dateBegin); return items; } @@ -64,5 +62,20 @@ public class TimeSeriesDataCachedRepository : TimeSeriesDataRepos return result; } + + public override async Task GetDatesRange(CancellationToken token) + { + if (FirstByDate == null) + return null; + + return await Task.Run(() => + { + return new DatesRangeDto + { + From = FirstByDate.Date, + To = LastData[^1].Date + }; + }); + } } diff --git a/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs b/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs index 9b339a5..ec255cb 100644 --- a/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs +++ b/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs @@ -18,16 +18,7 @@ public class TimeSeriesDataRepository : ITimeSeriesDataRepository protected virtual IQueryable GetQueryReadOnly() => this.db.Set(); - public virtual async Task> GetAsync(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token) - { - var query = GetQueryReadOnly(); - var entities = await query.ToArrayAsync(token); - var dtos = entities.Select(e => e.Adapt()); - - return dtos; - } - - public virtual async Task GetDatesRangeAsync(CancellationToken token) + public virtual async Task GetDatesRange(CancellationToken token) { var query = GetQueryReadOnly(); var minDate = await query.MinAsync(o => o.Date, token); @@ -42,6 +33,13 @@ public class TimeSeriesDataRepository : ITimeSeriesDataRepository public virtual async Task> GetGtDate(DateTimeOffset date, CancellationToken token) { + //var query = GetQueryReadOnly() + // .Where(q => q.Date >= dateBegin); + //var entities = await query.ToArrayAsync(token); + //var dtos = entities.Select(e => e.Adapt()); + + //return dtos; + var query = this.db.Set().Where(e => e.Date > date); var entities = await query.ToArrayAsync(token); @@ -60,7 +58,7 @@ public class TimeSeriesDataRepository : ITimeSeriesDataRepository return result; } - public async Task> GetLastAsync(int takeCount, CancellationToken token) + protected async Task> GetLastAsync(int takeCount, CancellationToken token) { var query = GetQueryReadOnly() .OrderByDescending(e => e.Date) @@ -72,17 +70,23 @@ public class TimeSeriesDataRepository : ITimeSeriesDataRepository return dtos; } - public async Task GetFirstAsync(CancellationToken token) + protected async Task GetFirstAsync(CancellationToken token) { var query = GetQueryReadOnly() .OrderBy(e => e.Date); var entity = await query.FirstOrDefaultAsync(token); - if(entity == null) + if (entity == null) return null; var dto = entity.Adapt(); return dto; } + + public Task> GetResampledData(DateTimeOffset dateBegin, DateTimeOffset dateEnd, int approxPointsCount = 1024) + { + //todo + throw new NotImplementedException(); + } } diff --git a/Persistence/API/IChangeLogApi.cs b/Persistence/API/IChangeLogApi.cs index 716944e..bb4a3c3 100644 --- a/Persistence/API/IChangeLogApi.cs +++ b/Persistence/API/IChangeLogApi.cs @@ -31,7 +31,7 @@ public interface IChangeLogApi /// /// /// - Task> AddAsync(TDto dto, CancellationToken token); + Task> Add(TDto dto, CancellationToken token); /// /// Добавить несколько записей @@ -39,7 +39,7 @@ public interface IChangeLogApi /// /// /// - Task> AddRangeAsync(IEnumerable dtos, CancellationToken token); + Task> AddRange(IEnumerable dtos, CancellationToken token); /// /// Обновить одну запись @@ -47,7 +47,7 @@ public interface IChangeLogApi /// /// /// - Task> UpdateAsync(TDto dto, CancellationToken token); + Task> Update(TDto dto, CancellationToken token); /// /// Обновить несколько записей @@ -55,7 +55,7 @@ public interface IChangeLogApi /// /// /// - Task> UpdateRangeAsync(IEnumerable dtos, CancellationToken token); + Task> UpdateRange(IEnumerable dtos, CancellationToken token); /// /// Удалить одну запись @@ -63,7 +63,7 @@ public interface IChangeLogApi /// /// /// - Task> DeleteAsync(int id, CancellationToken token); + Task> Delete(int id, CancellationToken token); /// /// Удалить несколько записей @@ -71,5 +71,5 @@ public interface IChangeLogApi /// /// /// - Task> DeleteRangeAsync(IEnumerable ids, CancellationToken token); + Task> DeleteRange(IEnumerable ids, CancellationToken token); } diff --git a/Persistence/API/IDictionaryElementApi.cs b/Persistence/API/IDictionaryElementApi.cs index 540d454..fac7870 100644 --- a/Persistence/API/IDictionaryElementApi.cs +++ b/Persistence/API/IDictionaryElementApi.cs @@ -13,7 +13,7 @@ public interface IDictionaryElementApi where TDto : class, new() /// ключ справочника /// /// - Task>> GetAsync(Guid dictionaryKey, CancellationToken token); + Task>> Get(Guid dictionaryKey, CancellationToken token); /// /// Добавить элемент в справочник @@ -22,7 +22,7 @@ public interface IDictionaryElementApi where TDto : class, new() /// /// /// - Task> AddAsync(Guid dictionaryKey, TDto dto, CancellationToken token); + Task> Add(Guid dictionaryKey, TDto dto, CancellationToken token); /// /// Изменить одну запись @@ -32,7 +32,7 @@ public interface IDictionaryElementApi where TDto : class, new() /// /// /// - Task> UpdateAsync(Guid dictionaryKey, Guid dictionaryElementKey, TDto dto, CancellationToken token); + Task> Update(Guid dictionaryKey, Guid dictionaryElementKey, TDto dto, CancellationToken token); /// /// Удалить одну запись @@ -41,5 +41,5 @@ public interface IDictionaryElementApi where TDto : class, new() /// ключ элемента в справочнике /// /// - Task> DeleteAsync(Guid dictionaryKey, Guid dictionaryElementKey, CancellationToken token); + Task> Delete(Guid dictionaryKey, Guid dictionaryElementKey, CancellationToken token); } diff --git a/Persistence/API/ISetpointApi.cs b/Persistence/API/ISetpointApi.cs index d086557..7af0895 100644 --- a/Persistence/API/ISetpointApi.cs +++ b/Persistence/API/ISetpointApi.cs @@ -14,7 +14,7 @@ public interface ISetpointApi /// ключи уставок /// /// - Task>> GetCurrentAsync(IEnumerable setpoitKeys, CancellationToken token); + Task>> GetCurrent(IEnumerable setpoitKeys, CancellationToken token); /// /// Получить значения уставок за определенный момент времени @@ -23,7 +23,7 @@ public interface ISetpointApi /// дата, на которую получаем данные /// /// - Task>> GetHistoryAsync(IEnumerable setpoitKeys, DateTimeOffset historyMoment, CancellationToken token); + Task>> GetHistory(IEnumerable setpoitKeys, DateTimeOffset historyMoment, CancellationToken token); /// /// Получить историю изменений значений уставок @@ -31,7 +31,7 @@ public interface ISetpointApi /// ключи уставок /// /// - Task>>> GetLogAsync(IEnumerable setpoitKeys, CancellationToken token); + Task>>> GetLog(IEnumerable setpoitKeys, CancellationToken token); /// /// Метод сохранения уставки @@ -40,5 +40,5 @@ public interface ISetpointApi /// значение /// /// - Task> SaveAsync(Guid setpointKey, object newValue, CancellationToken token); + Task> Save(Guid setpointKey, object newValue, CancellationToken token); } diff --git a/Persistence/API/ISyncApi.cs b/Persistence/API/ISyncApi.cs index 9df4301..7f72812 100644 --- a/Persistence/API/ISyncApi.cs +++ b/Persistence/API/ISyncApi.cs @@ -15,7 +15,7 @@ public interface ISyncApi where TDto : class, new() /// количество записей /// /// - Task>> GetPartAsync(DateTimeOffset dateBegin, int take = 24 * 60 * 60, CancellationToken token = default); + Task>> GetPart(DateTimeOffset dateBegin, int take = 24 * 60 * 60, CancellationToken token = default); /// /// Получить диапазон дат, для которых есть данные в репозитории diff --git a/Persistence/API/ITableDataApi.cs b/Persistence/API/ITableDataApi.cs index ae7099c..a310799 100644 --- a/Persistence/API/ITableDataApi.cs +++ b/Persistence/API/ITableDataApi.cs @@ -19,5 +19,5 @@ public interface ITableDataApi /// параметры фильтрации /// /// - Task>> GetPageAsync(TRequest request, CancellationToken token); + Task>> GetPage(TRequest request, CancellationToken token); } diff --git a/Persistence/API/IGraphDataApi.cs b/Persistence/API/ITimeSeriesBaseDataApi.cs similarity index 61% rename from Persistence/API/IGraphDataApi.cs rename to Persistence/API/ITimeSeriesBaseDataApi.cs index b609f2f..16b7f2b 100644 --- a/Persistence/API/IGraphDataApi.cs +++ b/Persistence/API/ITimeSeriesBaseDataApi.cs @@ -4,23 +4,23 @@ using Persistence.Models; namespace Persistence.API; /// -/// Интерфейс для работы с API графиков +/// Базовый интерфейс для работы с временными рядами /// -public interface IGraphDataApi +public interface ITimeSeriesBaseDataApi { /// - /// Получить список объектов с прореживанием, удовлетворящий диапазону дат + /// Получить список объектов с прореживанием, удовлетворяющий диапазону дат /// /// дата начала /// дата окончания /// /// - Task>> GetThinnedDataAsync(DateTimeOffset dateBegin, DateTimeOffset dateEnd, int approxPointsCount = 1024); + Task GetResampledData(DateTimeOffset dateBegin, DateTimeOffset dateEnd, int approxPointsCount = 1024); /// /// Получить диапазон дат, для которых есть данные в репозитории /// /// /// - Task> GetDatesRangeAsync(CancellationToken token); + Task GetDatesRange(CancellationToken token); } diff --git a/Persistence/API/ITimeSeriesDataApi.cs b/Persistence/API/ITimeSeriesDataApi.cs index a6a0363..a2406aa 100644 --- a/Persistence/API/ITimeSeriesDataApi.cs +++ b/Persistence/API/ITimeSeriesDataApi.cs @@ -11,24 +11,16 @@ namespace Persistence.API; /// /// Интерфейс для работы с API временных данных /// -public interface ITimeSeriesDataApi +public interface ITimeSeriesDataApi : ITimeSeriesBaseDataApi where TDto : class, ITimeSeriesAbstractDto, new() { /// /// Получить список объектов, удовлетворяющий диапазон дат /// /// дата начала - /// дата окончания /// /// - Task GetAsync(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token); - - /// - /// Получить диапазон дат, для которых есть данные в репозитории - /// - /// - /// - Task GetDatesRangeAsync(CancellationToken token); + Task Get(DateTimeOffset dateBegin, CancellationToken token); /// /// Добавление записей @@ -36,7 +28,7 @@ public interface ITimeSeriesDataApi /// /// /// - Task InsertRangeAsync(IEnumerable dtos, CancellationToken token); + Task InsertRange(IEnumerable dtos, CancellationToken token); } diff --git a/Persistence/Models/ChangeLogDto.cs b/Persistence/Models/ChangeLogDto.cs index 5d5e7f5..6b2a090 100644 --- a/Persistence/Models/ChangeLogDto.cs +++ b/Persistence/Models/ChangeLogDto.cs @@ -26,7 +26,7 @@ public class ChangeLogDto where T: class public DateTimeOffset Creation { get; set; } /// - /// Дата устаревания (например при удалении) + /// Дата устаревания (например, при удалении) /// public DateTimeOffset? Obsolete { get; set; } diff --git a/Persistence/Repositories/ISetpointRepository.cs b/Persistence/Repositories/ISetpointRepository.cs index 4253657..1e1e2c3 100644 --- a/Persistence/Repositories/ISetpointRepository.cs +++ b/Persistence/Repositories/ISetpointRepository.cs @@ -15,7 +15,7 @@ public interface ISetpointRepository /// дата, на которую получаем данные /// /// - Task> GetHistoryAsync(IEnumerable setpoitKeys, DateTimeOffset historyMoment, CancellationToken token); + Task> GetHistory(IEnumerable setpoitKeys, DateTimeOffset historyMoment, CancellationToken token); /// /// Получить историю изменений значений уставок @@ -23,7 +23,7 @@ public interface ISetpointRepository /// /// /// - Task>> GetLogAsync(IEnumerable setpoitKeys, CancellationToken token); + Task>> GetLog(IEnumerable setpoitKeys, CancellationToken token); /// /// Метод сохранения уставки @@ -35,5 +35,5 @@ public interface ISetpointRepository /// /// to do /// id User учесть в соответствующем методе репозитория - Task SaveAsync(Guid setpointKey, int idUser, object newValue, CancellationToken token); + Task Save(Guid setpointKey, int idUser, object newValue, CancellationToken token); } diff --git a/Persistence/Repositories/ITableDataRepository.cs b/Persistence/Repositories/ITableDataRepository.cs index 22ec55c..73d332d 100644 --- a/Persistence/Repositories/ITableDataRepository.cs +++ b/Persistence/Repositories/ITableDataRepository.cs @@ -15,5 +15,5 @@ public interface ITableDataRepository /// параметры фильтрации /// /// - Task> GetAsync(TRequest request, CancellationToken token); + Task> Get(TRequest request, CancellationToken token); } diff --git a/Persistence/Repositories/IGraphDataRepository.cs b/Persistence/Repositories/ITimeSeriesBaseRepository.cs similarity index 76% rename from Persistence/Repositories/IGraphDataRepository.cs rename to Persistence/Repositories/ITimeSeriesBaseRepository.cs index d110ffa..5e99582 100644 --- a/Persistence/Repositories/IGraphDataRepository.cs +++ b/Persistence/Repositories/ITimeSeriesBaseRepository.cs @@ -5,7 +5,7 @@ namespace Persistence.Repositories; /// /// Интерфейс по работе с прореженными данными /// -public interface IGraphDataRepository +public interface ITimeSeriesBaseRepository where TDto : class, new() { /// @@ -15,12 +15,12 @@ public interface IGraphDataRepository /// дата окончания /// /// - Task> GetThinnedDataAsync(DateTimeOffset dateBegin, DateTimeOffset dateEnd, int approxPointsCount = 1024); + Task> GetResampledData(DateTimeOffset dateBegin, DateTimeOffset dateEnd, int approxPointsCount = 1024); /// /// Получить диапазон дат, для которых есть данные в репозитории /// /// /// - Task GetDatesRangeAsync(CancellationToken token); + Task GetDatesRange(CancellationToken token); } diff --git a/Persistence/Repositories/ITimeSeriesDataRepository.cs b/Persistence/Repositories/ITimeSeriesDataRepository.cs index f3e49eb..9de7fc7 100644 --- a/Persistence/Repositories/ITimeSeriesDataRepository.cs +++ b/Persistence/Repositories/ITimeSeriesDataRepository.cs @@ -6,24 +6,9 @@ namespace Persistence.Repositories; /// Интерфейс по работе с временными данными /// /// -public interface ITimeSeriesDataRepository : ISyncRepository +public interface ITimeSeriesDataRepository : ISyncRepository, ITimeSeriesBaseRepository where TDto : class, ITimeSeriesAbstractDto, new() { - /// - /// Получить страницу списка объектов - /// - /// дата начала - /// дата окончания - /// - /// - Task> GetAsync(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token); - - /// - /// Получить диапазон дат, для которых есть данные в репозитории - /// - /// - /// - Task GetDatesRangeAsync(CancellationToken token); /// /// Добавление записей /// @@ -31,19 +16,4 @@ public interface ITimeSeriesDataRepository : ISyncRepository /// /// Task InsertRange(IEnumerable dtos, CancellationToken token); - - /// - /// Получение списка последних записей - /// - /// количество записей - /// - /// - Task> GetLastAsync(int takeCount, CancellationToken token); - - /// - /// Получение первой записи - /// - /// - /// - Task GetFirstAsync(CancellationToken token); } From 1fdd199954405b874f9f288618ddd6ed66bc406a Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Fri, 22 Nov 2024 15:47:00 +0500 Subject: [PATCH 4/5] =?UTF-8?q?1.=20=D0=A3=D0=B1=D1=80=D0=B0=D0=BD=20Id=20?= =?UTF-8?q?=D1=83=20DataSaub,=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=B2=20=D0=BA=D0=B0=D1=87=D0=B5=D1=81=D1=82=D0=B2=D0=B5=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B2=D0=B8=D1=87=D0=BD=D0=BE=D0=B3=D0=BE=20?= =?UTF-8?q?=D0=BA=D0=BB=D1=8E=D1=87=D0=B0=20=D0=B2=D1=8B=D1=81=D1=82=D1=83?= =?UTF-8?q?=D0=BF=D0=B0=D0=B5=D1=82=20Date=202.=20=D0=90=D0=B2=D1=82=D0=BE?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=D0=BE=D0=B4=D0=BE=D0=B2=20GetDatesRande,=20GetResa?= =?UTF-8?q?mpledData.=203.=20=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/TimeSeriesController.cs | 6 +- Persistence.API/Startup.cs | 5 ++ ... 20241122074646_InitialCreate.Designer.cs} | 17 ++-- ...ate.cs => 20241122074646_InitialCreate.cs} | 5 +- .../PersistenceDbContextModelSnapshot.cs | 15 +--- Persistence.Database/Entity/DataSaub.cs | 9 +- .../Clients/ITimeSeriesClient.cs | 17 +++- .../Controllers/DataSaubControllerTest.cs | 16 +++- .../TimeSeriesBaseControllerTest.cs | 87 ++++++++++++++++--- Persistence.Repository/Data/DataSaubDto.cs | 2 - .../TimeSeriesDataCachedRepository.cs | 20 +++++ .../Repositories/TimeSeriesDataRepository.cs | 23 ++++- Persistence/API/ITimeSeriesBaseDataApi.cs | 2 +- .../Repositories/ITimeSeriesBaseRepository.cs | 2 +- 14 files changed, 166 insertions(+), 60 deletions(-) rename Persistence.Database.Postgres/Migrations/{20241118091712_InitialCreate.Designer.cs => 20241122074646_InitialCreate.Designer.cs} (92%) rename Persistence.Database.Postgres/Migrations/{20241118091712_InitialCreate.cs => 20241122074646_InitialCreate.cs} (89%) diff --git a/Persistence.API/Controllers/TimeSeriesController.cs b/Persistence.API/Controllers/TimeSeriesController.cs index d4491cc..99e2d8c 100644 --- a/Persistence.API/Controllers/TimeSeriesController.cs +++ b/Persistence.API/Controllers/TimeSeriesController.cs @@ -32,9 +32,11 @@ public class TimeSeriesController : ControllerBase, ITimeSeriesDataApi GetResampledData(DateTimeOffset dateBegin, DateTimeOffset dateEnd, int approxPointsCount = 1024) + [HttpGet("resampled")] + public async Task GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) { - throw new NotImplementedException(); + var result = await this.timeSeriesDataRepository.GetResampledData(dateBegin, intervalSec, approxPointsCount); + return Ok(result); } [HttpPost] diff --git a/Persistence.API/Startup.cs b/Persistence.API/Startup.cs index 32466c8..e074845 100644 --- a/Persistence.API/Startup.cs +++ b/Persistence.API/Startup.cs @@ -33,6 +33,11 @@ public class Startup app.UseRouting(); + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + app.UseAuthentication(); app.UseAuthorization(); diff --git a/Persistence.Database.Postgres/Migrations/20241118091712_InitialCreate.Designer.cs b/Persistence.Database.Postgres/Migrations/20241122074646_InitialCreate.Designer.cs similarity index 92% rename from Persistence.Database.Postgres/Migrations/20241118091712_InitialCreate.Designer.cs rename to Persistence.Database.Postgres/Migrations/20241122074646_InitialCreate.Designer.cs index b340413..17ec6e1 100644 --- a/Persistence.Database.Postgres/Migrations/20241118091712_InitialCreate.Designer.cs +++ b/Persistence.Database.Postgres/Migrations/20241122074646_InitialCreate.Designer.cs @@ -12,7 +12,7 @@ using Persistence.Database.Model; namespace Persistence.Database.Postgres.Migrations { [DbContext(typeof(PersistenceDbContext))] - [Migration("20241118091712_InitialCreate")] + [Migration("20241122074646_InitialCreate")] partial class InitialCreate { /// @@ -29,12 +29,9 @@ namespace Persistence.Database.Postgres.Migrations modelBuilder.Entity("Persistence.Database.Model.DataSaub", b => { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("Date") + .HasColumnType("timestamp with time zone") + .HasColumnName("date"); b.Property("AxialLoad") .HasColumnType("double precision") @@ -52,10 +49,6 @@ namespace Persistence.Database.Postgres.Migrations .HasColumnType("double precision") .HasColumnName("blockSpeed"); - b.Property("Date") - .HasColumnType("timestamp with time zone") - .HasColumnName("date"); - b.Property("Flow") .HasColumnType("double precision") .HasColumnName("flow"); @@ -112,7 +105,7 @@ namespace Persistence.Database.Postgres.Migrations .HasColumnType("double precision") .HasColumnName("wellDepth"); - b.HasKey("Id"); + b.HasKey("Date"); b.ToTable("DataSaub"); }); diff --git a/Persistence.Database.Postgres/Migrations/20241118091712_InitialCreate.cs b/Persistence.Database.Postgres/Migrations/20241122074646_InitialCreate.cs similarity index 89% rename from Persistence.Database.Postgres/Migrations/20241118091712_InitialCreate.cs rename to Persistence.Database.Postgres/Migrations/20241122074646_InitialCreate.cs index 61ea137..dfa9396 100644 --- a/Persistence.Database.Postgres/Migrations/20241118091712_InitialCreate.cs +++ b/Persistence.Database.Postgres/Migrations/20241122074646_InitialCreate.cs @@ -1,6 +1,5 @@ using System; using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable @@ -19,8 +18,6 @@ namespace Persistence.Database.Postgres.Migrations name: "DataSaub", columns: table => new { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), date = table.Column(type: "timestamp with time zone", nullable: false), mode = table.Column(type: "integer", nullable: true), user = table.Column(type: "text", nullable: true), @@ -43,7 +40,7 @@ namespace Persistence.Database.Postgres.Migrations }, constraints: table => { - table.PrimaryKey("PK_DataSaub", x => x.id); + table.PrimaryKey("PK_DataSaub", x => x.date); }); } diff --git a/Persistence.Database.Postgres/Migrations/PersistenceDbContextModelSnapshot.cs b/Persistence.Database.Postgres/Migrations/PersistenceDbContextModelSnapshot.cs index 08c2720..394c112 100644 --- a/Persistence.Database.Postgres/Migrations/PersistenceDbContextModelSnapshot.cs +++ b/Persistence.Database.Postgres/Migrations/PersistenceDbContextModelSnapshot.cs @@ -26,12 +26,9 @@ namespace Persistence.Database.Postgres.Migrations modelBuilder.Entity("Persistence.Database.Model.DataSaub", b => { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("Date") + .HasColumnType("timestamp with time zone") + .HasColumnName("date"); b.Property("AxialLoad") .HasColumnType("double precision") @@ -49,10 +46,6 @@ namespace Persistence.Database.Postgres.Migrations .HasColumnType("double precision") .HasColumnName("blockSpeed"); - b.Property("Date") - .HasColumnType("timestamp with time zone") - .HasColumnName("date"); - b.Property("Flow") .HasColumnType("double precision") .HasColumnName("flow"); @@ -109,7 +102,7 @@ namespace Persistence.Database.Postgres.Migrations .HasColumnType("double precision") .HasColumnName("wellDepth"); - b.HasKey("Id"); + b.HasKey("Date"); b.ToTable("DataSaub"); }); diff --git a/Persistence.Database/Entity/DataSaub.cs b/Persistence.Database/Entity/DataSaub.cs index 39b56cb..fecda5a 100644 --- a/Persistence.Database/Entity/DataSaub.cs +++ b/Persistence.Database/Entity/DataSaub.cs @@ -1,12 +1,11 @@ -using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace Persistence.Database.Model; public class DataSaub : ITimestampedData { - [Column("id")] - public int Id { get; set; } - - [Column("date")] + [Key, Column("date")] public DateTimeOffset Date { get; set; } [Column("mode")] diff --git a/Persistence.IntegrationTests/Clients/ITimeSeriesClient.cs b/Persistence.IntegrationTests/Clients/ITimeSeriesClient.cs index 03b7638..4030d25 100644 --- a/Persistence.IntegrationTests/Clients/ITimeSeriesClient.cs +++ b/Persistence.IntegrationTests/Clients/ITimeSeriesClient.cs @@ -1,13 +1,22 @@ using Microsoft.AspNetCore.Mvc; +using Persistence.Models; using Refit; namespace Persistence.IntegrationTests.Clients; public interface ITimeSeriesClient where TDto : class, new() { - [Post("/api/dataSaub")] - Task> InsertRangeAsync(IEnumerable dtos); + private const string BaseRoute = "/api/dataSaub"; - [Get("/api/dataSaub")] - Task>> GetAsync(DateTimeOffset dateBegin, DateTimeOffset dateEnd); + [Post($"{BaseRoute}")] + Task> InsertRange(IEnumerable dtos); + + [Get($"{BaseRoute}")] + Task>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd); + + [Get($"{BaseRoute}/resampled")] + Task>> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024); + + [Get($"{BaseRoute}/datesRange")] + Task> GetDatesRange(); } diff --git a/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs b/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs index 0e15a60..ae19a8a 100644 --- a/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs +++ b/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs @@ -14,7 +14,6 @@ public class DataSaubControllerTest : TimeSeriesBaseControllerTest : BaseIntegrationTest - where TEntity : class + where TEntity : class, ITimestampedData, new() where TDto : class, new() { private ITimeSeriesClient client; @@ -26,7 +18,7 @@ public abstract class TimeSeriesBaseControllerTest : BaseIntegrat Task.Run(async () => { client = await factory.GetAuthorizedHttpClient>(string.Empty); - }).Wait(); + }).Wait(); } public async Task InsertRangeSuccess(TDto dto) @@ -35,7 +27,7 @@ public abstract class TimeSeriesBaseControllerTest : BaseIntegrat var expected = dto.Adapt(); //act - var response = await client.InsertRangeAsync(new TDto[] { expected }); + var response = await client.InsertRange(new TDto[] { expected }); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -51,11 +43,80 @@ public abstract class TimeSeriesBaseControllerTest : BaseIntegrat dbContext.SaveChanges(); - var response = await client.GetAsync(beginDate, endDate); + var response = await client.Get(beginDate, endDate); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.NotNull(response.Content); Assert.Single(response.Content); } + + public async Task GetDatesRangeSuccess(TEntity entity) + { + //arrange + var datesRangeExpected = 30; + + var entity2 = entity.Adapt(); + entity2.Date = entity.Date.AddDays(datesRangeExpected); + + var dbset = dbContext.Set(); + dbset.Add(entity); + dbset.Add(entity2); + + dbContext.SaveChanges(); + + var response = await client.GetDatesRange(); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + + var datesRangeActual = (response.Content.To - response.Content.From).Days; + Assert.Equal(datesRangeExpected, datesRangeActual); + } + + public async Task GetResampledDataSuccess(TEntity entity) + { + //arrange + var approxPointsCount = 10; + var differenceBetweenStartAndEndDays = 50; + + var entities = new List(); + for (var i = 1; i <= differenceBetweenStartAndEndDays; i++) + { + var entity2 = entity.Adapt(); + entity2.Date = entity.Date.AddDays(i - 1); + + entities.Add(entity2); + } + + var dbset = dbContext.Set(); + dbset.AddRange(entities); + + dbContext.SaveChanges(); + + var response = await client.GetResampledData(entity.Date.AddMinutes(-1), differenceBetweenStartAndEndDays * 24 * 60 * 60 + 60, approxPointsCount); + + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + + var ratio = entities.Count() / approxPointsCount; + if (ratio > 1) + { + var expectedResampledCount = entities + .Where((_, index) => index % ratio == 0) + .Count(); + + Assert.Equal(expectedResampledCount, response.Content.Count()); + } + else + { + Assert.Equal(entities.Count(), response.Content.Count()); + } + + + } + + } diff --git a/Persistence.Repository/Data/DataSaubDto.cs b/Persistence.Repository/Data/DataSaubDto.cs index bb9f74f..518380b 100644 --- a/Persistence.Repository/Data/DataSaubDto.cs +++ b/Persistence.Repository/Data/DataSaubDto.cs @@ -4,8 +4,6 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Persistence.Repository.Data; public class DataSaubDto : ITimeSeriesAbstractDto { - public int Id { get; set; } - public DateTimeOffset Date { get; set; } = DateTimeOffset.UtcNow; public int? Mode { get; set; } diff --git a/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs b/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs index 7c9d06e..52a580c 100644 --- a/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs +++ b/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs @@ -77,5 +77,25 @@ public class TimeSeriesDataCachedRepository : TimeSeriesDataRepos }; }); } + + public override async Task> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) + { + var dtos = LastData.Where(i => i.Date >= dateBegin); + if (LastData.Count == 0 || LastData[0].Date > dateBegin) + { + dtos = await base.GetGtDate(dateBegin, CancellationToken.None); + } + + var dateEnd = dateBegin.AddSeconds(intervalSec); + dtos = dtos + .Where(i => i.Date <= dateEnd); + + var ratio = dtos.Count() / approxPointsCount; + if (ratio > 1) + dtos = dtos + .Where((_, index) => index % ratio == 0); + + return dtos; + } } diff --git a/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs b/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs index ec255cb..7db1193 100644 --- a/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs +++ b/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs @@ -84,9 +84,26 @@ public class TimeSeriesDataRepository : ITimeSeriesDataRepository return dto; } - public Task> GetResampledData(DateTimeOffset dateBegin, DateTimeOffset dateEnd, int approxPointsCount = 1024) + public virtual Task> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) { - //todo - throw new NotImplementedException(); + //if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + // return null; + + //var cacheLastData = cacheItem.LastData; + + //if (cacheLastData.Count == 0 || cacheLastData[0].DateTime > dateBegin) + // return null; + + //var dateEnd = dateBegin.AddSeconds(intervalSec); + //var items = cacheLastData + // .Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd); + + //var ratio = items.Count() / approxPointsCount; + //if (ratio > 1) + // items = items + // .Where((_, index) => index % ratio == 0); + + //return items; + return null; } } diff --git a/Persistence/API/ITimeSeriesBaseDataApi.cs b/Persistence/API/ITimeSeriesBaseDataApi.cs index 16b7f2b..dcce959 100644 --- a/Persistence/API/ITimeSeriesBaseDataApi.cs +++ b/Persistence/API/ITimeSeriesBaseDataApi.cs @@ -15,7 +15,7 @@ public interface ITimeSeriesBaseDataApi /// дата окончания /// /// - Task GetResampledData(DateTimeOffset dateBegin, DateTimeOffset dateEnd, int approxPointsCount = 1024); + Task GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024); /// /// Получить диапазон дат, для которых есть данные в репозитории diff --git a/Persistence/Repositories/ITimeSeriesBaseRepository.cs b/Persistence/Repositories/ITimeSeriesBaseRepository.cs index 5e99582..b9cf358 100644 --- a/Persistence/Repositories/ITimeSeriesBaseRepository.cs +++ b/Persistence/Repositories/ITimeSeriesBaseRepository.cs @@ -15,7 +15,7 @@ public interface ITimeSeriesBaseRepository /// дата окончания /// /// - Task> GetResampledData(DateTimeOffset dateBegin, DateTimeOffset dateEnd, int approxPointsCount = 1024); + Task> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024); /// /// Получить диапазон дат, для которых есть данные в репозитории From f6648b812d4c2c695000e8377dd82f2b61382113 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Fri, 22 Nov 2024 16:48:55 +0500 Subject: [PATCH 5/5] =?UTF-8?q?=D0=92=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20G?= =?UTF-8?q?etResampledData=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20Cancelation=20token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/TimeSeriesController.cs | 4 +- .../TimeSeriesDataCachedRepository.cs | 8 +++- .../Repositories/TimeSeriesDataRepository.cs | 38 +++++++------------ Persistence/API/ITimeSeriesBaseDataApi.cs | 6 ++- .../Repositories/ITimeSeriesBaseRepository.cs | 7 +++- 5 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Persistence.API/Controllers/TimeSeriesController.cs b/Persistence.API/Controllers/TimeSeriesController.cs index 99e2d8c..a4a860a 100644 --- a/Persistence.API/Controllers/TimeSeriesController.cs +++ b/Persistence.API/Controllers/TimeSeriesController.cs @@ -33,9 +33,9 @@ public class TimeSeriesController : ControllerBase, ITimeSeriesDataApi GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) + public async Task GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default) { - var result = await this.timeSeriesDataRepository.GetResampledData(dateBegin, intervalSec, approxPointsCount); + var result = await this.timeSeriesDataRepository.GetResampledData(dateBegin, intervalSec, approxPointsCount, token); return Ok(result); } diff --git a/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs b/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs index 52a580c..20dbe00 100644 --- a/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs +++ b/Persistence.Repository/Repositories/TimeSeriesDataCachedRepository.cs @@ -78,12 +78,16 @@ public class TimeSeriesDataCachedRepository : TimeSeriesDataRepos }); } - public override async Task> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) + public override async Task> GetResampledData( + DateTimeOffset dateBegin, + double intervalSec = 600d, + int approxPointsCount = 1024, + CancellationToken token = default) { var dtos = LastData.Where(i => i.Date >= dateBegin); if (LastData.Count == 0 || LastData[0].Date > dateBegin) { - dtos = await base.GetGtDate(dateBegin, CancellationToken.None); + dtos = await base.GetGtDate(dateBegin, token); } var dateEnd = dateBegin.AddSeconds(intervalSec); diff --git a/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs b/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs index 7db1193..d73caf7 100644 --- a/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs +++ b/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs @@ -33,13 +33,6 @@ public class TimeSeriesDataRepository : ITimeSeriesDataRepository public virtual async Task> GetGtDate(DateTimeOffset date, CancellationToken token) { - //var query = GetQueryReadOnly() - // .Where(q => q.Date >= dateBegin); - //var entities = await query.ToArrayAsync(token); - //var dtos = entities.Select(e => e.Adapt()); - - //return dtos; - var query = this.db.Set().Where(e => e.Date > date); var entities = await query.ToArrayAsync(token); @@ -84,26 +77,23 @@ public class TimeSeriesDataRepository : ITimeSeriesDataRepository return dto; } - public virtual Task> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) + public async virtual Task> GetResampledData( + DateTimeOffset dateBegin, + double intervalSec = 600d, + int approxPointsCount = 1024, + CancellationToken token = default) { - //if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) - // return null; + var dtos = await GetGtDate(dateBegin, token); - //var cacheLastData = cacheItem.LastData; + var dateEnd = dateBegin.AddSeconds(intervalSec); + dtos = dtos + .Where(i => i.Date <= dateEnd); - //if (cacheLastData.Count == 0 || cacheLastData[0].DateTime > dateBegin) - // return null; + var ratio = dtos.Count() / approxPointsCount; + if (ratio > 1) + dtos = dtos + .Where((_, index) => index % ratio == 0); - //var dateEnd = dateBegin.AddSeconds(intervalSec); - //var items = cacheLastData - // .Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd); - - //var ratio = items.Count() / approxPointsCount; - //if (ratio > 1) - // items = items - // .Where((_, index) => index % ratio == 0); - - //return items; - return null; + return dtos; } } diff --git a/Persistence/API/ITimeSeriesBaseDataApi.cs b/Persistence/API/ITimeSeriesBaseDataApi.cs index dcce959..480f145 100644 --- a/Persistence/API/ITimeSeriesBaseDataApi.cs +++ b/Persistence/API/ITimeSeriesBaseDataApi.cs @@ -15,7 +15,11 @@ public interface ITimeSeriesBaseDataApi /// дата окончания /// /// - Task GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024); + Task GetResampledData( + DateTimeOffset dateBegin, + double intervalSec = 600d, + int approxPointsCount = 1024, + CancellationToken token = default); /// /// Получить диапазон дат, для которых есть данные в репозитории diff --git a/Persistence/Repositories/ITimeSeriesBaseRepository.cs b/Persistence/Repositories/ITimeSeriesBaseRepository.cs index b9cf358..7102d97 100644 --- a/Persistence/Repositories/ITimeSeriesBaseRepository.cs +++ b/Persistence/Repositories/ITimeSeriesBaseRepository.cs @@ -12,10 +12,13 @@ public interface ITimeSeriesBaseRepository /// Получить список объектов с прореживанием /// /// дата начала - /// дата окончания /// /// - Task> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024); + Task> GetResampledData( + DateTimeOffset dateBegin, + double intervalSec = 600d, + int approxPointsCount = 1024, + CancellationToken token = default); /// /// Получить диапазон дат, для которых есть данные в репозитории