From f22622116604b6f6afb9b87caf7f89d2c27288db Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Fri, 13 Dec 2024 16:51:39 +0500 Subject: [PATCH 01/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20Readme=20=D0=BF=D0=BE=20=D0=B7=D0=B0=D0=BF=D1=83?= =?UTF-8?q?=D1=81=D0=BA=D1=83=20Persistence=20-=20=D1=81=D0=B5=D1=80=D0=B2?= =?UTF-8?q?=D0=B8=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Persistence.API/Readme.md | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Persistence.API/Readme.md diff --git a/Persistence.API/Readme.md b/Persistence.API/Readme.md new file mode 100644 index 0000000..b5c5e29 --- /dev/null +++ b/Persistence.API/Readme.md @@ -0,0 +1,55 @@ +# Persistence Service Readme + +## Краткое описание +Persistence сервис отвечает за работу с хранимыми данными +в рамках совокупности различных систем. + +## Локальное развертывание +1. Скачать репозиторий по SSH +``` +ssh://git@git.ddrilling.ru:2221/on.nemtina/persistence.git +``` + +Для доступа к репозиториям редварительно необходимо сгенерировать SSH ключ и добавить его в Gitea + +2. Выбрать ветку master +3. Через терминал перейти в папку с решением и выполнить команду: +``` +dotnet ef database update --project Persistence.Database.Postgres --context PersistencePostgresContext +``` + +## Использование Swagger-а +1. Сконфигурировать appsettings.Development.json +(при отсутствии) занести флаг: +```json +"NeedUseKeyCloak": true +``` +2. Запустить решение в режиме Debug +3. Выполнить авторизацию через KeyCloak - качестве client_id указать: +``` +webapi +``` +После этого должен произойти редирект на страницу авторизации в KeyCloak + +4. Заполнить поля и авторизоваться +``` +Username or email: myuser +``` +``` +Password: 12345 +``` + +## Тестирование +Запуск тестов рекомендуется осуществлять без использования KeyCloak
Для этого +настройка appsettings.Tests.json должна содержать: +``` +"NeedUseKeyCloak": false, +"AuthUser": { + "username": "myuser", + "password": 12345, + "clientId": "webapi", + "grantType": "password" +} +``` + + From ed6f33a84b0b6f5b264752ea0fe6577bcf7f2cd8 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Fri, 27 Dec 2024 14:17:33 +0500 Subject: [PATCH 02/12] =?UTF-8?q?=D0=A3=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B4=D1=83=D0=B1=D0=BB=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20EFExtensionsSortBy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extensions/EFExtensionsSortBy.cs | 159 +++++++----------- 1 file changed, 61 insertions(+), 98 deletions(-) diff --git a/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs b/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs index bdfc8a2..bed529e 100644 --- a/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs +++ b/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs @@ -6,7 +6,7 @@ namespace DD.Persistence.Repository.Extensions; public static class EFExtensionsSortBy { - struct TypeAccessor + public struct TypeAccessor { public LambdaExpression KeySelector { get; set; } public MethodInfo OrderBy { get; set; } @@ -26,6 +26,42 @@ public static class EFExtensionsSortBy private static readonly MethodInfo methodThenByDescending = GetExtOrderMethod("ThenByDescending"); + public static Func> sortOrder = + (Type rootType, Type? type, TypeAccessor? accessor) => + { + if (type is null && accessor.HasValue) + { + var accessorValue = accessor.Value; + return Tuple.Create( + accessorValue.OrderBy, + accessorValue.OrderByDescending + ); + } + + return Tuple.Create( + methodOrderBy.MakeGenericMethod(rootType, type!), + methodOrderByDescending.MakeGenericMethod(rootType, type!) + ); + }; + + public static Func> thenSortOrder = + (Type rootType, Type? type, TypeAccessor? accessor) => + { + if (type is null && accessor.HasValue) + { + var accessorValue = accessor.Value; + return Tuple.Create( + accessorValue.ThenBy, + accessorValue.ThenByDescending + ); + } + + return Tuple.Create( + methodThenBy.MakeGenericMethod(rootType, type!), + methodThenByDescending.MakeGenericMethod(rootType, type!) + ); + }; + private static MethodInfo GetExtOrderMethod(string methodName) => typeof(Queryable) .GetMethods() @@ -83,10 +119,11 @@ public static class EFExtensionsSortBy var sortEnum = propertySorts.GetEnumerator(); sortEnum.MoveNext(); - var orderedQuery = query.SortBy(sortEnum.Current); + + var orderedQuery = query.SortBy(sortOrder, sortEnum.Current); while (sortEnum.MoveNext()) - orderedQuery = orderedQuery.ThenSortBy(sortEnum.Current); + orderedQuery = orderedQuery.SortBy(thenSortOrder, sortEnum.Current); return orderedQuery; } @@ -108,39 +145,14 @@ public static class EFExtensionsSortBy /// Запрос с примененной сортировкой public static IOrderedQueryable SortBy( this IQueryable query, + Func> orderMethod, string propertySort) { var parts = propertySort.Split(" ", 2, StringSplitOptions.RemoveEmptyEntries); var isDesc = parts.Length >= 2 && parts[1].ToLower().Trim() == "desc"; var propertyName = parts[0]; - var newQuery = query.SortBy(propertyName, isDesc); - return newQuery; - } - - /// - /// Добавить в запрос дополнительную сортировку по возрастанию или убыванию. - /// - /// - /// - /// - /// Свойство сортировки. - /// Состоит из названия свойства (в любом регистре) - /// и опционально указания направления сортировки "asc" или "desc" - /// - /// - /// var query = query("Date desc"); - /// - /// Запрос с примененной сортировкой - public static IOrderedQueryable ThenSortBy( - this IOrderedQueryable query, - string propertySort) - { - var parts = propertySort.Split(" ", 2, StringSplitOptions.RemoveEmptyEntries); - var isDesc = parts.Length >= 2 && parts[1].ToLower().Trim() == "desc"; - var propertyName = parts[0]; - - var newQuery = query.ThenSortBy(propertyName, isDesc); + var newQuery = query.SortBy(orderMethod, propertyName, isDesc); return newQuery; } @@ -154,25 +166,27 @@ public static class EFExtensionsSortBy /// Запрос с примененной сортировкой public static IOrderedQueryable SortBy( this IQueryable query, + Func> orderMethod, string propertyName, bool isDesc) { Type rootType = typeof(TSource); - var typePropSelector = TypePropSelectors.GetOrAdd(rootType, MakeTypeAccessors); - var propertyNameLower = propertyName.ToLower(); MethodInfo orderByDescending; MethodInfo orderByAscending; + TypeAccessor? rootTypeAccessor = null; + Type? type = null; LambdaExpression? lambdaExpression = null; - if (propertyName.Contains('.')) + const string Separator = "."; + if (propertyName.Contains(Separator)) { - Type type = rootType; + type = rootType; ParameterExpression rootExpression = Expression.Parameter(rootType, "x"); Expression expr = rootExpression; - var propertyPath = propertyName.Split(".", StringSplitOptions.RemoveEmptyEntries); + var propertyPath = propertyName.Split(Separator, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < propertyPath.Length; i++) { @@ -184,75 +198,24 @@ public static class EFExtensionsSortBy Type delegateType = typeof(Func<,>).MakeGenericType(rootType, type); lambdaExpression = Expression.Lambda(delegateType, expr, rootExpression); - orderByAscending = methodOrderBy.MakeGenericMethod(rootType, type); - orderByDescending = methodOrderByDescending.MakeGenericMethod(rootType, type); + Tuple order = orderMethod + .Invoke(rootType, type, null); + orderByAscending = order.Item1; + orderByDescending = order.Item2; } else { - var rootTypeAccessor = typePropSelector[propertyNameLower]; - orderByAscending = rootTypeAccessor.OrderBy; - orderByDescending = rootTypeAccessor.OrderByDescending; - lambdaExpression = rootTypeAccessor.KeySelector; - } + var typePropSelector = TypePropSelectors.GetOrAdd(rootType, MakeTypeAccessors); + var propertyNameLower = propertyName.ToLower(); - var genericMethod = isDesc - ? orderByDescending - : orderByAscending; + rootTypeAccessor = typePropSelector[propertyNameLower]; - var newQuery = (IOrderedQueryable)genericMethod - .Invoke(genericMethod, [query, lambdaExpression])!; - return newQuery; - } + Tuple order = orderMethod + .Invoke(rootType, type, rootTypeAccessor); + orderByAscending = order.Item1; + orderByDescending = order.Item2; - /// - /// Добавить в запрос дополнительную сортировку по возрастанию или убыванию - /// - /// - /// - /// Название свойства (в любом регистре) - /// Сортировать по убыванию - /// Запрос с примененной сортировкой - public static IOrderedQueryable ThenSortBy( - this IOrderedQueryable query, - string propertyName, - bool isDesc) - { - Type rootType = typeof(TSource); - var typePropSelector = TypePropSelectors.GetOrAdd(rootType, MakeTypeAccessors); - var propertyNameLower = propertyName.ToLower(); - - MethodInfo orderByDescending; - MethodInfo orderByAscending; - - LambdaExpression? lambdaExpression = null; - - if (propertyName.Contains('.')) - { - Type type = rootType; - ParameterExpression rootExpression = Expression.Parameter(rootType, "x"); - Expression expr = rootExpression; - - var propertyPath = propertyName.Split(".", StringSplitOptions.RemoveEmptyEntries); - - for (int i = 0; i < propertyPath.Length; i++) - { - PropertyInfo pi = type.GetProperty(propertyPath[i])!; - expr = Expression.Property(expr, pi); - type = pi.PropertyType; - } - - Type delegateType = typeof(Func<,>).MakeGenericType(rootType, type); - lambdaExpression = Expression.Lambda(delegateType, expr, rootExpression); - - orderByAscending = methodThenBy.MakeGenericMethod(rootType, type); - orderByDescending = methodThenByDescending.MakeGenericMethod(rootType, type); - } - else - { - var rootTypeAccessor = typePropSelector[propertyNameLower]; - orderByAscending = rootTypeAccessor.ThenBy; - orderByDescending = rootTypeAccessor.ThenByDescending; - lambdaExpression = rootTypeAccessor.KeySelector; + lambdaExpression = rootTypeAccessor.Value.KeySelector; } var genericMethod = isDesc From e50bd64be186886aaed515f7888a49803923a234 Mon Sep 17 00:00:00 2001 From: Alex Shibalkin Date: Thu, 16 Jan 2025 15:57:53 +0500 Subject: [PATCH 03/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B9=20=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D0=BE=D0=B4=20=D1=81=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D0=BE=20=D1=81=D0=B5=D1=80=D0=B8=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Clients/Interfaces/ISetpointClient.cs | 21 ++++++++---- .../Clients/SetpointClient.cs | 33 ++++++++++++++++++- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/DD.Persistence.Client/Clients/Interfaces/ISetpointClient.cs b/DD.Persistence.Client/Clients/Interfaces/ISetpointClient.cs index 86462ea..36ede35 100644 --- a/DD.Persistence.Client/Clients/Interfaces/ISetpointClient.cs +++ b/DD.Persistence.Client/Clients/Interfaces/ISetpointClient.cs @@ -24,12 +24,21 @@ public interface ISetpointClient : IDisposable /// Task> GetCurrent(IEnumerable setpointKeys, CancellationToken token); - /// - /// Получить диапазон дат, для которых есть данные в репозитории - /// - /// - /// - Task GetDatesRangeAsync(CancellationToken token); + /// + /// Получить актуальные значения уставок + /// + /// + /// + /// + Task> GetCurrentDictionary(Dictionary setpointConfigs, CancellationToken token); + + + /// + /// Получить диапазон дат, для которых есть данные в репозитории + /// + /// + /// + Task GetDatesRangeAsync(CancellationToken token); /// /// Получить значения уставок за определенный момент времени diff --git a/DD.Persistence.Client/Clients/SetpointClient.cs b/DD.Persistence.Client/Clients/SetpointClient.cs index 808f0b9..b9c472a 100644 --- a/DD.Persistence.Client/Clients/SetpointClient.cs +++ b/DD.Persistence.Client/Clients/SetpointClient.cs @@ -3,6 +3,7 @@ using DD.Persistence.Client.Clients.Base; using DD.Persistence.Client.Clients.Interfaces; using DD.Persistence.Client.Clients.Interfaces.Refit; using DD.Persistence.Models; +using System.Text.Json; namespace DD.Persistence.Client.Clients; @@ -23,7 +24,35 @@ public class SetpointClient : BaseClient, ISetpointClient return result!; } - public async Task> GetHistory(IEnumerable setpointKeys, DateTimeOffset historyMoment, CancellationToken token) + public async Task> GetCurrentDictionary(Dictionary setpointConfigs, CancellationToken token) + { + var data = await GetCurrent(setpointConfigs.Keys, token); + var dict = DeserializeResultToDict(setpointConfigs, data); + + return dict; + } + + private static Dictionary DeserializeResultToDict(Dictionary setpointConfigs, IEnumerable data) + { + var dict = new Dictionary(); + + foreach (var valueDto in data) + { + + if (valueDto.Value is not null && + valueDto.Value is JsonElement element && + setpointConfigs.TryGetValue(valueDto.Key, out var type) && + type is not null) + + dict[valueDto.Key] = element.Deserialize(type!) ?? valueDto.Value; + else + dict[valueDto.Key] = valueDto.Value; + } + + return dict; + } + + public async Task> GetHistory(IEnumerable setpointKeys, DateTimeOffset historyMoment, CancellationToken token) { var result = await ExecuteGetResponse( async () => await refitSetpointClient.GetHistory(setpointKeys, historyMoment, token), token); @@ -67,4 +96,6 @@ public class SetpointClient : BaseClient, ISetpointClient GC.SuppressFinalize(this); } + + } From d5942cd67014ff5bb7e878b2f3e85f70fd945e7f Mon Sep 17 00:00:00 2001 From: Alex Shibalkin Date: Thu, 16 Jan 2025 17:32:03 +0500 Subject: [PATCH 04/12] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=81?= =?UTF-8?q?=D0=BB=D0=BE=D0=B2=D0=B0=D1=80=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.Client/Clients/SetpointClient.cs | 8 +++++--- DD.Persistence.Client/DD.Persistence.Client.csproj | 10 +++++----- DD.Persistence.Models/DD.Persistence.Models.csproj | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/DD.Persistence.Client/Clients/SetpointClient.cs b/DD.Persistence.Client/Clients/SetpointClient.cs index b9c472a..5f0a838 100644 --- a/DD.Persistence.Client/Clients/SetpointClient.cs +++ b/DD.Persistence.Client/Clients/SetpointClient.cs @@ -4,6 +4,7 @@ using DD.Persistence.Client.Clients.Interfaces; using DD.Persistence.Client.Clients.Interfaces.Refit; using DD.Persistence.Models; using System.Text.Json; +using System.Text.Json.Serialization; namespace DD.Persistence.Client.Clients; @@ -11,7 +12,7 @@ public class SetpointClient : BaseClient, ISetpointClient { private readonly IRefitSetpointClient refitSetpointClient; - public SetpointClient(IRefitClientFactory refitSetpointClientFactory, ILogger logger) : base(logger) + public SetpointClient(IRefitClientFactory refitSetpointClientFactory, ILogger logger) : base(logger) { this.refitSetpointClient = refitSetpointClientFactory.Create(); } @@ -32,19 +33,20 @@ public class SetpointClient : BaseClient, ISetpointClient return dict; } + private static Dictionary DeserializeResultToDict(Dictionary setpointConfigs, IEnumerable data) { var dict = new Dictionary(); + foreach (var valueDto in data) { - if (valueDto.Value is not null && valueDto.Value is JsonElement element && setpointConfigs.TryGetValue(valueDto.Key, out var type) && type is not null) - dict[valueDto.Key] = element.Deserialize(type!) ?? valueDto.Value; + dict[valueDto.Key] = Convert.ChangeType(element.GetString(), type) ?? valueDto.Value; else dict[valueDto.Key] = valueDto.Value; } diff --git a/DD.Persistence.Client/DD.Persistence.Client.csproj b/DD.Persistence.Client/DD.Persistence.Client.csproj index 12bdea4..e56c2f8 100644 --- a/DD.Persistence.Client/DD.Persistence.Client.csproj +++ b/DD.Persistence.Client/DD.Persistence.Client.csproj @@ -11,9 +11,9 @@ DD.Persistence.Client - 1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.1.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1 - 1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.1.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1 DD.Persistence.Client @@ -33,15 +33,15 @@ snupkg - C:\Projects\Nuget\Persistence\Client + C:\Projects\Nuget\Persistence Readme.md - 1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) - 1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.2.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.2.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) diff --git a/DD.Persistence.Models/DD.Persistence.Models.csproj b/DD.Persistence.Models/DD.Persistence.Models.csproj index dc4772e..7506594 100644 --- a/DD.Persistence.Models/DD.Persistence.Models.csproj +++ b/DD.Persistence.Models/DD.Persistence.Models.csproj @@ -11,9 +11,9 @@ DD.Persistence.Models - 1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.1.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) - 1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.1.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) DD.Persistence.Models @@ -33,7 +33,7 @@ snupkg - C:\Projects\Nuget\Persistence\Models + C:\Projects\Nuget\Persistence From 5497b89c3b2e33b9506a83945fc49210407f733c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=B1=D0=B0=D0=BB=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Fri, 17 Jan 2025 10:36:28 +0500 Subject: [PATCH 05/12] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B5=D1=80=D0=B8=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.Client/Clients/SetpointClient.cs | 3 ++- DD.Persistence.Client/DD.Persistence.Client.csproj | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/DD.Persistence.Client/Clients/SetpointClient.cs b/DD.Persistence.Client/Clients/SetpointClient.cs index 5f0a838..5a187f0 100644 --- a/DD.Persistence.Client/Clients/SetpointClient.cs +++ b/DD.Persistence.Client/Clients/SetpointClient.cs @@ -5,6 +5,7 @@ using DD.Persistence.Client.Clients.Interfaces.Refit; using DD.Persistence.Models; using System.Text.Json; using System.Text.Json.Serialization; +using System.Globalization; namespace DD.Persistence.Client.Clients; @@ -46,7 +47,7 @@ public class SetpointClient : BaseClient, ISetpointClient setpointConfigs.TryGetValue(valueDto.Key, out var type) && type is not null) - dict[valueDto.Key] = Convert.ChangeType(element.GetString(), type) ?? valueDto.Value; + dict[valueDto.Key] = Convert.ChangeType(element.GetString(), type, CultureInfo.InvariantCulture) ?? valueDto.Value; else dict[valueDto.Key] = valueDto.Value; } diff --git a/DD.Persistence.Client/DD.Persistence.Client.csproj b/DD.Persistence.Client/DD.Persistence.Client.csproj index e56c2f8..2426147 100644 --- a/DD.Persistence.Client/DD.Persistence.Client.csproj +++ b/DD.Persistence.Client/DD.Persistence.Client.csproj @@ -11,9 +11,9 @@ DD.Persistence.Client - 1.1.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1 + 1.3.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1 - 1.1.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1 + 1.3.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1 DD.Persistence.Client @@ -40,8 +40,8 @@ - 1.2.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) - 1.2.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.3.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.3.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) From 2a0fa0f3f9492a138c25a9303b25fdbd3a4a4888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=B1=D0=B0=D0=BB=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Fri, 17 Jan 2025 10:50:36 +0500 Subject: [PATCH 06/12] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B1=D0=B0=D0=B3=D0=B0,=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D0=BE=D0=BC?= =?UTF-8?q?=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20GetCurrent=20=D0=B2=D0=BE?= =?UTF-8?q?=D0=B7=D0=B2=D1=80=D0=B0=D1=89=D0=B0=D0=BB=20=D0=BB=D0=B8=D1=88?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/SetpointRepository.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/DD.Persistence.Repository/Repositories/SetpointRepository.cs b/DD.Persistence.Repository/Repositories/SetpointRepository.cs index f7a719a..57cb564 100644 --- a/DD.Persistence.Repository/Repositories/SetpointRepository.cs +++ b/DD.Persistence.Repository/Repositories/SetpointRepository.cs @@ -16,14 +16,19 @@ namespace DD.Persistence.Repository.Repositories protected virtual IQueryable GetQueryReadOnly() => db.Set(); - public async Task> GetCurrent(IEnumerable setpointKeys, CancellationToken token) + public async Task> GetCurrent( + IEnumerable setpointKeys, + CancellationToken token) { var query = GetQueryReadOnly(); + var entities = await query .Where(e => setpointKeys.Contains(e.Key)) + .GroupBy(e => e.Key) + .Select(g => g.OrderByDescending(x => x.Created).FirstOrDefault()) .ToArrayAsync(token); - var dtos = entities.Select(e => e.Adapt()); + var dtos = entities.Select(e => e.Adapt()); return dtos; } From 457579c88d95b2fb24428e0d034936ed32c8d4b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=B1=D0=B0=D0=BB=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Fri, 17 Jan 2025 13:54:26 +0500 Subject: [PATCH 07/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D1=80?= =?UTF-8?q?=D0=B5=D0=BF=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D0=B5?= =?UTF-8?q?=D0=B2=20+=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B2=D0=BE=D0=B7=D0=B2=D1=80=D0=B0=D1=82=20=D0=BD?= =?UTF-8?q?=D0=B5=D0=BA=D0=BE=D1=80=D1=80=D0=B5=D0=BA=D1=82=D0=BD=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20ValueKind?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/SetpointController.cs | 3 +- DD.Persistence.Database/Entity/Setpoint.cs | 3 +- .../DD.Persistence.Repository.Test.csproj | 30 ++++++++++ .../RepositoryTestFixture.cs | 32 +++++++++++ .../SetpointRepositoryShould.cs | 56 +++++++++++++++++++ .../Repositories/SetpointRepository.cs | 3 +- DD.Persistence.sln | 6 ++ .../Repositories/ISetpointRepository.cs | 3 +- 8 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj create mode 100644 DD.Persistence.Repository.Test/RepositoryTestFixture.cs create mode 100644 DD.Persistence.Repository.Test/SetpointRepositoryShould.cs diff --git a/DD.Persistence.API/Controllers/SetpointController.cs b/DD.Persistence.API/Controllers/SetpointController.cs index e3b8b14..1d4c285 100644 --- a/DD.Persistence.API/Controllers/SetpointController.cs +++ b/DD.Persistence.API/Controllers/SetpointController.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using DD.Persistence.Models; using DD.Persistence.Repositories; using System.Net; +using System.Text.Json; namespace DD.Persistence.API.Controllers; @@ -104,7 +105,7 @@ public class SetpointController : ControllerBase, ISetpointApi public async Task Add(Guid setpointKey, object newValue, CancellationToken token) { var userId = User.GetUserId(); - await setpointRepository.Add(setpointKey, newValue, userId, token); + await setpointRepository.Add(setpointKey, (JsonElement)newValue, userId, token); return CreatedAtAction(nameof(Add), true); } diff --git a/DD.Persistence.Database/Entity/Setpoint.cs b/DD.Persistence.Database/Entity/Setpoint.cs index 94eca3f..75bca4f 100644 --- a/DD.Persistence.Database/Entity/Setpoint.cs +++ b/DD.Persistence.Database/Entity/Setpoint.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json; namespace DD.Persistence.Database.Model { @@ -10,7 +11,7 @@ namespace DD.Persistence.Database.Model public Guid Key { get; set; } [Column(TypeName = "jsonb"), Comment("Значение уставки")] - public required object Value { get; set; } + public required JsonElement Value { get; set; } [Comment("Дата создания уставки")] public DateTimeOffset Created { get; set; } diff --git a/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj b/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj new file mode 100644 index 0000000..4f29d86 --- /dev/null +++ b/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj @@ -0,0 +1,30 @@ + + + + net9.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DD.Persistence.Repository.Test/RepositoryTestFixture.cs b/DD.Persistence.Repository.Test/RepositoryTestFixture.cs new file mode 100644 index 0000000..81e3694 --- /dev/null +++ b/DD.Persistence.Repository.Test/RepositoryTestFixture.cs @@ -0,0 +1,32 @@ + +using DD.Persistence.Database; +using DD.Persistence.Database.Model; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Caching.Memory; +using Testcontainers.PostgreSql; +using Xunit; + +namespace DD.Persistence.Repository.Test; + +public class RepositoryTestFixture : IAsyncLifetime +{ + public readonly PostgreSqlContainer dbContainer = new PostgreSqlBuilder().Build(); + + + public PersistencePostgresContext GetDbContext() => new(new DbContextOptionsBuilder() + .UseNpgsql(dbContainer.GetConnectionString()).Options); + + public IMemoryCache GetMemoryCache() => new MemoryCache(new MemoryCacheOptions()); + + public virtual async Task InitializeAsync() + { + await dbContainer.StartAsync(); + var forumDbContext = new PersistencePostgresContext(new DbContextOptionsBuilder() + .UseNpgsql(dbContainer.GetConnectionString()).Options); + + await forumDbContext.Database.MigrateAsync(); + } + + public async Task DisposeAsync() => await dbContainer.DisposeAsync(); +} + diff --git a/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs b/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs new file mode 100644 index 0000000..6b05ff3 --- /dev/null +++ b/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs @@ -0,0 +1,56 @@ +using DD.Persistence.Database.Model; +using DD.Persistence.Repository.Repositories; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace DD.Persistence.Repository.Test; +public class SetpointRepositoryShould : IClassFixture +{ + private readonly RepositoryTestFixture fixture; + private readonly PersistencePostgresContext context; + private readonly SetpointRepository sut; + + public SetpointRepositoryShould(RepositoryTestFixture fixture) + { + this.fixture = fixture; + context = fixture.GetDbContext(); + sut = new SetpointRepository(context); + } + + [Fact] + public async Task ReturnValueKindNumber() + { + var id = Guid.NewGuid(); + var value = GetJsonFromObject(22); + await sut.Add(id, value, Guid.NewGuid(), CancellationToken.None); + + var t = fixture.dbContainer.GetConnectionString(); + //act + var result = await sut.GetCurrent([id], CancellationToken.None); + + + //assert + result.ShouldNotBeNull(); + result.ShouldNotBeEmpty(); + + var setpoint = result.First(); + + setpoint.Value.ShouldNotBeNull(); + setpoint + .Value.ShouldBeOfType() + .ValueKind.ShouldBe(JsonValueKind.Number); + } + + private JsonElement GetJsonFromObject(object value) + { + var jsonString = JsonSerializer.Serialize(value); + var doc = JsonDocument.Parse(jsonString); + return doc.RootElement; + } + +} diff --git a/DD.Persistence.Repository/Repositories/SetpointRepository.cs b/DD.Persistence.Repository/Repositories/SetpointRepository.cs index 57cb564..321d881 100644 --- a/DD.Persistence.Repository/Repositories/SetpointRepository.cs +++ b/DD.Persistence.Repository/Repositories/SetpointRepository.cs @@ -3,6 +3,7 @@ using Microsoft.EntityFrameworkCore; using DD.Persistence.Database.Model; using DD.Persistence.Models; using DD.Persistence.Repositories; +using System.Text.Json; namespace DD.Persistence.Repository.Repositories { @@ -93,7 +94,7 @@ namespace DD.Persistence.Repository.Repositories return dtos; } - public async Task Add(Guid setpointKey, object newValue, Guid idUser, CancellationToken token) + public async Task Add(Guid setpointKey, JsonElement newValue, Guid idUser, CancellationToken token) { var entity = new Setpoint() { diff --git a/DD.Persistence.sln b/DD.Persistence.sln index 5fb5aee..22c99b2 100644 --- a/DD.Persistence.sln +++ b/DD.Persistence.sln @@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.App", "DD.Pe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DD.Persistence.Models", "DD.Persistence.Models\DD.Persistence.Models.csproj", "{698B4571-BB7A-4A42-8B0B-6C7F2F5360FB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DD.Persistence.Repository.Test", "DD.Persistence.Repository.Test\DD.Persistence.Repository.Test.csproj", "{08B03623-A1C9-482F-B60E-09F293E04999}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -63,6 +65,10 @@ Global {698B4571-BB7A-4A42-8B0B-6C7F2F5360FB}.Debug|Any CPU.Build.0 = Debug|Any CPU {698B4571-BB7A-4A42-8B0B-6C7F2F5360FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {698B4571-BB7A-4A42-8B0B-6C7F2F5360FB}.Release|Any CPU.Build.0 = Release|Any CPU + {08B03623-A1C9-482F-B60E-09F293E04999}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08B03623-A1C9-482F-B60E-09F293E04999}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08B03623-A1C9-482F-B60E-09F293E04999}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08B03623-A1C9-482F-B60E-09F293E04999}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/DD.Persistence/Repositories/ISetpointRepository.cs b/DD.Persistence/Repositories/ISetpointRepository.cs index 0af805d..016a6c5 100644 --- a/DD.Persistence/Repositories/ISetpointRepository.cs +++ b/DD.Persistence/Repositories/ISetpointRepository.cs @@ -1,4 +1,5 @@ using DD.Persistence.Models; +using System.Text.Json; namespace DD.Persistence.Repositories; @@ -58,5 +59,5 @@ public interface ISetpointRepository /// /// to do /// id User учесть в соответствующем методе репозитория - Task Add(Guid setpointKey, object newValue, Guid idUser, CancellationToken token); + Task Add(Guid setpointKey, JsonElement newValue, Guid idUser, CancellationToken token); } From ee5425cf6d948ac4b9288eb4beed559e41adccfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=B1=D0=B0=D0=BB=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Fri, 17 Jan 2025 14:04:36 +0500 Subject: [PATCH 08/12] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B4=D0=B5=D1=81=D0=B5=D1=80=D0=B8?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.Client/Clients/SetpointClient.cs | 2 +- DD.Persistence.Client/DD.Persistence.Client.csproj | 8 ++++---- DD.Persistence.Models/DD.Persistence.Models.csproj | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/DD.Persistence.Client/Clients/SetpointClient.cs b/DD.Persistence.Client/Clients/SetpointClient.cs index 5a187f0..0432949 100644 --- a/DD.Persistence.Client/Clients/SetpointClient.cs +++ b/DD.Persistence.Client/Clients/SetpointClient.cs @@ -47,7 +47,7 @@ public class SetpointClient : BaseClient, ISetpointClient setpointConfigs.TryGetValue(valueDto.Key, out var type) && type is not null) - dict[valueDto.Key] = Convert.ChangeType(element.GetString(), type, CultureInfo.InvariantCulture) ?? valueDto.Value; + dict[valueDto.Key] = element.Deserialize(type) ?? valueDto.Value; else dict[valueDto.Key] = valueDto.Value; } diff --git a/DD.Persistence.Client/DD.Persistence.Client.csproj b/DD.Persistence.Client/DD.Persistence.Client.csproj index 2426147..3491596 100644 --- a/DD.Persistence.Client/DD.Persistence.Client.csproj +++ b/DD.Persistence.Client/DD.Persistence.Client.csproj @@ -11,9 +11,9 @@ DD.Persistence.Client - 1.3.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1 + 1.4.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1 - 1.3.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1 + 1.4.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1 DD.Persistence.Client @@ -40,8 +40,8 @@ - 1.3.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) - 1.3.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.4.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.4.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) diff --git a/DD.Persistence.Models/DD.Persistence.Models.csproj b/DD.Persistence.Models/DD.Persistence.Models.csproj index 7506594..6bcae66 100644 --- a/DD.Persistence.Models/DD.Persistence.Models.csproj +++ b/DD.Persistence.Models/DD.Persistence.Models.csproj @@ -11,9 +11,9 @@ DD.Persistence.Models - 1.1.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.2.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) - 1.1.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) + 1.2.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)) DD.Persistence.Models From e2b2fed68f558952a1aa7e459990975b78efac46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=B1=D0=B0=D0=BB=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Fri, 17 Jan 2025 16:39:36 +0500 Subject: [PATCH 09/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=B2=D0=B2=D0=BE=D0=B4=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=84=D0=B8=D0=B3=D1=83=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20Setpoint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/SetpointController.cs | 4 +- .../Clients/Interfaces/ISetpointClient.cs | 4 +- .../Interfaces/Refit/IRefitSetpointClient.cs | 6 +- .../Clients/SetpointClient.cs | 63 ++++++++++++------- DD.Persistence.Client/DependencyInjection.cs | 7 ++- .../ISetpointConfigStorage.cs | 11 ++++ .../SetpointConfigStorage.cs | 15 +++++ .../Repositories/SetpointRepository.cs | 14 +++++ DD.Persistence/API/ISetpointApi.cs | 2 +- .../Repositories/ISetpointRepository.cs | 8 +++ 10 files changed, 104 insertions(+), 30 deletions(-) create mode 100644 DD.Persistence.Client/ISetpointConfigStorage.cs create mode 100644 DD.Persistence.Client/SetpointConfigStorage.cs diff --git a/DD.Persistence.API/Controllers/SetpointController.cs b/DD.Persistence.API/Controllers/SetpointController.cs index 1d4c285..0850438 100644 --- a/DD.Persistence.API/Controllers/SetpointController.cs +++ b/DD.Persistence.API/Controllers/SetpointController.cs @@ -29,9 +29,9 @@ public class SetpointController : ControllerBase, ISetpointApi /// /// [HttpGet("current")] - public async Task>> GetCurrent([FromQuery] IEnumerable setpointKeys, CancellationToken token) + public async Task>> GetCurrent([FromQuery] IEnumerable setpointKeys, CancellationToken token) { - var result = await setpointRepository.GetCurrent(setpointKeys, token); + var result = await setpointRepository.GetCurrentDictionary(setpointKeys, token); return Ok(result); } diff --git a/DD.Persistence.Client/Clients/Interfaces/ISetpointClient.cs b/DD.Persistence.Client/Clients/Interfaces/ISetpointClient.cs index 36ede35..f197fe8 100644 --- a/DD.Persistence.Client/Clients/Interfaces/ISetpointClient.cs +++ b/DD.Persistence.Client/Clients/Interfaces/ISetpointClient.cs @@ -29,8 +29,8 @@ public interface ISetpointClient : IDisposable /// /// /// - /// - Task> GetCurrentDictionary(Dictionary setpointConfigs, CancellationToken token); + /// s + Task> GetCurrentDictionary(IEnumerable setpointConfigs, CancellationToken token); /// diff --git a/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitSetpointClient.cs b/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitSetpointClient.cs index 1acb398..1cd2742 100644 --- a/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitSetpointClient.cs +++ b/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitSetpointClient.cs @@ -1,5 +1,6 @@ using DD.Persistence.Models; using Refit; +using System.Text.Json; namespace DD.Persistence.Client.Clients.Interfaces.Refit; @@ -7,8 +8,11 @@ public interface IRefitSetpointClient : IRefitClient, IDisposable { private const string BaseRoute = "/api/setpoint"; + //[Get($"{BaseRoute}/current")] + //Task>> GetCurrent([Query(CollectionFormat.Multi)] IEnumerable setpointKeys, CancellationToken token); + [Get($"{BaseRoute}/current")] - Task>> GetCurrent([Query(CollectionFormat.Multi)] IEnumerable setpointKeys, CancellationToken token); + Task>> GetCurrent([Query(CollectionFormat.Multi)] IEnumerable setpointKeys, CancellationToken token); [Get($"{BaseRoute}/history")] Task>> GetHistory([Query(CollectionFormat.Multi)] IEnumerable setpointKeys, [Query] DateTimeOffset historyMoment, CancellationToken token); diff --git a/DD.Persistence.Client/Clients/SetpointClient.cs b/DD.Persistence.Client/Clients/SetpointClient.cs index 0432949..3078d9d 100644 --- a/DD.Persistence.Client/Clients/SetpointClient.cs +++ b/DD.Persistence.Client/Clients/SetpointClient.cs @@ -12,49 +12,66 @@ namespace DD.Persistence.Client.Clients; public class SetpointClient : BaseClient, ISetpointClient { private readonly IRefitSetpointClient refitSetpointClient; + private readonly ISetpointConfigStorage setpointConfigStorage; - public SetpointClient(IRefitClientFactory refitSetpointClientFactory, ILogger logger) : base(logger) + public SetpointClient( + IRefitClientFactory refitSetpointClientFactory, + ISetpointConfigStorage setpointConfigStorage, + ILogger logger) : base(logger) { this.refitSetpointClient = refitSetpointClientFactory.Create(); - } + this.setpointConfigStorage = setpointConfigStorage; + } public async Task> GetCurrent(IEnumerable setpointKeys, CancellationToken token) { var result = await ExecuteGetResponse( async () => await refitSetpointClient.GetCurrent(setpointKeys, token), token); - return result!; + return result!.Select(x => new SetpointValueDto { + Key = x.Key, + Value = DeserializeValue(x.Key, x.Value) + }); } - public async Task> GetCurrentDictionary(Dictionary setpointConfigs, CancellationToken token) + private object DeserializeValue(Guid key, JsonElement value) { - var data = await GetCurrent(setpointConfigs.Keys, token); - var dict = DeserializeResultToDict(setpointConfigs, data); + if (setpointConfigStorage.TryGetType(key, out var type)) + return value.Deserialize(type)!; - return dict; + return value; } - - private static Dictionary DeserializeResultToDict(Dictionary setpointConfigs, IEnumerable data) + public async Task> GetCurrentDictionary(IEnumerable setpointConfigs, CancellationToken token) { - var dict = new Dictionary(); + var result = await ExecuteGetResponse( + async () => await refitSetpointClient.GetCurrent(setpointConfigs, token), token); - foreach (var valueDto in data) - { - if (valueDto.Value is not null && - valueDto.Value is JsonElement element && - setpointConfigs.TryGetValue(valueDto.Key, out var type) && - type is not null) - - dict[valueDto.Key] = element.Deserialize(type) ?? valueDto.Value; - else - dict[valueDto.Key] = valueDto.Value; - } - - return dict; + return result!.ToDictionary(x => x.Key,x => DeserializeValue(x.Key,x.Value)); } + + //private Dictionary DeserializeResultToDict(IEnumerable data) + //{ + // var dict = new Dictionary(); + + + // foreach (var valueDto in data) + // { + // if (valueDto.Value is not null && + // valueDto.Value is JsonElement element && + // setpointConfigStorage.TryGetType(valueDto.Key, out var type) && + // type is not null) + + // dict[valueDto.Key] = element.Deserialize(type) ?? valueDto.Value; + // else + // dict[valueDto.Key] = valueDto.Value; + // } + + // return dict; + //} + public async Task> GetHistory(IEnumerable setpointKeys, DateTimeOffset historyMoment, CancellationToken token) { var result = await ExecuteGetResponse( diff --git a/DD.Persistence.Client/DependencyInjection.cs b/DD.Persistence.Client/DependencyInjection.cs index eced892..e5c7c29 100644 --- a/DD.Persistence.Client/DependencyInjection.cs +++ b/DD.Persistence.Client/DependencyInjection.cs @@ -15,7 +15,7 @@ public static class DependencyInjection /// /// /// - public static IServiceCollection AddPersistenceClients(this IServiceCollection services) + public static IServiceCollection AddPersistenceClients(this IServiceCollection services, Dictionary? setpointTypeConfigs = null) { services.AddTransient(typeof(IRefitClientFactory<>), typeof(RefitClientFactory<>)); services.AddTransient(); @@ -25,6 +25,11 @@ public static class DependencyInjection services.AddTransient, TimeSeriesClient>(); services.AddTransient(); services.AddTransient(); + + services.AddSingleton(provider => + { + return new SetpointConfigStorage(setpointTypeConfigs); + }); return services; } } diff --git a/DD.Persistence.Client/ISetpointConfigStorage.cs b/DD.Persistence.Client/ISetpointConfigStorage.cs new file mode 100644 index 0000000..2c73783 --- /dev/null +++ b/DD.Persistence.Client/ISetpointConfigStorage.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DD.Persistence.Client; +public interface ISetpointConfigStorage +{ + bool TryGetType(Guid id, out Type type); +} diff --git a/DD.Persistence.Client/SetpointConfigStorage.cs b/DD.Persistence.Client/SetpointConfigStorage.cs new file mode 100644 index 0000000..a0b3a17 --- /dev/null +++ b/DD.Persistence.Client/SetpointConfigStorage.cs @@ -0,0 +1,15 @@ +namespace DD.Persistence.Client; +internal class SetpointConfigStorage : ISetpointConfigStorage +{ + private readonly Dictionary setpointTypeConfigs; + + public SetpointConfigStorage(Dictionary? setpointTypeConfigs) + { + this.setpointTypeConfigs = setpointTypeConfigs?? new Dictionary(); + } + + public bool TryGetType(Guid id, out Type type) + { + return setpointTypeConfigs.TryGetValue(id, out type); + } +} diff --git a/DD.Persistence.Repository/Repositories/SetpointRepository.cs b/DD.Persistence.Repository/Repositories/SetpointRepository.cs index 321d881..30e67d5 100644 --- a/DD.Persistence.Repository/Repositories/SetpointRepository.cs +++ b/DD.Persistence.Repository/Repositories/SetpointRepository.cs @@ -32,6 +32,18 @@ namespace DD.Persistence.Repository.Repositories var dtos = entities.Select(e => e.Adapt()); return dtos; } + public async Task> GetCurrentDictionary(IEnumerable setpointKeys, CancellationToken token) + { + var query = GetQueryReadOnly(); + + var entities = await query + .Where(e => setpointKeys.Contains(e.Key)) + .GroupBy(e => e.Key) + .Select(g => g.OrderByDescending(x => x.Created).FirstOrDefault()) + .ToDictionaryAsync(x=> x.Key, x => (object)x.Value, token); + + return entities; + } public async Task> GetHistory(IEnumerable setpointKeys, DateTimeOffset historyMoment, CancellationToken token) { @@ -107,5 +119,7 @@ namespace DD.Persistence.Repository.Repositories await db.Set().AddAsync(entity, token); await db.SaveChangesAsync(token); } + + } } diff --git a/DD.Persistence/API/ISetpointApi.cs b/DD.Persistence/API/ISetpointApi.cs index f600f99..138e336 100644 --- a/DD.Persistence/API/ISetpointApi.cs +++ b/DD.Persistence/API/ISetpointApi.cs @@ -14,7 +14,7 @@ public interface ISetpointApi : ISyncApi /// ключи уставок /// /// - Task>> GetCurrent(IEnumerable setpoitKeys, CancellationToken token); + Task>> GetCurrent(IEnumerable setpoitKeys, CancellationToken token); /// /// Получить значения уставок за определенный момент времени diff --git a/DD.Persistence/Repositories/ISetpointRepository.cs b/DD.Persistence/Repositories/ISetpointRepository.cs index 016a6c5..165ce29 100644 --- a/DD.Persistence/Repositories/ISetpointRepository.cs +++ b/DD.Persistence/Repositories/ISetpointRepository.cs @@ -16,6 +16,14 @@ public interface ISetpointRepository /// Task> GetCurrent(IEnumerable setpointKeys, CancellationToken token); + /// + /// Получить значения уставок по набору ключей + /// + /// + /// + /// + Task> GetCurrentDictionary(IEnumerable setpointKeys, CancellationToken token); + /// /// Получить значения уставок за определенный момент времени /// From 5350febaba84122e604559a8f32b77285c3c6100 Mon Sep 17 00:00:00 2001 From: Alex Shibalkin Date: Mon, 20 Jan 2025 10:29:30 +0500 Subject: [PATCH 10/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B4=D0=B5=D1=81=D0=B5=D1=80=D0=B8=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B2=20=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D1=87=D0=B0?= =?UTF-8?q?=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Clients/SetpointClient.cs | 69 +++++++++---------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/DD.Persistence.Client/Clients/SetpointClient.cs b/DD.Persistence.Client/Clients/SetpointClient.cs index 3078d9d..0e8df6a 100644 --- a/DD.Persistence.Client/Clients/SetpointClient.cs +++ b/DD.Persistence.Client/Clients/SetpointClient.cs @@ -34,13 +34,7 @@ public class SetpointClient : BaseClient, ISetpointClient }); } - private object DeserializeValue(Guid key, JsonElement value) - { - if (setpointConfigStorage.TryGetType(key, out var type)) - return value.Deserialize(type)!; - - return value; - } + public async Task> GetCurrentDictionary(IEnumerable setpointConfigs, CancellationToken token) { @@ -51,32 +45,15 @@ public class SetpointClient : BaseClient, ISetpointClient return result!.ToDictionary(x => x.Key,x => DeserializeValue(x.Key,x.Value)); } - - //private Dictionary DeserializeResultToDict(IEnumerable data) - //{ - // var dict = new Dictionary(); - - - // foreach (var valueDto in data) - // { - // if (valueDto.Value is not null && - // valueDto.Value is JsonElement element && - // setpointConfigStorage.TryGetType(valueDto.Key, out var type) && - // type is not null) - - // dict[valueDto.Key] = element.Deserialize(type) ?? valueDto.Value; - // else - // dict[valueDto.Key] = valueDto.Value; - // } - - // return dict; - //} - public async Task> GetHistory(IEnumerable setpointKeys, DateTimeOffset historyMoment, CancellationToken token) { var result = await ExecuteGetResponse( async () => await refitSetpointClient.GetHistory(setpointKeys, historyMoment, token), token); + foreach(var dto in result) + dto.Value = DeserializeValue(dto.Key, (JsonElement)dto.Value); + + return result!; } @@ -85,6 +62,9 @@ public class SetpointClient : BaseClient, ISetpointClient var result = await ExecuteGetResponse( async () => await refitSetpointClient.GetLog(setpointKeys, token), token); + foreach(var item in result) + DeserializeList(result[item.Key]); + return result!; } @@ -97,14 +77,18 @@ public class SetpointClient : BaseClient, ISetpointClient } public async Task> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token) - { - var result = await ExecuteGetResponse( - async () => await refitSetpointClient.GetPart(dateBegin, take, token), token); + { + var result = await ExecuteGetResponse( + async () => await refitSetpointClient.GetPart(dateBegin, take, token), token); - return result!; - } + DeserializeList(result); - public async Task Add(Guid setpointKey, object newValue, CancellationToken token) + return result!; + } + + + + public async Task Add(Guid setpointKey, object newValue, CancellationToken token) { await ExecutePostResponse( async () => await refitSetpointClient.Add(setpointKey, newValue, token), token); @@ -117,5 +101,20 @@ public class SetpointClient : BaseClient, ISetpointClient GC.SuppressFinalize(this); } - + + private object DeserializeValue(Guid key, JsonElement value) + { + if (setpointConfigStorage.TryGetType(key, out var type)) + return value.Deserialize(type)!; + + return value; + } + private void DeserializeList(IEnumerable? result) + { + foreach (var log in result) + log.Value = DeserializeValue(log.Key, (JsonElement)log.Value); + + } + + } From f8942341140021249ebae3d65119fb83bda6e8ac Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Mon, 20 Jan 2025 11:38:10 +0500 Subject: [PATCH 11/12] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=B2=20readme.md:=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B8=20=D1=81=20?= =?UTF-8?q?dotnet=20ef=20database=20update,=20=D1=82=D0=B0=D0=BA=20=D0=BA?= =?UTF-8?q?=D0=B0=D0=BA=20=D1=8D=D1=82=D0=BE=20=D0=BF=D1=80=D0=BE=D0=B8?= =?UTF-8?q?=D1=81=D1=85=D0=BE=D0=B4=D0=B8=D1=82=20=D0=B0=D0=B2=D1=82=D0=BE?= =?UTF-8?q?=D0=BC=D0=B0=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA=D0=B5=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Persistence.API/Readme.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Persistence.API/Readme.md b/Persistence.API/Readme.md index b5c5e29..43bbbf3 100644 --- a/Persistence.API/Readme.md +++ b/Persistence.API/Readme.md @@ -12,11 +12,7 @@ ssh://git@git.ddrilling.ru:2221/on.nemtina/persistence.git Для доступа к репозиториям редварительно необходимо сгенерировать SSH ключ и добавить его в Gitea -2. Выбрать ветку master -3. Через терминал перейти в папку с решением и выполнить команду: -``` -dotnet ef database update --project Persistence.Database.Postgres --context PersistencePostgresContext -``` +2. Выбрать ветку dev ## Использование Swagger-а 1. Сконфигурировать appsettings.Development.json From 90ca38a74183b617fe87df71e1132874a8294579 Mon Sep 17 00:00:00 2001 From: Alex Shibalkin Date: Mon, 20 Jan 2025 14:01:46 +0500 Subject: [PATCH 12/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D1=82=D0=B5=D1=81=D1=82=20=D0=BD=D0=B0=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D1=83=20=D1=82=D0=B8=D0=BF?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.App/appsettings.Tests.json | 2 +- .../SetpointConfigStorage.cs | 5 +++ .../Controllers/SetpointControllerTest.cs | 33 ++++++++++++++++++- DD.Persistence.sln | 5 +++ Directory.Build.props | 15 +++++++++ 5 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 Directory.Build.props diff --git a/DD.Persistence.App/appsettings.Tests.json b/DD.Persistence.App/appsettings.Tests.json index 72c43d3..9934757 100644 --- a/DD.Persistence.App/appsettings.Tests.json +++ b/DD.Persistence.App/appsettings.Tests.json @@ -1,6 +1,6 @@ { "DbConnection": { - "Host": "postgres", + "Host": "localhost", "Port": 5432, "Database": "persistence", "Username": "postgres", diff --git a/DD.Persistence.Client/SetpointConfigStorage.cs b/DD.Persistence.Client/SetpointConfigStorage.cs index a0b3a17..5cfbabf 100644 --- a/DD.Persistence.Client/SetpointConfigStorage.cs +++ b/DD.Persistence.Client/SetpointConfigStorage.cs @@ -12,4 +12,9 @@ internal class SetpointConfigStorage : ISetpointConfigStorage { return setpointTypeConfigs.TryGetValue(id, out type); } + + public void AddOrReplace(Guid id, Type type) + { + setpointTypeConfigs[id] = type; + } } diff --git a/DD.Persistence.IntegrationTests/Controllers/SetpointControllerTest.cs b/DD.Persistence.IntegrationTests/Controllers/SetpointControllerTest.cs index 27432f3..c27f6cc 100644 --- a/DD.Persistence.IntegrationTests/Controllers/SetpointControllerTest.cs +++ b/DD.Persistence.IntegrationTests/Controllers/SetpointControllerTest.cs @@ -7,12 +7,15 @@ using Xunit; using DD.Persistence.Client.Clients.Interfaces.Refit; using DD.Persistence.Client.Clients; using Microsoft.Extensions.Logging; +using System.Text.Json; namespace DD.Persistence.IntegrationTests.Controllers { public class SetpointControllerTest : BaseIntegrationTest { private readonly ISetpointClient setpointClient; + private readonly SetpointConfigStorage configStorage; + private class TestObject { public string? Value1 { get; set; } @@ -26,8 +29,36 @@ namespace DD.Persistence.IntegrationTests.Controllers setpointClient = scope.ServiceProvider .GetRequiredService(); + + configStorage = (SetpointConfigStorage)scope.ServiceProvider.GetRequiredService(); } + + [Fact] + public async Task GetCurrent_returns_correctType() + { + var id = Guid.Parse("e0fcad22-1761-476e-a729-a3c59d51ba41"); + + configStorage.AddOrReplace(id, typeof(float)); + + await setpointClient.Add(id, 48.3f, CancellationToken.None); + + //act + var response = await setpointClient.GetCurrent([id], CancellationToken.None); + + //assert + Assert.NotNull(response); + Assert.NotEmpty(response); + Assert.Single(response); + var item = response.First(); + Assert.Equal(item.Key, id); + + Assert.IsNotType(item.Value); + Assert.Equal(item.Value, 48.3f); + } + + + [Fact] public async Task GetCurrent_returns_success() { @@ -39,7 +70,7 @@ namespace DD.Persistence.IntegrationTests.Controllers }; //act - var response = await setpointClient.GetCurrent(setpointKeys, new CancellationToken()); + var response = await setpointClient.GetCurrent(setpointKeys, CancellationToken.None); //assert Assert.NotNull(response); diff --git a/DD.Persistence.sln b/DD.Persistence.sln index 22c99b2..eeb198c 100644 --- a/DD.Persistence.sln +++ b/DD.Persistence.sln @@ -23,6 +23,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DD.Persistence.Models", "DD EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DD.Persistence.Repository.Test", "DD.Persistence.Repository.Test\DD.Persistence.Repository.Test.csproj", "{08B03623-A1C9-482F-B60E-09F293E04999}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{36D591C7-65C7-A0D1-1CBC-10CDE441BDC8}" + ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..cffb4fe --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,15 @@ + + + + + + <_Parameter1>$(AssemblyName).Test + + + <_Parameter1>DD.Persistence.IntegrationTests + + + <_Parameter1>DynamicProxyGenAssembly2 + + + \ No newline at end of file