Compare commits
1 Commits
master
...
feature/#4
Author | SHA1 | Date | |
---|---|---|---|
c844131bbe |
@ -1,25 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Host=db:5432;Database=persistence;Username=postgres;Password=postgres;Persist Security Info=True"
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"NeedUseKeyCloak": false,
|
||||
"KeyCloakAuthentication": {
|
||||
"Audience": "account",
|
||||
"Host": "http://192.168.0.10:8321/realms/Persistence"
|
||||
},
|
||||
"AuthUser": {
|
||||
"username": "myuser",
|
||||
"password": 12345,
|
||||
"clientId": "webapi",
|
||||
"grantType": "password",
|
||||
"http://schemas.xmlsoap.org/ws/2005/05/identity /claims/nameidentifier": "7d9f3574-6574-4ca3-845a-0276eb4aa8f6"
|
||||
},
|
||||
"ClientUrl": "http://localhost:5000/"
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
networks:
|
||||
persistence:
|
||||
external: false
|
||||
|
||||
services:
|
||||
db:
|
||||
image: timescale/timescaledb:latest-pg16
|
||||
container_name: some-timescaledb-16
|
||||
restart: always
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
networks:
|
||||
- persistence
|
||||
ports:
|
||||
- "5462:5432"
|
||||
volumes:
|
||||
- ./db:/var/lib/postgresql/data
|
||||
|
||||
persistence:
|
||||
image: git.ddrilling.ru/ddrilling/persistence:latest
|
||||
container_name: persistence
|
||||
restart: always
|
||||
depends_on:
|
||||
- db
|
||||
networks:
|
||||
- persistence
|
||||
ports:
|
||||
- "1111:8080"
|
||||
volumes:
|
||||
- ./appsettings.json:/app/appsettings.json
|
||||
|
38
.gitea/workflows/integrationTests.yaml
Normal file
38
.gitea/workflows/integrationTests.yaml
Normal file
@ -0,0 +1,38 @@
|
||||
name: Unit tests
|
||||
run-name: ${{ gitea.actor }} is testing
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
container: node
|
||||
|
||||
# Service containers to run with `runner-job`
|
||||
services:
|
||||
# Label used to access the service container
|
||||
postgres:
|
||||
# Docker Hub image
|
||||
image: postgres
|
||||
# Provide the password for postgres
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
# Set health checks to wait until postgres has started
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
ports:
|
||||
# Maps tcp port 5432 on service container to the host
|
||||
- 5442:5432
|
||||
|
||||
steps:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v4
|
||||
- name: Run integration tests
|
||||
run: dotnet test DD.Persistence.IntegrationTests
|
@ -1,80 +0,0 @@
|
||||
name: Unit tests
|
||||
run-name: ${{ gitea.actor }} is testing
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
tests-and-publication:
|
||||
runs-on: ubuntu-latest
|
||||
# container: node
|
||||
|
||||
# Service containers to run with `runner-job`
|
||||
services:
|
||||
# Label used to access the service container
|
||||
postgres:
|
||||
# Docker Hub image
|
||||
image: postgres
|
||||
# Provide the password for postgres
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
# Set health checks to wait until postgres has started
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
ports:
|
||||
# Maps tcp port 5432 on service container to the host
|
||||
- 5442:5432
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
if: ${{ steps.cache-dotnet.outputs.cache-hit != 'true' }}
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
- name: Add gitea as nuget source
|
||||
run: dotnet nuget add source --name gitea --username publisher --password ${{ secrets.PUBLISHER_PASSWORD }} --store-password-in-clear-text https://git.ddrilling.ru/api/packages/DDrilling/nuget/index.json
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build solution
|
||||
run: dotnet build --no-restore
|
||||
|
||||
- name: Run integration tests
|
||||
run: dotnet test DD.Persistence.IntegrationTests
|
||||
|
||||
- name: Run unit tests
|
||||
run: dotnet test DD.Persistence.Test --no-build
|
||||
|
||||
- name: Pack Persistence Client
|
||||
run: dotnet pack DD.Persistence.Client/DD.Persistence.Client.csproj -c Debug -o ./artifacts
|
||||
|
||||
- name: Pack Persistence Models
|
||||
run: dotnet pack DD.Persistence.Models/DD.Persistence.Models.csproj -c Debug -o ./artifacts
|
||||
|
||||
- name: Publish Persistence Client Package
|
||||
run: dotnet nuget push ./artifacts/DD.Persistence.Client.*.nupkg --source gitea --skip-duplicate
|
||||
|
||||
- name: Publish Persistence Models Package
|
||||
run: dotnet nuget push ./artifacts/DD.Persistence.Models.*.nupkg --source gitea --skip-duplicate
|
||||
|
||||
- name: Login to Gitea Docker Registry
|
||||
run: docker login -u publisher -p ${{ secrets.PUBLISHER_PASSWORD }} https://git.ddrilling.ru
|
||||
|
||||
- name: Docker Build
|
||||
run: docker build -t git.ddrilling.ru/ddrilling/persistence:latest --network=host --build-arg PUBLISHERPASSWORD="${{ secrets.PUBLISHER_PASSWORD }}" -f DD.Persistence.App/Dockerfile .
|
||||
|
||||
- name: Push Docker image to Gitea
|
||||
run: docker push git.ddrilling.ru/ddrilling/persistence:latest
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models.Requests;
|
||||
@ -24,7 +24,7 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
|
||||
public async Task<IActionResult> Add(
|
||||
[FromRoute] Guid idDiscriminator,
|
||||
[FromBody] ChangeLogValuesDto dto,
|
||||
[FromBody] DataWithWellDepthAndSectionDto dto,
|
||||
CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
@ -37,7 +37,7 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
|
||||
public async Task<IActionResult> AddRange(
|
||||
[FromRoute] Guid idDiscriminator,
|
||||
[FromBody] IEnumerable<ChangeLogValuesDto> dtos,
|
||||
[FromBody] IEnumerable<DataWithWellDepthAndSectionDto> dtos,
|
||||
CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
@ -70,7 +70,7 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> ClearAndAddRange(
|
||||
[FromRoute] Guid idDiscriminator,
|
||||
[FromBody] IEnumerable<ChangeLogValuesDto> dtos,
|
||||
[FromBody] IEnumerable<DataWithWellDepthAndSectionDto> dtos,
|
||||
CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
@ -81,7 +81,7 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
[HttpPut]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> Update(
|
||||
ChangeLogValuesDto dto,
|
||||
DataWithWellDepthAndSectionDto dto,
|
||||
CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
@ -93,7 +93,7 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
[HttpPut("range")]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> UpdateRange(
|
||||
IEnumerable<ChangeLogValuesDto> dtos,
|
||||
IEnumerable<DataWithWellDepthAndSectionDto> dtos,
|
||||
CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
@ -103,27 +103,29 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
}
|
||||
|
||||
[HttpGet("{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(PaginationContainer<ChangeLogValuesDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(PaginationContainer<DataWithWellDepthAndSectionDto>), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetCurrent(
|
||||
[FromRoute] Guid idDiscriminator,
|
||||
[FromQuery] SectionPartRequest filterRequest,
|
||||
[FromQuery] PaginationRequest paginationRequest,
|
||||
CancellationToken token)
|
||||
{
|
||||
var moment = new DateTimeOffset(3000, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
var result = await repository.GetByDate(idDiscriminator, moment, paginationRequest, token);
|
||||
var result = await repository.GetByDate(idDiscriminator, moment, filterRequest, paginationRequest, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("moment/{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(PaginationContainer<ChangeLogValuesDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(PaginationContainer<DataWithWellDepthAndSectionDto>), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetByDate(
|
||||
[FromRoute] Guid idDiscriminator,
|
||||
DateTimeOffset moment,
|
||||
[FromQuery] SectionPartRequest filterRequest,
|
||||
[FromQuery] PaginationRequest paginationRequest,
|
||||
CancellationToken token)
|
||||
{
|
||||
var result = await repository.GetByDate(idDiscriminator, moment, paginationRequest, token);
|
||||
var result = await repository.GetByDate(idDiscriminator, moment, filterRequest, paginationRequest, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
@ -153,9 +155,9 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
}
|
||||
|
||||
[HttpGet("part/{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(IEnumerable<ChangeLogValuesDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(IEnumerable<DataWithWellDepthAndSectionDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||
public async Task<ActionResult<IEnumerable<ChangeLogValuesDto>>> GetPart([FromRoute] Guid idDiscriminator, DateTimeOffset dateBegin, int take = 86400, CancellationToken token = default)
|
||||
public async Task<ActionResult<IEnumerable<DataWithWellDepthAndSectionDto>>> GetPart([FromRoute] Guid idDiscriminator, DateTimeOffset dateBegin, int take = 86400, CancellationToken token = default)
|
||||
{
|
||||
var result = await repository.GetGtDate(idDiscriminator, dateBegin, token);
|
||||
|
||||
@ -174,87 +176,4 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Метод, который возвращает статистику по количеству изменений в разрезе дней
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("statistics")]
|
||||
public async Task<ActionResult<IEnumerable<StatisticsChangeLogDto>>> GetStatisticsCountAsync([FromQuery] ChangeLogRequest request, CancellationToken token)
|
||||
{
|
||||
var result = new List<StatisticsChangeLogDto>() {
|
||||
new() { DateTime = DateTimeOffset.UtcNow.AddDays(-60), ChangesCount = 10},
|
||||
new() { DateTime = DateTimeOffset.UtcNow.AddDays(-50), ChangesCount = 2},
|
||||
new() { DateTime = DateTimeOffset.UtcNow.AddDays(-25), ChangesCount = 560},
|
||||
new() { DateTime = DateTimeOffset.UtcNow.AddDays(-2), ChangesCount = 78},
|
||||
new() { DateTime = DateTimeOffset.UtcNow.AddDays(-1), ChangesCount = 39},
|
||||
};
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Метод, который возвращает историю изменений в разрезе дней
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("history")]
|
||||
public async Task<ActionResult<IEnumerable<HistoryChangeLogDto>>> HistoryChangeLogAsync([FromQuery] ChangeLogRequest request, CancellationToken token)
|
||||
{
|
||||
var userId = Guid.CreateVersion7();
|
||||
var changeLogItemCurrentId = Guid.CreateVersion7();
|
||||
var changeLogItemCreation = DateTimeOffset.UtcNow;
|
||||
var changeLogItems = new List<ChangeLogDto>()
|
||||
{
|
||||
new ChangeLogDto()
|
||||
{
|
||||
Id = changeLogItemCurrentId,
|
||||
Creation = changeLogItemCreation,
|
||||
IdAuthor = userId,
|
||||
IdEditor = userId,
|
||||
Obsolete = null,
|
||||
Value = new ChangeLogValuesDto(){
|
||||
Id = Guid.CreateVersion7(),
|
||||
Value = new Dictionary<string, object>() {
|
||||
["1"] = new { id = 1, caption = "Изменение 1 (c правкой)" },
|
||||
["2"] = new { id = 2, caption = "Изменение 2 (с правкой)" },
|
||||
}
|
||||
}
|
||||
},
|
||||
new ChangeLogDto()
|
||||
{
|
||||
Id = Guid.CreateVersion7(),
|
||||
Creation = DateTimeOffset.UtcNow.AddDays(-10),
|
||||
IdAuthor = userId,
|
||||
IdEditor = userId,
|
||||
IdNext = changeLogItemCurrentId,
|
||||
Obsolete = DateTimeOffset.UtcNow.AddDays(-5),
|
||||
Value = new ChangeLogValuesDto(){
|
||||
Id = Guid.CreateVersion7(),
|
||||
Value = new Dictionary<string, object>() {
|
||||
["1"] = new { id = 1, caption = "Изменение 1" },
|
||||
["2"] = new { id = 2, caption = "Изменение 2" },
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
var result = new List<HistoryChangeLogDto>() {
|
||||
new() {
|
||||
Comment = "Петров И. Ю. попросил внести изменения",
|
||||
DateTime = changeLogItemCreation,
|
||||
DiscriminatorId = Guid.CreateVersion7(),
|
||||
User = new UserDto()
|
||||
{
|
||||
Id = userId,
|
||||
DisplayName = "Иванов И. И"
|
||||
},
|
||||
ChangeLogItems = changeLogItems
|
||||
},
|
||||
};
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
using DD.Persistence.Filter.Models.Abstractions;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models.Common;
|
||||
using DD.Persistence.Repositories;
|
||||
using DD.Persistence.Services.Interfaces;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -14,15 +12,14 @@ namespace DD.Persistence.API.Controllers;
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
[Route("api/[controller]")]
|
||||
[Route("api/[controller]/{discriminatorId}")]
|
||||
public class TimestampedValuesController : ControllerBase
|
||||
{
|
||||
private readonly ITimestampedValuesService timestampedValuesService;
|
||||
private readonly ITimestampedValuesRepository timestampedValuesRepository;
|
||||
public TimestampedValuesController(ITimestampedValuesService repository, ITimestampedValuesRepository timestampedValuesRepository)
|
||||
private readonly ITimestampedValuesService timestampedValuesRepository;
|
||||
|
||||
public TimestampedValuesController(ITimestampedValuesService repository)
|
||||
{
|
||||
this.timestampedValuesService = repository;
|
||||
this.timestampedValuesRepository = timestampedValuesRepository;
|
||||
this.timestampedValuesRepository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -32,11 +29,11 @@ public class TimestampedValuesController : ControllerBase
|
||||
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
[HttpPost("{discriminatorId}")]
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
|
||||
public async Task<IActionResult> AddRange([FromRoute] Guid discriminatorId, [FromBody] IEnumerable<TimestampedValuesDto> dtos, CancellationToken token)
|
||||
{
|
||||
var result = await timestampedValuesService.AddRange(discriminatorId, dtos, token);
|
||||
var result = await timestampedValuesRepository.AddRange(discriminatorId, dtos, token);
|
||||
|
||||
return CreatedAtAction(nameof(AddRange), result);
|
||||
}
|
||||
@ -44,9 +41,8 @@ public class TimestampedValuesController : ControllerBase
|
||||
/// <summary>
|
||||
/// Получение данных с фильтрацией. Значение фильтра null - отключен
|
||||
/// </summary>
|
||||
/// <param name="discriminatorIds">Набор дискриминаторов</param>
|
||||
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||
/// <param name="timestampBegin">Фильтр позднее даты</param>
|
||||
/// <param name="filterTree">Кастомный фильтр по набору значений</param>
|
||||
/// <param name="columnNames">Фильтр свойств набора</param>
|
||||
/// <param name="skip"></param>
|
||||
/// <param name="take"></param>
|
||||
@ -54,14 +50,9 @@ public class TimestampedValuesController : ControllerBase
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(IEnumerable<TimestampedValuesDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> Get([FromQuery] IEnumerable<Guid> discriminatorIds,
|
||||
DateTimeOffset? timestampBegin,
|
||||
[FromQuery] TNode? filterTree,
|
||||
[FromQuery] string[]? columnNames,
|
||||
int skip, int take,
|
||||
CancellationToken token)
|
||||
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> Get([FromRoute] Guid discriminatorId, DateTimeOffset? timestampBegin, [FromQuery] string[]? columnNames, int skip, int take, CancellationToken token)
|
||||
{
|
||||
var result = await timestampedValuesService.Get(discriminatorIds, timestampBegin, filterTree, columnNames, skip, take, token);
|
||||
var result = await timestampedValuesRepository.Get(discriminatorId, timestampBegin, columnNames, skip, take, token);
|
||||
|
||||
return result.Any() ? Ok(result) : NoContent();
|
||||
}
|
||||
@ -72,12 +63,12 @@ public class TimestampedValuesController : ControllerBase
|
||||
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||
/// <param name="timestampBegin">Фильтр позднее даты</param>
|
||||
/// <param name="token"></param>
|
||||
[HttpGet("{discriminatorId}/gtdate")]
|
||||
[HttpGet("gtdate")]
|
||||
[ProducesResponseType(typeof(IEnumerable<TimestampedValuesDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> GetGtDate([FromRoute] Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token)
|
||||
{
|
||||
var result = await timestampedValuesService.GetGtDate(discriminatorId, timestampBegin, token);
|
||||
var result = await timestampedValuesRepository.GetGtDate(discriminatorId, timestampBegin, token);
|
||||
|
||||
return result.Any() ? Ok(result) : NoContent();
|
||||
}
|
||||
@ -88,12 +79,12 @@ public class TimestampedValuesController : ControllerBase
|
||||
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||
/// <param name="take"></param>
|
||||
/// <param name="token"></param>
|
||||
[HttpGet("{discriminatorId}/first")]
|
||||
[HttpGet("first")]
|
||||
[ProducesResponseType(typeof(IEnumerable<TimestampedValuesDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> GetFirst([FromRoute] Guid discriminatorId, int take, CancellationToken token)
|
||||
{
|
||||
var result = await timestampedValuesService.GetFirst(discriminatorId, take, token);
|
||||
var result = await timestampedValuesRepository.GetFirst(discriminatorId, take, token);
|
||||
|
||||
return result.Any() ? Ok(result) : NoContent();
|
||||
}
|
||||
@ -104,12 +95,12 @@ public class TimestampedValuesController : ControllerBase
|
||||
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||
/// <param name="take"></param>
|
||||
/// <param name="token"></param>
|
||||
[HttpGet("{discriminatorId}/last")]
|
||||
[HttpGet("last")]
|
||||
[ProducesResponseType(typeof(IEnumerable<TimestampedValuesDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> GetLast([FromRoute] Guid discriminatorId, int take, CancellationToken token)
|
||||
{
|
||||
var result = await timestampedValuesService.GetLast(discriminatorId, take, token);
|
||||
var result = await timestampedValuesRepository.GetLast(discriminatorId, take, token);
|
||||
|
||||
return result.Any() ? Ok(result) : NoContent();
|
||||
}
|
||||
@ -122,12 +113,12 @@ public class TimestampedValuesController : ControllerBase
|
||||
/// <param name="intervalSec"></param>
|
||||
/// <param name="approxPointsCount"></param>
|
||||
/// <param name="token"></param>
|
||||
[HttpGet("{discriminatorId}/resampled")]
|
||||
[HttpGet("resampled")]
|
||||
[ProducesResponseType(typeof(IEnumerable<TimestampedValuesDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> GetResampledData([FromRoute] Guid discriminatorId, DateTimeOffset timestampBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default)
|
||||
{
|
||||
var result = await timestampedValuesService.GetResampledData(discriminatorId, timestampBegin, intervalSec, approxPointsCount, token);
|
||||
var result = await timestampedValuesRepository.GetResampledData(discriminatorId, timestampBegin, intervalSec, approxPointsCount, token);
|
||||
|
||||
return result.Any() ? Ok(result) : NoContent();
|
||||
}
|
||||
@ -137,7 +128,7 @@ public class TimestampedValuesController : ControllerBase
|
||||
/// </summary>
|
||||
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||
/// <param name="token"></param>
|
||||
[HttpGet("{discriminatorId}/count")]
|
||||
[HttpGet("count")]
|
||||
public async Task<ActionResult<int>> Count([FromRoute] Guid discriminatorId, CancellationToken token)
|
||||
{
|
||||
var result = await timestampedValuesRepository.Count(discriminatorId, token);
|
||||
@ -150,7 +141,7 @@ public class TimestampedValuesController : ControllerBase
|
||||
/// </summary>
|
||||
/// <param name="discriminatorId"></param>
|
||||
/// <param name="token"></param>
|
||||
[HttpGet("{discriminatorId}/datesRange")]
|
||||
[HttpGet("datesRange")]
|
||||
public async Task<ActionResult<DatesRangeDto>> GetDatesRange([FromRoute] Guid discriminatorId, CancellationToken token)
|
||||
{
|
||||
var result = await timestampedValuesRepository.GetDatesRange(discriminatorId, token);
|
||||
|
@ -25,11 +25,8 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DD.Persistence.Database.Postgres\DD.Persistence.Database.Postgres.csproj" />
|
||||
<ProjectReference Include="..\DD.Persistence.Database\DD.Persistence.Database.csproj" />
|
||||
<ProjectReference Include="..\DD.Persistence.Repository\DD.Persistence.Repository.csproj" />
|
||||
<ProjectReference Include="..\DD.Persistence\DD.Persistence.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Docs\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,4 +1,4 @@
|
||||
using DD.Persistence.Filter.Models.Abstractions;
|
||||
using DD.Persistence.Database.Postgres.Services;
|
||||
using DD.Persistence.Models.Configurations;
|
||||
using DD.Persistence.Services;
|
||||
using DD.Persistence.Services.Interfaces;
|
||||
@ -28,7 +28,6 @@ public static class DependencyInjection
|
||||
new OpenApiSchema {Type = "number", Format = "float" }
|
||||
]
|
||||
});
|
||||
c.MapType<TNode>(() => new OpenApiSchema { Type = "string" });
|
||||
|
||||
c.CustomOperationIds(e =>
|
||||
{
|
||||
@ -53,6 +52,7 @@ public static class DependencyInjection
|
||||
{
|
||||
services.AddTransient<IWitsDataService, WitsDataService>();
|
||||
services.AddTransient<ITimestampedValuesService, TimestampedValuesService>();
|
||||
services.AddTransient<IArchiveService, PostgresArchiveService>();
|
||||
}
|
||||
|
||||
#region Authentication
|
||||
|
@ -1,359 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36" version="24.8.3">
|
||||
<diagram name="Страница — 1" id="7k5Wemfp-yc9piGHxsiE">
|
||||
<mxGraphModel dx="2049" dy="1054" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1300" pageHeight="1050" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-1" value="" style="endArrow=none;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="355" y="930" as="sourcePoint" />
|
||||
<mxPoint x="355" y="210" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-2" value="" style="endArrow=none;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="555" y="930" as="sourcePoint" />
|
||||
<mxPoint x="555" y="210" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-4" value="<b>FRONT</b>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fillColor=#76608a;strokeColor=#432D57;fontColor=#ffffff;" vertex="1" parent="1">
|
||||
<mxGeometry x="325" y="180" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-5" value="<b>BACK</b>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;" vertex="1" parent="1">
|
||||
<mxGeometry x="525" y="180" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-7" value="<b>CACHE</b>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;" vertex="1" parent="1">
|
||||
<mxGeometry x="725" y="180" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-8" value="" style="endArrow=none;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="955" y="930" as="sourcePoint" />
|
||||
<mxPoint x="955" y="210" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-9" value="<b>COMMIT REPOSITORY</b>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;" vertex="1" parent="1">
|
||||
<mxGeometry x="880" y="180" width="155" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-32" value="" style="endArrow=none;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;align=center;" edge="1" parent="1" target="_dnhcZFeje3u91oS2JwL-7">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="755" y="930" as="sourcePoint" />
|
||||
<mxPoint x="756.5000000000002" y="300" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-52" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="555" y="300" as="sourcePoint" />
|
||||
<mxPoint x="755" y="300" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-53" value="<span style="font-size: 12px; text-wrap-mode: wrap;">GetOrCreate(userId, message)</span>" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;labelBackgroundColor=none;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-52">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-67" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="755" y="310" as="sourcePoint" />
|
||||
<mxPoint x="955" y="310.83" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-68" value="CreateCommit(userId, message)" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;labelBackgroundColor=none;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-67">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-69" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="955" y="330" as="sourcePoint" />
|
||||
<mxPoint x="755" y="330" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-70" value="CommitId" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-69">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-88" value="" style="endArrow=none;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="1155" y="930" as="sourcePoint" />
|
||||
<mxPoint x="1155" y="210" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-89" value="<b>CHANGE LOG REPOSITORY</b>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fillColor=#76608a;fontColor=#ffffff;strokeColor=#432D57;" vertex="1" parent="1">
|
||||
<mxGeometry x="1060" y="180" width="185" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-90" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="755" y="340" as="sourcePoint" />
|
||||
<mxPoint x="555" y="340" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-91" value="CommitId" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-90">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-93" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="555" y="380" as="sourcePoint" />
|
||||
<mxPoint x="1155" y="380" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-94" value="AddRange(items, commitId)" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;labelBackgroundColor=none;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-93">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-96" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1155" y="410" as="sourcePoint" />
|
||||
<mxPoint x="555" y="410" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-97" value="CREATED" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-96">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-100" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="555" y="420" as="sourcePoint" />
|
||||
<mxPoint x="355" y="420" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-101" value="CREATED" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-100">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-102" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=9;curved=1;targetPerimeterSpacing=3;fillColor=#f8cecc;gradientColor=#ea6b66;strokeColor=#b85450;opacity=50;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="555" y="420" as="sourcePoint" />
|
||||
<mxPoint x="555" y="290" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-104" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="355" y="290" as="sourcePoint" />
|
||||
<mxPoint x="555" y="290" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-105" value="Insert(items, message) [POST]" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;labelBackgroundColor=none;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-104">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-107" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=9;curved=1;targetPerimeterSpacing=3;fillColor=#f8cecc;gradientColor=#ea6b66;strokeColor=#b85450;opacity=50;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="354.13" y="420" as="sourcePoint" />
|
||||
<mxPoint x="354.13" y="290" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-108" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="355" y="520" as="sourcePoint" />
|
||||
<mxPoint x="555" y="520" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-109" value="Update(items, message) [PUT]" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-108">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-110" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="555" y="530" as="sourcePoint" />
|
||||
<mxPoint x="755" y="530" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-111" value="<span style="font-size: 12px; text-wrap-mode: wrap;">GetOrCreate(userId, message)</span>" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;labelBackgroundColor=none;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-110">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-112" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="755" y="560" as="sourcePoint" />
|
||||
<mxPoint x="555" y="560" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-113" value="CommitId" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-112">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-114" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=9;curved=1;targetPerimeterSpacing=3;fillColor=#f8cecc;gradientColor=#ea6b66;strokeColor=#b85450;opacity=50;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="554.5699999999999" y="650" as="sourcePoint" />
|
||||
<mxPoint x="554.5699999999999" y="520" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-115" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="555" y="610" as="sourcePoint" />
|
||||
<mxPoint x="1155" y="610" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-116" value="UpdateRange(items, commitId)" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-115">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-117" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1155" y="640" as="sourcePoint" />
|
||||
<mxPoint x="555" y="640" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-118" value="OK" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-117">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-119" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="555" y="650" as="sourcePoint" />
|
||||
<mxPoint x="355" y="650" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-120" value="OK" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-119">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-121" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="755" y="530" as="sourcePoint" />
|
||||
<mxPoint x="755" y="560" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="775" y="550" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-122" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="355" y="760" as="sourcePoint" />
|
||||
<mxPoint x="555" y="760" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-123" value="Delete(items, message) [DELETE]" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-122">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-124" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="555" y="770" as="sourcePoint" />
|
||||
<mxPoint x="755" y="770" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-125" value="<span style="font-size: 12px; text-wrap-mode: wrap;">GetOrCreate(userId, message)</span>" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;labelBackgroundColor=none;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-124">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-126" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="755" y="800" as="sourcePoint" />
|
||||
<mxPoint x="555" y="800" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-127" value="CommitId" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-126">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-128" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=9;curved=1;targetPerimeterSpacing=3;fillColor=#f8cecc;gradientColor=#ea6b66;strokeColor=#b85450;opacity=50;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="554.5699999999999" y="890" as="sourcePoint" />
|
||||
<mxPoint x="554.5699999999999" y="760" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-129" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="555" y="850" as="sourcePoint" />
|
||||
<mxPoint x="1155" y="850" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-130" value="UpdateRange(items, commitId)" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-129">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-131" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1155" y="880" as="sourcePoint" />
|
||||
<mxPoint x="555" y="880" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-132" value="OK" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-131">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-133" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="555" y="890" as="sourcePoint" />
|
||||
<mxPoint x="355" y="890" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-134" value="OK" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-133">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-135" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="755" y="770" as="sourcePoint" />
|
||||
<mxPoint x="755" y="800" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="775" y="790" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-136" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=9;curved=1;targetPerimeterSpacing=3;fillColor=#f8cecc;gradientColor=#ea6b66;strokeColor=#b85450;opacity=50;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="354.57" y="650" as="sourcePoint" />
|
||||
<mxPoint x="354.57" y="520" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-137" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=9;curved=1;targetPerimeterSpacing=3;fillColor=#f8cecc;gradientColor=#ea6b66;strokeColor=#b85450;opacity=50;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="354.57" y="890" as="sourcePoint" />
|
||||
<mxPoint x="354.57" y="760" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-138" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=10;curved=1;targetPerimeterSpacing=3;fillColor=#f8cecc;gradientColor=#ea6b66;strokeColor=#b85450;opacity=50;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="1155" y="411" as="sourcePoint" />
|
||||
<mxPoint x="1155" y="381" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-139" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=10;curved=1;targetPerimeterSpacing=3;fillColor=#f8cecc;gradientColor=#ea6b66;strokeColor=#b85450;opacity=50;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="1155" y="641" as="sourcePoint" />
|
||||
<mxPoint x="1155" y="611" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-140" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=10;curved=1;targetPerimeterSpacing=3;fillColor=#f8cecc;gradientColor=#ea6b66;strokeColor=#b85450;opacity=50;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="1154.75" y="881" as="sourcePoint" />
|
||||
<mxPoint x="1154.75" y="851" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-141" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=10;curved=1;targetPerimeterSpacing=3;fillColor=#dae8fc;gradientColor=#7ea6e0;strokeColor=#6c8ebf;opacity=50;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="755" y="830" as="sourcePoint" />
|
||||
<mxPoint x="754.93" y="312" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-142" value="" style="endArrow=none;html=1;rounded=0;fillColor=#dae8fc;strokeColor=#6c8ebf;strokeWidth=10;opacity=50;gradientColor=#7ea6e0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="165" y="882" as="sourcePoint" />
|
||||
<mxPoint x="165.22" y="292" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-143" value="<font color="#330066">User</font>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fillColor=#76608a;strokeColor=#432D57;fontColor=#ffffff;align=center;" vertex="1" parent="1">
|
||||
<mxGeometry x="155" y="180" width="21.5" height="43" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-146" value="" style="endArrow=classic;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170" y="280" as="sourcePoint" />
|
||||
<mxPoint x="360" y="280" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-147" value="SAVE" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;labelBackgroundColor=none;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-146">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-148" value="" style="endArrow=none;html=1;rounded=0;align=center;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="165.22" y="930" as="sourcePoint" />
|
||||
<mxPoint x="165.22" y="210" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-149" value="" style="endArrow=classic;html=1;rounded=0;dashed=1;align=center;" edge="1" parent="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="355" y="892" as="sourcePoint" />
|
||||
<mxPoint x="165" y="892" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="265" y="892" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-150" value="OK" style="edgeLabel;resizable=0;html=1;;align=center;verticalAlign=middle;" connectable="0" vertex="1" parent="_dnhcZFeje3u91oS2JwL-149">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-152" value="<h1 style="margin-top: 0px;">UML-диаграмма процесса пакетного редактирования</h1><p>.</p>" style="text;html=1;whiteSpace=wrap;overflow=hidden;rounded=0;align=center;" vertex="1" parent="1">
|
||||
<mxGeometry x="75" y="50" width="1150" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-154" value="frame" style="shape=umlFrame;whiteSpace=wrap;html=1;pointerEvents=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="250" width="1120" height="680" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_dnhcZFeje3u91oS2JwL-156" value="<p style="line-height: 120%;">Время жизни кеша задается внутри проекта</p>" style="shape=note;size=20;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#d0cee2;strokeColor=#56517e;opacity=50;" vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="660" width="120" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
@ -48,7 +48,4 @@ Password: 12345
|
||||
}
|
||||
```
|
||||
|
||||
## Пакетное редактирование (на примере ChangeLog)
|
||||
UML-диаграмма процесса редактирования находится по [ссылке](https://git.ddrilling.ru/on.nemtina/persistence/src/branch/master/DD.Persistence.API/Docs/ChangeLog_actions.drawio.xml)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
using DD.Persistence.Database;
|
||||
using DD.Persistence.Database.Model;
|
||||
using DD.Persistence.Database.Model;
|
||||
using DD.Persistence.Database.Postgres.Extensions;
|
||||
using DD.Persistence.Repository;
|
||||
|
||||
namespace DD.Persistence.API;
|
||||
|
||||
@ -14,7 +14,7 @@ public class Startup
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// AddRange services to the container.
|
||||
// Add services to the container.
|
||||
|
||||
services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
|
@ -28,6 +28,7 @@ COPY ["DD.Persistence/DD.Persistence.csproj", "DD.Persistence/"]
|
||||
COPY ["DD.Persistence.Database/DD.Persistence.Database.csproj", "DD.Persistence.Database/"]
|
||||
COPY ["DD.Persistence.Database.Postgres/DD.Persistence.Database.Postgres.csproj", "DD.Persistence.Database.Postgres/"]
|
||||
COPY ["DD.Persistence.Models/DD.Persistence.Models.csproj", "DD.Persistence.Models/"]
|
||||
COPY ["DD.Persistence.Repository/DD.Persistence.Repository.csproj", "DD.Persistence.Repository/"]
|
||||
|
||||
RUN dotnet restore "./DD.Persistence.App/DD.Persistence.App.csproj"
|
||||
|
||||
|
@ -6,7 +6,8 @@
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Host=localhost;Database=persistence;Username=postgres;Password=postgres;Persist Security Info=True"
|
||||
"DefaultConnection": "Host=localhost;Database=persistence;Username=postgres;Password=q;Persist Security Info=True",
|
||||
"SystemBaseConnection": "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True"
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"NeedUseKeyCloak": false,
|
||||
|
@ -7,19 +7,16 @@ using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||
using DD.Persistence.Models.Common;
|
||||
|
||||
namespace DD.Persistence.Client.Clients;
|
||||
/// <inheritdoc/>
|
||||
public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
{
|
||||
private readonly IRefitChangeLogClient refitChangeLogClient;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ChangeLogClient(IRefitClientFactory<IRefitChangeLogClient> refitClientFactory, ILogger<ChangeLogClient> logger) : base(logger)
|
||||
{
|
||||
this.refitChangeLogClient = refitClientFactory.Create();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
public async Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
||||
{
|
||||
var result = await ExecuteGetResponse(
|
||||
async () => await refitChangeLogClient.ClearAndAddRange(idDiscriminator, dtos, token), token);
|
||||
@ -27,17 +24,15 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<PaginationContainer<ChangeLogValuesDto>> GetByDate(Guid idDiscriminator, DateTimeOffset moment,
|
||||
PaginationRequest paginationRequest, CancellationToken token)
|
||||
public async Task<PaginationContainer<DataWithWellDepthAndSectionDto>> GetByDate(Guid idDiscriminator, DateTimeOffset moment,
|
||||
SectionPartRequest filterRequest, PaginationRequest paginationRequest, CancellationToken token)
|
||||
{
|
||||
var result = await ExecuteGetResponse(
|
||||
async () => await refitChangeLogClient.GetByDate(idDiscriminator, moment, paginationRequest, token), token);
|
||||
async () => await refitChangeLogClient.GetByDate(idDiscriminator, moment, filterRequest, paginationRequest, token), token);
|
||||
|
||||
return result!;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IEnumerable<ChangeLogDto>> GetChangeLogForInterval(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
|
||||
{
|
||||
var result = await ExecuteGetResponse(
|
||||
@ -46,8 +41,7 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
return result!;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token)
|
||||
public async Task<int> Add(Guid idDiscriminator, DataWithWellDepthAndSectionDto dto, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
async () => await refitChangeLogClient.Add(idDiscriminator, dto, token), token);
|
||||
@ -55,8 +49,7 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
public async Task<int> AddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
async () => await refitChangeLogClient.AddRange(idDiscriminator, dtos, token), token);
|
||||
@ -64,8 +57,7 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> Update(ChangeLogValuesDto dto, CancellationToken token)
|
||||
public async Task<int> Update(DataWithWellDepthAndSectionDto dto, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
async () => await refitChangeLogClient.Update(dto, token), token);
|
||||
@ -73,8 +65,7 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
public async Task<int> UpdateRange(IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
async () => await refitChangeLogClient.UpdateRange(dtos, token), token);
|
||||
@ -82,7 +73,6 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> Delete(Guid id, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
@ -91,7 +81,6 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> DeleteRange(IEnumerable<Guid> ids, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
@ -100,7 +89,6 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<DatesRangeDto?> GetDatesRange(Guid idDiscriminator, CancellationToken token)
|
||||
{
|
||||
var result = await ExecuteGetResponse(
|
||||
@ -109,7 +97,6 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
refitChangeLogClient.Dispose();
|
||||
|
@ -16,7 +16,7 @@ public interface IChangeLogClient : IDisposable
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token);
|
||||
Task<int> Add(Guid idDiscriminator, DataWithWellDepthAndSectionDto dto, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Добавить несколько записей
|
||||
@ -25,7 +25,7 @@ public interface IChangeLogClient : IDisposable
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<int> AddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Импорт с заменой: удаление старых строк и добавление новых
|
||||
@ -34,7 +34,7 @@ public interface IChangeLogClient : IDisposable
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить одну запись
|
||||
@ -57,10 +57,11 @@ public interface IChangeLogClient : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="moment"></param>
|
||||
/// <param name="filterRequest"></param>
|
||||
/// <param name="paginationRequest"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<PaginationContainer<ChangeLogValuesDto>> GetByDate(Guid idDiscriminator, DateTimeOffset moment, PaginationRequest paginationRequest, CancellationToken token);
|
||||
Task<PaginationContainer<DataWithWellDepthAndSectionDto>> GetByDate(Guid idDiscriminator, DateTimeOffset moment, SectionPartRequest filterRequest, PaginationRequest paginationRequest, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение исторических данных за определенный период времени
|
||||
@ -86,7 +87,7 @@ public interface IChangeLogClient : IDisposable
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> Update(ChangeLogValuesDto dto, CancellationToken token);
|
||||
Task<int> Update(DataWithWellDepthAndSectionDto dto, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить несколько записей
|
||||
@ -94,5 +95,5 @@ public interface IChangeLogClient : IDisposable
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<int> UpdateRange(IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||
}
|
@ -20,34 +20,15 @@ public interface ITimestampedValuesClient : IDisposable
|
||||
Task<int> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить данные с фильтрацией для нескольких систем. Значение фильтра null - отключен
|
||||
/// Получить данные с фильтрацией. Значение фильтра null - отключен
|
||||
/// </summary>
|
||||
/// <param name="discriminatorIds">Набор дискриминаторов (идентификаторов)</param>
|
||||
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||
/// <param name="timestampBegin">Фильтр позднее даты</param>
|
||||
/// <param name="filterTree">Кастомный фильтр по набору значений</param>
|
||||
/// <param name="columnNames">Фильтр свойств набора</param>
|
||||
/// <param name="skip"></param>
|
||||
/// <param name="take"></param>
|
||||
/// <param name="token"></param>
|
||||
Task<IEnumerable<TimestampedValuesDto>> Get(IEnumerable<Guid> discriminatorIds,
|
||||
DateTimeOffset? timestampBegin,
|
||||
string? filterTree,
|
||||
IEnumerable<string>? columnNames,
|
||||
int skip,
|
||||
int take,
|
||||
CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить данные с фильтрацией для нескольких систем. Значение фильтра null - отключен
|
||||
/// </summary>
|
||||
/// <param name="discriminatorId"></param>
|
||||
/// <param name="geTimestamp"></param>
|
||||
/// <param name="filterTree"></param>
|
||||
/// <param name="columnNames">Фильтр свойств набора</param>
|
||||
/// <param name="skip"></param>
|
||||
/// <param name="take"></param>
|
||||
/// <param name="token"></param>
|
||||
Task<IEnumerable<T>> Get<T>(Guid discriminatorId, DateTimeOffset? geTimestamp, string? filterTree, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
||||
Task<IEnumerable<TimestampedValuesDto>> Get(Guid discriminatorId, DateTimeOffset? timestampBegin, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить данные, начиная с заданной отметки времени
|
||||
@ -97,6 +78,19 @@ public interface ITimestampedValuesClient : IDisposable
|
||||
/// <param name="token"></param>
|
||||
Task<DatesRangeDto?> GetDatesRange(Guid discriminatorId, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="geTimestamp"></param>
|
||||
/// <param name="columnNames"></param>
|
||||
/// <param name="skip"></param>
|
||||
/// <param name="take"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<T>> Get<T>(Guid idDiscriminator, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
@ -5,74 +5,42 @@ using Refit;
|
||||
|
||||
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||
|
||||
/// <summary>
|
||||
/// Refit интерфейс для IRefitChangeLogClient
|
||||
/// </summary>
|
||||
public interface IRefitChangeLogClient : IRefitClient, IDisposable
|
||||
{
|
||||
private const string BaseRoute = "/api/ChangeLog";
|
||||
|
||||
/// <summary>
|
||||
/// Импорт с заменой: удаление старых строк и добавление новых
|
||||
/// </summary>
|
||||
[Post($"{BaseRoute}/replace/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<int>> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<IApiResponse<int>> ClearAndAddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение актуальных данных на определенную дату (с пагинацией)
|
||||
/// </summary>
|
||||
[Get($"{BaseRoute}/moment/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<PaginationContainer<ChangeLogValuesDto>>> GetByDate(
|
||||
Task<IApiResponse<PaginationContainer<DataWithWellDepthAndSectionDto>>> GetByDate(
|
||||
Guid idDiscriminator,
|
||||
DateTimeOffset moment,
|
||||
[Query] SectionPartRequest filterRequest,
|
||||
[Query] PaginationRequest paginationRequest,
|
||||
CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение исторических данных за определенный период времени
|
||||
/// </summary>
|
||||
[Get($"{BaseRoute}/history/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<IEnumerable<ChangeLogDto>>> GetChangeLogForInterval(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Добавить одну запись
|
||||
/// </summary>
|
||||
[Post($"{BaseRoute}/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<int>> Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token);
|
||||
Task<IApiResponse<int>> Add(Guid idDiscriminator, DataWithWellDepthAndSectionDto dto, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Добавить несколько записей
|
||||
/// </summary>
|
||||
[Post($"{BaseRoute}/range/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<int>> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<IApiResponse<int>> AddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить одну запись
|
||||
/// </summary>
|
||||
[Put($"{BaseRoute}")]
|
||||
Task<IApiResponse<int>> Update(ChangeLogValuesDto dto, CancellationToken token);
|
||||
Task<IApiResponse<int>> Update(DataWithWellDepthAndSectionDto dto, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить несколько записей
|
||||
/// </summary>
|
||||
[Put($"{BaseRoute}/range")]
|
||||
Task<IApiResponse<int>> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<IApiResponse<int>> UpdateRange(IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить одну запись
|
||||
/// </summary>
|
||||
[Delete($"{BaseRoute}")]
|
||||
Task<IApiResponse<int>> Delete(Guid id, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить несколько записей
|
||||
/// </summary>
|
||||
[Delete($"{BaseRoute}/range")]
|
||||
Task<IApiResponse<int>> DeleteRange([Body] IEnumerable<Guid> ids, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
|
||||
/// </summary>
|
||||
[Get($"{BaseRoute}/datesRange/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<DatesRangeDto?>> GetDatesRange(Guid idDiscriminator, CancellationToken token);
|
||||
|
||||
|
@ -9,59 +9,53 @@ namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||
/// </summary>
|
||||
public interface IRefitTimestampedValuesClient : IRefitClient, IDisposable
|
||||
{
|
||||
private const string baseUrl = "/api/TimestampedValues";
|
||||
private const string baseUrl = "/api/TimestampedValues/{discriminatorId}";
|
||||
|
||||
/// <summary>
|
||||
/// Записать новые данные
|
||||
/// </summary>
|
||||
[Post($"{baseUrl}/{{discriminatorId}}")]
|
||||
[Post(baseUrl)]
|
||||
Task<IApiResponse<int>> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных с фильтрацией
|
||||
/// </summary>
|
||||
[Get($"{baseUrl}")]
|
||||
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> Get([Query(CollectionFormat.Multi)] IEnumerable<Guid> discriminatorIds,
|
||||
DateTimeOffset? timestampBegin,
|
||||
[Query] string? filterTree,
|
||||
[Query(CollectionFormat.Multi)] IEnumerable<string>? columnNames,
|
||||
int skip,
|
||||
int take,
|
||||
CancellationToken token);
|
||||
[Get(baseUrl)]
|
||||
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> Get(Guid discriminatorId, DateTimeOffset? timestampBegin, [Query(CollectionFormat.Multi)] IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить данные, начиная с заданной отметки времени
|
||||
/// </summary>
|
||||
[Get($"{baseUrl}/{{discriminatorId}}/gtdate")]
|
||||
[Get($"{baseUrl}/gtdate")]
|
||||
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить данные c начала
|
||||
/// </summary>
|
||||
[Get($"{baseUrl}/{{discriminatorId}}/first")]
|
||||
[Get($"{baseUrl}/first")]
|
||||
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> GetFirst(Guid discriminatorId, int take, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить данные c конца
|
||||
/// </summary>
|
||||
[Get($"{baseUrl}/{{discriminatorId}}/last")]
|
||||
[Get($"{baseUrl}/last")]
|
||||
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> GetLast(Guid discriminatorId, int take, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить список объектов с прореживанием, удовлетворяющий диапазону временных отметок
|
||||
/// </summary>
|
||||
[Get($"{baseUrl}/{{discriminatorId}}/resampled")]
|
||||
[Get($"{baseUrl}/resampled")]
|
||||
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> GetResampledData(Guid discriminatorId, DateTimeOffset timestampBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// Получить количество записей по указанному набору в БД. Для пагинации
|
||||
/// </summary>
|
||||
[Get($"{baseUrl}/{{discriminatorId}}/count")]
|
||||
[Get($"{baseUrl}/count")]
|
||||
Task<IApiResponse<int>> Count(Guid discriminatorId, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить диапазон дат, в пределах которых хранятся даные
|
||||
/// </summary>
|
||||
[Get($"{baseUrl}/{{discriminatorId}}/datesRange")]
|
||||
[Get($"{baseUrl}/datesRange")]
|
||||
Task<IApiResponse<DatesRangeDto?>> GetDatesRange(Guid discriminatorId, CancellationToken token);
|
||||
}
|
||||
|
@ -32,20 +32,11 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IEnumerable<TimestampedValuesDto>> Get(IEnumerable<Guid> discriminatorIds, DateTimeOffset? geTimestamp, string? filterTree, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
||||
{
|
||||
var result = await ExecuteGetResponse(
|
||||
async () => await refitTimestampedSetClient.Get(discriminatorIds, geTimestamp, filterTree, columnNames, skip, take, token), token);
|
||||
return result!;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IEnumerable<T>> Get<T>(Guid discriminatorId, DateTimeOffset? geTimestamp, string? filterTree, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
||||
{
|
||||
var data = await Get([discriminatorId], geTimestamp, filterTree, columnNames, skip, take, token);
|
||||
var mapper = GetMapper<T>(discriminatorId);
|
||||
|
||||
return data.Select(mapper.DeserializeTimeStampedData);
|
||||
public async Task<IEnumerable<TimestampedValuesDto>> Get(Guid discriminatorId, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
||||
{
|
||||
var result = await ExecuteGetResponse(
|
||||
async () => await refitTimestampedSetClient.Get(discriminatorId, geTimestamp, columnNames, skip, take, token), token);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -54,7 +45,7 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
|
||||
var result = await ExecuteGetResponse(
|
||||
async () => await refitTimestampedSetClient.GetGtDate(discriminatorId, timestampBegin, token), token);
|
||||
|
||||
return result!;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -63,7 +54,7 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
|
||||
var result = await ExecuteGetResponse(
|
||||
async () => await refitTimestampedSetClient.GetFirst(discriminatorId, take, token), token);
|
||||
|
||||
return result!;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -72,7 +63,7 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
|
||||
var result = await ExecuteGetResponse(
|
||||
async () => await refitTimestampedSetClient.GetLast(discriminatorId, take, token), token);
|
||||
|
||||
return result!;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -81,7 +72,7 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
|
||||
var result = await ExecuteGetResponse(
|
||||
async () => await refitTimestampedSetClient.GetResampledData(discriminatorId, dateBegin, intervalSec, approxPointsCount, token), token);
|
||||
|
||||
return result!;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -102,6 +93,15 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IEnumerable<T>> Get<T>(Guid idDiscriminator, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
||||
{
|
||||
var data = await Get(idDiscriminator, geTimestamp, columnNames, skip, take, token);
|
||||
var mapper = GetMapper<T>(idDiscriminator);
|
||||
|
||||
return data.Select(mapper.DeserializeTimeStampedData);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IEnumerable<T>> GetLast<T>(Guid idDiscriminator, int take, CancellationToken token)
|
||||
{
|
||||
|
@ -11,9 +11,9 @@
|
||||
<!--Наименование-->
|
||||
<Title>DD.Persistence.Client</Title>
|
||||
<!--Версия пакета-->
|
||||
<VersionPrefix>1.6.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1</VersionPrefix>
|
||||
<VersionPrefix>1.5.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1</VersionPrefix>
|
||||
<!--Версия сборки-->
|
||||
<AssemblyVersion>1.6.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1</AssemblyVersion>
|
||||
<AssemblyVersion>1.5.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1</AssemblyVersion>
|
||||
<!--Id пакета-->
|
||||
<PackageId>DD.Persistence.Client</PackageId>
|
||||
|
||||
@ -40,8 +40,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>1.6.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
|
||||
<AssemblyVersion>1.6.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
|
||||
<VersionPrefix>1.5.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
|
||||
<AssemblyVersion>1.5.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -52,6 +52,7 @@
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.3.0" />
|
||||
<PackageReference Include="Refit" Version="8.0.0" />
|
||||
<PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" />
|
||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.3.0" />
|
||||
</ItemGroup>
|
||||
|
80
DD.Persistence.Client/Helpers/ApiTokenHelper.cs
Normal file
80
DD.Persistence.Client/Helpers/ApiTokenHelper.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using DD.Persistence.Models.Configurations;
|
||||
using RestSharp;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DD.Persistence.Client.Helpers;
|
||||
public static class ApiTokenHelper
|
||||
{
|
||||
public static void Authorize(this HttpClient httpClient, IConfiguration configuration)
|
||||
{
|
||||
var authUser = configuration
|
||||
.GetSection(nameof(AuthUser))
|
||||
.Get<AuthUser>()!;
|
||||
var needUseKeyCloak = configuration
|
||||
.GetSection("NeedUseKeyCloak")
|
||||
.Get<bool>()!;
|
||||
var keycloakGetTokenUrl = configuration.GetSection("KeycloakGetTokenUrl").Get<string>() ?? string.Empty;
|
||||
|
||||
var jwtToken = needUseKeyCloak
|
||||
? authUser.CreateKeyCloakJwtToken(keycloakGetTokenUrl)
|
||||
: authUser.CreateDefaultJwtToken();
|
||||
|
||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
|
||||
}
|
||||
|
||||
public static void Authorize(this HttpClient httpClient, string jwtToken)
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
|
||||
}
|
||||
|
||||
private static string CreateDefaultJwtToken(this AuthUser authUser)
|
||||
{
|
||||
var nameIdetifier = Guid.NewGuid().ToString();
|
||||
var claims = new List<Claim>()
|
||||
{
|
||||
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())
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
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 keycloakResponse = restClient.Post(request);
|
||||
if (keycloakResponse.IsSuccessful && !String.IsNullOrEmpty(keycloakResponse.Content))
|
||||
{
|
||||
var token = JsonSerializer.Deserialize<JwtToken>(keycloakResponse.Content)!;
|
||||
return token.AccessToken;
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DD.Persistence.Database.Postgres\DD.Persistence.Database.Postgres.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,40 +0,0 @@
|
||||
using DD.Persistence.Database.Model;
|
||||
using DD.Persistence.Database.Postgres.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Test;
|
||||
public class DbFixture : IDisposable
|
||||
{
|
||||
private string connectionString { get; }
|
||||
public ServiceProvider serviceProvider { get; private set; }
|
||||
|
||||
public DbFixture()
|
||||
{
|
||||
connectionString = $"Host=localhost;Port=5462;Username=postgres;Password=postgres;Database={Guid.CreateVersion7()}";
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection
|
||||
.AddDbContext<PersistenceDbContext>(options => options.UseNpgsql(connectionString),
|
||||
ServiceLifetime.Transient);
|
||||
|
||||
serviceProvider = serviceCollection.BuildServiceProvider();
|
||||
|
||||
var context = serviceProvider.GetRequiredService<PersistenceDbContext>();
|
||||
context.Database.EnsureCreated();
|
||||
context.Database.AddPartitioning();
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var dbContext = new PersistencePostgresContext(
|
||||
new DbContextOptionsBuilder<PersistencePostgresContext>()
|
||||
.UseNpgsql(connectionString)
|
||||
.Options);
|
||||
|
||||
dbContext.Database.EnsureDeleted();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Npgsql;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Test;
|
||||
|
||||
public class UnitTestCheckHyperTables : IClassFixture<DbFixture>
|
||||
{
|
||||
private ServiceProvider _serviceProvider;
|
||||
|
||||
public UnitTestCheckHyperTables(DbFixture fixture)
|
||||
{
|
||||
_serviceProvider = fixture.serviceProvider;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateHyperTable_For_ParameterData_Return_Success()
|
||||
{
|
||||
var chunksCount = 0;
|
||||
|
||||
var entity = new ParameterData()
|
||||
{
|
||||
DiscriminatorId = Guid.NewGuid(),
|
||||
ParameterId = 1,
|
||||
Timestamp = DateTime.UtcNow,
|
||||
Value = "123"
|
||||
};
|
||||
|
||||
using (var context = _serviceProvider.GetService<PersistenceDbContext>()!)
|
||||
{
|
||||
context.ParameterData.Add(entity);
|
||||
|
||||
var entity2 = entity.Adapt<ParameterData>();
|
||||
entity2.ParameterId = 2;
|
||||
context.ParameterData.Add(entity2);
|
||||
|
||||
var entity3 = entity2.Adapt<ParameterData>();
|
||||
entity3.ParameterId = 3;
|
||||
context.ParameterData.Add(entity3);
|
||||
|
||||
var entity4 = entity3.Adapt<ParameterData>();
|
||||
entity4.ParameterId = 4;
|
||||
context.ParameterData.Add(entity4);
|
||||
|
||||
var entity5 = entity3.Adapt<ParameterData>();
|
||||
entity5.Timestamp = DateTime.UtcNow.AddDays(1).AddHours(1);
|
||||
context.ParameterData.Add(entity5);
|
||||
|
||||
var entity6 = entity3.Adapt<ParameterData>();
|
||||
entity6.DiscriminatorId = Guid.CreateVersion7();
|
||||
context.ParameterData.Add(entity6);
|
||||
|
||||
context.SaveChanges();
|
||||
|
||||
string sql = "select count(*) from (select show_chunks('parameter_data'));";
|
||||
var queryRow = context.Database.SqlQueryRaw<int>(sql);
|
||||
|
||||
chunksCount = queryRow.AsEnumerable().FirstOrDefault();
|
||||
}
|
||||
|
||||
Assert.Equal(5, chunksCount);
|
||||
}
|
||||
}
|
@ -1,13 +1,6 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Database.Postgres.Repositories;
|
||||
using DD.Persistence.Database.Postgres.RepositoriesCached;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Repositories;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DD.Persistence.Database.Model;
|
||||
|
||||
|
@ -25,8 +25,6 @@ public static class EFExtensionsPartitioning
|
||||
/// <param name="db"></param>
|
||||
private static void AddParameterDataPartitioning(this DatabaseFacade db)
|
||||
{
|
||||
var dayCount = 1;
|
||||
var sectionCount = 128;
|
||||
var type = typeof(ParameterData);
|
||||
var tableAttribute = type.GetCustomAttribute<TableAttribute>();
|
||||
if (tableAttribute is null)
|
||||
@ -34,16 +32,13 @@ public static class EFExtensionsPartitioning
|
||||
return;
|
||||
}
|
||||
|
||||
var sqlCreateHypertableString = $"SELECT create_hypertable('{tableAttribute.Name}'," +
|
||||
$"by_range('{nameof(ParameterData.Timestamp)}', INTERVAL '{dayCount} day'), if_not_exists => {true});";
|
||||
db.ExecuteSqlRaw(sqlCreateHypertableString);
|
||||
|
||||
var sqlCreateDimensionParameterId = $"SELECT add_dimension('{tableAttribute.Name}'," +
|
||||
$"by_hash('{nameof(ParameterData.ParameterId)}', {sectionCount}), if_not_exists => {true});";
|
||||
db.ExecuteSqlRaw(sqlCreateDimensionParameterId);
|
||||
|
||||
var sqlCreateDimensionDiscriminatorId = $"SELECT add_dimension('{tableAttribute.Name}'," +
|
||||
$"by_hash('{nameof(ParameterData.DiscriminatorId)}', {sectionCount}), if_not_exists => {true});";
|
||||
db.ExecuteSqlRaw(sqlCreateDimensionDiscriminatorId);
|
||||
const int sectionsNumber = 2;
|
||||
const int chunkTimeInterval = 5;
|
||||
var sqlString = $"SELECT create_hypertable({tableAttribute.Name}," +
|
||||
$"'{nameof(ParameterData.Timestamp)}'," +
|
||||
$"'{nameof(ParameterData.ParameterId)}'," +
|
||||
$"{sectionsNumber}," +
|
||||
$"chunk_time_interval => INTERVAL '{chunkTimeInterval} day');";
|
||||
db.ExecuteSqlRaw(sqlString);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
namespace DD.Persistence.Database.Postgres.Migrations
|
||||
{
|
||||
[DbContext(typeof(PersistencePostgresContext))]
|
||||
[Migration("20250210055116_Init")]
|
||||
[Migration("20250122120353_Init")]
|
||||
partial class Init
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@ -26,45 +26,21 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.ChangeLog", b =>
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.DataScheme", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
b.Property<Guid>("DiscriminatorId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ записи");
|
||||
.HasComment("Идентификатор схемы данных");
|
||||
|
||||
b.Property<DateTimeOffset>("Creation")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата создания записи");
|
||||
|
||||
b.Property<Guid>("DiscriminatorId")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Дискриминатор таблицы");
|
||||
|
||||
b.Property<Guid>("IdAuthor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Автор изменения");
|
||||
|
||||
b.Property<Guid?>("IdEditor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Редактор");
|
||||
|
||||
b.Property<Guid?>("IdNext")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id заменяющей записи");
|
||||
|
||||
b.Property<DateTimeOffset?>("Obsolete")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата устаревания (например при удалении)");
|
||||
|
||||
b.Property<string>("Value")
|
||||
b.Property<string>("PropNames")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasComment("Значение");
|
||||
.HasComment("Наименования полей в порядке индексации");
|
||||
|
||||
b.HasKey("Id");
|
||||
b.HasKey("DiscriminatorId");
|
||||
|
||||
b.ToTable("change_log");
|
||||
b.ToTable("data_scheme");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
|
||||
@ -112,53 +88,6 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
b.ToTable("parameter_data");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.SchemeProperty", b =>
|
||||
{
|
||||
b.Property<Guid>("DiscriminatorId")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Идентификатор схемы данных");
|
||||
|
||||
b.Property<int>("Index")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Индекс поля");
|
||||
|
||||
b.Property<byte>("PropertyKind")
|
||||
.HasColumnType("smallint")
|
||||
.HasComment("Тип индексируемого поля");
|
||||
|
||||
b.Property<string>("PropertyName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasComment("Наименования индексируемого поля");
|
||||
|
||||
b.HasKey("DiscriminatorId", "Index");
|
||||
|
||||
b.ToTable("scheme_property");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.Setpoint", b =>
|
||||
{
|
||||
b.Property<Guid>("Key")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ");
|
||||
|
||||
b.Property<DateTimeOffset>("Timestamp")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата создания уставки");
|
||||
|
||||
b.Property<Guid>("IdUser")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id автора последнего изменения");
|
||||
|
||||
b.Property<JsonElement>("Value")
|
||||
.HasColumnType("jsonb")
|
||||
.HasComment("Значение уставки");
|
||||
|
||||
b.HasKey("Key", "Timestamp");
|
||||
|
||||
b.ToTable("setpoint");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.TechMessage", b =>
|
||||
{
|
||||
b.Property<Guid>("EventId")
|
||||
@ -214,6 +143,82 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
b.ToTable("timestamped_values");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Model.ChangeLog", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ записи");
|
||||
|
||||
b.Property<DateTimeOffset>("Creation")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата создания записи");
|
||||
|
||||
b.Property<double>("DepthEnd")
|
||||
.HasColumnType("double precision")
|
||||
.HasComment("Глубина забоя на дату окончания интервала");
|
||||
|
||||
b.Property<double>("DepthStart")
|
||||
.HasColumnType("double precision")
|
||||
.HasComment("Глубина забоя на дату начала интервала");
|
||||
|
||||
b.Property<Guid>("IdAuthor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Автор изменения");
|
||||
|
||||
b.Property<Guid>("IdDiscriminator")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Дискриминатор таблицы");
|
||||
|
||||
b.Property<Guid?>("IdEditor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Редактор");
|
||||
|
||||
b.Property<Guid?>("IdNext")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id заменяющей записи");
|
||||
|
||||
b.Property<Guid>("IdSection")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ секции");
|
||||
|
||||
b.Property<DateTimeOffset?>("Obsolete")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата устаревания (например при удалении)");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasComment("Значение");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("change_log");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Model.Setpoint", b =>
|
||||
{
|
||||
b.Property<Guid>("Key")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ");
|
||||
|
||||
b.Property<DateTimeOffset>("Timestamp")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата создания уставки");
|
||||
|
||||
b.Property<Guid>("IdUser")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id автора последнего изменения");
|
||||
|
||||
b.Property<JsonElement>("Value")
|
||||
.HasColumnType("jsonb")
|
||||
.HasComment("Значение уставки");
|
||||
|
||||
b.HasKey("Key", "Timestamp");
|
||||
|
||||
b.ToTable("setpoint");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.TechMessage", b =>
|
||||
{
|
||||
b.HasOne("DD.Persistence.Database.Entity.DataSourceSystem", "System")
|
||||
@ -224,6 +229,17 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
|
||||
b.Navigation("System");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedValues", b =>
|
||||
{
|
||||
b.HasOne("DD.Persistence.Database.Entity.DataScheme", "DataScheme")
|
||||
.WithMany()
|
||||
.HasForeignKey("DiscriminatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("DataScheme");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
@ -17,12 +17,15 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ записи"),
|
||||
DiscriminatorId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор таблицы"),
|
||||
IdDiscriminator = table.Column<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор таблицы"),
|
||||
IdAuthor = table.Column<Guid>(type: "uuid", nullable: false, comment: "Автор изменения"),
|
||||
IdEditor = table.Column<Guid>(type: "uuid", nullable: true, comment: "Редактор"),
|
||||
Creation = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата создания записи"),
|
||||
Obsolete = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true, comment: "Дата устаревания (например при удалении)"),
|
||||
IdNext = table.Column<Guid>(type: "uuid", nullable: true, comment: "Id заменяющей записи"),
|
||||
DepthStart = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина забоя на дату начала интервала"),
|
||||
DepthEnd = table.Column<double>(type: "double precision", nullable: false, comment: "Глубина забоя на дату окончания интервала"),
|
||||
IdSection = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ секции"),
|
||||
Value = table.Column<string>(type: "jsonb", nullable: false, comment: "Значение")
|
||||
},
|
||||
constraints: table =>
|
||||
@ -30,6 +33,18 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
table.PrimaryKey("PK_change_log", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "data_scheme",
|
||||
columns: table => new
|
||||
{
|
||||
DiscriminatorId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Идентификатор схемы данных"),
|
||||
PropNames = table.Column<string>(type: "jsonb", nullable: false, comment: "Наименования полей в порядке индексации")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_data_scheme", x => x.DiscriminatorId);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "data_source_system",
|
||||
columns: table => new
|
||||
@ -57,20 +72,6 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
table.PrimaryKey("PK_parameter_data", x => new { x.DiscriminatorId, x.ParameterId, x.Timestamp });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "scheme_property",
|
||||
columns: table => new
|
||||
{
|
||||
DiscriminatorId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Идентификатор схемы данных"),
|
||||
Index = table.Column<int>(type: "integer", nullable: false, comment: "Индекс поля"),
|
||||
PropertyName = table.Column<string>(type: "text", nullable: false, comment: "Наименования индексируемого поля"),
|
||||
PropertyKind = table.Column<byte>(type: "smallint", nullable: false, comment: "Тип индексируемого поля")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_scheme_property", x => new { x.DiscriminatorId, x.Index });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "setpoint",
|
||||
columns: table => new
|
||||
@ -96,6 +97,12 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_timestamped_values", x => new { x.DiscriminatorId, x.Timestamp });
|
||||
table.ForeignKey(
|
||||
name: "FK_timestamped_values_data_scheme_DiscriminatorId",
|
||||
column: x => x.DiscriminatorId,
|
||||
principalTable: "data_scheme",
|
||||
principalColumn: "DiscriminatorId",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
@ -135,9 +142,6 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
migrationBuilder.DropTable(
|
||||
name: "parameter_data");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "scheme_property");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "setpoint");
|
||||
|
||||
@ -149,6 +153,9 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "data_source_system");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "data_scheme");
|
||||
}
|
||||
}
|
||||
}
|
@ -23,45 +23,21 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.ChangeLog", b =>
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.DataScheme", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
b.Property<Guid>("DiscriminatorId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ записи");
|
||||
.HasComment("Идентификатор схемы данных");
|
||||
|
||||
b.Property<DateTimeOffset>("Creation")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата создания записи");
|
||||
|
||||
b.Property<Guid>("DiscriminatorId")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Дискриминатор таблицы");
|
||||
|
||||
b.Property<Guid>("IdAuthor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Автор изменения");
|
||||
|
||||
b.Property<Guid?>("IdEditor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Редактор");
|
||||
|
||||
b.Property<Guid?>("IdNext")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id заменяющей записи");
|
||||
|
||||
b.Property<DateTimeOffset?>("Obsolete")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата устаревания (например при удалении)");
|
||||
|
||||
b.Property<string>("Value")
|
||||
b.Property<string>("PropNames")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasComment("Значение");
|
||||
.HasComment("Наименования полей в порядке индексации");
|
||||
|
||||
b.HasKey("Id");
|
||||
b.HasKey("DiscriminatorId");
|
||||
|
||||
b.ToTable("change_log");
|
||||
b.ToTable("data_scheme");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
|
||||
@ -109,53 +85,6 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
b.ToTable("parameter_data");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.SchemeProperty", b =>
|
||||
{
|
||||
b.Property<Guid>("DiscriminatorId")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Идентификатор схемы данных");
|
||||
|
||||
b.Property<int>("Index")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Индекс поля");
|
||||
|
||||
b.Property<byte>("PropertyKind")
|
||||
.HasColumnType("smallint")
|
||||
.HasComment("Тип индексируемого поля");
|
||||
|
||||
b.Property<string>("PropertyName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasComment("Наименования индексируемого поля");
|
||||
|
||||
b.HasKey("DiscriminatorId", "Index");
|
||||
|
||||
b.ToTable("scheme_property");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.Setpoint", b =>
|
||||
{
|
||||
b.Property<Guid>("Key")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ");
|
||||
|
||||
b.Property<DateTimeOffset>("Timestamp")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата создания уставки");
|
||||
|
||||
b.Property<Guid>("IdUser")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id автора последнего изменения");
|
||||
|
||||
b.Property<JsonElement>("Value")
|
||||
.HasColumnType("jsonb")
|
||||
.HasComment("Значение уставки");
|
||||
|
||||
b.HasKey("Key", "Timestamp");
|
||||
|
||||
b.ToTable("setpoint");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.TechMessage", b =>
|
||||
{
|
||||
b.Property<Guid>("EventId")
|
||||
@ -211,6 +140,82 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
b.ToTable("timestamped_values");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Model.ChangeLog", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ записи");
|
||||
|
||||
b.Property<DateTimeOffset>("Creation")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата создания записи");
|
||||
|
||||
b.Property<double>("DepthEnd")
|
||||
.HasColumnType("double precision")
|
||||
.HasComment("Глубина забоя на дату окончания интервала");
|
||||
|
||||
b.Property<double>("DepthStart")
|
||||
.HasColumnType("double precision")
|
||||
.HasComment("Глубина забоя на дату начала интервала");
|
||||
|
||||
b.Property<Guid>("IdAuthor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Автор изменения");
|
||||
|
||||
b.Property<Guid>("IdDiscriminator")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Дискриминатор таблицы");
|
||||
|
||||
b.Property<Guid?>("IdEditor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Редактор");
|
||||
|
||||
b.Property<Guid?>("IdNext")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id заменяющей записи");
|
||||
|
||||
b.Property<Guid>("IdSection")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ секции");
|
||||
|
||||
b.Property<DateTimeOffset?>("Obsolete")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата устаревания (например при удалении)");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasComment("Значение");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("change_log");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Model.Setpoint", b =>
|
||||
{
|
||||
b.Property<Guid>("Key")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Ключ");
|
||||
|
||||
b.Property<DateTimeOffset>("Timestamp")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата создания уставки");
|
||||
|
||||
b.Property<Guid>("IdUser")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id автора последнего изменения");
|
||||
|
||||
b.Property<JsonElement>("Value")
|
||||
.HasColumnType("jsonb")
|
||||
.HasComment("Значение уставки");
|
||||
|
||||
b.HasKey("Key", "Timestamp");
|
||||
|
||||
b.ToTable("setpoint");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.TechMessage", b =>
|
||||
{
|
||||
b.HasOne("DD.Persistence.Database.Entity.DataSourceSystem", "System")
|
||||
@ -221,6 +226,17 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
|
||||
b.Navigation("System");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedValues", b =>
|
||||
{
|
||||
b.HasOne("DD.Persistence.Database.Entity.DataScheme", "DataScheme")
|
||||
.WithMany()
|
||||
.HasForeignKey("DiscriminatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("DataScheme");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DD.Persistence.Database.Model;
|
||||
|
||||
/// <summary>
|
||||
/// EF контекст для базы данных Postgres
|
||||
/// EF êîíòåêñò äëÿ ÁÄ Postgres
|
||||
/// </summary>
|
||||
public partial class PersistencePostgresContext : PersistenceDbContext
|
||||
{
|
||||
|
56
DD.Persistence.Database.Postgres/Services/ArchiveService.cs
Normal file
56
DD.Persistence.Database.Postgres/Services/ArchiveService.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using DD.Persistence.Services.Interfaces;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Npgsql;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Сервис по работе с источником данных - базой postgres
|
||||
/// </summary>
|
||||
public class PostgresArchiveService : IArchiveService
|
||||
{
|
||||
private string connectionString;
|
||||
private ILogger<PostgresArchiveService> logger;
|
||||
|
||||
/// <summary>
|
||||
/// Сервис по работе с источником данных - базой postgres
|
||||
/// </summary>
|
||||
/// <param name="configuration"></param>
|
||||
public PostgresArchiveService(IConfiguration configuration, ILogger<PostgresArchiveService> logger)
|
||||
{
|
||||
this.connectionString = configuration.GetConnectionString("SystemBaseConnection")!;
|
||||
this.logger = logger;
|
||||
}
|
||||
public Task Create(string newName, CancellationToken token)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task Rename(string newName, CancellationToken token)
|
||||
{
|
||||
await using var connection = new NpgsqlConnection(connectionString);
|
||||
try
|
||||
{
|
||||
await connection.OpenAsync();
|
||||
|
||||
var sqlCloseConnect =
|
||||
$"SELECT pg_terminate_backend(pg_stat_activity.pid) " +
|
||||
$"FROM pg_stat_activity " +
|
||||
$"WHERE pg_stat_activity.datname = 'persistence' AND pid <> pg_backend_pid();";
|
||||
await using var command = new NpgsqlCommand(sqlCloseConnect, connection);
|
||||
await command.ExecuteNonQueryAsync();
|
||||
|
||||
var rename = $"ALTER DATABASE persistence RENAME TO {newName};";
|
||||
await using var sqlRenameDatabase = new NpgsqlCommand(rename, connection);
|
||||
await sqlRenameDatabase.ExecuteNonQueryAsync();
|
||||
}
|
||||
catch (NpgsqlException exception)
|
||||
{
|
||||
this.logger.LogError(exception.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
@ -7,14 +7,11 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ardalis.Specification.EntityFrameworkCore" Version="8.0.0" />
|
||||
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="UuidExtensions" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
using DD.Persistence.ModelsAbstractions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -11,13 +11,13 @@ namespace DD.Persistence.Database.Entity;
|
||||
/// Часть записи, описывающая изменение
|
||||
/// </summary>
|
||||
[Table("change_log")]
|
||||
public class ChangeLog : IDiscriminatorItem, IChangeLog
|
||||
public class ChangeLog : IChangeLog, IWithSectionPart
|
||||
{
|
||||
[Key, Comment("Ключ записи")]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[Comment("Дискриминатор таблицы")]
|
||||
public Guid DiscriminatorId { get; set; }
|
||||
public Guid IdDiscriminator { get; set; }
|
||||
|
||||
[Comment("Автор изменения")]
|
||||
public Guid IdAuthor { get; set; }
|
||||
@ -34,6 +34,15 @@ public class ChangeLog : IDiscriminatorItem, IChangeLog
|
||||
[Comment("Id заменяющей записи")]
|
||||
public Guid? IdNext { get; set; }
|
||||
|
||||
[Comment("Глубина забоя на дату начала интервала")]
|
||||
public double DepthStart { get; set; }
|
||||
|
||||
[Comment("Глубина забоя на дату окончания интервала")]
|
||||
public double DepthEnd { get; set; }
|
||||
|
||||
[Comment("Ключ секции")]
|
||||
public Guid IdSection { get; set; }
|
||||
|
||||
[Column(TypeName = "jsonb"), Comment("Значение")]
|
||||
public required IDictionary<string, object> Value { get; set; }
|
||||
}
|
||||
|
15
DD.Persistence.Database/Entity/DataScheme.cs
Normal file
15
DD.Persistence.Database/Entity/DataScheme.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace DD.Persistence.Database.Entity;
|
||||
|
||||
[Table("data_scheme")]
|
||||
public class DataScheme
|
||||
{
|
||||
[Key, Comment("Идентификатор схемы данных"),]
|
||||
public Guid DiscriminatorId { get; set; }
|
||||
|
||||
[Comment("Наименования полей в порядке индексации"), Column(TypeName = "jsonb")]
|
||||
public string[] PropNames { get; set; } = [];
|
||||
}
|
@ -7,7 +7,7 @@ namespace DD.Persistence.Database.Entity;
|
||||
|
||||
[Table("parameter_data")]
|
||||
[PrimaryKey(nameof(DiscriminatorId), nameof(ParameterId), nameof(Timestamp))]
|
||||
public class ParameterData : IDiscriminatorItem, ITimestampedItem
|
||||
public class ParameterData : ITimestampedItem
|
||||
{
|
||||
[Required, Comment("Дискриминатор системы")]
|
||||
public Guid DiscriminatorId { get; set; }
|
||||
|
@ -1,24 +0,0 @@
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DD.Persistence.Database.Entity;
|
||||
|
||||
[Table("scheme_property")]
|
||||
[PrimaryKey(nameof(DiscriminatorId), nameof(Index))]
|
||||
public class SchemeProperty : IDiscriminatorItem
|
||||
{
|
||||
[Comment("Идентификатор схемы данных")]
|
||||
public Guid DiscriminatorId { get; set; }
|
||||
|
||||
[Comment("Индекс поля")]
|
||||
public int Index { get; set; }
|
||||
|
||||
[Comment("Наименования индексируемого поля")]
|
||||
public required string PropertyName { get; set; }
|
||||
|
||||
[Comment("Тип индексируемого поля")]
|
||||
public required JsonValueKind PropertyKind { get; set; }
|
||||
}
|
@ -17,15 +17,15 @@ public class TechMessage : ITimestampedItem
|
||||
[Comment("Дата возникновения")]
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
|
||||
[Column(TypeName = "varchar(512)"), Comment("Текст сообщения")]
|
||||
public required string Text { get; set; }
|
||||
[Column(TypeName = "varchar(512)"), Comment("Текст сообщения")]
|
||||
public required string Text { get; set; }
|
||||
|
||||
[Required, Comment("Id системы, к которой относится сообщение")]
|
||||
public required Guid SystemId { get; set; }
|
||||
[Required, Comment("Id системы, к которой относится сообщение")]
|
||||
public required Guid SystemId { get; set; }
|
||||
|
||||
[Required, ForeignKey(nameof(SystemId)), Comment("Система, к которой относится сообщение")]
|
||||
public virtual required DataSourceSystem System { get; set; }
|
||||
[Required, ForeignKey(nameof(SystemId)), Comment("Система, к которой относится сообщение")]
|
||||
public virtual required DataSourceSystem System { get; set; }
|
||||
|
||||
[Comment("Статус события")]
|
||||
public int EventState { get; set; }
|
||||
}
|
||||
[Comment("Статус события")]
|
||||
public int EventState { get; set; }
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ namespace DD.Persistence.Database.Entity;
|
||||
|
||||
[Table("timestamped_values")]
|
||||
[PrimaryKey(nameof(DiscriminatorId), nameof(Timestamp))]
|
||||
public class TimestampedValues : IDiscriminatorItem, ITimestampedItem, IValuesItem
|
||||
public class TimestampedValues : ITimestampedItem
|
||||
{
|
||||
[Comment("Временная отметка"), Key]
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
@ -17,4 +17,7 @@ public class TimestampedValues : IDiscriminatorItem, ITimestampedItem, IValuesIt
|
||||
|
||||
[Comment("Данные"), Column(TypeName = "jsonb")]
|
||||
public required object[] Values { get; set; }
|
||||
|
||||
[Required, ForeignKey(nameof(DiscriminatorId)), Comment("Идентификаторы")]
|
||||
public virtual DataScheme? DataScheme { get; set; }
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public interface IChangeLog
|
||||
/// <summary>
|
||||
/// Дискриминатор таблицы
|
||||
/// </summary>
|
||||
public Guid DiscriminatorId { get; set; }
|
||||
public Guid IdDiscriminator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Значение
|
||||
|
@ -1,8 +0,0 @@
|
||||
namespace DD.Persistence.Database.EntityAbstractions;
|
||||
public interface IDiscriminatorItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Дискриминатор
|
||||
/// </summary>
|
||||
Guid DiscriminatorId { get; set; }
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
|
||||
namespace DD.Persistence.Database.EntityAbstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Сущность с данными, принадлежащими к определенной схеме
|
||||
/// </summary>
|
||||
public interface IValuesItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Значения
|
||||
/// </summary>
|
||||
object[] Values { get; set; }
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
using Ardalis.Specification;
|
||||
using DD.Persistence.Database.Helpers;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Extensions;
|
||||
|
||||
public static class SpecificationExtensions
|
||||
{
|
||||
public static Expression<Func<T, bool>>? Or<T>(this ISpecification<T> spec, ISpecification<T> otherSpec)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(T), "x");
|
||||
|
||||
var exprSpec1 = CombineWhereExpressions(spec.WhereExpressions, parameter);
|
||||
var exprSpec2 = CombineWhereExpressions(otherSpec.WhereExpressions, parameter);
|
||||
|
||||
Expression? orExpression = exprSpec1 is not null && exprSpec2 is not null
|
||||
? Expression.OrElse(exprSpec1, exprSpec2)
|
||||
: exprSpec1 ?? exprSpec2;
|
||||
|
||||
if (orExpression is null)
|
||||
return null;
|
||||
|
||||
var lambdaExpr = Expression.Lambda<Func<T, bool>>(orExpression, parameter);
|
||||
|
||||
return lambdaExpr;
|
||||
}
|
||||
|
||||
public static Expression? CombineWhereExpressions<T>(IEnumerable<WhereExpressionInfo<T>> whereExpressions, ParameterExpression parameter)
|
||||
{
|
||||
Expression? newExpr = null;
|
||||
foreach (var where in whereExpressions)
|
||||
{
|
||||
var expr = ParameterReplacerVisitor.Replace(where.Filter.Body, where.Filter.Parameters[0], parameter);
|
||||
newExpr = newExpr is null ? expr : Expression.AndAlso(newExpr, expr);
|
||||
}
|
||||
return newExpr;
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
using Ardalis.Specification;
|
||||
using Ardalis.Specification.EntityFrameworkCore;
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
using DD.Persistence.Database.Specifications.Operation;
|
||||
using DD.Persistence.Database.Specifications.ValuesItem;
|
||||
using DD.Persistence.Filter.Models;
|
||||
using DD.Persistence.Filter.Models.Abstractions;
|
||||
using DD.Persistence.Filter.Models.Enumerations;
|
||||
using DD.Persistence.Filter.Visitors;
|
||||
using DD.Persistence.Models;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Helpers;
|
||||
public static class FilterBuilder
|
||||
{
|
||||
public static IQueryable<TEntity> ApplyFilter<TEntity>(this IQueryable<TEntity> query, DataSchemeDto dataSchemeDto, TNode root)
|
||||
where TEntity : class, IValuesItem
|
||||
{
|
||||
var filterSpec = dataSchemeDto.BuildFilter<TEntity>(root);
|
||||
if (filterSpec != null)
|
||||
return query.WithSpecification(filterSpec);
|
||||
return query;
|
||||
}
|
||||
|
||||
private static ISpecification<TEntity>? BuildFilter<TEntity>(this DataSchemeDto dataSchemeDto, TNode root)
|
||||
where TEntity : IValuesItem
|
||||
{
|
||||
var result = dataSchemeDto.BuildSpecificationByNextNode<TEntity>(root);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ISpecification<TEntity>? BuildSpecificationByNextNode<TEntity>(this DataSchemeDto dataSchemeDto, TNode node)
|
||||
where TEntity : IValuesItem
|
||||
{
|
||||
var visitor = new NodeVisitor<ISpecification<TEntity>?>(
|
||||
dataSchemeDto.VertexProcessing<TEntity>,
|
||||
dataSchemeDto.LeafProcessing<TEntity>
|
||||
);
|
||||
|
||||
var result = node.AcceptVisitor(visitor);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ISpecification<TEntity>? VertexProcessing<TEntity>(this DataSchemeDto dataSchemeDto, TVertex vertex)
|
||||
where TEntity : IValuesItem
|
||||
{
|
||||
var leftSpecification = dataSchemeDto.BuildSpecificationByNextNode<TEntity>(vertex.Left);
|
||||
var rigthSpecification = dataSchemeDto.BuildSpecificationByNextNode<TEntity>(vertex.Rigth);
|
||||
if (leftSpecification is null)
|
||||
return rigthSpecification;
|
||||
if (rigthSpecification is null)
|
||||
return leftSpecification;
|
||||
|
||||
ISpecification<TEntity>? result = null;
|
||||
switch (vertex.Operation)
|
||||
{
|
||||
case OperationEnum.And:
|
||||
result = new AndSpec<TEntity>(leftSpecification, rigthSpecification);
|
||||
break;
|
||||
case OperationEnum.Or:
|
||||
result = new OrSpec<TEntity>(leftSpecification, rigthSpecification);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ISpecification<TEntity>? LeafProcessing<TEntity>(this DataSchemeDto dataSchemeDto, TLeaf leaf)
|
||||
where TEntity : IValuesItem
|
||||
{
|
||||
var schemeProperty = dataSchemeDto.FirstOrDefault(e => e.PropertyName.Equals(leaf.PropName));
|
||||
if (schemeProperty is null)
|
||||
throw new ArgumentException($"Свойство {leaf.PropName} не найдено в схеме данных");
|
||||
|
||||
ISpecification<TEntity>? result = null;
|
||||
switch (schemeProperty.PropertyKind)
|
||||
{
|
||||
case JsonValueKind.String:
|
||||
var stringValue = Convert.ToString(leaf.Value);
|
||||
var stringSpecifications = StringSpecifications<TEntity>();
|
||||
result = stringSpecifications[leaf.Operation](schemeProperty.Index, stringValue);
|
||||
break;
|
||||
case JsonValueKind.Number:
|
||||
var doubleValue = Convert.ToDouble(leaf.Value);
|
||||
var doubleSpecifications = DoubleSpecifications<TEntity>();
|
||||
result = doubleSpecifications[leaf.Operation](schemeProperty.Index, doubleValue);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Dictionary<OperationEnum, Func<int, string?, ISpecification<TEntity>>> StringSpecifications<TEntity>()
|
||||
where TEntity : IValuesItem => new()
|
||||
{
|
||||
{ OperationEnum.Equal, (int index, string? value) => new ValueEqualSpec<TEntity>(index, value) },
|
||||
{ OperationEnum.NotEqual, (int index, string? value) => new ValueNotEqualSpec<TEntity>(index, value) },
|
||||
{ OperationEnum.Greate, (int index, string? value) => new ValueGreateSpec<TEntity>(index, value) },
|
||||
{ OperationEnum.GreateOrEqual, (int index, string? value) => new ValueGreateOrEqualSpec<TEntity>(index, value) },
|
||||
{ OperationEnum.Less, (int index, string? value) => new ValueLessSpec<TEntity>(index, value) },
|
||||
{ OperationEnum.LessOrEqual, (int index, string? value) => new ValueLessOrEqualSpec<TEntity>(index, value) }
|
||||
};
|
||||
private static Dictionary<OperationEnum, Func<int, double?, ISpecification<TEntity>>> DoubleSpecifications<TEntity>()
|
||||
where TEntity : IValuesItem => new()
|
||||
{
|
||||
{ OperationEnum.Equal, (int index, double? value) => new ValueEqualSpec<TEntity>(index, value) },
|
||||
{ OperationEnum.NotEqual, (int index, double? value) => new ValueNotEqualSpec<TEntity>(index, value) },
|
||||
{ OperationEnum.Greate, (int index, double? value) => new ValueGreateSpec<TEntity>(index, value) },
|
||||
{ OperationEnum.GreateOrEqual, (int index, double? value) => new ValueGreateOrEqualSpec<TEntity>(index, value) },
|
||||
{ OperationEnum.Less, (int index, double? value) => new ValueLessSpec<TEntity>(index, value) },
|
||||
{ OperationEnum.LessOrEqual, (int index, double? value) => new ValueLessOrEqualSpec<TEntity>(index, value) }
|
||||
};
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DD.Persistence.Database.Helpers;
|
||||
public class ParameterReplacerVisitor : ExpressionVisitor
|
||||
{
|
||||
private readonly Expression _newExpression;
|
||||
private readonly ParameterExpression _oldParameter;
|
||||
|
||||
private ParameterReplacerVisitor(ParameterExpression oldParameter, Expression newExpression)
|
||||
{
|
||||
_oldParameter = oldParameter;
|
||||
_newExpression = newExpression;
|
||||
}
|
||||
|
||||
internal static Expression Replace(Expression expression, ParameterExpression oldParameter, Expression newExpression)
|
||||
=> new ParameterReplacerVisitor(oldParameter, newExpression).Visit(expression);
|
||||
|
||||
protected override Expression VisitParameter(ParameterExpression p)
|
||||
=> p == _oldParameter ? _newExpression : p;
|
||||
}
|
@ -10,7 +10,7 @@ public class PersistenceDbContext : DbContext
|
||||
{
|
||||
public DbSet<Setpoint> Setpoint => Set<Setpoint>();
|
||||
|
||||
public DbSet<SchemeProperty> SchemeProperty => Set<SchemeProperty>();
|
||||
public DbSet<DataScheme> DataSchemes => Set<DataScheme>();
|
||||
|
||||
public DbSet<TimestampedValues> TimestampedValues => Set<TimestampedValues>();
|
||||
|
||||
@ -30,6 +30,10 @@ public class PersistenceDbContext : DbContext
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<DataScheme>()
|
||||
.Property(e => e.PropNames)
|
||||
.HasJsonConversion();
|
||||
|
||||
modelBuilder.Entity<TimestampedValues>()
|
||||
.Property(e => e.Values)
|
||||
.HasJsonConversion();
|
||||
|
@ -1,43 +0,0 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Repositories;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DD.Persistence.Database.Repositories;
|
||||
public class SchemePropertyRepository : ISchemePropertyRepository
|
||||
{
|
||||
protected DbContext db;
|
||||
public SchemePropertyRepository(DbContext db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
protected IQueryable<SchemeProperty> GetQueryReadOnly() => db.Set<SchemeProperty>();
|
||||
|
||||
public virtual async Task AddRange(DataSchemeDto dataSchemeDto, CancellationToken token)
|
||||
{
|
||||
var entities = dataSchemeDto.Select(e =>
|
||||
KeyValuePair.Create(dataSchemeDto.DiscriminatorId, e)
|
||||
.Adapt<SchemeProperty>()
|
||||
);
|
||||
|
||||
await db.Set<SchemeProperty>().AddRangeAsync(entities, token);
|
||||
await db.SaveChangesAsync(token);
|
||||
}
|
||||
|
||||
public virtual async Task<DataSchemeDto?> Get(Guid dataSchemeId, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.Where(e => e.DiscriminatorId == dataSchemeId);
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
|
||||
DataSchemeDto? result = null;
|
||||
if (entities.Length != 0)
|
||||
{
|
||||
var properties = entities.Select(e => e.Adapt<SchemePropertyDto>()).ToArray();
|
||||
result = new DataSchemeDto(dataSchemeId, properties);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Database.Postgres.Helpers;
|
||||
using DD.Persistence.Filter.Models.Abstractions;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models.Common;
|
||||
using DD.Persistence.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Repositories;
|
||||
public class TimestampedValuesRepository : ITimestampedValuesRepository
|
||||
{
|
||||
private readonly DbContext db;
|
||||
private readonly ISchemePropertyRepository schemePropertyRepository;
|
||||
public TimestampedValuesRepository(DbContext db, ISchemePropertyRepository schemePropertyRepository)
|
||||
{
|
||||
this.db = db;
|
||||
this.schemePropertyRepository = schemePropertyRepository;
|
||||
}
|
||||
|
||||
protected IQueryable<TimestampedValues> GetQueryReadOnly() => db.Set<TimestampedValues>();
|
||||
|
||||
public async Task<int> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token)
|
||||
{
|
||||
var timestampedValuesEntities = dtos.Select(dto => new TimestampedValues()
|
||||
{
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = dto.Timestamp.ToUniversalTime(),
|
||||
Values = dto.Values.Values.ToArray()
|
||||
});
|
||||
|
||||
await db.AddRangeAsync(timestampedValuesEntities, token);
|
||||
|
||||
var result = await db.SaveChangesAsync(token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IDictionary<Guid, IEnumerable<(DateTimeOffset Timestamp, object[] Values)>>> Get(IEnumerable<Guid> discriminatorIds,
|
||||
DateTimeOffset? geTimestamp,
|
||||
TNode? filterTree,
|
||||
IEnumerable<string>? columnNames,
|
||||
int skip,
|
||||
int take,
|
||||
CancellationToken token)
|
||||
{
|
||||
var resultQuery = Array.Empty<TimestampedValues>().AsQueryable();
|
||||
foreach (var discriminatorId in discriminatorIds)
|
||||
{
|
||||
var scheme = await schemePropertyRepository.Get(discriminatorId, token);
|
||||
if (scheme == null)
|
||||
throw new NotSupportedException($"Для переданного дискриминатора {discriminatorId} не была обнаружена схема данных");
|
||||
|
||||
var geTimestampUtc = geTimestamp!.Value.ToUniversalTime();
|
||||
var query = GetQueryReadOnly()
|
||||
.Where(e => e.DiscriminatorId == discriminatorId)
|
||||
.Where(entity => entity.Timestamp >= geTimestampUtc);
|
||||
|
||||
if (filterTree != null)
|
||||
query = query.ApplyFilter(scheme, filterTree);
|
||||
|
||||
resultQuery = resultQuery.Any() ? resultQuery.Union(query) : query;
|
||||
}
|
||||
var groupedQuery = resultQuery!
|
||||
.GroupBy(e => e.DiscriminatorId)
|
||||
.Select(g => KeyValuePair.Create(
|
||||
g.Key,
|
||||
g.OrderBy(i => i.Timestamp).Skip(skip).Take(take))
|
||||
);
|
||||
|
||||
var entities = await groupedQuery.ToArrayAsync(token);
|
||||
var result = entities.ToDictionary(k => k.Key, v => v.Value.Select(e => (
|
||||
e.Timestamp,
|
||||
e.Values
|
||||
)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetFirst(Guid discriminatorId, int takeCount, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.OrderBy(e => e.Timestamp)
|
||||
.Take(takeCount);
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
|
||||
var result = entities.Select(e => (
|
||||
e.Timestamp,
|
||||
e.Values
|
||||
));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetLast(Guid discriminatorId, int takeCount, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.OrderByDescending(e => e.Timestamp)
|
||||
.Take(takeCount);
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
|
||||
var result = entities.Select(e => (
|
||||
e.Timestamp,
|
||||
e.Values
|
||||
));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ToDo: прореживание должно осуществляться до материализации
|
||||
public async Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetResampledData(
|
||||
Guid discriminatorId,
|
||||
DateTimeOffset dateBegin,
|
||||
double intervalSec = 600d,
|
||||
int approxPointsCount = 1024,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var result = await GetGtDate(discriminatorId, dateBegin, token);
|
||||
|
||||
var dateEnd = dateBegin.AddSeconds(intervalSec);
|
||||
result = result
|
||||
.Where(i => i.Item1 <= dateEnd);
|
||||
|
||||
var ratio = result.Count() / approxPointsCount;
|
||||
if (ratio > 1)
|
||||
result = result
|
||||
.Where((_, index) => index % ratio == 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetGtDate(Guid discriminatorId, DateTimeOffset gtTimestamp, CancellationToken token)
|
||||
{
|
||||
var gtTimestampUtc = gtTimestamp.ToUniversalTime();
|
||||
var query = GetQueryReadOnly()
|
||||
.Where(entity => entity.Timestamp > gtTimestampUtc);
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
|
||||
var result = entities.Select(e => (
|
||||
e.Timestamp,
|
||||
e.Values
|
||||
));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<DatesRangeDto?> GetDatesRange(Guid discriminatorId, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.GroupBy(entity => entity.DiscriminatorId)
|
||||
.Select(group => new
|
||||
{
|
||||
Min = group.Min(entity => entity.Timestamp),
|
||||
Max = group.Max(entity => entity.Timestamp),
|
||||
});
|
||||
|
||||
var item = await query.FirstOrDefaultAsync(token);
|
||||
if (item is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var dto = new DatesRangeDto
|
||||
{
|
||||
From = item.Min,
|
||||
To = item.Max,
|
||||
};
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<int> Count(Guid discriminatorId, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.Where(e => e.DiscriminatorId == discriminatorId);
|
||||
|
||||
var result = await query.CountAsync(token);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using Ardalis.Specification;
|
||||
|
||||
namespace DD.Persistence.Database.Specifications.Operation;
|
||||
public class AndSpec<TEntity> : Specification<TEntity>
|
||||
{
|
||||
public AndSpec(ISpecification<TEntity> first, ISpecification<TEntity> second)
|
||||
{
|
||||
if (first is null || second is null)
|
||||
return;
|
||||
|
||||
ApplyCriteria(first);
|
||||
ApplyCriteria(second);
|
||||
}
|
||||
|
||||
private void ApplyCriteria(ISpecification<TEntity> specification)
|
||||
{
|
||||
foreach (var criteria in specification.WhereExpressions)
|
||||
{
|
||||
Query.Where(criteria.Filter);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
using Ardalis.Specification;
|
||||
using DD.Persistence.Database.Postgres.Extensions;
|
||||
|
||||
namespace DD.Persistence.Database.Specifications.Operation;
|
||||
public class OrSpec<TEntity> : Specification<TEntity>
|
||||
{
|
||||
public OrSpec(ISpecification<TEntity> first, ISpecification<TEntity> second)
|
||||
{
|
||||
var orExpression = first.Or(second);
|
||||
if (orExpression == null)
|
||||
return;
|
||||
|
||||
Query.Where(orExpression);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using Ardalis.Specification;
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
|
||||
namespace DD.Persistence.Database.Specifications.ValuesItem;
|
||||
|
||||
/// <summary>
|
||||
/// Спецификация эквивалентности значений IValuesItem в соответствии с индексацией
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class ValueEqualSpec<TEntity> : Specification<TEntity>
|
||||
where TEntity : IValuesItem
|
||||
{
|
||||
public ValueEqualSpec(int index, string? value)
|
||||
{
|
||||
Query.Where(e => Convert.ToString(e.Values[index]) == value);
|
||||
}
|
||||
|
||||
public ValueEqualSpec(int index, double? value)
|
||||
{
|
||||
Query.Where(e => Convert.ToDouble(e.Values[index]) == value);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using Ardalis.Specification;
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
|
||||
namespace DD.Persistence.Database.Specifications.ValuesItem;
|
||||
|
||||
/// <summary>
|
||||
/// Спецификация "больше либо равно" для значений IValuesItem в соответствии с индексацией
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class ValueGreateOrEqualSpec<TEntity> : Specification<TEntity>
|
||||
where TEntity : IValuesItem
|
||||
{
|
||||
public ValueGreateOrEqualSpec(int index, string? value)
|
||||
{
|
||||
Query.Where(e => string.Compare(Convert.ToString(e.Values[index]), value) >= 0);
|
||||
}
|
||||
|
||||
public ValueGreateOrEqualSpec(int index, double? value)
|
||||
{
|
||||
Query.Where(e => Convert.ToDouble(e.Values[index]) >= value);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using Ardalis.Specification;
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
|
||||
namespace DD.Persistence.Database.Specifications.ValuesItem;
|
||||
|
||||
/// <summary>
|
||||
/// Спецификация "больше" для значений IValuesItem в соответствии с индексацией
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class ValueGreateSpec<TEntity> : Specification<TEntity>
|
||||
where TEntity : IValuesItem
|
||||
{
|
||||
public ValueGreateSpec(int index, string? value)
|
||||
{
|
||||
Query.Where(e => string.Compare(Convert.ToString(e.Values[index]), value) > 0);
|
||||
}
|
||||
|
||||
public ValueGreateSpec(int index, double? value)
|
||||
{
|
||||
Query.Where(e => Convert.ToDouble(e.Values[index]) > value);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using Ardalis.Specification;
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
|
||||
namespace DD.Persistence.Database.Specifications.ValuesItem;
|
||||
|
||||
/// <summary>
|
||||
/// Спецификация "меньше либо равно" для значений IValuesItem в соответствии с индексацией
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class ValueLessOrEqualSpec<TEntity> : Specification<TEntity>
|
||||
where TEntity : IValuesItem
|
||||
{
|
||||
public ValueLessOrEqualSpec(int index, string? value)
|
||||
{
|
||||
Query.Where(e => string.Compare(Convert.ToString(e.Values[index]), value) <= 0);
|
||||
}
|
||||
|
||||
public ValueLessOrEqualSpec(int index, double? value)
|
||||
{
|
||||
Query.Where(e => Convert.ToDouble(e.Values[index]) <= value);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using Ardalis.Specification;
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
|
||||
namespace DD.Persistence.Database.Specifications.ValuesItem;
|
||||
|
||||
/// <summary>
|
||||
/// Спецификация "меньше" для значений IValuesItem в соответствии с индексацией
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class ValueLessSpec<TEntity> : Specification<TEntity>
|
||||
where TEntity : IValuesItem
|
||||
{
|
||||
public ValueLessSpec(int index, string? value)
|
||||
{
|
||||
Query.Where(e => string.Compare(Convert.ToString(e.Values[index]), value) < 0);
|
||||
}
|
||||
|
||||
public ValueLessSpec(int index, double? value)
|
||||
{
|
||||
Query.Where(e => Convert.ToDouble(e.Values[index]) < value);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using Ardalis.Specification;
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
|
||||
namespace DD.Persistence.Database.Specifications.ValuesItem;
|
||||
|
||||
/// <summary>
|
||||
/// Спецификация неравенства значений IValuesItem в соответствии с индексацией
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class ValueNotEqualSpec<TEntity> : Specification<TEntity>
|
||||
where TEntity : IValuesItem
|
||||
{
|
||||
public ValueNotEqualSpec(int index, string? value)
|
||||
{
|
||||
Query.Where(e => Convert.ToString(e.Values[index]) != value);
|
||||
}
|
||||
|
||||
public ValueNotEqualSpec(int index, double? value)
|
||||
{
|
||||
Query.Where(e => Convert.ToDouble(e.Values[index]) != value);
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
using DD.Persistence.Models.Configurations;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DD.Persistence.IntegrationTests;
|
||||
|
||||
/// <summary>
|
||||
/// Класс, позволяющий генерировать api-token
|
||||
/// </summary>
|
||||
public static class ApiTokenHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Метод авторизации
|
||||
/// </summary>
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <returns></returns>
|
||||
public static void Authorize(this HttpClient httpClient, IConfiguration configuration)
|
||||
{
|
||||
var authUser = configuration
|
||||
.GetSection(nameof(AuthUser))
|
||||
.Get<AuthUser>()!;
|
||||
|
||||
var jwtToken = authUser.CreateDefaultJwtToken();
|
||||
|
||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Авторизация через собственный jwt-токен
|
||||
/// </summary>
|
||||
/// <param name="authUser"></param>
|
||||
/// <returns></returns>
|
||||
private static string CreateDefaultJwtToken(this AuthUser authUser)
|
||||
{
|
||||
var nameIdetifier = Guid.NewGuid().ToString();
|
||||
var claims = new List<Claim>()
|
||||
{
|
||||
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())
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@ -50,7 +50,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
var insertedCount = 10;
|
||||
var createdResult = CreateChangeLogItems(insertedCount, (-15, 15));
|
||||
var idDiscriminator = createdResult.Item1;
|
||||
var dtos = createdResult.Item2.Select(e => e.Adapt<ChangeLogValuesDto>());
|
||||
var dtos = createdResult.Item2.Select(e => e.Adapt<DataWithWellDepthAndSectionDto>());
|
||||
|
||||
// act
|
||||
var result = await client.ClearAndAddRange(idDiscriminator, dtos, new CancellationToken());
|
||||
@ -102,9 +102,10 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
var result = await client.Add(idDiscriminator, dto, new CancellationToken());
|
||||
|
||||
var entity = dbContext.ChangeLog
|
||||
.Where(x => x.DiscriminatorId == idDiscriminator)
|
||||
.Where(x => x.IdDiscriminator == idDiscriminator)
|
||||
.FirstOrDefault();
|
||||
dto = entity.Adapt<ChangeLogValuesDto>();
|
||||
dto = entity.Adapt<DataWithWellDepthAndSectionDto>();
|
||||
dto.DepthEnd += 10;
|
||||
|
||||
// act
|
||||
result = await client.Update(dto, new CancellationToken());
|
||||
@ -146,9 +147,12 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
dbContext.ChangeLog.AddRange(entities);
|
||||
dbContext.SaveChanges();
|
||||
|
||||
dtos = entities.Select(c => new ChangeLogValuesDto()
|
||||
dtos = entities.Select(c => new DataWithWellDepthAndSectionDto()
|
||||
{
|
||||
DepthEnd = c.DepthEnd + 10,
|
||||
DepthStart = c.DepthStart + 10,
|
||||
Id = c.Id,
|
||||
IdSection = c.IdSection,
|
||||
Value = c.Value
|
||||
}).ToArray();
|
||||
|
||||
@ -239,6 +243,12 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
|
||||
var deletedCount = await client.DeleteRange(idsToDelete, new CancellationToken());
|
||||
|
||||
var filterRequest = new SectionPartRequest()
|
||||
{
|
||||
DepthStart = 0,
|
||||
DepthEnd = 1000,
|
||||
};
|
||||
|
||||
var paginationRequest = new PaginationRequest()
|
||||
{
|
||||
Skip = 0,
|
||||
@ -247,7 +257,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
};
|
||||
|
||||
var moment = DateTimeOffset.UtcNow.AddDays(16);
|
||||
var result = await client.GetByDate(idDiscriminator, moment, paginationRequest, new CancellationToken());
|
||||
var result = await client.GetByDate(idDiscriminator, moment, filterRequest, paginationRequest, new CancellationToken());
|
||||
|
||||
Assert.NotNull(result);
|
||||
|
||||
@ -280,7 +290,11 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
var idDiscriminator = changeLogItems.Item1;
|
||||
var entities = changeLogItems.Item2;
|
||||
|
||||
var dtos = entities.Select(e => e.Adapt<ChangeLogValuesDto>()).ToArray();
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
entity.DepthEnd += 10;
|
||||
}
|
||||
var dtos = entities.Select(e => e.Adapt<DataWithWellDepthAndSectionDto>()).ToArray();
|
||||
await client.UpdateRange(dtos, new CancellationToken());
|
||||
|
||||
//act
|
||||
@ -294,16 +308,19 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
}
|
||||
|
||||
|
||||
private static IEnumerable<ChangeLogValuesDto> Generate(int count)
|
||||
private static IEnumerable<DataWithWellDepthAndSectionDto> Generate(int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
yield return new ChangeLogValuesDto()
|
||||
yield return new DataWithWellDepthAndSectionDto()
|
||||
{
|
||||
Value = new Dictionary<string, object>()
|
||||
{
|
||||
{ "Key", 1 }
|
||||
},
|
||||
Id = Guid.NewGuid()
|
||||
DepthStart = generatorRandomDigits.Next(1, 5),
|
||||
DepthEnd = generatorRandomDigits.Next(5, 15),
|
||||
Id = Guid.NewGuid(),
|
||||
IdSection = Guid.NewGuid()
|
||||
};
|
||||
|
||||
}
|
||||
@ -318,7 +335,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
var entities = dtos.Select(d =>
|
||||
{
|
||||
var entity = d.Adapt<ChangeLog>();
|
||||
entity.DiscriminatorId = idDiscriminator;
|
||||
entity.IdDiscriminator = idDiscriminator;
|
||||
entity.Creation = DateTimeOffset.UtcNow.AddDays(generatorRandomDigits.Next(minDayCount, maxDayCount));
|
||||
|
||||
return entity;
|
||||
|
@ -38,70 +38,53 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Get_returns_BadRequest()
|
||||
public async Task Get_returns_success()
|
||||
{
|
||||
//arrange
|
||||
Cleanup();
|
||||
|
||||
var firstDiscriminatorId = Guid.NewGuid();
|
||||
discriminatorIds.Append(firstDiscriminatorId);
|
||||
var discriminatorId = Guid.NewGuid();
|
||||
discriminatorIds.Append(discriminatorId);
|
||||
|
||||
var secondDiscriminatorId = Guid.NewGuid();
|
||||
discriminatorIds.Append(secondDiscriminatorId);
|
||||
//act
|
||||
var response = await timestampedValuesClient.Get(discriminatorId, null, null, 0, 1, CancellationToken.None);
|
||||
|
||||
try
|
||||
{
|
||||
//act
|
||||
var response = await timestampedValuesClient.Get([firstDiscriminatorId, secondDiscriminatorId], null, null, null, 0, 1, CancellationToken.None);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var expectedMessage = $"На сервере произошла ошибка, в результате которой он не может успешно обработать запрос";
|
||||
|
||||
//assert
|
||||
Assert.Equal(expectedMessage, ex.Message);
|
||||
}
|
||||
//assert
|
||||
Assert.Null(response);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
public async Task Get_AfterSave_returns_success()
|
||||
{
|
||||
//arrange
|
||||
Cleanup();
|
||||
|
||||
var firstDiscriminatorId = Guid.NewGuid();
|
||||
discriminatorIds.Append(firstDiscriminatorId);
|
||||
|
||||
var secondDiscriminatorId = Guid.NewGuid();
|
||||
discriminatorIds.Append(secondDiscriminatorId);
|
||||
var discriminatorId = Guid.NewGuid();
|
||||
discriminatorIds.Append(discriminatorId);
|
||||
|
||||
var timestampBegin = DateTimeOffset.UtcNow.AddDays(-1);
|
||||
var columnNames = new List<string>() { "A", "C" };
|
||||
var skip = 0;
|
||||
var take = 6; // Ровно столько значений будет удовлетворять фильтру (\"A\">3) (для одного дискриминатора)
|
||||
var skip = 5;
|
||||
var take = 5;
|
||||
|
||||
var customFilter = "(\"A\">3)";
|
||||
|
||||
var dtos = (await AddRange(firstDiscriminatorId)).ToList();
|
||||
dtos.AddRange(await AddRange(secondDiscriminatorId));
|
||||
var dtos = await AddRange(discriminatorId);
|
||||
|
||||
//act
|
||||
var response = await timestampedValuesClient.Get([firstDiscriminatorId, secondDiscriminatorId],
|
||||
timestampBegin, customFilter, columnNames, skip, take, CancellationToken.None);
|
||||
var response = await timestampedValuesClient.Get(discriminatorId, timestampBegin, columnNames, skip, take, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
Assert.NotNull(response);
|
||||
Assert.NotEmpty(response);
|
||||
|
||||
var expectedCount = take * 2;
|
||||
var actualCount = response.Count();
|
||||
Assert.Equal(expectedCount, actualCount);
|
||||
Assert.Equal(take, actualCount);
|
||||
|
||||
var actualColumnNames = response.SelectMany(e => e.Values.Keys).Distinct().ToList();
|
||||
Assert.Equal(columnNames, actualColumnNames);
|
||||
|
||||
var expectedValueKind = JsonValueKind.Number;
|
||||
var actualValueKind = ((JsonElement)response.First().Values["A"]).ValueKind;
|
||||
var actualValueKind = ((JsonElement) response.First().Values["A"]).ValueKind;
|
||||
Assert.Equal(expectedValueKind, actualValueKind);
|
||||
|
||||
expectedValueKind = JsonValueKind.String;
|
||||
@ -109,7 +92,6 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest
|
||||
Assert.Equal(expectedValueKind, actualValueKind);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task GetGtDate_returns_success()
|
||||
{
|
||||
@ -276,7 +258,7 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest
|
||||
var count = 2048;
|
||||
var timestampBegin = DateTimeOffset.UtcNow;
|
||||
var dtos = await AddRange(discriminatorId, count);
|
||||
|
||||
|
||||
|
||||
//act
|
||||
var response = await timestampedValuesClient.GetResampledData(discriminatorId, timestampBegin, count);
|
||||
@ -388,7 +370,7 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest
|
||||
var response = await timestampedValuesClient.AddRange(discriminatorId, generatedDtos, CancellationToken.None);
|
||||
|
||||
// assert
|
||||
//Assert.Equal(generatedDtos.Count(), response);
|
||||
Assert.Equal(generatedDtos.Count(), response);
|
||||
|
||||
return generatedDtos;
|
||||
}
|
||||
@ -416,12 +398,8 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
foreach (var item in discriminatorIds)
|
||||
{
|
||||
memoryCache.Remove(item);
|
||||
}
|
||||
discriminatorIds = [];
|
||||
dbContext.CleanupDbSet<TimestampedValues>();
|
||||
dbContext.CleanupDbSet<SchemeProperty>();
|
||||
dbContext.CleanupDbSet<DataScheme>();
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
|
||||
using DD.Persistence.API;
|
||||
using DD.Persistence.Client;
|
||||
using DD.Persistence.Database.Model;
|
||||
using RestSharp;
|
||||
using DD.Persistence.App;
|
||||
using DD.Persistence.Client.Helpers;
|
||||
using DD.Persistence.Factories;
|
||||
|
@ -38,5 +38,5 @@ public class ChangeLogDto
|
||||
/// <summary>
|
||||
/// Объект записи
|
||||
/// </summary>
|
||||
public ChangeLogValuesDto Value { get; set; } = default!;
|
||||
public DataWithWellDepthAndSectionDto Value { get; set; } = default!;
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
namespace DD.Persistence.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Dto для хранения записей, содержащих начальную и конечную глубину забоя, а также секцию
|
||||
/// </summary>
|
||||
public class ChangeLogValuesDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Ключ записи
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Объект записи
|
||||
/// </summary>
|
||||
public required IDictionary<string, object> Value { get; set; }
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace DD.Persistence.Models;
|
||||
namespace DD.Persistence.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Схема для набора данных
|
||||
/// </summary>
|
||||
public class DataSchemeDto : IEnumerable<SchemePropertyDto>, IEquatable<IEnumerable<SchemePropertyDto>>
|
||||
public class DataSchemeDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Дискриминатор
|
||||
@ -13,30 +11,7 @@ public class DataSchemeDto : IEnumerable<SchemePropertyDto>, IEquatable<IEnumera
|
||||
public Guid DiscriminatorId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Поля
|
||||
/// Наименования полей
|
||||
/// </summary>
|
||||
private IEnumerable<SchemePropertyDto> Properties { get; } = [];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DataSchemeDto(Guid discriminatorId, IEnumerable<SchemePropertyDto> Properties)
|
||||
{
|
||||
DiscriminatorId = discriminatorId;
|
||||
this.Properties = Properties;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<SchemePropertyDto> GetEnumerator()
|
||||
=> Properties.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(IEnumerable<SchemePropertyDto>? otherProperties)
|
||||
{
|
||||
if (otherProperties is null)
|
||||
return false;
|
||||
|
||||
return Properties.SequenceEqual(otherProperties);
|
||||
}
|
||||
public string[] PropNames { get; set; } = [];
|
||||
}
|
||||
|
32
DD.Persistence.Models/DataWithWellDepthAndSectionDto.cs
Normal file
32
DD.Persistence.Models/DataWithWellDepthAndSectionDto.cs
Normal file
@ -0,0 +1,32 @@
|
||||
namespace DD.Persistence.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Dto для хранения записей, содержащих начальную и конечную глубину забоя, а также секцию
|
||||
/// </summary>
|
||||
public class DataWithWellDepthAndSectionDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Ключ записи
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Глубина забоя на дату начала интервала
|
||||
/// </summary>
|
||||
public double DepthStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Глубина забоя на дату окончания интервала
|
||||
/// </summary>
|
||||
public double DepthEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ключ секции
|
||||
/// </summary>
|
||||
public Guid IdSection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Объект записи
|
||||
/// </summary>
|
||||
public required IDictionary<string, object> Value { get; set; }
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
namespace DD.Persistence.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Модель, необходимая для отображения истории по журналу изменений
|
||||
/// </summary>
|
||||
public class HistoryChangeLogDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Дата и время изменений
|
||||
/// </summary>
|
||||
public DateTimeOffset DateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Пользователь, совершивший изменение данных
|
||||
/// </summary>
|
||||
public required UserDto User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Проект, с которым связаны изменения
|
||||
/// </summary>
|
||||
public Guid DiscriminatorId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Список изменений
|
||||
/// </summary>
|
||||
public required IEnumerable<ChangeLogDto> ChangeLogItems { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Комментарий к изменению
|
||||
/// </summary>
|
||||
public required string Comment { get; set; }
|
||||
}
|
9
DD.Persistence.Models/IWithSectionPart.cs
Normal file
9
DD.Persistence.Models/IWithSectionPart.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace DD.Persistence.ModelsAbstractions;
|
||||
public interface IWithSectionPart
|
||||
{
|
||||
public double DepthStart { get; set; }
|
||||
|
||||
public double DepthEnd { get; set; }
|
||||
|
||||
public Guid IdSection { get; set; }
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
namespace DD.Persistence.Models.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Запрос, используемый для получения данных по журналу операций
|
||||
/// </summary>
|
||||
public class ChangeLogRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Дискриминатор задачи
|
||||
/// </summary>
|
||||
public Guid DiscriminatorId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Пользователь
|
||||
/// </summary>
|
||||
public Guid UserId { get; set; }
|
||||
}
|
22
DD.Persistence.Models/Requests/SectionPartRequest.cs
Normal file
22
DD.Persistence.Models/Requests/SectionPartRequest.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace DD.Persistence.Models.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Запрос для фильтрации данных по секции и глубине
|
||||
/// </summary>
|
||||
public class SectionPartRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Глубина забоя на дату начала интервала
|
||||
/// </summary>
|
||||
public double? DepthStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Глубина забоя на дату окончания интервала
|
||||
/// </summary>
|
||||
public double? DepthEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ключ секции
|
||||
/// </summary>
|
||||
public Guid? IdSection { get; set; }
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DD.Persistence.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Индексируемого поле из схемы для набора данных
|
||||
/// </summary>
|
||||
public class SchemePropertyDto : IEquatable<SchemePropertyDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Индекс поля
|
||||
/// </summary>
|
||||
public required int Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Наименование индексируемого поля
|
||||
/// </summary>
|
||||
public required string PropertyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Тип индексируемого поля
|
||||
/// </summary>
|
||||
public required JsonValueKind PropertyKind { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(SchemePropertyDto? other)
|
||||
{
|
||||
return Index == other?.Index && PropertyName == other?.PropertyName && PropertyKind == other?.PropertyKind;
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DD.Persistence.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Модель, необходимая для отображения статистики по журналу изменений
|
||||
/// </summary>
|
||||
public class StatisticsChangeLogDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Дата и время изменений
|
||||
/// </summary>
|
||||
public DateTimeOffset DateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Количество изменений
|
||||
/// </summary>
|
||||
public int ChangesCount { get; set; }
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DD.Persistence.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Класс, описывающий пользователя
|
||||
/// </summary>
|
||||
public class UserDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Идентификатор пользователя
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Имя пользователя для отображения
|
||||
/// </summary>
|
||||
public required string DisplayName { get; set; }
|
||||
}
|
@ -20,6 +20,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DD.Persistence.Database.Postgres\DD.Persistence.Database.Postgres.csproj" />
|
||||
<ProjectReference Include="..\DD.Persistence.Repository\DD.Persistence.Repository.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,7 +1,12 @@
|
||||
using DD.Persistence.Database.Model;
|
||||
using DD.Persistence.Database.Postgres.Repositories;
|
||||
using DD.Persistence.Repository.Repositories;
|
||||
using Shouldly;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DD.Persistence.Repository.Test;
|
||||
public class SetpointRepositoryShould : IClassFixture<RepositoryTestFixture>
|
||||
@ -24,6 +29,7 @@ public class SetpointRepositoryShould : IClassFixture<RepositoryTestFixture>
|
||||
var value = GetJsonFromObject(22);
|
||||
await sut.Add(id, value, Guid.NewGuid(), CancellationToken.None);
|
||||
|
||||
var t = fixture.dbContainer.GetConnectionString();
|
||||
//act
|
||||
var result = await sut.GetCurrent([id], CancellationToken.None);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Helpers;
|
||||
namespace DD.Persistence.Repository;
|
||||
/// <summary>
|
||||
/// Цикличный массив
|
||||
/// </summary>
|
19
DD.Persistence.Repository/DD.Persistence.Repository.csproj
Normal file
19
DD.Persistence.Repository/DD.Persistence.Repository.csproj
Normal file
@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||
<PackageReference Include="UuidExtensions" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DD.Persistence.Database\DD.Persistence.Database.csproj" />
|
||||
<ProjectReference Include="..\DD.Persistence\DD.Persistence.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,19 +1,15 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Database.Postgres.Repositories;
|
||||
using DD.Persistence.Database.Postgres.RepositoriesCached;
|
||||
using DD.Persistence.Database.Repositories;
|
||||
using DD.Persistence.Database.RepositoriesCached;
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Repositories;
|
||||
using DD.Persistence.Repository.Repositories;
|
||||
using DD.Persistence.Repository.RepositoriesCached;
|
||||
using Mapster;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DD.Persistence.Database;
|
||||
|
||||
namespace DD.Persistence.Repository;
|
||||
public static class DependencyInjection
|
||||
{
|
||||
// ToDo: перенести в другой файл
|
||||
public static void MapsterSetup()
|
||||
{
|
||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||
@ -21,17 +17,14 @@ public static class DependencyInjection
|
||||
.Ignore(dest => dest.System, dest => dest.SystemId);
|
||||
|
||||
TypeAdapterConfig<ChangeLog, ChangeLogDto>.NewConfig()
|
||||
.Map(dest => dest.Value, src => new ChangeLogValuesDto()
|
||||
.Map(dest => dest.Value, src => new DataWithWellDepthAndSectionDto()
|
||||
{
|
||||
DepthEnd = src.DepthEnd,
|
||||
DepthStart = src.DepthStart,
|
||||
IdSection = src.IdSection,
|
||||
Value = src.Value,
|
||||
Id = src.Id
|
||||
});
|
||||
|
||||
TypeAdapterConfig<KeyValuePair<Guid, SchemePropertyDto>, SchemeProperty>.NewConfig()
|
||||
.Map(dest => dest.DiscriminatorId, src => src.Key)
|
||||
.Map(dest => dest.Index, src => src.Value.Index)
|
||||
.Map(dest => dest.PropertyKind, src => src.Value.PropertyKind)
|
||||
.Map(dest => dest.PropertyName, src => src.Value.PropertyName);
|
||||
}
|
||||
|
||||
public static IServiceCollection AddInfrastructure(this IServiceCollection services)
|
||||
@ -42,15 +35,13 @@ public static class DependencyInjection
|
||||
|
||||
MapsterSetup();
|
||||
|
||||
//services.AddTransient(typeof(PersistenceRepository<TimestampedValues>));
|
||||
|
||||
services.AddTransient<ISetpointRepository, SetpointRepository>();
|
||||
services.AddTransient<IChangeLogRepository, ChangeLogRepository>();
|
||||
services.AddTransient<ITimestampedValuesRepository, TimestampedValuesRepository>();
|
||||
services.AddTransient<ITechMessagesRepository, TechMessagesRepository>();
|
||||
services.AddTransient<IParameterRepository, ParameterRepository>();
|
||||
services.AddTransient<IDataSourceSystemRepository, DataSourceSystemCachedRepository>();
|
||||
services.AddTransient<ISchemePropertyRepository, SchemePropertyCachedRepository>();
|
||||
services.AddTransient<IDataSourceSystemRepository, DataSourceSystemCachedRepository>();
|
||||
services.AddTransient<IDataSchemeRepository, DataSchemeCachedRepository>();
|
||||
|
||||
return services;
|
||||
}
|
@ -2,7 +2,7 @@ using System.Collections.Concurrent;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DD.Persistence.Database.Extensions;
|
||||
namespace DD.Persistence.Repository.Extensions;
|
||||
|
||||
public static class EFExtensionsSortBy
|
||||
{
|
@ -1,16 +1,36 @@
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
using DD.Persistence.Extensions;
|
||||
using DD.Persistence.Models.Common;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using DD.Persistence.Models.Requests;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using DD.Persistence.Models.Common;
|
||||
using DD.Persistence.ModelsAbstractions;
|
||||
using DD.Persistence.Database.EntityAbstractions;
|
||||
using DD.Persistence.Extensions;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Helpers;
|
||||
namespace DD.Persistence.Repository;
|
||||
|
||||
/// <summary>
|
||||
/// класс с набором методов, необходимых для фильтрации записей
|
||||
/// </summary>
|
||||
public static class QueryBuilders
|
||||
{
|
||||
public static IQueryable<TEntity> Apply<TEntity>(this IQueryable<TEntity> query, SectionPartRequest request)
|
||||
where TEntity : class, IWithSectionPart
|
||||
{
|
||||
if (request.IdSection.HasValue)
|
||||
{
|
||||
query = query.Where(e => e.IdSection == request.IdSection);
|
||||
}
|
||||
if (request.DepthStart.HasValue)
|
||||
{
|
||||
query = query.Where(e => e.DepthStart >= request.DepthStart);
|
||||
}
|
||||
if (request.DepthEnd.HasValue)
|
||||
{
|
||||
query = query.Where(e => e.DepthEnd <= request.DepthEnd);
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
public static IQueryable<TEntity> Apply<TEntity>(this IQueryable<TEntity> query, DateTimeOffset momentUtc)
|
||||
where TEntity : class, IChangeLog
|
||||
{
|
||||
@ -23,15 +43,23 @@ public static class QueryBuilders
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
public static async Task<PaginationContainer<TDto>> ApplyPagination<TEntity, TDto>(
|
||||
this IQueryable<TEntity> query,
|
||||
PaginationRequest request,
|
||||
Func<TEntity, TDto> Convert,
|
||||
CancellationToken token)
|
||||
where TEntity : class
|
||||
where TEntity : class, IWithSectionPart
|
||||
where TDto : class
|
||||
{
|
||||
if (!String.IsNullOrEmpty(request.SortSettings))
|
||||
if (String.IsNullOrEmpty(request.SortSettings))
|
||||
{
|
||||
query = query
|
||||
.OrderBy(e => e.IdSection)
|
||||
.ThenBy(e => e.DepthStart)
|
||||
.ThenBy(e => e.DepthEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.SortBy(request.SortSettings);
|
||||
}
|
||||
@ -53,4 +81,4 @@ public static class QueryBuilders
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Database.Postgres.Helpers;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models.Common;
|
||||
using DD.Persistence.Models.Requests;
|
||||
@ -8,7 +7,7 @@ using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using UuidExtensions;
|
||||
|
||||
namespace DD.Persistence.Database.Repositories;
|
||||
namespace DD.Persistence.Repository.Repositories;
|
||||
public class ChangeLogRepository : IChangeLogRepository
|
||||
{
|
||||
private readonly DbContext db;
|
||||
@ -18,7 +17,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public async Task<int> AddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
public async Task<int> AddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
||||
{
|
||||
var entities = new List<ChangeLog>();
|
||||
foreach (var dto in dtos)
|
||||
@ -54,7 +53,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
public async Task<int> MarkAsDeleted(Guid idEditor, Guid idDiscriminator, CancellationToken token)
|
||||
{
|
||||
var query = db.Set<ChangeLog>()
|
||||
.Where(s => s.DiscriminatorId == idDiscriminator)
|
||||
.Where(s => s.IdDiscriminator == idDiscriminator)
|
||||
.Where(e => e.Obsolete == null);
|
||||
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
@ -77,7 +76,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
return await db.SaveChangesAsync(token);
|
||||
}
|
||||
|
||||
public async Task<int> ClearAndAddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
public async Task<int> ClearAndAddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
@ -92,7 +91,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<int> UpdateRange(Guid idEditor, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
public async Task<int> UpdateRange(Guid idEditor, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
||||
{
|
||||
var dbSet = db.Set<ChangeLog>();
|
||||
|
||||
@ -112,7 +111,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
throw new ArgumentException($"Entity with id = {dto.Id} doesn't exist in Db", nameof(dto));
|
||||
}
|
||||
|
||||
var newEntity = CreateEntityFromDto(idEditor, updatedEntity.DiscriminatorId, dto);
|
||||
var newEntity = CreateEntityFromDto(idEditor, updatedEntity.IdDiscriminator, dto);
|
||||
dbSet.Add(newEntity);
|
||||
|
||||
updatedEntity.IdNext = newEntity.Id;
|
||||
@ -128,14 +127,16 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
|
||||
}
|
||||
|
||||
public async Task<PaginationContainer<ChangeLogValuesDto>> GetByDate(
|
||||
public async Task<PaginationContainer<DataWithWellDepthAndSectionDto>> GetByDate(
|
||||
Guid idDiscriminator,
|
||||
DateTimeOffset momentUtc,
|
||||
SectionPartRequest filterRequest,
|
||||
PaginationRequest paginationRequest,
|
||||
CancellationToken token)
|
||||
{
|
||||
var query = CreateQuery(idDiscriminator);
|
||||
query = query.Apply(momentUtc);
|
||||
query = query.Apply(filterRequest);
|
||||
|
||||
var result = await query.ApplyPagination(paginationRequest, Convert, token);
|
||||
|
||||
@ -144,14 +145,14 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
|
||||
private IQueryable<ChangeLog> CreateQuery(Guid idDiscriminator)
|
||||
{
|
||||
var query = db.Set<ChangeLog>().Where(e => e.DiscriminatorId == idDiscriminator);
|
||||
var query = db.Set<ChangeLog>().Where(e => e.IdDiscriminator == idDiscriminator);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ChangeLogDto>> GetChangeLogForInterval(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
|
||||
{
|
||||
var query = db.Set<ChangeLog>().Where(s => s.DiscriminatorId == idDiscriminator);
|
||||
var query = db.Set<ChangeLog>().Where(s => s.IdDiscriminator == idDiscriminator);
|
||||
|
||||
var min = new DateTimeOffset(dateBegin.ToUniversalTime().Date, TimeSpan.Zero);
|
||||
var max = new DateTimeOffset(dateEnd.ToUniversalTime().Date, TimeSpan.Zero);
|
||||
@ -171,7 +172,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
|
||||
public async Task<IEnumerable<DateOnly>> GetDatesChange(Guid idDiscriminator, CancellationToken token)
|
||||
{
|
||||
var query = db.Set<ChangeLog>().Where(e => e.DiscriminatorId == idDiscriminator);
|
||||
var query = db.Set<ChangeLog>().Where(e => e.IdDiscriminator == idDiscriminator);
|
||||
|
||||
var datesCreateQuery = query
|
||||
.Select(e => e.Creation)
|
||||
@ -186,7 +187,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
|
||||
var datesUpdate = await datesUpdateQuery.ToArrayAsync(token);
|
||||
|
||||
var dates = datesCreate.Concat(datesUpdate);
|
||||
var dates = Enumerable.Concat(datesCreate, datesUpdate);
|
||||
var datesOnly = dates
|
||||
.Select(d => new DateOnly(d.Year, d.Month, d.Day))
|
||||
.Distinct()
|
||||
@ -195,27 +196,30 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
return datesOnly;
|
||||
}
|
||||
|
||||
private static ChangeLog CreateEntityFromDto(Guid idAuthor, Guid idDiscriminator, ChangeLogValuesDto dto)
|
||||
private static ChangeLog CreateEntityFromDto(Guid idAuthor, Guid idDiscriminator, DataWithWellDepthAndSectionDto dto)
|
||||
{
|
||||
var entity = new ChangeLog()
|
||||
{
|
||||
Id = Uuid7.Guid(),
|
||||
Creation = DateTimeOffset.UtcNow,
|
||||
IdAuthor = idAuthor,
|
||||
DiscriminatorId = idDiscriminator,
|
||||
IdDiscriminator = idDiscriminator,
|
||||
IdEditor = idAuthor,
|
||||
|
||||
Value = dto.Value
|
||||
Value = dto.Value,
|
||||
IdSection = dto.IdSection,
|
||||
DepthStart = dto.DepthStart,
|
||||
DepthEnd = dto.DepthEnd,
|
||||
};
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ChangeLogValuesDto>> GetGtDate(Guid idDiscriminator, DateTimeOffset dateBegin, CancellationToken token)
|
||||
public async Task<IEnumerable<DataWithWellDepthAndSectionDto>> GetGtDate(Guid idDiscriminator, DateTimeOffset dateBegin, CancellationToken token)
|
||||
{
|
||||
var date = dateBegin.ToUniversalTime();
|
||||
var query = db.Set<ChangeLog>()
|
||||
.Where(e => e.DiscriminatorId == idDiscriminator)
|
||||
var query = this.db.Set<ChangeLog>()
|
||||
.Where(e => e.IdDiscriminator == idDiscriminator)
|
||||
.Where(e => e.Creation >= date || e.Obsolete >= date);
|
||||
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
@ -228,12 +232,12 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
public async Task<DatesRangeDto?> GetDatesRange(Guid idDiscriminator, CancellationToken token)
|
||||
{
|
||||
var query = db.Set<ChangeLog>()
|
||||
.Where(e => e.DiscriminatorId == idDiscriminator)
|
||||
.Where(e => e.IdDiscriminator == idDiscriminator)
|
||||
.GroupBy(e => 1)
|
||||
.Select(group => new
|
||||
{
|
||||
Min = group.Min(e => e.Creation),
|
||||
Max = group.Max(e => e.Obsolete.HasValue && e.Obsolete > e.Creation
|
||||
Max = group.Max(e => (e.Obsolete.HasValue && e.Obsolete > e.Creation)
|
||||
? e.Obsolete.Value
|
||||
: e.Creation),
|
||||
});
|
||||
@ -252,5 +256,5 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
};
|
||||
}
|
||||
|
||||
private ChangeLogValuesDto Convert(ChangeLog entity) => entity.Adapt<ChangeLogValuesDto>();
|
||||
private DataWithWellDepthAndSectionDto Convert(ChangeLog entity) => entity.Adapt<DataWithWellDepthAndSectionDto>();
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Repositories;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DD.Persistence.Repository.Repositories;
|
||||
public class DataSchemeRepository : IDataSchemeRepository
|
||||
{
|
||||
protected DbContext db;
|
||||
public DataSchemeRepository(DbContext db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
protected virtual IQueryable<DataScheme> GetQueryReadOnly() => db.Set<DataScheme>();
|
||||
|
||||
public virtual async Task Add(DataSchemeDto dataSourceSystemDto, CancellationToken token)
|
||||
{
|
||||
var entity = dataSourceSystemDto.Adapt<DataScheme>();
|
||||
|
||||
await db.Set<DataScheme>().AddAsync(entity, token);
|
||||
await db.SaveChangesAsync(token);
|
||||
}
|
||||
|
||||
public virtual async Task<DataSchemeDto?> Get(Guid dataSchemeId, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.Where(e => e.DiscriminatorId == dataSchemeId);
|
||||
var entity = await query.ToArrayAsync();
|
||||
var dto = entity.Select(e => e.Adapt<DataSchemeDto>()).FirstOrDefault();
|
||||
|
||||
return dto;
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ using DD.Persistence.Repositories;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Repositories;
|
||||
namespace DD.Persistence.Repository.Repositories;
|
||||
public class DataSourceSystemRepository : IDataSourceSystemRepository
|
||||
{
|
||||
protected DbContext db;
|
||||
@ -12,7 +12,7 @@ public class DataSourceSystemRepository : IDataSourceSystemRepository
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
protected IQueryable<DataSourceSystem> GetQueryReadOnly() => db.Set<DataSourceSystem>();
|
||||
protected virtual IQueryable<DataSourceSystem> GetQueryReadOnly() => db.Set<DataSourceSystem>();
|
||||
|
||||
public virtual async Task Add(DataSourceSystemDto dataSourceSystemDto, CancellationToken token)
|
||||
{
|
@ -5,7 +5,7 @@ using DD.Persistence.Models;
|
||||
using DD.Persistence.Repositories;
|
||||
using DD.Persistence.Models.Common;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Repositories;
|
||||
namespace DD.Persistence.Repository.Repositories;
|
||||
public class ParameterRepository : IParameterRepository
|
||||
{
|
||||
private DbContext db;
|
||||
@ -15,7 +15,7 @@ public class ParameterRepository : IParameterRepository
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
protected IQueryable<ParameterData> GetQueryReadOnly() => db.Set<ParameterData>();
|
||||
protected virtual IQueryable<ParameterData> GetQueryReadOnly() => db.Set<ParameterData>();
|
||||
|
||||
public async Task<DatesRangeDto> GetDatesRangeAsync(Guid idDiscriminator, CancellationToken token)
|
||||
{
|
@ -6,7 +6,7 @@ using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Repositories
|
||||
namespace DD.Persistence.Repository.Repositories
|
||||
{
|
||||
public class SetpointRepository : ISetpointRepository
|
||||
{
|
||||
@ -16,11 +16,11 @@ namespace DD.Persistence.Database.Postgres.Repositories
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
protected IQueryable<Setpoint> GetQueryReadOnly() => db.Set<Setpoint>();
|
||||
protected virtual IQueryable<Setpoint> GetQueryReadOnly() => db.Set<Setpoint>();
|
||||
|
||||
public async Task<IEnumerable<SetpointValueDto>> GetCurrent(
|
||||
IEnumerable<Guid> setpointKeys,
|
||||
CancellationToken token)
|
||||
IEnumerable<Guid> setpointKeys,
|
||||
CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly();
|
||||
|
@ -7,7 +7,7 @@ using DD.Persistence.Repositories;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.Repositories
|
||||
namespace DD.Persistence.Repository.Repositories
|
||||
{
|
||||
public class TechMessagesRepository : ITechMessagesRepository
|
||||
{
|
||||
@ -20,7 +20,7 @@ namespace DD.Persistence.Database.Postgres.Repositories
|
||||
this.sourceSystemRepository = sourceSystemRepository;
|
||||
}
|
||||
|
||||
protected IQueryable<TechMessage> GetQueryReadOnly() => db.Set<TechMessage>()
|
||||
protected virtual IQueryable<TechMessage> GetQueryReadOnly() => db.Set<TechMessage>()
|
||||
.Include(e => e.System);
|
||||
|
||||
public async Task<PaginationContainer<TechMessageDto>> GetPage(PaginationRequest request, CancellationToken token)
|
@ -0,0 +1,179 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models.Common;
|
||||
using DD.Persistence.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DD.Persistence.Repository.Repositories;
|
||||
public class TimestampedValuesRepository : ITimestampedValuesRepository
|
||||
{
|
||||
private readonly DbContext db;
|
||||
|
||||
public TimestampedValuesRepository(DbContext db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
protected virtual IQueryable<TimestampedValues> GetQueryReadOnly() => this.db.Set<TimestampedValues>();
|
||||
|
||||
public async virtual Task<int> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token)
|
||||
{
|
||||
var timestampedValuesEntities = new List<TimestampedValues>();
|
||||
foreach (var dto in dtos)
|
||||
{
|
||||
var timestampedValuesEntity = new TimestampedValues()
|
||||
{
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = dto.Timestamp.ToUniversalTime(),
|
||||
Values = dto.Values.Values.ToArray()
|
||||
};
|
||||
timestampedValuesEntities.Add(timestampedValuesEntity);
|
||||
}
|
||||
|
||||
await db.Set<TimestampedValues>().AddRangeAsync(timestampedValuesEntities, token);
|
||||
|
||||
var result = await db.SaveChangesAsync(token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> Get(Guid discriminatorId, DateTimeOffset? timestampBegin, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.Where(entity => entity.DiscriminatorId == discriminatorId);
|
||||
|
||||
// Фильтрация по дате
|
||||
if (timestampBegin.HasValue)
|
||||
{
|
||||
query = ApplyGeTimestamp(query, timestampBegin.Value);
|
||||
}
|
||||
|
||||
query = query
|
||||
.OrderBy(item => item.Timestamp)
|
||||
.Skip(skip)
|
||||
.Take(take);
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
|
||||
var result = entities.Select(e => Tuple.Create(
|
||||
e.Timestamp,
|
||||
e.Values
|
||||
));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetFirst(Guid discriminatorId, int takeCount, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.OrderBy(e => e.Timestamp)
|
||||
.Take(takeCount);
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
|
||||
var result = entities.Select(e => Tuple.Create(
|
||||
e.Timestamp,
|
||||
e.Values
|
||||
));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetLast(Guid discriminatorId, int takeCount, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.OrderByDescending(e => e.Timestamp)
|
||||
.Take(takeCount);
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
|
||||
var result = entities.Select(e => Tuple.Create(
|
||||
e.Timestamp,
|
||||
e.Values
|
||||
));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ToDo: прореживание должно осуществляться до материализации
|
||||
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetResampledData(
|
||||
Guid discriminatorId,
|
||||
DateTimeOffset dateBegin,
|
||||
double intervalSec = 600d,
|
||||
int approxPointsCount = 1024,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var result = await GetGtDate(discriminatorId, dateBegin, token);
|
||||
|
||||
var dateEnd = dateBegin.AddSeconds(intervalSec);
|
||||
result = result
|
||||
.Where(i => i.Item1 <= dateEnd);
|
||||
|
||||
var ratio = result.Count() / approxPointsCount;
|
||||
if (ratio > 1)
|
||||
result = result
|
||||
.Where((_, index) => index % ratio == 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.Where(e => e.Timestamp > timestampBegin);
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
|
||||
var result = entities.Select(e => Tuple.Create(
|
||||
e.Timestamp,
|
||||
e.Values
|
||||
));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async virtual Task<DatesRangeDto?> GetDatesRange(Guid discriminatorId, CancellationToken token)
|
||||
{
|
||||
var query = GetQueryReadOnly()
|
||||
.GroupBy(entity => entity.DiscriminatorId)
|
||||
.Select(group => new
|
||||
{
|
||||
Min = group.Min(entity => entity.Timestamp),
|
||||
Max = group.Max(entity => entity.Timestamp),
|
||||
});
|
||||
|
||||
var item = await query.FirstOrDefaultAsync(token);
|
||||
if (item is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var dto = new DatesRangeDto
|
||||
{
|
||||
From = item.Min,
|
||||
To = item.Max,
|
||||
};
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
public virtual Task<int> Count(Guid discriminatorId, CancellationToken token)
|
||||
{
|
||||
var dbSet = db.Set<TimestampedValues>();
|
||||
var query = dbSet.Where(entity => entity.DiscriminatorId == discriminatorId);
|
||||
|
||||
return query.CountAsync(token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Применить фильтр по дате
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="timestampBegin"></param>
|
||||
/// <returns></returns>
|
||||
private IQueryable<TimestampedValues> ApplyGeTimestamp(IQueryable<TimestampedValues> query, DateTimeOffset timestampBegin)
|
||||
{
|
||||
var geTimestampUtc = timestampBegin.ToUniversalTime();
|
||||
|
||||
var result = query
|
||||
.Where(entity => entity.Timestamp >= geTimestampUtc);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,21 +1,21 @@
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Repository.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using DD.Persistence.Database.Repositories;
|
||||
|
||||
namespace DD.Persistence.Database.RepositoriesCached;
|
||||
public class SchemePropertyCachedRepository : SchemePropertyRepository
|
||||
namespace DD.Persistence.Repository.RepositoriesCached;
|
||||
public class DataSchemeCachedRepository : DataSchemeRepository
|
||||
{
|
||||
private readonly IMemoryCache memoryCache;
|
||||
|
||||
public SchemePropertyCachedRepository(DbContext db, IMemoryCache memoryCache) : base(db)
|
||||
public DataSchemeCachedRepository(DbContext db, IMemoryCache memoryCache) : base(db)
|
||||
{
|
||||
this.memoryCache = memoryCache;
|
||||
}
|
||||
|
||||
public override async Task AddRange(DataSchemeDto dataSourceSystemDto, CancellationToken token)
|
||||
public override async Task Add(DataSchemeDto dataSourceSystemDto, CancellationToken token)
|
||||
{
|
||||
await base.AddRange(dataSourceSystemDto, token);
|
||||
await base.Add(dataSourceSystemDto, token);
|
||||
|
||||
memoryCache.Set(dataSourceSystemDto.DiscriminatorId, dataSourceSystemDto);
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Database.Postgres.Repositories;
|
||||
using DD.Persistence.Repository.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace DD.Persistence.Database.Postgres.RepositoriesCached;
|
||||
namespace DD.Persistence.Repository.RepositoriesCached;
|
||||
public class DataSourceSystemCachedRepository : DataSourceSystemRepository
|
||||
{
|
||||
private static readonly string SystemCacheKey = $"{typeof(DataSourceSystem).FullName}CacheKey";
|
@ -0,0 +1,103 @@
|
||||
//using DD.Persistence.Models;
|
||||
//using DD.Persistence.Models.Common;
|
||||
//using DD.Persistence.Repositories;
|
||||
//using Microsoft.EntityFrameworkCore;
|
||||
|
||||
//namespace DD.Persistence.Repository.Repositories;
|
||||
|
||||
//public class TimestampedValuesCachedRepository : TimestampedValuesRepository
|
||||
//{
|
||||
// public static TimestampedValuesDto? FirstByDate { get; private set; }
|
||||
// public static CyclicArray<TimestampedValuesDto> LastData { get; } = new CyclicArray<TimestampedValuesDto>(CacheItemsCount);
|
||||
|
||||
// private const int CacheItemsCount = 3600;
|
||||
|
||||
// public TimestampedValuesCachedRepository(DbContext db, IDataSourceSystemRepository<ValuesIdentityDto> relatedDataRepository) : base(db, relatedDataRepository)
|
||||
// {
|
||||
// //Task.Run(async () =>
|
||||
// //{
|
||||
// // var firstDateItem = await base.GetFirst(CancellationToken.None);
|
||||
// // if (firstDateItem == null)
|
||||
// // {
|
||||
// // return;
|
||||
// // }
|
||||
|
||||
// // FirstByDate = firstDateItem;
|
||||
|
||||
// // var dtos = await base.GetLast(CacheItemsCount, CancellationToken.None);
|
||||
// // dtos = dtos.OrderBy(d => d.Timestamp);
|
||||
// // LastData.AddRange(dtos);
|
||||
// //}).Wait();
|
||||
// }
|
||||
|
||||
// public override async Task<IEnumerable<TimestampedValuesDto>> GetGtDate(Guid discriminatorId, DateTimeOffset dateBegin, CancellationToken token)
|
||||
// {
|
||||
|
||||
// if (LastData.Count == 0 || LastData[0].Timestamp > dateBegin)
|
||||
// {
|
||||
// var dtos = await base.GetGtDate(discriminatorId, dateBegin, token);
|
||||
// return dtos;
|
||||
// }
|
||||
|
||||
// var items = LastData
|
||||
// .Where(i => i.Timestamp >= dateBegin);
|
||||
|
||||
// return items;
|
||||
// }
|
||||
|
||||
// public override async Task<int> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token)
|
||||
// {
|
||||
// var result = await base.AddRange(discriminatorId, dtos, token);
|
||||
// if (result > 0)
|
||||
// {
|
||||
|
||||
// dtos = dtos.OrderBy(x => x.Timestamp);
|
||||
|
||||
// FirstByDate = dtos.First();
|
||||
// LastData.AddRange(dtos);
|
||||
// }
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// public override async Task<DatesRangeDto?> GetDatesRange(Guid discriminatorId, CancellationToken token)
|
||||
// {
|
||||
// if (FirstByDate == null)
|
||||
// return null;
|
||||
|
||||
// return await Task.Run(() =>
|
||||
// {
|
||||
// return new DatesRangeDto
|
||||
// {
|
||||
// From = FirstByDate.Timestamp,
|
||||
// To = LastData[^1].Timestamp
|
||||
// };
|
||||
// });
|
||||
// }
|
||||
|
||||
// public override async Task<IEnumerable<TimestampedValuesDto>> GetResampledData(
|
||||
// Guid discriminatorId,
|
||||
// DateTimeOffset dateBegin,
|
||||
// double intervalSec = 600d,
|
||||
// int approxPointsCount = 1024,
|
||||
// CancellationToken token = default)
|
||||
// {
|
||||
// var dtos = LastData.Where(i => i.Timestamp >= dateBegin);
|
||||
// if (LastData.Count == 0 || LastData[0].Timestamp > dateBegin)
|
||||
// {
|
||||
// dtos = await base.GetGtDate(discriminatorId, dateBegin, token);
|
||||
// }
|
||||
|
||||
// var dateEnd = dateBegin.AddSeconds(intervalSec);
|
||||
// dtos = dtos
|
||||
// .Where(i => i.Timestamp <= dateEnd);
|
||||
|
||||
// var ratio = dtos.Count() / approxPointsCount;
|
||||
// if (ratio > 1)
|
||||
// dtos = dtos
|
||||
// .Where((_, index) => index % ratio == 0);
|
||||
|
||||
// return dtos;
|
||||
// }
|
||||
//}
|
||||
|
@ -16,7 +16,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DD.Persistence.Database.Postgres\DD.Persistence.Database.Postgres.csproj" />
|
||||
<ProjectReference Include="..\DD.Persistence.Database\DD.Persistence.Database.csproj" />
|
||||
<ProjectReference Include="..\DD.Persistence\DD.Persistence.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,278 +0,0 @@
|
||||
using Ardalis.Specification.EntityFrameworkCore;
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Filter.Models;
|
||||
using DD.Persistence.Filter.Models.Enumerations;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Database.Postgres.Helpers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DD.Persistence.Test;
|
||||
|
||||
/// ToDo: переписать под Theory
|
||||
public class FilterBuilderShould
|
||||
{
|
||||
private readonly SpecificationEvaluator SpecificationEvaluator;
|
||||
public FilterBuilderShould()
|
||||
{
|
||||
this.SpecificationEvaluator = new SpecificationEvaluator();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestFilterBuilding()
|
||||
{
|
||||
//arrange
|
||||
var discriminatorId = Guid.NewGuid();
|
||||
var dataSchemeProperties = new SchemePropertyDto[]
|
||||
{
|
||||
new SchemePropertyDto()
|
||||
{
|
||||
Index = 0,
|
||||
PropertyName = "A",
|
||||
PropertyKind = JsonValueKind.String
|
||||
},
|
||||
new SchemePropertyDto()
|
||||
{
|
||||
Index = 1,
|
||||
PropertyName = "B",
|
||||
PropertyKind = JsonValueKind.Number
|
||||
},
|
||||
new SchemePropertyDto()
|
||||
{
|
||||
Index = 2,
|
||||
PropertyName = "C",
|
||||
PropertyKind = JsonValueKind.String
|
||||
}
|
||||
};
|
||||
var dataScheme = new DataSchemeDto(discriminatorId, dataSchemeProperties);
|
||||
var filterDate = DateTime.Now.AddMinutes(-1);
|
||||
var root = new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TVertex(
|
||||
OperationEnum.And,
|
||||
new TLeaf(OperationEnum.Greate, "A", filterDate),
|
||||
new TLeaf(OperationEnum.Less, "B", 2.22)
|
||||
),
|
||||
new TLeaf(OperationEnum.Equal, "C", "IsEqualText")
|
||||
);
|
||||
var queryableData = new[]
|
||||
{
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-1),
|
||||
Values = new object[] { filterDate.AddMinutes(-1), 200, "IsEqualText" } // true
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-2),
|
||||
Values = new object[] { filterDate.AddMinutes(1), 2.21, "IsNotEqualText" } // true
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-3),
|
||||
Values = new object[] { filterDate.AddMinutes(-1), 2.22, "IsNotEqualText" } // false
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-4),
|
||||
Values = new object[] { filterDate.AddMinutes(-1), 2.21, "IsNotEqualText" } // false
|
||||
}
|
||||
}
|
||||
.AsQueryable();
|
||||
|
||||
//act
|
||||
queryableData = queryableData.ApplyFilter(dataScheme, root);
|
||||
|
||||
//assert
|
||||
var result = queryableData.ToList();
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result);
|
||||
|
||||
var expectedCount = 2;
|
||||
var actualCount = result.Count();
|
||||
Assert.Equal(expectedCount, actualCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestFilterOperations()
|
||||
{
|
||||
//arrange
|
||||
var discriminatorId = Guid.NewGuid();
|
||||
var dataSchemeProperties = new SchemePropertyDto[]
|
||||
{
|
||||
new SchemePropertyDto()
|
||||
{
|
||||
Index = 0,
|
||||
PropertyName = "A",
|
||||
PropertyKind = JsonValueKind.Number
|
||||
}
|
||||
};
|
||||
var dataScheme = new DataSchemeDto(discriminatorId, dataSchemeProperties);
|
||||
var root = new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TVertex(
|
||||
OperationEnum.And,
|
||||
new TVertex(
|
||||
OperationEnum.And,
|
||||
new TVertex(
|
||||
OperationEnum.And,
|
||||
new TVertex(
|
||||
OperationEnum.And,
|
||||
new TLeaf(OperationEnum.Less, "A", 2),
|
||||
new TLeaf(OperationEnum.LessOrEqual, "A", 1.99)
|
||||
),
|
||||
new TLeaf(OperationEnum.GreateOrEqual, "A", 1.97)
|
||||
),
|
||||
new TLeaf(OperationEnum.Greate, "A", 1.96)
|
||||
),
|
||||
new TLeaf(OperationEnum.NotEqual, "A", 1.98)
|
||||
),
|
||||
new TLeaf(OperationEnum.Equal, "A", 1)
|
||||
);
|
||||
var queryableData = new[]
|
||||
{
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-1),
|
||||
Values = new object[] { 1 } // true
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-2),
|
||||
Values = new object[] { 1.96 } // false
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-3),
|
||||
Values = new object[] { 1.97 } // true
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-4),
|
||||
Values = new object[] { 1.98 } // false
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-5),
|
||||
Values = new object[] { 1.99 } // true
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-6),
|
||||
Values = new object[] { 2 } // false
|
||||
}
|
||||
}
|
||||
.AsQueryable();
|
||||
|
||||
//act
|
||||
queryableData = queryableData.ApplyFilter(dataScheme, root);
|
||||
|
||||
//assert
|
||||
var result = queryableData.ToList();
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result);
|
||||
|
||||
var expectedCount = 3;
|
||||
var actualCount = result.Count();
|
||||
Assert.Equal(expectedCount, actualCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestFilterValues()
|
||||
{
|
||||
//arrange
|
||||
var discriminatorId = Guid.NewGuid();
|
||||
var filterDate = DateTimeOffset.Now;
|
||||
var dataSchemeProperties = new SchemePropertyDto[]
|
||||
{
|
||||
new SchemePropertyDto()
|
||||
{
|
||||
Index = 0,
|
||||
PropertyName = "A",
|
||||
PropertyKind = JsonValueKind.Number
|
||||
},
|
||||
new SchemePropertyDto()
|
||||
{
|
||||
Index = 1,
|
||||
PropertyName = "B",
|
||||
PropertyKind = JsonValueKind.Number
|
||||
},
|
||||
new SchemePropertyDto()
|
||||
{
|
||||
Index = 2,
|
||||
PropertyName = "C",
|
||||
PropertyKind = JsonValueKind.String
|
||||
},
|
||||
new SchemePropertyDto()
|
||||
{
|
||||
Index = 3,
|
||||
PropertyName = "D",
|
||||
PropertyKind = JsonValueKind.String
|
||||
}
|
||||
};
|
||||
var dataScheme = new DataSchemeDto(discriminatorId, dataSchemeProperties);
|
||||
|
||||
var root = new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TLeaf(OperationEnum.Equal, "A", 1),
|
||||
new TLeaf(OperationEnum.Equal, "B", 1.11)
|
||||
),
|
||||
new TLeaf(OperationEnum.Equal, "C", "IsEqualText")
|
||||
),
|
||||
new TLeaf(OperationEnum.Equal, "D", filterDate)
|
||||
);
|
||||
var queryableData = new[]
|
||||
{
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-1),
|
||||
Values = new object[] { 1, 2.22, "IsNotEqualText", DateTimeOffset.Now.AddMinutes(-1) } // true
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-2),
|
||||
Values = new object[] { 2, 1.11, "IsNotEqualText", DateTimeOffset.Now.AddMinutes(-1) } // true
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-3),
|
||||
Values = new object[] { 2, 2.22, "IsEqualText", DateTimeOffset.Now.AddMinutes(-1) } // true
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-4),
|
||||
Values = new object[] { 2, 2.22, "IsNotEqualText", filterDate } // true
|
||||
},
|
||||
new TimestampedValues {
|
||||
DiscriminatorId = discriminatorId,
|
||||
Timestamp = DateTimeOffset.Now.AddMinutes(-1),
|
||||
Values = new object[] { 2, 2.22, "IsNotEqualText", DateTimeOffset.Now.AddMinutes(-1) } // false
|
||||
}
|
||||
}
|
||||
.AsQueryable();
|
||||
|
||||
//act
|
||||
queryableData = queryableData.ApplyFilter(dataScheme, root);
|
||||
|
||||
//assert
|
||||
var result = queryableData.ToList();
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result);
|
||||
|
||||
var expectedCount = 4;
|
||||
var actualCount = result.Count();
|
||||
Assert.Equal(expectedCount, actualCount);
|
||||
}
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Repositories;
|
||||
using DD.Persistence.Services;
|
||||
using NSubstitute;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DD.Persistence.Test;
|
||||
namespace DD.Persistence.Repository.Test;
|
||||
public class TimestampedValuesServiceShould
|
||||
{
|
||||
private readonly ITimestampedValuesRepository timestampedValuesRepository = Substitute.For<ITimestampedValuesRepository>();
|
||||
private readonly ISchemePropertyRepository dataSchemeRepository = Substitute.For<ISchemePropertyRepository>();
|
||||
private readonly TimestampedValuesService timestampedValuesService;
|
||||
private readonly IDataSchemeRepository dataSchemeRepository = Substitute.For<IDataSchemeRepository>();
|
||||
private TimestampedValuesService timestampedValuesService;
|
||||
|
||||
public TimestampedValuesServiceShould()
|
||||
{
|
||||
@ -19,14 +18,11 @@ public class TimestampedValuesServiceShould
|
||||
[Fact]
|
||||
public async Task TestServiceEfficiency()
|
||||
{
|
||||
var discriminatorIds = new[] { Guid.NewGuid(), Guid.NewGuid() };
|
||||
var discriminatorId = Guid.NewGuid();
|
||||
const int count = 10;
|
||||
var dtos = Generate(count, DateTimeOffset.UtcNow);
|
||||
var addRangeResult = await timestampedValuesService
|
||||
.AddRange(discriminatorIds.First(), dtos, CancellationToken.None);
|
||||
Assert.Equal(0, addRangeResult);
|
||||
addRangeResult = await timestampedValuesService
|
||||
.AddRange(discriminatorIds.Last(), dtos, CancellationToken.None);
|
||||
.AddRange(discriminatorId, dtos, CancellationToken.None);
|
||||
Assert.Equal(0, addRangeResult);
|
||||
|
||||
var columnNames = new[] { "A", "B", "C", "D" };
|
||||
@ -34,21 +30,22 @@ public class TimestampedValuesServiceShould
|
||||
.AddHours(-1)
|
||||
.ToUniversalTime();
|
||||
var getResult = await timestampedValuesService
|
||||
.Get(discriminatorIds, geTimestamp, null, columnNames, 0, count, CancellationToken.None);
|
||||
.Get(discriminatorId, geTimestamp, columnNames, 0, count, CancellationToken.None);
|
||||
Assert.NotNull(getResult);
|
||||
Assert.Empty(getResult);
|
||||
}
|
||||
|
||||
private static IEnumerable<TimestampedValuesDto> Generate(int countToCreate, DateTimeOffset from)
|
||||
{
|
||||
var result = new List<TimestampedValuesDto>();
|
||||
for (int i = 0; i < countToCreate; i++)
|
||||
{
|
||||
var values = new Dictionary<string, object>()
|
||||
{
|
||||
{ "A", GetJsonFromObject(i) },
|
||||
{ "B", GetJsonFromObject(i * 1.1) },
|
||||
{ "C", GetJsonFromObject($"Any{i}") },
|
||||
{ "D", GetJsonFromObject(DateTimeOffset.Now) }
|
||||
{ "A", i },
|
||||
{ "B", i * 1.1 },
|
||||
{ "C", $"Any{i}" },
|
||||
{ "D", DateTimeOffset.Now },
|
||||
};
|
||||
|
||||
yield return new TimestampedValuesDto()
|
||||
@ -58,11 +55,4 @@ public class TimestampedValuesServiceShould
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonElement GetJsonFromObject(object value)
|
||||
{
|
||||
var jsonString = JsonSerializer.Serialize(value);
|
||||
var doc = JsonDocument.Parse(jsonString);
|
||||
return doc.RootElement;
|
||||
}
|
||||
}
|
||||
|
@ -1,107 +0,0 @@
|
||||
using DD.Persistence.Filter.Models;
|
||||
using DD.Persistence.Filter.Models.Enumerations;
|
||||
using DD.Persistence.Filter.TreeBuilder;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace DD.Persistence.Test;
|
||||
public class TreeBuilderTest
|
||||
{
|
||||
[Fact]
|
||||
public void TreeBuildingShouldBuilt()
|
||||
{
|
||||
//arrange
|
||||
var treeString = "(\"A\"==1)||(\"B\"==2)&&(\"C\"==3)||((\"D\"==4)||(\"E\"==5))&&(\"F\"==6)";
|
||||
|
||||
//act
|
||||
var root = treeString.BuildTree();
|
||||
|
||||
//assert
|
||||
Assert.NotNull(root);
|
||||
|
||||
var expectedRoot = JsonConvert.SerializeObject(new TVertex(
|
||||
OperationEnum.And,
|
||||
new TVertex(
|
||||
OperationEnum.And,
|
||||
new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TLeaf(OperationEnum.Equal, "A", 1.0),
|
||||
new TLeaf(OperationEnum.Equal, "B", 2.0)
|
||||
),
|
||||
new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TLeaf(OperationEnum.Equal, "C", 3.0),
|
||||
new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TLeaf(OperationEnum.Equal, "D", 4.0),
|
||||
new TLeaf(OperationEnum.Equal, "E", 5.0)
|
||||
)
|
||||
)
|
||||
),
|
||||
new TLeaf(OperationEnum.Equal, "F", 6.0)
|
||||
));
|
||||
var actualRoot = JsonConvert.SerializeObject(root);
|
||||
Assert.Equal(expectedRoot, actualRoot);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TreeOperationsShouldBuilt()
|
||||
{
|
||||
//arrange
|
||||
var treeString = "(\"A\"==1)||(\"B\"!=1)||(\"C\">1)||(\"D\">=1)||(\"E\"<1)||(\"F\"<=1)";
|
||||
|
||||
//act
|
||||
var root = treeString.BuildTree();
|
||||
|
||||
//assert
|
||||
Assert.NotNull(root);
|
||||
|
||||
var expectedRoot = JsonConvert.SerializeObject(new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TLeaf(OperationEnum.Equal, "A", 1.0),
|
||||
new TLeaf(OperationEnum.NotEqual, "B", 1.0)
|
||||
),
|
||||
new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TLeaf(OperationEnum.Greate, "C", 1.0),
|
||||
new TLeaf(OperationEnum.GreateOrEqual, "D", 1.0)
|
||||
)
|
||||
),
|
||||
new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TLeaf(OperationEnum.Less, "E", 1.0),
|
||||
new TLeaf(OperationEnum.LessOrEqual, "F", 1.0)
|
||||
)
|
||||
));
|
||||
var actualRoot = JsonConvert.SerializeObject(root);
|
||||
Assert.Equal(expectedRoot, actualRoot);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LeafValuesShouldBuilt()
|
||||
{
|
||||
//arrange
|
||||
var treeString = "(\"A\"==1.2345)||(\"B\"==12345)||(\"C\"==\"12345\")";
|
||||
|
||||
//act
|
||||
var root = treeString.BuildTree();
|
||||
|
||||
//assert
|
||||
Assert.NotNull(root);
|
||||
|
||||
var expectedRoot = JsonConvert.SerializeObject(new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TVertex(
|
||||
OperationEnum.Or,
|
||||
new TLeaf(OperationEnum.Equal, "A", 1.2345),
|
||||
new TLeaf(OperationEnum.Equal, "B", 12345.0)
|
||||
),
|
||||
new TLeaf(OperationEnum.Equal, "C", "12345")
|
||||
));
|
||||
var actualRoot = JsonConvert.SerializeObject(root);
|
||||
Assert.Equal(expectedRoot, actualRoot);
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence", "DD.Persis
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.API", "DD.Persistence.API\DD.Persistence.API.csproj", "{8650A227-929E-45F0-AEF7-2C91F45FE884}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.Repository", "DD.Persistence.Repository\DD.Persistence.Repository.csproj", "{493D6D92-231B-4CB6-831B-BE13884B0DE4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.Database", "DD.Persistence.Database\DD.Persistence.Database.csproj", "{F77475D1-D074-407A-9D69-2FADDDAE2056}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.IntegrationTests", "DD.Persistence.IntegrationTests\DD.Persistence.IntegrationTests.csproj", "{10752C25-3773-4081-A1F2-215A1D950126}"
|
||||
@ -28,13 +30,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DD.Persistence.Test", "DD.Persistence.Test\DD.Persistence.Test.csproj", "{B8C774E6-6B75-41AC-B3CF-10BD3623B2FA}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Элементы решения", "Элементы решения", "{E0CEF8FC-C131-4CF3-9F0A-E7B4F895B811}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.gitea\workflows\integrationTests.yaml = .gitea\workflows\integrationTests.yaml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DD.Persistence.Database.Postgres.Test", "DD.Persistence.Database.Postgres.Test\DD.Persistence.Database.Postgres.Test.csproj", "{47142566-9EAB-4FB5-92EC-9DCB02CAC890}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -49,6 +44,10 @@ Global
|
||||
{8650A227-929E-45F0-AEF7-2C91F45FE884}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8650A227-929E-45F0-AEF7-2C91F45FE884}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8650A227-929E-45F0-AEF7-2C91F45FE884}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{493D6D92-231B-4CB6-831B-BE13884B0DE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{493D6D92-231B-4CB6-831B-BE13884B0DE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{493D6D92-231B-4CB6-831B-BE13884B0DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{493D6D92-231B-4CB6-831B-BE13884B0DE4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F77475D1-D074-407A-9D69-2FADDDAE2056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F77475D1-D074-407A-9D69-2FADDDAE2056}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F77475D1-D074-407A-9D69-2FADDDAE2056}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@ -81,10 +80,6 @@ Global
|
||||
{B8C774E6-6B75-41AC-B3CF-10BD3623B2FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B8C774E6-6B75-41AC-B3CF-10BD3623B2FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B8C774E6-6B75-41AC-B3CF-10BD3623B2FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{47142566-9EAB-4FB5-92EC-9DCB02CAC890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{47142566-9EAB-4FB5-92EC-9DCB02CAC890}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{47142566-9EAB-4FB5-92EC-9DCB02CAC890}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{47142566-9EAB-4FB5-92EC-9DCB02CAC890}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -7,7 +7,7 @@ namespace DD.Persistence.API;
|
||||
/// <summary>
|
||||
/// Интерфейс для работы с API журнала изменений
|
||||
/// </summary>
|
||||
public interface IChangeLogApi : ISyncWithDiscriminatorApi<ChangeLogValuesDto>
|
||||
public interface IChangeLogApi : ISyncWithDiscriminatorApi<DataWithWellDepthAndSectionDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Импорт с заменой: удаление старых строк и добавление новых
|
||||
@ -16,26 +16,28 @@ public interface IChangeLogApi : ISyncWithDiscriminatorApi<ChangeLogValuesDto>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<IActionResult> ClearAndAddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных на текущую дату (с пагинацией)
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="filterRequest">параметры запроса фильтрации</param>
|
||||
/// <param name="paginationRequest">параметры запроса пагинации</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> GetCurrent(Guid idDiscriminator, PaginationRequest paginationRequest, CancellationToken token);
|
||||
Task<IActionResult> GetCurrent(Guid idDiscriminator, SectionPartRequest filterRequest, PaginationRequest paginationRequest, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных на определенную дату (с пагинацией)
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="moment"></param>
|
||||
/// <param name="filterRequest">параметры запроса фильтрации</param>
|
||||
/// <param name="paginationRequest">параметры запроса пагинации</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> GetByDate(Guid idDiscriminator, DateTimeOffset moment, PaginationRequest paginationRequest, CancellationToken token);
|
||||
Task<IActionResult> GetByDate(Guid idDiscriminator, DateTimeOffset moment, SectionPartRequest filterRequest, PaginationRequest paginationRequest, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение исторических данных за определенный период времени
|
||||
@ -54,7 +56,7 @@ public interface IChangeLogApi : ISyncWithDiscriminatorApi<ChangeLogValuesDto>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token);
|
||||
Task<IActionResult> Add(Guid idDiscriminator, DataWithWellDepthAndSectionDto dto, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Добавить несколько записей
|
||||
@ -63,7 +65,7 @@ public interface IChangeLogApi : ISyncWithDiscriminatorApi<ChangeLogValuesDto>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<IActionResult> AddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить одну запись
|
||||
@ -71,7 +73,7 @@ public interface IChangeLogApi : ISyncWithDiscriminatorApi<ChangeLogValuesDto>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> Update(ChangeLogValuesDto dto, CancellationToken token);
|
||||
Task<IActionResult> Update(DataWithWellDepthAndSectionDto dto, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить несколько записей
|
||||
@ -79,7 +81,7 @@ public interface IChangeLogApi : ISyncWithDiscriminatorApi<ChangeLogValuesDto>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<IActionResult> UpdateRange(IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить одну запись
|
||||
|
@ -1,9 +1,7 @@
|
||||
namespace DD.Persistence.Extensions;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static class IEnumerableExtensions
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
if (source == null)
|
||||
@ -17,7 +15,6 @@ public static class IEnumerableExtensions
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool IsNullOrEmpty<T>(this IEnumerable<T>? enumerable)
|
||||
{
|
||||
if (enumerable == null)
|
||||
|
@ -1,22 +0,0 @@
|
||||
namespace DD.Persistence.Filter.Models.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Посетитель бинарного дерева
|
||||
/// </summary>
|
||||
/// <typeparam name="TVisitResult"></typeparam>
|
||||
public interface INodeVisitor<TVisitResult>
|
||||
{
|
||||
/// <summary>
|
||||
/// Посетить узел
|
||||
/// </summary>
|
||||
/// <param name="vertex"></param>
|
||||
/// <returns></returns>
|
||||
TVisitResult Visit(TVertex vertex);
|
||||
|
||||
/// <summary>
|
||||
/// Посетить лист
|
||||
/// </summary>
|
||||
/// <param name="leaf"></param>
|
||||
/// <returns></returns>
|
||||
TVisitResult Visit(TLeaf leaf);
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
using DD.Persistence.Filter.Models.Enumerations;
|
||||
using DD.Persistence.Filter.TreeBuilder;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace DD.Persistence.Filter.Models.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Абстрактная модель вершины
|
||||
/// </summary>
|
||||
|
||||
public abstract class TNode : IParsable<TNode?>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public TNode(OperationEnum operation)
|
||||
{
|
||||
Operation = operation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Логическая операция
|
||||
/// </summary>
|
||||
public OperationEnum Operation { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static TNode? Parse(string s, IFormatProvider? provider)
|
||||
{
|
||||
var result = s.BuildTree();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out TNode result)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
result = default(TNode);
|
||||
return false;
|
||||
}
|
||||
|
||||
result = s.BuildTree();
|
||||
if (result is null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Принять посетителя
|
||||
/// </summary>
|
||||
/// <typeparam name="TVisitResult"></typeparam>
|
||||
/// <param name="visitor"></param>
|
||||
/// <returns></returns>
|
||||
public abstract TVisitResult AcceptVisitor<TVisitResult>(INodeVisitor<TVisitResult> visitor);
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
namespace DD.Persistence.Filter.Models.Enumerations;
|
||||
|
||||
/// <summary>
|
||||
/// Логические операции
|
||||
/// </summary>
|
||||
public enum OperationEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// И
|
||||
/// </summary>
|
||||
And = 1,
|
||||
|
||||
/// <summary>
|
||||
/// ИЛИ
|
||||
/// </summary>
|
||||
Or = 2,
|
||||
|
||||
/// <summary>
|
||||
/// РАВНО
|
||||
/// </summary>
|
||||
Equal = 3,
|
||||
|
||||
/// <summary>
|
||||
/// НЕ РАВНО
|
||||
/// </summary>
|
||||
NotEqual = 4,
|
||||
|
||||
/// <summary>
|
||||
/// БОЛЬШЕ
|
||||
/// </summary>
|
||||
Greate = 5,
|
||||
|
||||
/// <summary>
|
||||
/// БОЛЬШЕ ЛИБО РАВНО
|
||||
/// </summary>
|
||||
GreateOrEqual = 6,
|
||||
|
||||
/// <summary>
|
||||
/// МЕНЬШЕ
|
||||
/// </summary>
|
||||
Less = 7,
|
||||
|
||||
/// <summary>
|
||||
/// МЕНЬШЕ ЛИБО РАВНО
|
||||
/// </summary>
|
||||
LessOrEqual = 8
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using DD.Persistence.Filter.Models.Abstractions;
|
||||
using DD.Persistence.Filter.Models.Enumerations;
|
||||
|
||||
namespace DD.Persistence.Filter.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Модель листа
|
||||
/// </summary>
|
||||
public class TLeaf : TNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Наименование поля
|
||||
/// </summary>
|
||||
public string PropName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Значение для фильтрации
|
||||
/// </summary>
|
||||
public object? Value { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TLeaf(OperationEnum operation, string fieldName, object? value) : base(operation)
|
||||
{
|
||||
PropName = fieldName;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override TVisitResult AcceptVisitor<TVisitResult>(INodeVisitor<TVisitResult> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using DD.Persistence.Filter.Models.Abstractions;
|
||||
using DD.Persistence.Filter.Models.Enumerations;
|
||||
|
||||
namespace DD.Persistence.Filter.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Модель узла
|
||||
/// </summary>
|
||||
public class TVertex : TNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Левый потомок
|
||||
/// </summary>
|
||||
public TNode Left { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Правый потомок
|
||||
/// </summary>
|
||||
public TNode Rigth { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TVertex(OperationEnum operation, TNode left, TNode rigth) : base(operation)
|
||||
{
|
||||
Left = left;
|
||||
Rigth = rigth;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override TVisitResult AcceptVisitor<TVisitResult>(INodeVisitor<TVisitResult> visitor)
|
||||
{
|
||||
return visitor.Visit(this);
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
using DD.Persistence.Filter.Models.Enumerations;
|
||||
|
||||
namespace DD.Persistence.Filter.TreeBuilder.Expressions.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейс для выражений
|
||||
/// </summary>
|
||||
interface IExpression
|
||||
{
|
||||
/// <summary>
|
||||
/// Получить логическую операцию
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
OperationEnum GetOperation();
|
||||
|
||||
/// <summary>
|
||||
/// Получить логическую операцию в виде строки (для регулярных выражений)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
string GetOperationString();
|
||||
|
||||
/// <summary>
|
||||
/// Реализация правила
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
void Interpret(InterpreterContext context);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user