#408 Репозиторий хранения данных WITS0 #7

Merged
on.nemtina merged 9 commits from WitsData into master 2024-12-12 16:11:56 +05:00
8 changed files with 111 additions and 66 deletions
Showing only changes of commit 393bb93760 - Show all commits

View File

@ -27,12 +27,12 @@ public class WitsDataController : ControllerBase, IWitsDataApi
/// <param name="discriminatorId"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("datesRange")]
public async Task<ActionResult<DatesRangeDto>> GetDatesRangeAsync([FromQuery] int discriminatorId, CancellationToken token)
[HttpGet("{discriminatorId}/datesRange")]
public async Task<ActionResult<DatesRangeDto>> GetDatesRangeAsync([FromRoute] int discriminatorId, CancellationToken token)

discriminatorId лучше добавить в роут

discriminatorId лучше добавить в роут
{
var result = await witsDataService.GetDatesRangeAsync(discriminatorId, token);
return Ok(result);
return result == null ? NoContent() : Ok(result);
}
/// <summary>
@ -43,8 +43,8 @@ public class WitsDataController : ControllerBase, IWitsDataApi
/// <param name="take"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("part")]
public async Task<ActionResult<IEnumerable<WitsDataDto>>> GetPart([FromQuery] int discriminatorId, [FromQuery] DateTimeOffset dateBegin, [FromQuery] int take, CancellationToken token)
[HttpGet("{discriminatorId}/part")]
public async Task<ActionResult<IEnumerable<WitsDataDto>>> GetPart([FromRoute] int discriminatorId, [FromQuery] DateTimeOffset dateBegin, [FromQuery] int take, CancellationToken token)

discriminatorId лучше добавить в роут

