Compare commits

..

2 Commits

26 changed files with 191 additions and 128 deletions

View File

@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Persistence.API;
using Persistence.Repositories; using Persistence.Repositories;
using Persistence.Repository.Data; using Persistence.Repository.Data;

View File

@ -24,9 +24,10 @@ public class TimeSeriesController<TDto> : ControllerBase, ITimeSeriesDataApi<TDt
} }
[HttpGet("datesRange")] [HttpGet("datesRange")]
public Task<IActionResult> GetDatesRangeAsync(CancellationToken token) public async Task<IActionResult> GetDatesRangeAsync(CancellationToken token)
{ {
throw new NotImplementedException(); var result = await this.timeSeriesDataRepository.GetDatesRangeAsync(token);
return Ok(result);
} }
[HttpPost] [HttpPost]

View File

@ -1,12 +0,0 @@
namespace Persistence.API;
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}

View File

@ -1,8 +1,6 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Persistence.Database;
using Persistence.Database.Model;
namespace Persistence.Database.Model; namespace Persistence.Database.Model;

View File

@ -12,7 +12,7 @@ using Persistence.Database.Model;
namespace Persistence.Database.Postgres.Migrations namespace Persistence.Database.Postgres.Migrations
{ {
[DbContext(typeof(PersistenceDbContext))] [DbContext(typeof(PersistenceDbContext))]
[Migration("20241115105149_InitialCreate")] [Migration("20241118091712_InitialCreate")]
partial class InitialCreate partial class InitialCreate
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -52,6 +52,10 @@ namespace Persistence.Database.Postgres.Migrations
.HasColumnType("double precision") .HasColumnType("double precision")
.HasColumnName("blockSpeed"); .HasColumnName("blockSpeed");
b.Property<DateTimeOffset>("Date")
.HasColumnType("timestamp with time zone")
.HasColumnName("date");
b.Property<double?>("Flow") b.Property<double?>("Flow")
.HasColumnType("double precision") .HasColumnType("double precision")
.HasColumnName("flow"); .HasColumnName("flow");
@ -100,10 +104,6 @@ namespace Persistence.Database.Postgres.Migrations
.HasColumnType("double precision") .HasColumnType("double precision")
.HasColumnName("rotorTorque"); .HasColumnName("rotorTorque");
b.Property<int>("TimeStamp")
.HasColumnType("integer")
.HasColumnName("timestamp");
b.Property<string>("User") b.Property<string>("User")
.HasColumnType("text") .HasColumnType("text")
.HasColumnName("user"); .HasColumnName("user");

View File

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore.Migrations; using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable #nullable disable
@ -20,7 +21,7 @@ namespace Persistence.Database.Postgres.Migrations
{ {
id = table.Column<int>(type: "integer", nullable: false) id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
timestamp = table.Column<int>(type: "integer", nullable: false), date = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
mode = table.Column<int>(type: "integer", nullable: true), mode = table.Column<int>(type: "integer", nullable: true),
user = table.Column<string>(type: "text", nullable: true), user = table.Column<string>(type: "text", nullable: true),
wellDepth = table.Column<double>(type: "double precision", nullable: true), wellDepth = table.Column<double>(type: "double precision", nullable: true),

View File

@ -49,6 +49,10 @@ namespace Persistence.Database.Postgres.Migrations
.HasColumnType("double precision") .HasColumnType("double precision")
.HasColumnName("blockSpeed"); .HasColumnName("blockSpeed");
b.Property<DateTimeOffset>("Date")
.HasColumnType("timestamp with time zone")
.HasColumnName("date");
b.Property<double?>("Flow") b.Property<double?>("Flow")
.HasColumnType("double precision") .HasColumnType("double precision")
.HasColumnName("flow"); .HasColumnName("flow");
@ -97,10 +101,6 @@ namespace Persistence.Database.Postgres.Migrations
.HasColumnType("double precision") .HasColumnType("double precision")
.HasColumnName("rotorTorque"); .HasColumnName("rotorTorque");
b.Property<int>("TimeStamp")
.HasColumnType("integer")
.HasColumnName("timestamp");
b.Property<string>("User") b.Property<string>("User")
.HasColumnType("text") .HasColumnType("text")
.HasColumnName("user"); .HasColumnName("user");

View File

@ -18,4 +18,8 @@
<ProjectReference Include="..\Persistence.Database\Persistence.Database.csproj" /> <ProjectReference Include="..\Persistence.Database\Persistence.Database.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>
</Project> </Project>

View File

@ -4,7 +4,6 @@ using System.Data.Common;
namespace Persistence.Database.Model; namespace Persistence.Database.Model;
public partial class PersistenceDbContext : DbContext, IPersistenceDbContext public partial class PersistenceDbContext : DbContext, IPersistenceDbContext
{ {
private readonly DbConnection connection = null!;
public DbSet<DataSaub> DataSaub => Set<DataSaub>(); public DbSet<DataSaub> DataSaub => Set<DataSaub>();
public DbSet<Setpoint> Setpoint => Set<Setpoint>(); public DbSet<Setpoint> Setpoint => Set<Setpoint>();
@ -21,16 +20,6 @@ public partial class PersistenceDbContext : DbContext, IPersistenceDbContext
} }
public PersistenceDbContext(DbConnection connection)
{
this.connection = connection;
}
protected virtual DbConnection GetConnection()
{
return connection;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
if (!optionsBuilder.IsConfigured) if (!optionsBuilder.IsConfigured)

View File

@ -6,8 +6,8 @@ public class DataSaub : ITimestampedData
[Column("id")] [Column("id")]
public int Id { get; set; } public int Id { get; set; }
[Column("timestamp")] [Column("date")]
public int TimeStamp { get; set; } public DateTimeOffset Date { get; set; }
[Column("mode")] [Column("mode")]
public int? Mode { get; set; } public int? Mode { get; set; }

View File

@ -7,5 +7,8 @@ using System.Threading.Tasks;
namespace Persistence.Database.Model; namespace Persistence.Database.Model;
public interface ITimestampedData public interface ITimestampedData
{ {
int TimeStamp { get; set; } /// <summary>
/// Дата (должна быть обязательно в UTC)
/// </summary>
DateTimeOffset Date { get; set; }
} }

View File

@ -1,11 +1,5 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Persistence.Repository.Data;
using Refit; using Refit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Persistence.IntegrationTests.Clients; namespace Persistence.IntegrationTests.Clients;
public interface ITimeSeriesClient<TDto> public interface ITimeSeriesClient<TDto>
@ -13,4 +7,7 @@ public interface ITimeSeriesClient<TDto>
{ {
[Post("/api/dataSaub")] [Post("/api/dataSaub")]
Task<IApiResponse<int>> InsertRangeAsync(IEnumerable<TDto> dtos); Task<IApiResponse<int>> InsertRangeAsync(IEnumerable<TDto> dtos);
[Get("/api/dataSaub")]
Task<IApiResponse<IEnumerable<TDto>>> GetAsync(DateTimeOffset dateBegin, DateTimeOffset dateEnd);
} }

View File

@ -1,36 +1,56 @@
using Persistence.Repository.Data; using Persistence.Database.Model;
using System; using Persistence.Repository.Data;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit; using Xunit;
namespace Persistence.IntegrationTests.Controllers; namespace Persistence.IntegrationTests.Controllers;
public class DataSaubControllerTest : TimeSeriesBaseControllerTest<DataSaubDto> public class DataSaubControllerTest : TimeSeriesBaseControllerTest<DataSaub, DataSaubDto>
{ {
private readonly DataSaubDto dto = new DataSaubDto() private readonly DataSaubDto dto = new DataSaubDto()
{ {
AxialLoad = 1, AxialLoad = 1,
BitDepth = 2, BitDepth = 2,
BlockPosition = 3, BlockPosition = 3,
BlockSpeed = 4, BlockSpeed = 4,
Date = DateTimeOffset.Now, Date = DateTimeOffset.Now,
Flow = 5, Flow = 5,
HookWeight = 6, HookWeight = 6,
Id = 7, Id = 7,
IdFeedRegulator = 8, IdFeedRegulator = 8,
Mode = 9, Mode = 9,
Mse = 10, Mse = 10,
MseState = 11, MseState = 11,
Pressure = 12, Pressure = 12,
Pump0Flow = 13, Pump0Flow = 13,
Pump1Flow = 14, Pump1Flow = 14,
Pump2Flow = 15, Pump2Flow = 15,
RotorSpeed = 16, RotorSpeed = 16,
RotorTorque = 17, RotorTorque = 17,
User = string.Empty, User = string.Empty,
WellDepth = 18, WellDepth = 18,
};
private readonly DataSaub entity = new DataSaub()
{
AxialLoad = 1,
BitDepth = 2,
BlockPosition = 3,
BlockSpeed = 4,
Date = DateTimeOffset.UtcNow,
Flow = 5,
HookWeight = 6,
Id = 7,
IdFeedRegulator = 8,
Mode = 9,
Mse = 10,
MseState = 11,
Pressure = 12,
Pump0Flow = 13,
Pump1Flow = 14,
Pump2Flow = 15,
RotorSpeed = 16,
RotorTorque = 17,
User = string.Empty,
WellDepth = 18,
}; };
public DataSaubControllerTest(WebAppFactoryFixture factory) : base(factory) public DataSaubControllerTest(WebAppFactoryFixture factory) : base(factory)
@ -42,4 +62,12 @@ public class DataSaubControllerTest : TimeSeriesBaseControllerTest<DataSaubDto>
{ {
await InsertRangeSuccess(dto); await InsertRangeSuccess(dto);
} }
[Fact]
public async Task Get_returns_success()
{
var beginDate = DateTimeOffset.UtcNow.AddDays(-1);
var endDate = DateTimeOffset.UtcNow;
await GetSuccess(beginDate, endDate, entity);
}
} }

View File

@ -1,6 +1,7 @@
using Mapster; using Mapster;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration.UserSecrets;
using Persistence.IntegrationTests.Clients; using Persistence.IntegrationTests.Clients;
using Persistence.Models; using Persistence.Models;
using System; using System;
@ -12,14 +13,15 @@ using System.Threading.Tasks;
using Xunit; using Xunit;
namespace Persistence.IntegrationTests.Controllers; namespace Persistence.IntegrationTests.Controllers;
public abstract class TimeSeriesBaseControllerTest<TDto> : BaseIntegrationTest public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrationTest
where TEntity : class
where TDto : class, new() where TDto : class, new()
{ {
private ITimeSeriesClient<TDto> client; private ITimeSeriesClient<TDto> client;
public TimeSeriesBaseControllerTest(WebAppFactoryFixture factory) : base(factory) public TimeSeriesBaseControllerTest(WebAppFactoryFixture factory) : base(factory)
{ {
//dbContext.CleanupDbSet<TEntity>(); dbContext.CleanupDbSet<TEntity>();
client = factory.GetHttpClient<ITimeSeriesClient<TDto>>(string.Empty); client = factory.GetHttpClient<ITimeSeriesClient<TDto>>(string.Empty);
} }
@ -34,18 +36,22 @@ public abstract class TimeSeriesBaseControllerTest<TDto> : BaseIntegrationTest
//assert //assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(1, response.Content); Assert.Equal(1, response.Content);
}
//var entity = GetByWellId(); public async Task GetSuccess(DateTimeOffset beginDate, DateTimeOffset endDate, TEntity entity)
{
//arrange
var dbset = dbContext.Set<TEntity>();
//Assert.NotNull(entity); dbset.Add(entity);
//var actual = entity.Adapt<ChangeLogDto<TDto>>(); dbContext.SaveChanges();
//Assert.Equal(ProcessMapPlanBase.IdStateActual, actual.IdState);
//var excludeProps = new[] { var response = await client.GetAsync(beginDate, endDate);
// nameof(ProcessMapPlanBaseDto.Id),
// nameof(ProcessMapPlanBaseDto.Section) //assert
//}; Assert.Equal(HttpStatusCode.OK, response.StatusCode);
//MatchHelper.Match(expected, actual.Item, excludeProps); Assert.NotNull(response.Content);
Assert.Single(response.Content);
} }
} }

View File

@ -0,0 +1,14 @@
using Microsoft.EntityFrameworkCore;
using Persistence.Database.Model;
namespace Persistence.IntegrationTests;
public static class EFCoreExtensions
{
public static void CleanupDbSet<T>(this DbContext dbContext)
where T : class
{
var dbset = dbContext.Set<T>();
dbset.RemoveRange(dbset);
dbContext.SaveChanges();
}
}

View File

@ -4,9 +4,9 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Persistence.Database.Model; using Persistence.Database.Model;
using Persistence.Database.Postgres;
using Persistence.API; using Persistence.API;
using Refit; using Refit;
using System.Net.Http.Headers;
using System.Text.Json; using System.Text.Json;
using Persistence.Database.Postgres; using Persistence.Database.Postgres;

View File

@ -1,14 +1,12 @@
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Persistence.Database.Model;
using Persistence.Models; using Persistence.Models;
using Persistence.Repositories; using Persistence.Repositories;
using Persistence.Database.Model;
using Persistence.Repository.Data;
using Persistence.Database;
namespace Persistence.Repository.Repositories; namespace Persistence.Repository.Repositories;
public class TimeSeriesDataRepository<TEntity, TDto> : ITimeSeriesDataRepository<TDto> public class TimeSeriesDataRepository<TEntity, TDto> : ITimeSeriesDataRepository<TDto>
where TEntity : class where TEntity : class, ITimestampedData, new()
where TDto : class, ITimeSeriesAbstractDto, new() where TDto : class, ITimeSeriesAbstractDto, new()
{ {
private DbContext db; private DbContext db;
@ -29,14 +27,27 @@ public class TimeSeriesDataRepository<TEntity, TDto> : ITimeSeriesDataRepository
return dtos; return dtos;
} }
public Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token) public async Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token)
{ {
throw new NotImplementedException(); var query = GetQueryReadOnly();
var minDate = await query.MinAsync(o => o.Date, token);
var maxDate = await query.MaxAsync(o => o.Date, token);
return new DatesRangeDto
{
From = minDate,
To = maxDate
};
} }
public Task<IEnumerable<TDto>> GetGtDate(DateTimeOffset date, CancellationToken token) public async Task<IEnumerable<TDto>> GetGtDate(DateTimeOffset date, CancellationToken token)
{ {
throw new NotImplementedException(); var query = this.db.Set<TEntity>().Where(e => e.Date > date);
var entities = await query.ToArrayAsync(token);
var dtos = entities.Select(e => e.Adapt<TDto>());
return dtos;
} }
public async Task<int> InsertRange(IEnumerable<TDto> dtos, CancellationToken token) public async Task<int> InsertRange(IEnumerable<TDto> dtos, CancellationToken token)

View File

@ -5,9 +5,19 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Persistence.Models; namespace Persistence.Models;
/// <summary>
/// Диапазон дат
/// </summary>
public class DatesRangeDto public class DatesRangeDto
{ {
public DateTimeOffset dateBegin { get; set; } /// <summary>
/// Дата начала диапазона
/// </summary>
public DateTimeOffset From { get; set; }
public DateTimeOffset dateEnd { get; set; } /// <summary>
/// Дата окончания диапазона
/// </summary>
public DateTimeOffset To { get; set; }
} }

View File

@ -1,10 +1,4 @@
using System; namespace Persistence.Models;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Persistence.Models;
/// <summary> /// <summary>
/// Интерфейс, описывающий временные данные /// Интерфейс, описывающий временные данные

View File

@ -1,10 +1,23 @@
namespace Persistence.Models; namespace Persistence.Models;
/// <summary>
/// Контейнер для поддержки постраничного просмотра таблиц
/// </summary>
/// <typeparam name="T"></typeparam>
public class RequestDto public class RequestDto
{ {
/// <summary>
/// Кол-во записей пропущенных с начала таблицы в запросе от api
/// </summary>
public int Skip { get; set; } public int Skip { get; set; }
/// <summary>
/// Кол-во записей в запросе от api
/// </summary>
public int Take { get; set; } public int Take { get; set; }
/// <summary>
/// Настройки сортировки
/// </summary>
public string SortSettings { get; set; } = string.Empty; public string SortSettings { get; set; } = string.Empty;
} }

View File

@ -1,12 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Persistence.Models; namespace Persistence.Models;
/// <summary>
/// Модель для описания лога уставки
/// </summary>
public class SetpointLogDto : SetpointValueDto public class SetpointLogDto : SetpointValueDto
{ {
/// <summary>
/// Дата сохранения уставки
/// </summary>
public DateTimeOffset Created { get; set; } public DateTimeOffset Created { get; set; }
/// <summary>
/// Ключ пользователя
/// </summary>
public int IdUser { get; set; } public int IdUser { get; set; }
} }

View File

@ -1,14 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Persistence.Models; namespace Persistence.Models;
/// <summary>
/// Модель для хранения значения уставки
/// </summary>
public class SetpointValueDto public class SetpointValueDto
{ {
/// Идентификатор уставки
/// <summary>
/// </summary>
public Guid Key { get; set; } public Guid Key { get; set; }
/// <summary>
/// Значение уставки
/// </summary>
public required object Value { get; set; } public required object Value { get; set; }
} }

View File

@ -1,11 +1,8 @@
using System; namespace Persistence.Models;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Persistence.Models; /// <summary>
/// Модель, описывающая пользователя
/// </summary>
public class UserDto public class UserDto
{ {
/// <inheritdoc/> /// <inheritdoc/>

View File

@ -1,4 +1,4 @@
using Persistence.Models; using Persistence.Models;
namespace Persistence.Repositories; namespace Persistence.Repositories;

View File

@ -1,12 +1,12 @@
namespace Persistence.Services; namespace Persistence.Services;
/// <summary> /// <summary>
/// /// Сервис по работе с БД
/// </summary> /// </summary>
internal interface IArchiveService internal interface IArchiveService
{ {
/// <summary> /// <summary>
/// /// Переименование БД
/// </summary> /// </summary>
/// <param name="connectionString"></param> /// <param name="connectionString"></param>
/// <param name="databaseName"></param> /// <param name="databaseName"></param>
@ -15,7 +15,7 @@ internal interface IArchiveService
Task RenameDatabase(string connectionString, string databaseName, CancellationToken token); Task RenameDatabase(string connectionString, string databaseName, CancellationToken token);
/// <summary> /// <summary>
/// /// Создание БД
/// </summary> /// </summary>
/// <param name="connectionString"></param> /// <param name="connectionString"></param>
/// <param name="databaseName"></param> /// <param name="databaseName"></param>

View File

@ -1,4 +1,5 @@
namespace Persistence.Services; namespace Persistence.Services;
public interface ITimeSeriesDataObserverService public interface ITimeSeriesDataObserverService
{ {
} }