diff --git a/Persistence.API/Controllers/ChangeLogController.cs b/Persistence.API/Controllers/ChangeLogController.cs index cad59c4..ff5696b 100644 --- a/Persistence.API/Controllers/ChangeLogController.cs +++ b/Persistence.API/Controllers/ChangeLogController.cs @@ -12,7 +12,7 @@ namespace Persistence.API.Controllers; [Route("api/[controller]")] public class ChangeLogController : ControllerBase, IChangeLogApi { - private IChangeLogRepository repository; + private readonly IChangeLogRepository repository; public ChangeLogController(IChangeLogRepository repository) { diff --git a/Persistence.API/Controllers/TechMessagesController.cs b/Persistence.API/Controllers/TechMessagesController.cs index a7b0094..fa5bb3b 100644 --- a/Persistence.API/Controllers/TechMessagesController.cs +++ b/Persistence.API/Controllers/TechMessagesController.cs @@ -1,9 +1,9 @@ -using System.Net; -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Persistence.Models; using Persistence.Models.Requests; using Persistence.Repositories; +using System.Net; namespace Persistence.API.Controllers; @@ -15,115 +15,115 @@ namespace Persistence.API.Controllers; [Route("api/[controller]")] public class TechMessagesController : ControllerBase { - private readonly ITechMessagesRepository techMessagesRepository; - private static readonly Dictionary categories = new Dictionary() - { - { 0, "System" }, - { 1, "Авария" }, - { 2, "Предупреждение" }, - { 3, "Инфо" }, - { 4, "Прочее" } - }; + private readonly ITechMessagesRepository techMessagesRepository; + private static readonly Dictionary categories = new() + { + { 0, "System" }, + { 1, "Авария" }, + { 2, "Предупреждение" }, + { 3, "Инфо" }, + { 4, "Прочее" } + }; - public TechMessagesController(ITechMessagesRepository techMessagesRepository) - { - this.techMessagesRepository = techMessagesRepository; - } + public TechMessagesController(ITechMessagesRepository techMessagesRepository) + { + this.techMessagesRepository = techMessagesRepository; + } - /// - /// Получить список технологических сообщений в виде страницы - /// - /// - /// - /// - [HttpGet] - public async Task>> GetPage([FromQuery] PaginationRequest request, CancellationToken token) - { - var result = await techMessagesRepository.GetPage(request, token); + /// + /// Получить список технологических сообщений в виде страницы + /// + /// + /// + /// + [HttpGet] + public async Task>> GetPage([FromQuery] PaginationRequest request, CancellationToken token) + { + var result = await techMessagesRepository.GetPage(request, token); - return Ok(result); - } + return Ok(result); + } - /// - /// Получить статистику по системам - /// - /// - /// - /// - /// - [HttpGet("statistics")] - public async Task>> GetStatistics([FromQuery] IEnumerable autoDrillingSystem, [FromQuery] IEnumerable categoryIds, CancellationToken token) - { - var result = await techMessagesRepository.GetStatistics(autoDrillingSystem, categoryIds, token); + /// + /// Получить статистику по системам + /// + /// + /// + /// + /// + [HttpGet("statistics")] + public async Task>> GetStatistics([FromQuery] IEnumerable autoDrillingSystem, [FromQuery] IEnumerable categoryIds, CancellationToken token) + { + var result = await techMessagesRepository.GetStatistics(autoDrillingSystem, categoryIds, token); - return Ok(result); - } + return Ok(result); + } - /// - /// Получить список всех систем - /// - /// - /// - [HttpGet("systems")] - public async Task>> GetSystems(CancellationToken token) - { - var result = await techMessagesRepository.GetSystems(token); + /// + /// Получить список всех систем + /// + /// + /// + [HttpGet("systems")] + public async Task>> GetSystems(CancellationToken token) + { + var result = await techMessagesRepository.GetSystems(token); - return Ok(result); - } + return Ok(result); + } - /// - /// Получить диапазон дат, для которых есть данные в репозитории - /// - /// - /// - [HttpGet("range")] - public async Task> GetDatesRangeAsync(CancellationToken token) - { - var result = await techMessagesRepository.GetDatesRangeAsync(token); + /// + /// Получить диапазон дат, для которых есть данные в репозитории + /// + /// + /// + [HttpGet("range")] + public async Task> GetDatesRangeAsync(CancellationToken token) + { + var result = await techMessagesRepository.GetDatesRangeAsync(token); - return Ok(result); - } + return Ok(result); + } - /// - /// Получить порцию записей, начиная с заданной даты - /// - /// - /// - /// - /// - [HttpGet("part")] - public async Task>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token) - { - var result = await techMessagesRepository.GetPart(dateBegin, take, token); + /// + /// Получить порцию записей, начиная с заданной даты + /// + /// + /// + /// + /// + [HttpGet("part")] + public async Task>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token) + { + var result = await techMessagesRepository.GetPart(dateBegin, take, token); - return Ok(result); - } + return Ok(result); + } - /// - /// Добавить новые технологические сообщения - /// - /// - /// - /// - [HttpPost] - [ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)] - public async Task AddRange([FromBody] IEnumerable dtos, CancellationToken token) - { - var userId = User.GetUserId(); + /// + /// Добавить новые технологические сообщения + /// + /// + /// + /// + [HttpPost] + [ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)] + public async Task AddRange([FromBody] IEnumerable dtos, CancellationToken token) + { + var userId = User.GetUserId(); var result = await techMessagesRepository.AddRange(dtos, userId, token); - return CreatedAtAction(nameof(AddRange), result); - } + return CreatedAtAction(nameof(AddRange), result); + } - /// - /// Получить словарь категорий - /// - /// - [HttpGet("categories")] - public ActionResult> GetImportantCategories() - { - return Ok(categories); - } + /// + /// Получить словарь категорий + /// + /// + [HttpGet("categories")] + public ActionResult> GetImportantCategories() + { + return Ok(categories); + } } \ No newline at end of file diff --git a/Persistence.API/DependencyInjection.cs b/Persistence.API/DependencyInjection.cs index bf297a6..c97f4e0 100644 --- a/Persistence.API/DependencyInjection.cs +++ b/Persistence.API/DependencyInjection.cs @@ -28,12 +28,11 @@ public static class DependencyInjection c.MapType(() => new OpenApiSchema { Type = "string", Format = "date" }); c.MapType(() => new OpenApiSchema { - AnyOf = new OpenApiSchema[] - { + AnyOf = [ new OpenApiSchema {Type = "string", Format = "string" }, new OpenApiSchema {Type = "number", Format = "int32" }, - new OpenApiSchema {Type = "number", Format = "float" }, - } + new OpenApiSchema {Type = "number", Format = "float" } + ] }); c.CustomOperationIds(e => @@ -45,8 +44,8 @@ public static class DependencyInjection var needUseKeyCloak = configuration.GetSection("NeedUseKeyCloak").Get(); if (needUseKeyCloak) - c.AddKeycloackSecurity(configuration); - else c.AddDefaultSecurity(configuration); + c.AddKeycloakSecurity(configuration); + else c.AddDefaultSecurity(); var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); @@ -134,12 +133,12 @@ public static class DependencyInjection } #endregion - #region Security (Swagger) - private static void AddKeycloackSecurity(this SwaggerGenOptions options, IConfiguration configuration) + #region Keycloak + private static void AddKeycloakSecurity(this SwaggerGenOptions options, IConfiguration configuration) { - options.AddSecurityDefinition("Keycloack", new OpenApiSecurityScheme + options.AddSecurityDefinition("Keycloak", new OpenApiSecurityScheme { - Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'", + Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345token'", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.OAuth2, @@ -147,7 +146,7 @@ public static class DependencyInjection { Implicit = new OpenApiOAuthFlow { - AuthorizationUrl = new Uri(configuration["Authentication:AuthorizationUrl"]), + AuthorizationUrl = new Uri(configuration["Authentication:AuthorizationUrl"]!), } } }); @@ -160,7 +159,7 @@ public static class DependencyInjection Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, - Id = "Keycloack" + Id = "Keycloak" }, Scheme = "Bearer", Name = "Bearer", @@ -171,11 +170,11 @@ public static class DependencyInjection }); } - private static void AddDefaultSecurity(this SwaggerGenOptions options, IConfiguration configuration) + private static void AddDefaultSecurity(this SwaggerGenOptions options) { options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { - Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'", + Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345token'", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, diff --git a/Persistence.API/Extensions.cs b/Persistence.API/Extensions.cs index 601a2f4..a429915 100644 --- a/Persistence.API/Extensions.cs +++ b/Persistence.API/Extensions.cs @@ -7,9 +7,8 @@ public static class Extensions { public static T GetUserId(this ClaimsPrincipal principal) { - if (principal == null) - throw new ArgumentNullException(nameof(principal)); - + ArgumentNullException.ThrowIfNull(principal, nameof(principal)); + var loggedInUserId = principal.FindFirstValue(ClaimTypes.NameIdentifier); if (String.IsNullOrEmpty(loggedInUserId)) diff --git a/Persistence.Client/Clients/ITechMessagesClient.cs b/Persistence.Client/Clients/ITechMessagesClient.cs index a9c80c1..1fde2a9 100644 --- a/Persistence.Client/Clients/ITechMessagesClient.cs +++ b/Persistence.Client/Clients/ITechMessagesClient.cs @@ -4,29 +4,29 @@ using Refit; namespace Persistence.Client.Clients { - /// - /// Интерфейс клиента для хранения технологических сообщений - /// - public interface ITechMessagesClient - { - private const string BaseRoute = "/api/techMessages"; + /// + /// Интерфейс клиента для хранения технологических сообщений + /// + public interface ITechMessagesClient + { + private const string BaseRoute = "/api/techMessages"; - [Get($"{BaseRoute}")] - Task>> GetPage([Query] PaginationRequest request, CancellationToken token); + [Get($"{BaseRoute}")] + Task>> GetPage([Query] PaginationRequest request, CancellationToken token); - [Post($"{BaseRoute}")] - Task> AddRange([Body] IEnumerable dtos, CancellationToken token); + [Post($"{BaseRoute}")] + Task> AddRange([Body] IEnumerable dtos, CancellationToken token); - [Get($"{BaseRoute}/systems")] - Task>> GetSystems(CancellationToken token); + [Get($"{BaseRoute}/systems")] + Task>> GetSystems(CancellationToken token); - [Get($"{BaseRoute}/range")] - Task> GetDatesRangeAsync(CancellationToken token); + [Get($"{BaseRoute}/range")] + Task> GetDatesRangeAsync(CancellationToken token); - [Get($"{BaseRoute}/part")] - Task>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token); + [Get($"{BaseRoute}/part")] + Task>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token); - [Get($"{BaseRoute}/statistics")] - Task>> GetStatistics([Query] string autoDrillingSystem, [Query] int categoryId, CancellationToken token); - } + [Get($"{BaseRoute}/statistics")] + Task>> GetStatistics([Query] string autoDrillingSystem, [Query] int categoryId, CancellationToken token); + } } diff --git a/Persistence.Client/Helpers/ApiTokenHelper.cs b/Persistence.Client/Helpers/ApiTokenHelper.cs index d829fcf..d21363f 100644 --- a/Persistence.Client/Helpers/ApiTokenHelper.cs +++ b/Persistence.Client/Helpers/ApiTokenHelper.cs @@ -1,75 +1,74 @@ -using System.IdentityModel.Tokens.Jwt; -using System.Net.Http.Headers; -using System.Security.Claims; -using System.Text.Json; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using Persistence.Models.Configurations; using RestSharp; +using System.IdentityModel.Tokens.Jwt; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Text.Json; namespace Persistence.Client.Helpers; public static class ApiTokenHelper { - public static void Authorize(this HttpClient httpClient, IConfiguration configuration) - { - var authUser = configuration - .GetSection(nameof(AuthUser)) - .Get()!; - var needUseKeyCloak = configuration - .GetSection("NeedUseKeyCloak") - .Get()!; - var keycloakGetTokenUrl = configuration.GetSection("KeycloakGetTokenUrl").Get() ?? string.Empty; + public static void Authorize(this HttpClient httpClient, IConfiguration configuration) + { + var authUser = configuration + .GetSection(nameof(AuthUser)) + .Get()!; + var needUseKeyCloak = configuration + .GetSection("NeedUseKeyCloak") + .Get()!; + var keycloakGetTokenUrl = configuration.GetSection("KeycloakGetTokenUrl").Get() ?? string.Empty; - var jwtToken = needUseKeyCloak - ? authUser.CreateKeyCloakJwtToken(keycloakGetTokenUrl) - : authUser.CreateDefaultJwtToken(); + var jwtToken = needUseKeyCloak + ? authUser.CreateKeyCloakJwtToken(keycloakGetTokenUrl) + : authUser.CreateDefaultJwtToken(); - httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken); - } + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken); + } - private static string CreateDefaultJwtToken(this AuthUser authUser) - { - var nameIdetifier = Guid.NewGuid().ToString(); - var claims = new List() - { - new(ClaimTypes.NameIdentifier, nameIdetifier), - new("client_id", authUser.ClientId), - new("username", authUser.Username), - new("password", authUser.Password), - new("grant_type", authUser.GrantType), - new(ClaimTypes.NameIdentifier.ToString(), Guid.NewGuid().ToString()) - }; + private static string CreateDefaultJwtToken(this AuthUser authUser) + { + var nameIdetifier = Guid.NewGuid().ToString(); + var claims = new List() + { + new(ClaimTypes.NameIdentifier, nameIdetifier), + new("client_id", authUser.ClientId), + new("username", authUser.Username), + new("password", authUser.Password), + new("grant_type", authUser.GrantType) + }; - var tokenDescriptor = new SecurityTokenDescriptor - { - Issuer = JwtParams.Issuer, - Audience = JwtParams.Audience, - Subject = new ClaimsIdentity(claims), - Expires = DateTime.UtcNow.AddHours(1), - SigningCredentials = new SigningCredentials(JwtParams.SecurityKey, SecurityAlgorithms.HmacSha256Signature) - }; - var tokenHandler = new JwtSecurityTokenHandler(); - var token = tokenHandler.CreateToken(tokenDescriptor); - return tokenHandler.WriteToken(token); - } + var tokenDescriptor = new SecurityTokenDescriptor + { + Issuer = JwtParams.Issuer, + Audience = JwtParams.Audience, + Subject = new ClaimsIdentity(claims), + Expires = DateTime.UtcNow.AddHours(1), + SigningCredentials = new SigningCredentials(JwtParams.SecurityKey, SecurityAlgorithms.HmacSha256Signature) + }; + var tokenHandler = new JwtSecurityTokenHandler(); + var token = tokenHandler.CreateToken(tokenDescriptor); + return tokenHandler.WriteToken(token); + } - private static string CreateKeyCloakJwtToken(this AuthUser authUser, string keycloakGetTokenUrl) - { - var restClient = new RestClient(); + private static string CreateKeyCloakJwtToken(this AuthUser authUser, string keycloakGetTokenUrl) + { + var restClient = new RestClient(); - var request = new RestRequest(keycloakGetTokenUrl, Method.Post); - request.AddParameter("username", authUser.Username); - request.AddParameter("password", authUser.Password); - request.AddParameter("client_id", authUser.ClientId); - request.AddParameter("grant_type", authUser.GrantType); + var request = new RestRequest(keycloakGetTokenUrl, Method.Post); + request.AddParameter("username", authUser.Username); + request.AddParameter("password", authUser.Password); + request.AddParameter("client_id", authUser.ClientId); + request.AddParameter("grant_type", authUser.GrantType); - var keyCloackResponse = restClient.Post(request); - if (keyCloackResponse.IsSuccessful && !String.IsNullOrEmpty(keyCloackResponse.Content)) - { - var token = JsonSerializer.Deserialize(keyCloackResponse.Content)!; - return token.AccessToken; - } + var keycloakResponse = restClient.Post(request); + if (keycloakResponse.IsSuccessful && !String.IsNullOrEmpty(keycloakResponse.Content)) + { + var token = JsonSerializer.Deserialize(keycloakResponse.Content)!; + return token.AccessToken; + } - return String.Empty; - } + return String.Empty; + } } diff --git a/Persistence.Client/PersistenceClientFactory.cs b/Persistence.Client/PersistenceClientFactory.cs index 77f59d4..697c901 100644 --- a/Persistence.Client/PersistenceClientFactory.cs +++ b/Persistence.Client/PersistenceClientFactory.cs @@ -16,7 +16,7 @@ namespace Persistence.Client PropertyNameCaseInsensitive = true }; private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions)); - private HttpClient httpClient; + private readonly HttpClient httpClient; public PersistenceClientFactory(IHttpClientFactory httpClientFactory, IConfiguration configuration) { this.httpClient = httpClientFactory.CreateClient(); diff --git a/Persistence.Database.Postgres/DependencyInjection.cs b/Persistence.Database.Postgres/DependencyInjection.cs index bbd936b..3acd55c 100644 --- a/Persistence.Database.Postgres/DependencyInjection.cs +++ b/Persistence.Database.Postgres/DependencyInjection.cs @@ -1,7 +1,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Npgsql; namespace Persistence.Database.Model; diff --git a/Persistence.Database/Entity/ChangeLog.cs b/Persistence.Database/Entity/ChangeLog.cs index 9a8001b..edffb52 100644 --- a/Persistence.Database/Entity/ChangeLog.cs +++ b/Persistence.Database/Entity/ChangeLog.cs @@ -1,8 +1,8 @@  -using System.ComponentModel.DataAnnotations.Schema; -using System.ComponentModel.DataAnnotations; using Microsoft.EntityFrameworkCore; using Persistence.Models; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace Persistence.Database.Model; diff --git a/Persistence.IntegrationTests/BaseIntegrationTest.cs b/Persistence.IntegrationTests/BaseIntegrationTest.cs index e2f333e..ff4f814 100644 --- a/Persistence.IntegrationTests/BaseIntegrationTest.cs +++ b/Persistence.IntegrationTests/BaseIntegrationTest.cs @@ -3,8 +3,7 @@ using Persistence.Database.Model; using Xunit; namespace Persistence.IntegrationTests; -public abstract class BaseIntegrationTest : IClassFixture, - IDisposable +public abstract class BaseIntegrationTest : IClassFixture, IDisposable { protected readonly IServiceScope scope; @@ -21,5 +20,6 @@ public abstract class BaseIntegrationTest : IClassFixture, { scope.Dispose(); dbContext.Dispose(); + GC.SuppressFinalize(this); } } diff --git a/Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs b/Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs index 8c3b422..d989df0 100644 --- a/Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs +++ b/Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs @@ -13,7 +13,7 @@ namespace Persistence.IntegrationTests.Controllers; public class ChangeLogControllerTest : BaseIntegrationTest { private readonly IChangeLogClient client; - private static Random generatorRandomDigits = new Random(); + private static readonly Random generatorRandomDigits = new(); public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory) { @@ -28,7 +28,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest { // arrange var idDiscriminator = Guid.NewGuid(); - var dtos = Generate(2, DateTimeOffset.UtcNow); + var dtos = Generate(2); // act var result = await client.ClearAndAddRange(idDiscriminator, dtos); @@ -52,7 +52,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest // assert Assert.Equal(HttpStatusCode.OK, result.StatusCode); - Assert.Equal(insertedCount*2, result.Content); + Assert.Equal(insertedCount * 2, result.Content); } [Fact] @@ -61,7 +61,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest // arrange var count = 1; var idDiscriminator = Guid.NewGuid(); - var dtos = Generate(count, DateTimeOffset.UtcNow); + var dtos = Generate(count); var dto = dtos.FirstOrDefault()!; // act @@ -78,7 +78,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest // arrange var count = 3; var idDiscriminator = Guid.NewGuid(); - var dtos = Generate(count, DateTimeOffset.UtcNow); + var dtos = Generate(count); // act var result = await client.AddRange(idDiscriminator, dtos); @@ -93,7 +93,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest { // arrange var idDiscriminator = Guid.NewGuid(); - var dtos = Generate(1, DateTimeOffset.UtcNow); + var dtos = Generate(1); var dto = dtos.FirstOrDefault()!; var result = await client.Add(idDiscriminator, dto); Assert.Equal(HttpStatusCode.Created, result.StatusCode); @@ -102,7 +102,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest .Where(x => x.IdDiscriminator == idDiscriminator) .FirstOrDefault(); dto = entity.Adapt(); - dto.DepthEnd = dto.DepthEnd + 10; + dto.DepthEnd += 10; // act result = await client.Update(dto); @@ -143,7 +143,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest { // arrange var count = 2; - var dtos = Generate(count, DateTimeOffset.UtcNow); + var dtos = Generate(count); var entities = dtos.Select(d => d.Adapt()).ToArray(); dbContext.ChangeLog.AddRange(entities); dbContext.SaveChanges(); @@ -169,7 +169,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest public async Task Delete_returns_success() { // arrange - var dtos = Generate(1, DateTimeOffset.UtcNow); + var dtos = Generate(1); var dto = dtos.FirstOrDefault()!; var entity = dto.Adapt(); dbContext.ChangeLog.Add(entity); @@ -188,7 +188,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest { // arrange var count = 10; - var dtos = Generate(count, DateTimeOffset.UtcNow); + var dtos = Generate(count); var entities = dtos.Select(d => d.Adapt()).ToArray(); dbContext.ChangeLog.AddRange(entities); dbContext.SaveChanges(); @@ -248,8 +248,8 @@ public class ChangeLogControllerTest : BaseIntegrationTest var filterRequest = new SectionPartRequest() { - DepthStart = 0, - DepthEnd = 1000, + DepthStart = 0, + DepthEnd = 1000, }; var paginationRequest = new PaginationRequest() @@ -294,7 +294,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest foreach (var entity in entities) { - entity.DepthEnd = entity.DepthEnd + 10; + entity.DepthEnd += 10; } var dtos = entities.Select(e => e.Adapt()).ToArray(); await client.UpdateRange(dtos); @@ -311,7 +311,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest } - private static IEnumerable Generate(int count, DateTimeOffset from) + private static IEnumerable Generate(int count) { for (int i = 0; i < count; i++) yield return new DataWithWellDepthAndSectionDto() @@ -334,7 +334,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest var maxDayCount = daysRange.Item2; Guid idDiscriminator = Guid.NewGuid(); - var dtos = Generate(count, DateTimeOffset.UtcNow); + var dtos = Generate(count); var entities = dtos.Select(d => { var entity = d.Adapt(); diff --git a/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs b/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs index cdb2381..7edd0f3 100644 --- a/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs +++ b/Persistence.IntegrationTests/Controllers/DataSaubControllerTest.cs @@ -28,7 +28,7 @@ public class DataSaubControllerTest : TimeSeriesBaseControllerTest(); + public class TechMessagesControllerTest : BaseIntegrationTest + { + private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DrillingSystem).FullName}CacheKey"; + private readonly ITechMessagesClient techMessagesClient; + private readonly IMemoryCache memoryCache; + public TechMessagesControllerTest(WebAppFactoryFixture factory) : base(factory) + { + var scope = factory.Services.CreateScope(); + var persistenceClientFactory = scope.ServiceProvider + .GetRequiredService(); - techMessagesClient = persistenceClientFactory.GetClient(); - memoryCache = scope.ServiceProvider.GetRequiredService(); - } + techMessagesClient = persistenceClientFactory.GetClient(); + memoryCache = scope.ServiceProvider.GetRequiredService(); + } - [Fact] - public async Task GetPage_returns_success() - { - //arrange - memoryCache.Remove(SystemCacheKey); - dbContext.CleanupDbSet(); - dbContext.CleanupDbSet(); + [Fact] + public async Task GetPage_returns_success() + { + //arrange + memoryCache.Remove(SystemCacheKey); + dbContext.CleanupDbSet(); + dbContext.CleanupDbSet(); - var PaginationRequest = new PaginationRequest() - { - Skip = 1, - Take = 2, - SortSettings = nameof(TechMessage.CategoryId) - }; + var PaginationRequest = new PaginationRequest() + { + Skip = 1, + Take = 2, + SortSettings = nameof(TechMessage.CategoryId) + }; - //act - var response = await techMessagesClient.GetPage(PaginationRequest, new CancellationToken()); + //act + var response = await techMessagesClient.GetPage(PaginationRequest, new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content); - Assert.Empty(response.Content.Items); - Assert.Equal(PaginationRequest.Skip, response.Content.Skip); - Assert.Equal(PaginationRequest.Take, response.Content.Take); - } + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + Assert.Empty(response.Content.Items); + Assert.Equal(PaginationRequest.Skip, response.Content.Skip); + Assert.Equal(PaginationRequest.Take, response.Content.Take); + } - [Fact] - public async Task GetPage_AfterSave_returns_success() - { - //arrange - var dtos = await InsertRange(); - var dtosCount = dtos.Count(); - var PaginationRequest = new PaginationRequest() - { - Skip = 0, - Take = 2, - SortSettings = nameof(TechMessage.CategoryId) - }; + [Fact] + public async Task GetPage_AfterSave_returns_success() + { + //arrange + var dtos = await InsertRange(); + var dtosCount = dtos.Count(); + var PaginationRequest = new PaginationRequest() + { + Skip = 0, + Take = 2, + SortSettings = nameof(TechMessage.CategoryId) + }; - //act - var response = await techMessagesClient.GetPage(PaginationRequest, new CancellationToken()); + //act + var response = await techMessagesClient.GetPage(PaginationRequest, new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content); - Assert.Equal(dtosCount, response.Content.Count); - } + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + Assert.Equal(dtosCount, response.Content.Count); + } - [Fact] - public async Task InsertRange_returns_success() - { - await InsertRange(); - } + [Fact] + public async Task InsertRange_returns_success() + { + await InsertRange(); + } - [Fact] - public async Task InsertRange_returns_BadRequest() - { - //arrange - var dtos = new List() - { - new TechMessageDto() - { - EventId = Guid.NewGuid(), - CategoryId = -1, // < 0 + [Fact] + public async Task InsertRange_returns_BadRequest() + { + //arrange + var dtos = new List() + { + new() + { + EventId = Guid.NewGuid(), + CategoryId = -1, // < 0 Timestamp = DateTimeOffset.UtcNow, - Depth = -1, // < 0 + Depth = -1, // < 0 MessageText = string.Empty, // length < 0 System = string.Concat(Enumerable.Repeat(nameof(TechMessageDto.System), 100)), // length > 256 UserId = Guid.NewGuid() - } - }; + } + }; - //act - var response = await techMessagesClient.AddRange(dtos, new CancellationToken()); + //act + var response = await techMessagesClient.AddRange(dtos, new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); - } + //assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } - [Fact] - public async Task GetSystems_returns_success() - { - //arrange - memoryCache.Remove(SystemCacheKey); - dbContext.CleanupDbSet(); - dbContext.CleanupDbSet(); + [Fact] + public async Task GetSystems_returns_success() + { + //arrange + memoryCache.Remove(SystemCacheKey); + dbContext.CleanupDbSet(); + dbContext.CleanupDbSet(); - //act - var response = await techMessagesClient.GetSystems(new CancellationToken()); + //act + var response = await techMessagesClient.GetSystems(new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content); - Assert.Empty(response.Content); - } + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + Assert.Empty(response.Content); + } - [Fact] - public async Task GetSystems_AfterSave_returns_success() - { - //arrange - var dtos = await InsertRange(); - var systems = dtos - .Select(e => e.System) - .Distinct() - .ToArray(); + [Fact] + public async Task GetSystems_AfterSave_returns_success() + { + //arrange + var dtos = await InsertRange(); + var systems = dtos + .Select(e => e.System) + .Distinct() + .ToArray(); - //act - var response = await techMessagesClient.GetSystems(new CancellationToken()); + //act + var response = await techMessagesClient.GetSystems(new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content); - string?[]? content = response.Content?.ToArray(); - Assert.Equal(systems, content); - } + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + string?[]? content = response.Content?.ToArray(); + Assert.Equal(systems, content); + } - [Fact] - public async Task GetStatistics_returns_success() - { - //arrange - memoryCache.Remove(SystemCacheKey); - dbContext.CleanupDbSet(); - dbContext.CleanupDbSet(); + [Fact] + public async Task GetStatistics_returns_success() + { + //arrange + memoryCache.Remove(SystemCacheKey); + dbContext.CleanupDbSet(); + dbContext.CleanupDbSet(); - var imortantId = 1; - var autoDrillingSystem = nameof(TechMessageDto.System); + var importantId = 1; + var autoDrillingSystem = nameof(TechMessageDto.System); - //act - var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken()); + //act + var response = await techMessagesClient.GetStatistics(autoDrillingSystem, importantId, new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content); - Assert.Empty(response.Content); - } + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + Assert.Empty(response.Content); + } - [Fact] - public async Task GetStatistics_AfterSave_returns_success() - { - //arrange - var imortantId = 0; - var autoDrillingSystem = nameof(TechMessageDto.System); - var dtos = await InsertRange(); - var filteredDtos = dtos.Where(e => e.CategoryId == imortantId && e.System == autoDrillingSystem); + [Fact] + public async Task GetStatistics_AfterSave_returns_success() + { + //arrange + var importantId = 0; + var autoDrillingSystem = nameof(TechMessageDto.System); + var dtos = await InsertRange(); + var filteredDtos = dtos.Where(e => e.CategoryId == importantId && e.System == autoDrillingSystem); - //act - var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken()); + //act + var response = await techMessagesClient.GetStatistics(autoDrillingSystem, importantId, new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content); - var categories = response.Content - .FirstOrDefault()?.Categories - .FirstOrDefault(e => e.Key == 0).Value; - Assert.Equal(filteredDtos.Count(), categories); - } + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + var categories = response.Content + .FirstOrDefault()?.Categories + .FirstOrDefault(e => e.Key == 0).Value; + Assert.Equal(filteredDtos.Count(), categories); + } - [Fact] - public async Task GetDatesRange_returns_success() - { - //act - var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken()); + [Fact] + public async Task GetDatesRange_returns_success() + { + //act + var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content); - //Assert.Equal(DateTimeOffset.MinValue, response.Content?.From); - //Assert.Equal(DateTimeOffset.MaxValue, response.Content?.To); - } + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + //Assert.Equal(DateTimeOffset.MinValue, response.Content?.From); + //Assert.Equal(DateTimeOffset.MaxValue, response.Content?.To); + } - [Fact] - public async Task GetDatesRange_AfterSave_returns_success() - { - //arrange - await InsertRange(); + [Fact] + public async Task GetDatesRange_AfterSave_returns_success() + { + //arrange + await InsertRange(); - //act - var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken()); + //act + var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content); - Assert.NotNull(response.Content?.From); - Assert.NotNull(response.Content?.To); - } + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + Assert.NotNull(response.Content?.From); + Assert.NotNull(response.Content?.To); + } - [Fact] - public async Task GetPart_returns_success() - { - //arrange - var dateBegin = DateTimeOffset.UtcNow; - var take = 2; + [Fact] + public async Task GetPart_returns_success() + { + //arrange + var dateBegin = DateTimeOffset.UtcNow; + var take = 2; - //act - var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken()); + //act + var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content); - Assert.Empty(response.Content); - } + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + Assert.Empty(response.Content); + } - [Fact] - public async Task GetPart_AfterSave_returns_success() - { - //arrange - var dateBegin = DateTimeOffset.UtcNow; - var take = 1; - await InsertRange(); + [Fact] + public async Task GetPart_AfterSave_returns_success() + { + //arrange + var dateBegin = DateTimeOffset.UtcNow; + var take = 1; + await InsertRange(); - //act - var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken()); + //act + var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(response.Content); - Assert.NotEmpty(response.Content); - } + //assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Content); + Assert.NotEmpty(response.Content); + } - private async Task> InsertRange() - { - //arrange - memoryCache.Remove(SystemCacheKey); - dbContext.CleanupDbSet(); - dbContext.CleanupDbSet(); + private async Task> InsertRange() + { + //arrange + memoryCache.Remove(SystemCacheKey); + dbContext.CleanupDbSet(); + dbContext.CleanupDbSet(); - var dtos = new List() - { - new TechMessageDto() - { - EventId = Guid.NewGuid(), - CategoryId = 1, - Timestamp = DateTimeOffset.UtcNow, - Depth = 1.11, - MessageText = nameof(TechMessageDto.MessageText), - System = nameof(TechMessageDto.System).ToLower(), - UserId = Guid.NewGuid() - }, - new TechMessageDto() - { - EventId = Guid.NewGuid(), - CategoryId = 2, - Timestamp = DateTimeOffset.UtcNow, - Depth = 2.22, - MessageText = nameof(TechMessageDto.MessageText), - System = nameof(TechMessageDto.System).ToLower(), - UserId = Guid.NewGuid() - } - }; + var dtos = new List() + { + new() + { + EventId = Guid.NewGuid(), + CategoryId = 1, + Timestamp = DateTimeOffset.UtcNow, + Depth = 1.11, + MessageText = nameof(TechMessageDto.MessageText), + System = nameof(TechMessageDto.System).ToLower(), + UserId = Guid.NewGuid() + }, + new() + { + EventId = Guid.NewGuid(), + CategoryId = 2, + Timestamp = DateTimeOffset.UtcNow, + Depth = 2.22, + MessageText = nameof(TechMessageDto.MessageText), + System = nameof(TechMessageDto.System).ToLower(), + UserId = Guid.NewGuid() + } + }; - //act - var response = await techMessagesClient.AddRange(dtos, new CancellationToken()); + //act + var response = await techMessagesClient.AddRange(dtos, new CancellationToken()); - //assert - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - Assert.Equal(dtos.Count, response.Content); + //assert + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + Assert.Equal(dtos.Count, response.Content); - return dtos; - } - } + return dtos; + } + } } diff --git a/Persistence.IntegrationTests/Controllers/TimeSeriesBaseControllerTest.cs b/Persistence.IntegrationTests/Controllers/TimeSeriesBaseControllerTest.cs index f5cb591..952522d 100644 --- a/Persistence.IntegrationTests/Controllers/TimeSeriesBaseControllerTest.cs +++ b/Persistence.IntegrationTests/Controllers/TimeSeriesBaseControllerTest.cs @@ -12,7 +12,7 @@ public abstract class TimeSeriesBaseControllerTest : BaseIntegrat where TEntity : class, ITimestampedData, new() where TDto : class, new() { - private ITimeSeriesClient timeSeriesClient; + private readonly ITimeSeriesClient timeSeriesClient; public TimeSeriesBaseControllerTest(WebAppFactoryFixture factory) : base(factory) { @@ -31,7 +31,7 @@ public abstract class TimeSeriesBaseControllerTest : BaseIntegrat var expected = dto.Adapt(); //act - var response = await timeSeriesClient.AddRange(new TDto[] { expected }); + var response = await timeSeriesClient.AddRange([expected]); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -116,7 +116,7 @@ public abstract class TimeSeriesBaseControllerTest : BaseIntegrat } else { - Assert.Equal(entities.Count(), response.Content.Count()); + Assert.Equal(entities.Count, response.Content.Count()); } diff --git a/Persistence.IntegrationTests/Controllers/TimestampedSetControllerTest.cs b/Persistence.IntegrationTests/Controllers/TimestampedSetControllerTest.cs index 296c7b6..1e7aa7e 100644 --- a/Persistence.IntegrationTests/Controllers/TimestampedSetControllerTest.cs +++ b/Persistence.IntegrationTests/Controllers/TimestampedSetControllerTest.cs @@ -111,7 +111,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest Guid idDiscriminator = Guid.NewGuid(); int count = 10; IEnumerable testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7))); - var insertResponse = await client.AddRange(idDiscriminator, testSets); + await client.AddRange(idDiscriminator, testSets); var expectedCount = count / 2; // act @@ -133,7 +133,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest var expectedCount = 1; int count = 10 + expectedCount; IEnumerable testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7))); - var insertResponse = await client.AddRange(idDiscriminator, testSets); + await client.AddRange(idDiscriminator, testSets); // act var response = await client.Get(idDiscriminator, null, null, count - expectedCount, count); @@ -174,7 +174,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest var dateMin = DateTimeOffset.Now; var dateMax = DateTimeOffset.Now.AddSeconds(count - 1); IEnumerable testSets = Generate(count, dateMin.ToOffset(TimeSpan.FromHours(7))); - var insertResponse = await client.AddRange(idDiscriminator, testSets); + await client.AddRange(idDiscriminator, testSets); var tolerance = TimeSpan.FromSeconds(1); // act @@ -195,7 +195,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest Guid idDiscriminator = Guid.NewGuid(); int count = 144; IEnumerable testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7))); - var insertResponse = await client.AddRange(idDiscriminator, testSets); + await client.AddRange(idDiscriminator, testSets); // act var response = await client.Count(idDiscriminator); diff --git a/Persistence.IntegrationTests/WebAppFactoryFixture.cs b/Persistence.IntegrationTests/WebAppFactoryFixture.cs index 0092c06..e9bff4c 100644 --- a/Persistence.IntegrationTests/WebAppFactoryFixture.cs +++ b/Persistence.IntegrationTests/WebAppFactoryFixture.cs @@ -60,5 +60,7 @@ public class WebAppFactoryFixture : WebApplicationFactory .Options); await dbContext.Database.EnsureDeletedAsync(); + + GC.SuppressFinalize(dbContext); } } diff --git a/Persistence.Repository/Extensions/EFExtensionsSortBy.cs b/Persistence.Repository/Extensions/EFExtensionsSortBy.cs index e2bbee8..a716f43 100644 --- a/Persistence.Repository/Extensions/EFExtensionsSortBy.cs +++ b/Persistence.Repository/Extensions/EFExtensionsSortBy.cs @@ -44,7 +44,7 @@ public static class EFExtensionsSortBy var name = propertyInfo.Name.ToLower(); ParameterExpression arg = Expression.Parameter(type, "x"); MemberExpression property = Expression.Property(arg, propertyInfo.Name); - var selector = Expression.Lambda(property, new ParameterExpression[] { arg }); + var selector = Expression.Lambda(property, [ arg ]); var typeAccessor = new TypeAccessor { KeySelector = selector, @@ -261,7 +261,7 @@ public static class EFExtensionsSortBy : orderByAscending; var newQuery = (IOrderedQueryable)genericMethod - .Invoke(genericMethod, [ query, lambdaExpression ])!; + .Invoke(genericMethod, [query, lambdaExpression])!; return newQuery; } } \ No newline at end of file diff --git a/Persistence.Repository/QueryBuilders.cs b/Persistence.Repository/QueryBuilders.cs index 6070a8a..a0e17be 100644 --- a/Persistence.Repository/QueryBuilders.cs +++ b/Persistence.Repository/QueryBuilders.cs @@ -29,7 +29,7 @@ public static class QueryBuilders return query; } - public static IQueryable Apply(this IQueryable query,DateTimeOffset momentUtc) + public static IQueryable Apply(this IQueryable query, DateTimeOffset momentUtc) where TEntity : class, IChangeLog { momentUtc = momentUtc.ToUniversalTime(); @@ -40,7 +40,7 @@ public static class QueryBuilders return query; } - + public static async Task> ApplyPagination( this IQueryable query, diff --git a/Persistence.Repository/Repositories/ChangeLogRepository.cs b/Persistence.Repository/Repositories/ChangeLogRepository.cs index ac00e05..6b9dd1e 100644 --- a/Persistence.Repository/Repositories/ChangeLogRepository.cs +++ b/Persistence.Repository/Repositories/ChangeLogRepository.cs @@ -9,7 +9,7 @@ using UuidExtensions; namespace Persistence.Repository.Repositories; public class ChangeLogRepository : IChangeLogRepository { - private DbContext db; + private readonly DbContext db; public ChangeLogRepository(DbContext db) { @@ -123,7 +123,7 @@ public class ChangeLogRepository : IChangeLogRepository return result; - + } public async Task> GetByDate( diff --git a/Persistence.Repository/Repositories/TechMessagesRepository.cs b/Persistence.Repository/Repositories/TechMessagesRepository.cs index d2efbe4..4a7b69e 100644 --- a/Persistence.Repository/Repositories/TechMessagesRepository.cs +++ b/Persistence.Repository/Repositories/TechMessagesRepository.cs @@ -5,174 +5,174 @@ using Persistence.Database.Entity; using Persistence.Models; using Persistence.Models.Requests; using Persistence.Repositories; -using Persistence.Repository.Extensions; +using UuidExtensions; namespace Persistence.Repository.Repositories { - public class TechMessagesRepository : ITechMessagesRepository - { - private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DrillingSystem).FullName}CacheKey"; - private const int CacheExpirationInMinutes = 60; - private readonly IMemoryCache memoryCache; - private DbContext db; + public class TechMessagesRepository : ITechMessagesRepository + { + private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DrillingSystem).FullName}CacheKey"; + private const int CacheExpirationInMinutes = 60; + private readonly IMemoryCache memoryCache; + private readonly DbContext db; - public TechMessagesRepository(DbContext db, IMemoryCache memoryCache) - { - this.memoryCache = memoryCache; - this.db = db; - } + public TechMessagesRepository(DbContext db, IMemoryCache memoryCache) + { + this.memoryCache = memoryCache; + this.db = db; + } - protected virtual IQueryable GetQueryReadOnly() => db.Set() - .Include(e => e.System); + protected virtual IQueryable GetQueryReadOnly() => db.Set() + .Include(e => e.System); - public async Task> GetPage(PaginationRequest request, CancellationToken token) - { - var query = GetQueryReadOnly(); - var count = await query.CountAsync(token); + public async Task> GetPage(PaginationRequest request, CancellationToken token) + { + var query = GetQueryReadOnly(); + var count = await query.CountAsync(token); - var sort = request.SortSettings != string.Empty - ? request.SortSettings - : nameof(TechMessage.Timestamp); - var entities = await query - .SortBy(request.SortSettings) - .Skip(request.Skip) - .Take(request.Take) - .ToArrayAsync(token); + var sort = request.SortSettings != string.Empty + ? request.SortSettings! + : nameof(TechMessage.Timestamp); + var entities = await query + .SortBy(sort) + .Skip(request.Skip) + .Take(request.Take) + .ToArrayAsync(token); - var dto = new PaginationContainer() - { - Skip = request.Skip, - Take = request.Take, - Count = count, - Items = entities.Select(e => e.Adapt()) - }; + var dto = new PaginationContainer() + { + Skip = request.Skip, + Take = request.Take, + Count = count, + Items = entities.Select(e => e.Adapt()) + }; - return dto; - } + return dto; + } - public async Task> GetStatistics(IEnumerable autoDrillingSystem, IEnumerable categoryIds, CancellationToken token) - { - var query = GetQueryReadOnly(); - var systems = autoDrillingSystem.Select(s => s.ToLower().Trim()); - var result = await query - .Where(e => systems.Count() == 0 || systems.Contains(e.System.Name.ToLower().Trim())) - .GroupBy(e => e.System.Name, (key, group) => new - { - System = key, - Categories = group - .Where(g => categoryIds.Count() == 0 || categoryIds.Contains(g.CategoryId)) - }) - .ToArrayAsync(token); + public async Task> GetStatistics(IEnumerable autoDrillingSystem, IEnumerable categoryIds, CancellationToken token) + { + var query = GetQueryReadOnly(); + var systems = autoDrillingSystem.Select(s => s.ToLower().Trim()); + var result = await query + .Where(e => !systems.Any() || systems.Contains(e.System.Name.ToLower().Trim())) + .GroupBy(e => e.System.Name, (key, group) => new + { + System = key, + Categories = group + .Where(g => !categoryIds.Any() || categoryIds.Contains(g.CategoryId)) + }) + .ToArrayAsync(token); - var entities = new List(); - foreach (var e in result) - { - var categories = e.Categories - .GroupBy(g => g.CategoryId) - .ToDictionary(c => c.Key, v => v.Count()); - var entity = new MessagesStatisticDto() - { - System = e.System, - Categories = categories - }; - entities.Add(entity); - } + var entities = new List(); + foreach (var e in result) + { + var categories = e.Categories + .GroupBy(g => g.CategoryId) + .ToDictionary(c => c.Key, v => v.Count()); + var entity = new MessagesStatisticDto() + { + System = e.System, + Categories = categories + }; + entities.Add(entity); + } - return entities; - } + return entities; + } - public async Task> GetSystems(CancellationToken token) - { - var entities = await GetDrillingSystems(token); - var result = entities.Select(e => e.Name); + public async Task> GetSystems(CancellationToken token) + { + var entities = await GetDrillingSystems(token); + var result = entities.Select(e => e.Name); - return result; - } + return result; + } - public async Task AddRange(IEnumerable dtos, Guid userId, CancellationToken token) - { + public async Task AddRange(IEnumerable dtos, Guid userId, CancellationToken token) + { - var entities = new List(); - foreach (var dto in dtos) - { - var entity = dto.Adapt(); - var systems = await GetDrillingSystems(token); - var systemId = systems.FirstOrDefault(e => e.Name.ToLower().Trim() == dto.System.ToLower().Trim())?.SystemId - ?? await CreateDrillingSystem(dto.System, token); + var entities = new List(); + foreach (var dto in dtos) + { + var entity = dto.Adapt(); + var systems = await GetDrillingSystems(token); + var systemId = systems.FirstOrDefault(e => e.Name.ToLower().Trim() == dto.System.ToLower().Trim())?.SystemId + ?? await CreateDrillingSystem(dto.System, token); - entity.SystemId = systemId; - entity.UserId = userId; + entity.SystemId = systemId; + entity.UserId = userId; - entities.Add(entity); - } + entities.Add(entity); + } - await db.Set().AddRangeAsync(entities, token); - var result = await db.SaveChangesAsync(token); + await db.Set().AddRangeAsync(entities, token); + var result = await db.SaveChangesAsync(token); - return result; - } + return result; + } - public async Task> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token) - { - var query = GetQueryReadOnly(); - var entities = await query - .Where(e => e.Timestamp >= dateBegin) - .Take(take) - .ToArrayAsync(token); - var dtos = entities - .Select(e => e.Adapt()); + public async Task> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token) + { + var query = GetQueryReadOnly(); + var entities = await query + .Where(e => e.Timestamp >= dateBegin) + .Take(take) + .ToArrayAsync(token); + var dtos = entities + .Select(e => e.Adapt()); - return dtos; - } + return dtos; + } - public async Task GetDatesRangeAsync(CancellationToken token) - { - var query = GetQueryReadOnly() - .GroupBy(e => 1) - .Select(group => new - { - Min = group.Min(e => e.Timestamp), - Max = group.Max(e => e.Timestamp), - }); - var values = await query.FirstOrDefaultAsync(token); - var result = new DatesRangeDto() - { - From = values?.Min ?? DateTimeOffset.MinValue, - To = values?.Max ?? DateTimeOffset.MaxValue - }; + public async Task GetDatesRangeAsync(CancellationToken token) + { + var query = GetQueryReadOnly() + .GroupBy(e => 1) + .Select(group => new + { + Min = group.Min(e => e.Timestamp), + Max = group.Max(e => e.Timestamp), + }); + var values = await query.FirstOrDefaultAsync(token); + var result = new DatesRangeDto() + { + From = values?.Min ?? DateTimeOffset.MinValue, + To = values?.Max ?? DateTimeOffset.MaxValue + }; - return result; - } + return result; + } - private async Task> GetDrillingSystems(CancellationToken token) - { - var systems = await memoryCache.GetOrCreateAsync(SystemCacheKey, async f => - { - f.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(CacheExpirationInMinutes); + private async Task> GetDrillingSystems(CancellationToken token) + { + var systems = await memoryCache.GetOrCreateAsync(SystemCacheKey, async f => + { + f.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(CacheExpirationInMinutes); - var query = db.Set(); - var entities = await query.ToListAsync(token); - var dtos = entities.Select(e => e.Adapt()); + var query = db.Set(); + var entities = await query.ToListAsync(token); + var dtos = entities.Select(e => e.Adapt()); - return dtos; - }); + return dtos; + }); - return systems!; - } - private async Task CreateDrillingSystem(string name, CancellationToken token) - { - memoryCache.Remove(SystemCacheKey); + return systems!; + } + private async Task CreateDrillingSystem(string name, CancellationToken token) + { + memoryCache.Remove(SystemCacheKey); - var entity = new Database.Entity.DrillingSystem() - { - SystemId = default, - Name = name.ToLower().Trim() - }; + var entity = new DrillingSystem() + { + SystemId = Uuid7.Guid(), + Name = name.ToLower().Trim() + }; - await db.Set().AddAsync(entity); - await db.SaveChangesAsync(token); + await db.Set().AddAsync(entity, token); + await db.SaveChangesAsync(token); - return entity.SystemId; - } - } + return entity.SystemId; + } + } } diff --git a/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs b/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs index b06da73..ba60f27 100644 --- a/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs +++ b/Persistence.Repository/Repositories/TimeSeriesDataRepository.cs @@ -9,7 +9,7 @@ public class TimeSeriesDataRepository : ITimeSeriesDataRepository where TEntity : class, ITimestampedData, new() where TDto : class, ITimeSeriesAbstractDto, new() { - private DbContext db; + private readonly DbContext db; public TimeSeriesDataRepository(DbContext db) { diff --git a/Persistence/API/ISyncWithDiscriminatorApi.cs b/Persistence/API/ISyncWithDiscriminatorApi.cs index c0c72f0..5d358d5 100644 --- a/Persistence/API/ISyncWithDiscriminatorApi.cs +++ b/Persistence/API/ISyncWithDiscriminatorApi.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using Persistence.Models; namespace Persistence.API; diff --git a/Persistence/EFExtensions.cs b/Persistence/EFExtensions.cs index 00474cc..425e52a 100644 --- a/Persistence/EFExtensions.cs +++ b/Persistence/EFExtensions.cs @@ -1,16 +1,11 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Concurrent; using System.Linq.Expressions; using System.Reflection; -using System.Text; -using System.Threading.Tasks; namespace Persistence; public static class EFExtensions { - struct TypeAcessor + struct TypeAccessor { public LambdaExpression KeySelector { get; set; } public MethodInfo OrderBy { get; set; } @@ -25,7 +20,7 @@ public static class EFExtensions private static readonly MethodInfo methodThenBy = GetExtOrderMethod("ThenBy"); private static readonly MethodInfo methodThenByDescending = GetExtOrderMethod("ThenByDescending"); - private static ConcurrentDictionary> TypePropSelectors { get; set; } = new(); + private static ConcurrentDictionary> TypePropSelectors { get; set; } = new(); private static MethodInfo GetExtOrderMethod(string methodName) => typeof(System.Linq.Queryable) @@ -35,17 +30,17 @@ public static class EFExtensions m.GetParameters().Length == 2 && m.GetParameters()[1].ParameterType.IsAssignableTo(typeof(LambdaExpression))) .Single(); - private static Dictionary MakeTypeAcessors(Type type) + private static Dictionary MakeTypeAccessors(Type type) { - var propContainer = new Dictionary(); + var propContainer = new Dictionary(); var properties = type.GetProperties(); foreach (var propertyInfo in properties) { var name = propertyInfo.Name.ToLower(); ParameterExpression arg = Expression.Parameter(type, "x"); MemberExpression property = Expression.Property(arg, propertyInfo.Name); - var selector = Expression.Lambda(property, new ParameterExpression[] { arg }); - var typeAccessor = new TypeAcessor + var selector = Expression.Lambda(property, [arg]); + var typeAccessor = new TypeAccessor { KeySelector = selector, OrderBy = methodOrderBy.MakeGenericMethod(type, propertyInfo.PropertyType), @@ -99,16 +94,16 @@ public static class EFExtensions string propertyName, bool isDesc) { - var typePropSelector = TypePropSelectors.GetOrAdd(typeof(TSource), MakeTypeAcessors); - var propertyNamelower = propertyName.ToLower(); - var typeAccessor = typePropSelector[propertyNamelower]; + var typePropSelector = TypePropSelectors.GetOrAdd(typeof(TSource), MakeTypeAccessors); + var propertyNameLower = propertyName.ToLower(); + var typeAccessor = typePropSelector[propertyNameLower]; var genericMethod = isDesc ? typeAccessor.OrderByDescending : typeAccessor.OrderBy; var newQuery = (IOrderedQueryable)genericMethod - .Invoke(genericMethod, new object[] { query, typeAccessor.KeySelector })!; + .Invoke(genericMethod, [query, typeAccessor.KeySelector])!; return newQuery; } } diff --git a/Persistence/Models/DataWithWellDepthAndSectionDto.cs b/Persistence/Models/DataWithWellDepthAndSectionDto.cs index 7939dd0..033ddb8 100644 --- a/Persistence/Models/DataWithWellDepthAndSectionDto.cs +++ b/Persistence/Models/DataWithWellDepthAndSectionDto.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Persistence.Models; +namespace Persistence.Models; /// /// Dto для хранения записей, содержащих начальную и конечную глубину забоя, а также секцию diff --git a/Persistence/Models/PaginationContainer.cs b/Persistence/Models/PaginationContainer.cs index a0c64b2..7054b2c 100644 --- a/Persistence/Models/PaginationContainer.cs +++ b/Persistence/Models/PaginationContainer.cs @@ -11,7 +11,7 @@ public class PaginationContainer /// public PaginationContainer() { - Items = Enumerable.Empty(); + Items = []; } /// diff --git a/Persistence/Repositories/ITimeSeriesBaseRepository.cs b/Persistence/Repositories/ITimeSeriesBaseRepository.cs index 74cc545..abe6b05 100644 --- a/Persistence/Repositories/ITimeSeriesBaseRepository.cs +++ b/Persistence/Repositories/ITimeSeriesBaseRepository.cs @@ -1,6 +1,4 @@ -using Persistence.Models; - -namespace Persistence.Repositories; +namespace Persistence.Repositories; /// /// Интерфейс по работе с прореженными данными