discriminatorId лучше добавить в роут
{
var result = await witsDataService.GetPart(discriminatorId, dateBegin, take, token);
@ -60,8 +60,8 @@ public class WitsDataController : ControllerBase, IWitsDataApi
/// <param name="approxPointsCount">Количество точек</param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("graph")]
public async Task<ActionResult<IEnumerable<WitsDataDto>>> GetValuesForGraph([FromQuery] int discriminatorId,
[HttpGet("{discriminatorId}/graph")]
public async Task<ActionResult<IEnumerable<WitsDataDto>>> GetValuesForGraph([FromRoute] int discriminatorId,

discriminatorId лучше добавить в роут

discriminatorId лучше добавить в роут
[FromQuery] DateTimeOffset dateFrom, [FromQuery] DateTimeOffset dateTo, [FromQuery] int approxPointsCount, CancellationToken token)
{
var result = await witsDataService.GetValuesForGraph(discriminatorId, dateFrom, dateTo, approxPointsCount, token);

View File

@ -1,4 +1,5 @@
using Persistence.Models;
using Microsoft.AspNetCore.Mvc;
using Persistence.Models;
using Refit;
namespace Persistence.Client.Clients;
@ -6,15 +7,15 @@ public interface IWitsDataClient
{
private const string BaseRoute = "/api/witsData";
[Get($"{BaseRoute}/graph")]
Task<IApiResponse<IEnumerable<WitsDataDto>>> GetValuesForGraph([Query] int discriminatorId, [Query] DateTimeOffset dateFrom, [Query] DateTimeOffset dateTo, [Query] int approxPointsCount, CancellationToken token);
[Get($"{BaseRoute}/{{discriminatorId}}/graph")]

discriminatorId лучше добавить в роут

discriminatorId лучше добавить в роут
Task<IApiResponse<IEnumerable<WitsDataDto>>> GetValuesForGraph(int discriminatorId, [Query] DateTimeOffset dateFrom, [Query] DateTimeOffset dateTo, [Query] int approxPointsCount, CancellationToken token);
[Post($"{BaseRoute}/")]
Task<IApiResponse<int>> AddRange([Body] IEnumerable<WitsDataDto> dtos, CancellationToken token);
Task<IApiResponse<int>> AddRange(IEnumerable<WitsDataDto> dtos, CancellationToken token);
[Get($"{BaseRoute}/part")]
Task<IApiResponse<IEnumerable<WitsDataDto>>> GetPart([Query] int discriminatorId, [Query] DateTimeOffset dateBegin, [Query] int take = 24 * 60 * 60, CancellationToken token = default);
[Get($"{BaseRoute}/{{discriminatorId}}/part")]
Task<IApiResponse<IEnumerable<WitsDataDto>>> GetPart(int discriminatorId, [Query] DateTimeOffset dateBegin, [Query] int take = 24 * 60 * 60, CancellationToken token = default);
[Get($"{BaseRoute}/datesRange")]
Task<IApiResponse<DatesRangeDto>> GetDatesRangeAsync([Query] int discriminatorId, CancellationToken token);
[Get($"{BaseRoute}/{{discriminatorId}}/datesRange")]
Task<IApiResponse<DatesRangeDto>> GetDatesRangeAsync(int discriminatorId, CancellationToken token);
}

View File

@ -140,7 +140,7 @@ namespace Persistence.IntegrationTests.Controllers
dbContext.CleanupDbSet<Setpoint>();
//act
var response = await setpointClient.GetDatesRangeAsync(new CancellationToken());
var response = await setpointClient.GetDatesRangeAsync(CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -159,10 +159,10 @@ namespace Persistence.IntegrationTests.Controllers
var dateBegin = DateTimeOffset.MinValue;
var take = 1;
var part = await setpointClient.GetPart(dateBegin, take, new CancellationToken());
var part = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);
//act
var response = await setpointClient.GetDatesRangeAsync(new CancellationToken());
var response = await setpointClient.GetDatesRangeAsync(CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -188,7 +188,7 @@ namespace Persistence.IntegrationTests.Controllers
var take = 2;
//act
var response = await setpointClient.GetPart(dateBegin, take, new CancellationToken());
var response = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -205,7 +205,7 @@ namespace Persistence.IntegrationTests.Controllers
await Add();
//act
var response = await setpointClient.GetPart(dateBegin, take, new CancellationToken());
var response = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

View File

@ -40,7 +40,7 @@ namespace Persistence.IntegrationTests.Controllers
};
//act
var response = await techMessagesClient.GetPage(requestDto, new CancellationToken());
var response = await techMessagesClient.GetPage(requestDto, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -64,7 +64,7 @@ namespace Persistence.IntegrationTests.Controllers
};
//act
var response = await techMessagesClient.GetPage(requestDto, new CancellationToken());
var response = await techMessagesClient.GetPage(requestDto, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -97,7 +97,7 @@ namespace Persistence.IntegrationTests.Controllers
};
//act
var response = await techMessagesClient.AddRange(dtos, new CancellationToken());
var response = await techMessagesClient.AddRange(dtos, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
@ -112,7 +112,7 @@ namespace Persistence.IntegrationTests.Controllers
dbContext.CleanupDbSet<Database.Entity.DrillingSystem>();
//act
var response = await techMessagesClient.GetSystems(new CancellationToken());
var response = await techMessagesClient.GetSystems(CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -131,7 +131,7 @@ namespace Persistence.IntegrationTests.Controllers
.ToArray();
//act
var response = await techMessagesClient.GetSystems(new CancellationToken());
var response = await techMessagesClient.GetSystems(CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -152,7 +152,7 @@ namespace Persistence.IntegrationTests.Controllers
var autoDrillingSystem = nameof(TechMessageDto.System);
//act
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken());
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -170,7 +170,7 @@ namespace Persistence.IntegrationTests.Controllers
var filteredDtos = dtos.Where(e => e.CategoryId == imortantId && e.System == autoDrillingSystem);
//act
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken());
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -185,7 +185,7 @@ namespace Persistence.IntegrationTests.Controllers
public async Task GetDatesRange_returns_success()
{
//act
var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken());
var response = await techMessagesClient.GetDatesRangeAsync(CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -201,7 +201,7 @@ namespace Persistence.IntegrationTests.Controllers
await InsertRange();
//act
var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken());
var response = await techMessagesClient.GetDatesRangeAsync(CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -218,7 +218,7 @@ namespace Persistence.IntegrationTests.Controllers
var take = 2;
//act
var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken());
var response = await techMessagesClient.GetPart(dateBegin, take, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -235,7 +235,7 @@ namespace Persistence.IntegrationTests.Controllers
await InsertRange();
//act
var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken());
var response = await techMessagesClient.GetPart(dateBegin, take, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -276,7 +276,7 @@ namespace Persistence.IntegrationTests.Controllers
//act
var response = await techMessagesClient.AddRange(dtos, new CancellationToken());
var response = await techMessagesClient.AddRange(dtos, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);

View File

@ -29,7 +29,7 @@ public class WitsDataControllerTest : BaseIntegrationTest
var discriminatorId = 1;
//act
var response = await witsDataClient.GetDatesRangeAsync(discriminatorId, new CancellationToken());
var response = await witsDataClient.GetDatesRangeAsync(discriminatorId, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -47,7 +47,7 @@ public class WitsDataControllerTest : BaseIntegrationTest
var take = 1;
//act
var response = await witsDataClient.GetPart(discriminatorId, dateBegin, take, new CancellationToken());
var response = await witsDataClient.GetPart(discriminatorId, dateBegin, take, CancellationToken.None);

Лучше в тестах писать не new CancellationToken(), а CancellationToken.None (по согласованию с Никитой)

Лучше в тестах писать не new CancellationToken(), а CancellationToken.None (по согласованию с Никитой)
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -77,7 +77,7 @@ public class WitsDataControllerTest : BaseIntegrationTest
var approxPointCount = 12;
//act
var response = await witsDataClient.GetValuesForGraph(discriminatorId, dateFrom, dateTo, approxPointCount, new CancellationToken());
var response = await witsDataClient.GetValuesForGraph(discriminatorId, dateFrom, dateTo, approxPointCount, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -95,7 +95,7 @@ public class WitsDataControllerTest : BaseIntegrationTest
var discriminatorId = dtos.FirstOrDefault()!.DiscriminatorId;
//act
var response = await witsDataClient.GetDatesRangeAsync(discriminatorId, new CancellationToken());
var response = await witsDataClient.GetDatesRangeAsync(discriminatorId, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -111,9 +111,9 @@ public class WitsDataControllerTest : BaseIntegrationTest
var expectedDateTo = dtos
Review

Здесь 2 раза сравнивается минимум с From

Здесь 2 раза сравнивается минимум с From
.Select(e => e.Timestamped)
.Min()
.Max()
.ToString("dd.MM.yyyy-HH:mm:ss");
var actualDateTo = response.Content.From.DateTime
var actualDateTo = response.Content.To.DateTime
.ToString("dd.MM.yyyy-HH:mm:ss");
Assert.Equal(expectedDateTo, actualDateTo);
}
@ -130,13 +130,22 @@ public class WitsDataControllerTest : BaseIntegrationTest
var take = 1;
//act
var response = await witsDataClient.GetPart(discriminatorId, dateBegin, take, new CancellationToken());
var response = await witsDataClient.GetPart(discriminatorId, dateBegin, take, CancellationToken.None);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.NotEmpty(response.Content);
Assert.Equal(take, response.Content.Count());
Review

Здесь желательно проверить не только количество элементов, но и содержание (id, discriminatorId или что-то в этом роде): вдруг вернулся не тот элемент?

Здесь желательно проверить не только количество элементов, но и содержание (id, discriminatorId или что-то в этом роде): вдруг вернулся не тот элемент?
var expectedDto = dtos.FirstOrDefault();
var actualDto = response.Content.FirstOrDefault();
Assert.Equal(expectedDto?.DiscriminatorId, actualDto?.DiscriminatorId);
var expectedValueDto = expectedDto?.Values.FirstOrDefault();
var actualValueDto = actualDto?.Values.FirstOrDefault();
Assert.Equal(expectedValueDto?.ItemId, actualValueDto?.ItemId);
Assert.Equal(expectedValueDto?.RecordId, actualValueDto?.RecordId);
}
[Fact]
@ -152,7 +161,7 @@ public class WitsDataControllerTest : BaseIntegrationTest
var approxPointCount = 12;
//act
var response = await witsDataClient.GetValuesForGraph(discriminatorId, dateFrom, dateTo, approxPointCount, new CancellationToken());
var response = await witsDataClient.GetValuesForGraph(discriminatorId, dateFrom, dateTo, approxPointCount, CancellationToken.None);

AddRange_returns_BadRequest

AddRange_returns_BadRequest
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@ -161,7 +170,7 @@ public class WitsDataControllerTest : BaseIntegrationTest
}
[Fact]
public async Task InsertRange_returns_BadRequest()
public async Task AddRange_returns_BadRequest()
{
//arrange
var dtos = new List<WitsDataDto>()
@ -183,7 +192,7 @@ public class WitsDataControllerTest : BaseIntegrationTest
};
//act
var response = await witsDataClient.AddRange(dtos, new CancellationToken());
var response = await witsDataClient.AddRange(dtos, CancellationToken.None);

i < countToCreate && i < 100
А это так и нужно?

i < countToCreate && i < 100 А это так и нужно?

По сути нет, это на всякий случай - вдруг кому то когда нибудь придёт идея написать в этом контроллере тест и передать в качестве count >100. Хотя, наверное, лучше тогда человеку сразу увидеть ошибку, чем гадать - почему он говорит создать 150 записей, а создаётся 100 ))

По сути нет, это на всякий случай - вдруг кому то когда нибудь придёт идея написать в этом контроллере тест и передать в качестве count >100. Хотя, наверное, лучше тогда человеку сразу увидеть ошибку, чем гадать - почему он говорит создать 150 записей, а создаётся 100 ))
//assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
@ -193,8 +202,9 @@ public class WitsDataControllerTest : BaseIntegrationTest
{
var dtos = new List<WitsDataDto>();
var timestamped = DateTimeOffset.UtcNow;
for (var i = 0; i < countToCreate && i < 100; i++)
for (var i = 0; i < countToCreate; i++)
{
var random = new Random();
dtos.Add(new WitsDataDto()

Лучше new Random() вынести на уровень выше, чтобы в цикле не создавался каждый раз новый экземпляр

Лучше new Random() вынести на уровень выше, чтобы в цикле не создавался каждый раз новый экземпляр
{
DiscriminatorId = 1,
@ -205,14 +215,14 @@ public class WitsDataControllerTest : BaseIntegrationTest
{
RecordId = i + 1,
ItemId = i + 1,
Value = new Random().Next(1, 100)
Value = random.Next(1, 100)
}
}
});
}
//act
var response = await witsDataClient.AddRange(dtos, new CancellationToken());
var response = await witsDataClient.AddRange(dtos, CancellationToken.None);
//assert
var count = dtos.SelectMany(e => e.Values).Count();

View File

@ -58,7 +58,8 @@ public class ParameterRepository : IParameterRepository
var universalDateTo = dateTo.ToUniversalTime();
query = query
.Where(e => e.DiscriminatorId == discriminatorId && e.Timestamp >= universalDateFrom && e.Timestamp <= universalDateTo)
.Where(e => e.DiscriminatorId == discriminatorId)

Тут для удобства чтения лучше разделиnь Where на 2 части:
.Where(e => e.DiscriminatorId == discriminatorId)
.Where(e => e.Timestamp >= universalDateFrom && e.Timestamp <= universalDateTo)

Тут для удобства чтения лучше разделиnь Where на 2 части: .Where(e => e.DiscriminatorId == discriminatorId) .Where(e => e.Timestamp >= universalDateFrom && e.Timestamp <= universalDateTo)
.Where(e => e.Timestamp >= universalDateFrom && e.Timestamp <= universalDateTo)
.OrderBy(e => e.Timestamp);
if (ratio != null)
{
@ -67,7 +68,7 @@ public class ParameterRepository : IParameterRepository
var entities = await query
.Take((int)(2.5 * approxPointsCount))
Review

ToArrayAsync(token)

ToArrayAsync(token)
.ToListAsync(token);
.ToArrayAsync(token);
var dtos = entities.Select(e => e.Adapt<ParameterDto>());

View File

@ -2,6 +2,9 @@
namespace Persistence.Models.Configurations;
/// <summary>

Тут нужны комментарии, без комментариев не очень понятно

Тут нужны комментарии, без комментариев не очень понятно
/// Протокол Wits
/// </summary>
public class WitsInfo
{
public int RecordId { get; set; }

View File

@ -18,7 +18,7 @@ public class WitsDataService : IWitsDataService
private const int multiplier = 1000;
private const string witsConfigPath = "Persistence.Services.Config.WitsConfig.json";
public WitsDataService(IParameterRepository witsDataRepository, IConfiguration configuration)
public WitsDataService(IParameterRepository witsDataRepository)

IConfiguration configuration можно удалить, он нигде не используется

IConfiguration configuration можно удалить, он нигде не используется
{
this.witsDataRepository = witsDataRepository;
@ -96,30 +96,60 @@ public class WitsDataService : IWitsDataService
private IEnumerable<WitsDataDto> AdaptToWitsData(IEnumerable<ParameterDto> dtos)
{
var result = new List<WitsDataDto>();
foreach (var dto in dtos)
var witsGroup = dtos
.GroupBy(e => new { e.DiscriminatorId, e.Timestamp });
foreach (var witsInGroup in witsGroup)

Тут тоже лучше разделить на 2 подзапроса:
result.Where(e => e.DiscriminatorId == dto.DiscriminatorId)
.Where(e => e.Timestamped == dto.Timestamp)
.FirstOrDefault();

Тут тоже лучше разделить на 2 подзапроса: result.Where(e => e.DiscriminatorId == dto.DiscriminatorId) .Where(e => e.Timestamped == dto.Timestamp) .FirstOrDefault();
{
var witsDataDto = result.FirstOrDefault(e => e.DiscriminatorId == dto.DiscriminatorId && e.Timestamped == dto.Timestamp);
if (witsDataDto == null)
var witsDataDto = new WitsDataDto()
{
witsDataDto = new WitsDataDto()
{
DiscriminatorId = dto.DiscriminatorId,
Timestamped = dto.Timestamp
};
result.Add(witsDataDto);
}
var recordId = DecodeRecordId(dto.ParameterId);
var itemId = DecodeItemId(dto.ParameterId);
var witsValueDto = new WitsValueDto()
{
RecordId = recordId,
ItemId = itemId,
Value = ConvertValue(recordId, itemId, dto.Value)
DiscriminatorId = witsInGroup.Key.DiscriminatorId,
Timestamped = witsInGroup.Key.Timestamp
};
witsDataDto.Values.Append(witsValueDto);
witsDataDto.Values = witsInGroup.Select(e =>
{
var recordId = DecodeRecordId(e.ParameterId);
var itemId = DecodeItemId(e.ParameterId);
return new WitsValueDto()
{
RecordId = recordId,
ItemId = itemId,
Value = ConvertValue(recordId, itemId, e.Value)
};
});
  1. Тут внутрь witsDataDto ничего не добавляется потому что Append возвращает новую последовательность, поэтому писать нужно так:
    witsDataDto.Values = witsDataDto.Values.Append(witsValueDto)

  2. Не совсем понятный код: цикл по dto, потом поиск еще не добавленных элементов внутрь result и Append.
    Это лучше бы отрефакторить. Ниже приложила вариант того, как можно читаемость (по моему мнению) улучшить.

  3. И еще параметр take. Желательно иметь значение по умолчанию, а то если пользователь нечаянно null отправит, то запрос ничего не выдаст

image

1. Тут внутрь witsDataDto ничего не добавляется потому что Append возвращает новую последовательность, поэтому писать нужно так: witsDataDto.Values = witsDataDto.Values.Append(witsValueDto) 2. Не совсем понятный код: цикл по dto, потом поиск еще не добавленных элементов внутрь result и Append. Это лучше бы отрефакторить. Ниже приложила вариант того, как можно читаемость (по моему мнению) улучшить. 3. И еще параметр take. Желательно иметь значение по умолчанию, а то если пользователь нечаянно null отправит, то запрос ничего не выдаст ![image](/attachments/0dc037f6-7cac-40a5-a8cf-2ca8c60acd5c)
result.Add(witsDataDto);
}
//foreach (var dto in dtos)
//{
// var witsDataDto = result
// .Where(e => e.DiscriminatorId == dto.DiscriminatorId)
// .Where(e => e.Timestamped == dto.Timestamp)
// .FirstOrDefault();
// if (witsDataDto == null)
// {
// witsDataDto = new WitsDataDto()
// {
// DiscriminatorId = dto.DiscriminatorId,
// Timestamped = dto.Timestamp
// };
// result.Add(witsDataDto);
// }
// var recordId = DecodeRecordId(dto.ParameterId);
// var itemId = DecodeItemId(dto.ParameterId);
// var witsValueDto = new WitsValueDto()
// {
// RecordId = recordId,
// ItemId = itemId,
// Value = ConvertValue(recordId, itemId, dto.Value)
// };
// witsDataDto.Values = witsDataDto.Values.Append(witsValueDto);
//}
return result;
}