Setpoint API #1
51
Persistence.API/Controllers/SetpointController.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Persistence.Models;
|
||||
using Persistence.Repositories;
|
||||
|
||||
namespace Persistence.API.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class SetpointController : ControllerBase, ISetpointApi
|
||||
{
|
||||
private readonly ISetpointRepository setpointRepository;
|
||||
|
||||
public SetpointController(ISetpointRepository setpointRepository)
|
||||
{
|
||||
this.setpointRepository = setpointRepository;
|
||||
}
|
||||
|
||||
[HttpGet("current")]
|
||||
|
||||
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetCurrent([FromQuery] IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||
{
|
||||
var result = await setpointRepository.GetCurrent(setpointKeys, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("history")]
|
||||
on.nemtina
commented
Здесь метод [HttpGet] Здесь метод [HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetHistory([FromQuery] IEnumerable<Guid> setpointKeys, [FromQuery] DateTimeOffset historyMoment, CancellationToken token)
|
||||
{
|
||||
var result = await setpointRepository.GetHistory(setpointKeys, historyMoment, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("log")]
|
||||
on.nemtina
commented
Здесь метод [HttpGet] Здесь метод [HttpGet]
|
||||
public async Task<ActionResult<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([FromQuery] IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||
{
|
||||
var result = await setpointRepository.GetLog(setpointKeys, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
on.nemtina
commented
Здесь можно просто [HttpPost] Здесь можно просто [HttpPost]
|
||||
public async Task<ActionResult<int>> Save(Guid setpointKey, object newValue, CancellationToken token)
|
||||
{
|
||||
// ToDo: вычитка idUser
|
||||
on.nemtina
commented
Добавить todo, что необходимо решить вопрос с получением пользователя и авторизацией Добавить todo, что необходимо решить вопрос с получением пользователя и авторизацией
|
||||
await setpointRepository.Save(setpointKey, newValue, 0, token);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
146
Persistence.Database.Postgres/Migrations/20241118052225_SetpointMigration.Designer.cs
generated
Normal file
@ -0,0 +1,146 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using Persistence.Database.Model;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Persistence.Database.Postgres.Migrations
|
||||
{
|
||||
[DbContext(typeof(PersistenceDbContext))]
|
||||
[Migration("20241118052225_SetpointMigration")]
|
||||
partial class SetpointMigration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseCollation("Russian_Russia.1251")
|
||||
.HasAnnotation("ProductVersion", "8.0.10")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<double?>("AxialLoad")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("axialLoad");
|
||||
|
||||
b.Property<double?>("BitDepth")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("bitDepth");
|
||||
|
||||
b.Property<double?>("BlockPosition")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("blockPosition");
|
||||
|
||||
b.Property<double?>("BlockSpeed")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("blockSpeed");
|
||||
|
||||
b.Property<double?>("Flow")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("flow");
|
||||
|
||||
b.Property<double?>("HookWeight")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("hookWeight");
|
||||
|
||||
b.Property<int>("IdFeedRegulator")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("idFeedRegulator");
|
||||
|
||||
b.Property<int?>("Mode")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("mode");
|
||||
|
||||
b.Property<double?>("Mse")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("mse");
|
||||
|
||||
b.Property<short>("MseState")
|
||||
.HasColumnType("smallint")
|
||||
.HasColumnName("mseState");
|
||||
|
||||
b.Property<double?>("Pressure")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("pressure");
|
||||
|
||||
b.Property<double?>("Pump0Flow")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("pump0Flow");
|
||||
|
||||
b.Property<double?>("Pump1Flow")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("pump1Flow");
|
||||
|
||||
b.Property<double?>("Pump2Flow")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("pump2Flow");
|
||||
|
||||
b.Property<double?>("RotorSpeed")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("rotorSpeed");
|
||||
|
||||
b.Property<double?>("RotorTorque")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("rotorTorque");
|
||||
|
||||
b.Property<int>("TimeStamp")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("timestamp");
|
||||
|
||||
b.Property<string>("User")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("user");
|
||||
|
||||
b.Property<double?>("WellDepth")
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("wellDepth");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("DataSaub");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Persistence.Database.Model.Setpoint", b =>
|
||||
{
|
||||
b.Property<Guid>("Key")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ");
|
||||
|
||||
b.Property<DateTimeOffset>("Created")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата изменения уставки");
|
||||
|
||||
b.Property<int>("IdUser")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Id автора последнего изменения");
|
||||
|
||||
b.Property<object>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasComment("Значение уставки");
|
||||
|
||||
b.HasKey("Key", "Created");
|
||||
|
||||
b.ToTable("Setpoint");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Persistence.Database.Postgres.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class SetpointMigration : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Setpoint",
|
||||
columns: table => new
|
||||
{
|
||||
Key = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ"),
|
||||
Created = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата изменения уставки"),
|
||||
Value = table.Column<object>(type: "jsonb", nullable: false, comment: "Значение уставки"),
|
||||
IdUser = table.Column<int>(type: "integer", nullable: false, comment: "Id автора последнего изменения")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Setpoint", x => new { x.Key, x.Created });
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Setpoint");
|
||||
}
|
||||
}
|
||||
}
|
@ -106,6 +106,30 @@ namespace Persistence.Database.Postgres.Migrations
|
||||
|
||||
b.ToTable("DataSaub");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Persistence.Database.Model.Setpoint", b =>
|
||||
{
|
||||
b.Property<Guid>("Key")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ");
|
||||
|
||||
b.Property<DateTimeOffset>("Created")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата изменения уставки");
|
||||
|
||||
b.Property<int>("IdUser")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Id автора последнего изменения");
|
||||
|
||||
b.Property<object>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasComment("Значение уставки");
|
||||
|
||||
b.HasKey("Key", "Created");
|
||||
|
||||
b.ToTable("Setpoint");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Data.Common;
|
||||
|
||||
namespace Persistence.Database.Model;
|
||||
@ -6,6 +6,8 @@ public partial class PersistenceDbContext : DbContext, IPersistenceDbContext
|
||||
{
|
||||
public DbSet<DataSaub> DataSaub => Set<DataSaub>();
|
||||
|
||||
public DbSet<Setpoint> Setpoint => Set<Setpoint>();
|
||||
|
||||
public PersistenceDbContext()
|
||||
: base()
|
||||
{
|
||||
|
21
Persistence.Database/Entity/Setpoint.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Persistence.Database.Model
|
||||
{
|
||||
[PrimaryKey(nameof(Key), nameof(Created))]
|
||||
public class Setpoint
|
||||
{
|
||||
[Comment("Ключ")]
|
||||
public Guid Key { get; set; }
|
||||
|
||||
[Column(TypeName = "jsonb"), Comment("Значение уставки")]
|
||||
public required object Value { get; set; }
|
||||
|
||||
[Comment("Дата создания уставки")]
|
||||
public DateTimeOffset Created { get; set; }
|
||||
on.nemtina
commented
Должно быть "Дата создания уставки" Должно быть "Дата создания уставки"
|
||||
|
||||
[Comment("Id автора последнего изменения")]
|
||||
public int IdUser { get; set; }
|
||||
}
|
||||
}
|
17
Persistence.Database/Model/IPersistenceDbContext.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Persistence.Database.Model;
|
||||
public interface IPersistenceDbContext : IDisposable
|
||||
{
|
||||
DbSet<DataSaub> DataSaub { get; }
|
||||
DbSet<Setpoint> Setpoint { get; }
|
||||
DatabaseFacade Database { get; }
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
|
||||
}
|
25
Persistence.IntegrationTests/Clients/ISetpointClient.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using Persistence.Models;
|
||||
using Refit;
|
||||
|
||||
namespace Persistence.IntegrationTests.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Интерфейс для тестирования API, предназначенного для работы с уставками
|
||||
/// </summary>
|
||||
on.nemtina
commented
Заголовки методов запроса должны соответствовать тем, что в контроллере (там часть нужно поменять с post на get) Заголовки методов запроса должны соответствовать тем, что в контроллере (там часть нужно поменять с post на get)
|
||||
public interface ISetpointClient
|
||||
{
|
||||
private const string BaseRoute = "/api/setpoint";
|
||||
|
||||
[Get($"{BaseRoute}/current")]
|
||||
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetCurrent([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys);
|
||||
|
||||
[Get($"{BaseRoute}/history")]
|
||||
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetHistory([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, [Query] DateTimeOffset historyMoment);
|
||||
|
||||
[Get($"{BaseRoute}/log")]
|
||||
Task<IApiResponse<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys);
|
||||
|
||||
[Post($"{BaseRoute}/")]
|
||||
Task<IApiResponse> Save(Guid setpointKey, object newValue);
|
||||
}
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
using System.Net;
|
||||
using Persistence.IntegrationTests.Clients;
|
||||
using Xunit;
|
||||
|
||||
namespace Persistence.IntegrationTests.Controllers
|
||||
{
|
||||
public class SetpointControllerTest : BaseIntegrationTest
|
||||
{
|
||||
private ISetpointClient client;
|
||||
private class TestObject
|
||||
{
|
||||
public string? value1 { get; set; }
|
||||
public int? value2 { get; set; }
|
||||
}
|
||||
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||
{
|
||||
client = factory.GetHttpClient<ISetpointClient>(string.Empty);
|
||||
}
|
||||
|
||||
on.nemtina
commented
Эту строчку лучше убрать, а в интерфейсе ISetpointClient прописать так:
Эту строчку лучше убрать, а в интерфейсе ISetpointClient прописать так:
```
private const string BaseRoute = "/api/setpoint";
[Post($"{BaseRoute}/current")]
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetCurrent(IEnumerable<Guid> setpointKeys);```
|
||||
[Fact]
|
||||
public async Task GetCurrent_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var setpointKeys = new List<Guid>()
|
||||
{
|
||||
Guid.NewGuid(),
|
||||
Guid.NewGuid()
|
||||
};
|
||||
|
||||
//act
|
||||
var response = await client.GetCurrent(setpointKeys);
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCurrent_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var setpointKey = await Save();
|
||||
|
||||
//act
|
||||
var response = await client.GetCurrent([setpointKey]);
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotEmpty(response.Content);
|
||||
Assert.Equal(setpointKey, response.Content.FirstOrDefault()?.Key);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetHistory_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var setpointKeys = new List<Guid>()
|
||||
{
|
||||
Guid.NewGuid(),
|
||||
Guid.NewGuid()
|
||||
};
|
||||
var historyMoment = DateTimeOffset.UtcNow;
|
||||
|
||||
//act
|
||||
var response = await client.GetHistory(setpointKeys, historyMoment);
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetHistory_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var setpointKey = await Save();
|
||||
var historyMoment = DateTimeOffset.UtcNow;
|
||||
historyMoment = historyMoment.AddDays(1);
|
||||
|
||||
//act
|
||||
var response = await client.GetHistory([setpointKey], historyMoment);
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotEmpty(response.Content);
|
||||
Assert.Equal(setpointKey, response.Content.FirstOrDefault()?.Key);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetLog_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var setpointKeys = new List<Guid>()
|
||||
{
|
||||
Guid.NewGuid(),
|
||||
Guid.NewGuid()
|
||||
};
|
||||
|
||||
on.nemtina
commented
General_test_success не нужен, вместо него нужно для каждого кейса написать свой тест. General_test_success не нужен, вместо него нужно для каждого кейса написать свой тест.
Данные тесты должны быть аналогичны GetCurrent_returns_success, GetHistory_returns_success, GetLog_returns_success, только внутри блока //arrange вызвать метод Save.
Метод Save сделать отдельным приватным методом.
|
||||
//act
|
||||
var response = await client.GetLog(setpointKeys);
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.Empty(response.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetLog_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var setpointKey = await Save();
|
||||
|
||||
//act
|
||||
var response = await client.GetLog([setpointKey]);
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotEmpty(response.Content);
|
||||
Assert.Equal(setpointKey, response.Content.FirstOrDefault()?.Key);
|
||||
on.nemtina
commented
Assert.Equal(expected, actual) Assert.Equal(expected, actual)
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Save_returns_success()
|
||||
{
|
||||
await Save();
|
||||
}
|
||||
|
||||
private async Task<Guid> Save()
|
||||
{
|
||||
//arrange
|
||||
var setpointKey = Guid.NewGuid();
|
||||
var setpointValue = new TestObject()
|
||||
{
|
||||
value1 = "1",
|
||||
value2 = 2
|
||||
};
|
||||
|
||||
//act
|
||||
var response = await client.Save(setpointKey, setpointValue);
|
||||
|
||||
//assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
return setpointKey;
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ using Refit;
|
||||
using RestSharp;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
using Persistence.Database.Postgres;
|
||||
|
||||
namespace Persistence.IntegrationTests;
|
||||
public class WebAppFactoryFixture : WebApplicationFactory<Startup>
|
||||
|
28
Persistence.Repository/Data/SetpointDto.cs
Normal file
@ -0,0 +1,28 @@
|
||||
namespace Persistence.Repository.Data
|
||||
{
|
||||
/// <summary>
|
||||
on.nemtina
commented
Решили, что для всех protected и public классов (а также для интерфейсов) нужно писать комментарии Решили, что для всех protected и public классов (а также для интерфейсов) нужно писать комментарии
|
||||
/// Модель для работы с уставкой
|
||||
/// </summary>
|
||||
public class SetpointDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Идентификатор уставки
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Значение уставки
|
||||
/// </summary>
|
||||
public required object Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Дата сохранения уставки
|
||||
/// </summary>
|
||||
public DateTimeOffset Edit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ключ пользователя
|
||||
/// </summary>
|
||||
public int IdUser { get; set; }
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Persistence.Database.Model;
|
||||
using Persistence.Repositories;
|
||||
using Persistence.Repository.Data;
|
||||
@ -15,7 +15,8 @@ public static class DependencyInjection
|
||||
{
|
||||
MapsterSetup();
|
||||
|
||||
services.AddTransient<ITimeSeriesDataRepository<DataSaubDto>, TimeSeriesDataCachedRepository<DataSaub, DataSaubDto>>();
|
||||
services.AddTransient<ITimeSeriesDataRepository<DataSaubDto>, TimeSeriesDataRepository<DataSaub, DataSaubDto>>();
|
||||
services.AddTransient<ISetpointRepository, SetpointRepository>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
73
Persistence.Repository/Repositories/SetpointRepository.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Persistence.Database.Model;
|
||||
using Persistence.Models;
|
||||
using Persistence.Repositories;
|
||||
|
||||
namespace Persistence.Repository.Repositories
|
||||
{
|
||||
public class SetpointRepository : ISetpointRepository
|
||||
{
|
||||
private DbContext db;
|
||||
public SetpointRepository(DbContext db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
protected virtual IQueryable<Setpoint> GetQueryReadOnly() => db.Set<Setpoint>();
|
||||
|
||||
public async Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly();
|
||||
var entities = await query
|
||||
.Where(e => setpointKeys.Contains(e.Key))
|
||||
.ToArrayAsync(token);
|
||||
var dtos = entities.Select(e => e.Adapt<SetpointValueDto>());
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly();
|
||||
var entities = await query
|
||||
.Where(e => setpointKeys.Contains(e.Key))
|
||||
on.nemtina
commented
Здесь не строгое равенство дат. Здесь не строгое равенство дат.
Нужно отсортировать уставки по возрастанию дат.
Взять те, у которых Created меньше historyMoment
Из отсортированного и отфильтрованного списка взять последнюю
|
||||
.ToArrayAsync(token);
|
||||
var filteredEntities = entities
|
||||
.GroupBy(e => e.Key)
|
||||
.Select(e => e.OrderBy(o => o.Created))
|
||||
on.nemtina
commented
Здесь нужно еще просортировать, чтобы гарантированно взять нужную близлежайшую к historyMoment уставку Здесь нужно еще просортировать, чтобы гарантированно взять нужную близлежайшую к historyMoment уставку
|
||||
.Select(e => e.Where(e => e.Created <= historyMoment).Last());
|
||||
var dtos = filteredEntities
|
||||
.Select(e => e.Adapt<SetpointValueDto>());
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||
{
|
||||
on.nemtina
commented
Лучше так: Лучше так:
var dtos = entities
.GroupBy(e => e.Key)
.ToDictionary(e => e.Key, v => v.Select(z => z.Adapt<SetpointLogDto>()))
|
||||
var query = GetQueryReadOnly();
|
||||
var entities = await query
|
||||
.Where(e => setpointKeys.Contains(e.Key))
|
||||
.ToArrayAsync(token);
|
||||
var dtos = entities
|
||||
.GroupBy(e => e.Key)
|
||||
.ToDictionary(e => e.Key, v => v.Select(z => z.Adapt<SetpointLogDto>()));
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task Save(Guid setpointKey, object newValue, int idUser, CancellationToken token)
|
||||
{
|
||||
var entity = new Setpoint()
|
||||
{
|
||||
Key = setpointKey,
|
||||
Value = newValue,
|
||||
IdUser = idUser,
|
||||
Created = DateTimeOffset.UtcNow
|
||||
on.nemtina
commented
Можно так: Created = DateTimeOffset.UtcNow Можно так: Created = DateTimeOffset.UtcNow
|
||||
};
|
||||
|
||||
await db.Set<Setpoint>().AddAsync(entity, token);
|
||||
await db.SaveChangesAsync(token);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
namespace Persistence.Models;
|
||||
namespace Persistence.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Модель для описания лога уставки
|
||||
@ -8,8 +8,8 @@ public class SetpointLogDto : SetpointValueDto
|
||||
/// <summary>
|
||||
/// Дата сохранения уставки
|
||||
/// </summary>
|
||||
public DateTimeOffset DateEdit { get; set; }
|
||||
|
||||
public DateTimeOffset Created { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ключ пользователя
|
||||
/// </summary>
|
||||
|
@ -1,18 +1,18 @@
|
||||
namespace Persistence.Models;
|
||||
namespace Persistence.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Модель для хранения значения уставки
|
||||
/// </summary>
|
||||
public class SetpointValueDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Идентификатор уставки
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
public Guid Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Значение уставки
|
||||
/// </summary>
|
||||
public object Value { get; set; }
|
||||
public required object Value { get; set; }
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Persistence.Models;
|
||||
using Persistence.Models;
|
||||
|
||||
namespace Persistence.Repositories;
|
||||
|
||||
@ -7,23 +7,30 @@ namespace Persistence.Repositories;
|
||||
/// </summary>
|
||||
public interface ISetpointRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Получить значения уставок по набору ключей
|
||||
/// </summary>
|
||||
/// <param name="setpointKeys"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить значения уставок за определенный момент времени
|
||||
/// </summary>
|
||||
/// <param name="setpoitKeys"></param>
|
||||
/// <param name="historyMoment">дата, на которую получаем данные</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpoitKeys, DateTimeOffset historyMoment, CancellationToken token);
|
||||
/// <summary>
|
||||
/// Получить значения уставок за определенный момент времени
|
||||
/// </summary>
|
||||
/// <param name="setpointKeys"></param>
|
||||
/// <param name="historyMoment">дата, на которую получаем данные</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить историю изменений значений уставок
|
||||
/// </summary>
|
||||
/// <param name="setpoitKeys"></param>
|
||||
/// <param name="setpointKeys"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpoitKeys, CancellationToken token);
|
||||
Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Метод сохранения уставки
|
||||
@ -35,5 +42,5 @@ public interface ISetpointRepository
|
||||
/// <returns></returns>
|
||||
/// to do
|
||||
/// id User учесть в соответствующем методе репозитория
|
||||
Task<int> Save(Guid setpointKey, int idUser, object newValue, CancellationToken token);
|
||||
Task Save(Guid setpointKey, object newValue, int idUser, CancellationToken token);
|
||||
}
|
||||
|
Здесь метод [HttpGet]