forked from ddrilling/AsbCloudServer
Новая реализация парсинга траекторий и фабрики парсеров
This commit is contained in:
parent
108644c13d
commit
94c7e1e7c9
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Requests.Import;
|
using AsbCloudApp.Requests.ParserOptions;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services.Parser;
|
||||||
using AsbCloudInfrastructure.Services.Trajectory.Parser;
|
using AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services;
|
namespace AsbCloudInfrastructure.Services;
|
||||||
@ -12,19 +12,30 @@ public class ParserServiceFactory
|
|||||||
public const int IdTrajectoryFactManualParserService = 1;
|
public const int IdTrajectoryFactManualParserService = 1;
|
||||||
public const int IdTrajectoryPlanParserService = 2;
|
public const int IdTrajectoryPlanParserService = 2;
|
||||||
|
|
||||||
private readonly IDictionary<int, Func<IParserService>> parsers = new Dictionary<int, Func<IParserService>>
|
private readonly IDictionary<int, Func<object>> parsers = new Dictionary<int, Func<object>>
|
||||||
{
|
{
|
||||||
{ IdTrajectoryPlanParserService, () => new TrajectoryPlanParserService() },
|
{ IdTrajectoryPlanParserService, () => new TrajectoryPlanParserService() },
|
||||||
{ IdTrajectoryFactManualParserService, () => new TrajectoryFactManualParserService() }
|
{ IdTrajectoryFactManualParserService, () => new TrajectoryFactManualParserService() }
|
||||||
};
|
};
|
||||||
|
|
||||||
public IParserService<TDto, TOptions> Create<TDto, TOptions>(int idImportService)
|
public IParserService<TDto> GetParser<TDto>(int idParserService)
|
||||||
where TDto : class, IId
|
where TDto : class, IId
|
||||||
where TOptions : ParserOptionsRequestBase
|
|
||||||
{
|
{
|
||||||
var parser = parsers[idImportService].Invoke();
|
if (!parsers.TryGetValue(idParserService, out var parserService))
|
||||||
|
throw new ArgumentNullException(nameof(idParserService), "Сервис не зарегистрирован");
|
||||||
|
|
||||||
return parser as IParserService<TDto, TOptions>
|
return parserService.Invoke() as IParserService<TDto>
|
||||||
?? throw new ArgumentNullException(nameof(idImportService), "Не удалось распознать файл");
|
?? throw new ArgumentNullException(nameof(idParserService), "Ошибка приведения типа");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IParserServiceWithOptions<TDto, TOptions> GetParserWithOptions<TDto, TOptions>(int idParserService)
|
||||||
|
where TDto : class, IId
|
||||||
|
where TOptions : IParserOptionsRequest
|
||||||
|
{
|
||||||
|
if (!parsers.TryGetValue(idParserService, out var parserService))
|
||||||
|
throw new ArgumentNullException(nameof(idParserService), "Сервис не зарегистрирован");
|
||||||
|
|
||||||
|
return parserService.Invoke() as IParserServiceWithOptions<TDto, TOptions>
|
||||||
|
?? throw new ArgumentNullException(nameof(idParserService), "Ошибка приведения типа");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,6 +6,8 @@ namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
|||||||
|
|
||||||
public class TrajectoryFactManualParserService : TrajectoryParserService<TrajectoryGeoFactDto>
|
public class TrajectoryFactManualParserService : TrajectoryParserService<TrajectoryGeoFactDto>
|
||||||
{
|
{
|
||||||
|
protected override string SheetName => "Фактическая траектория";
|
||||||
|
|
||||||
protected override ValidationResultDto<TrajectoryGeoFactDto> ParseRow(IXLRow row)
|
protected override ValidationResultDto<TrajectoryGeoFactDto> ParseRow(IXLRow row)
|
||||||
{
|
{
|
||||||
var trajectoryRow = new TrajectoryGeoFactDto
|
var trajectoryRow = new TrajectoryGeoFactDto
|
||||||
|
@ -1,78 +1,31 @@
|
|||||||
using AsbCloudApp.Data.Trajectory;
|
using AsbCloudApp.Data.Trajectory;
|
||||||
using ClosedXML.Excel;
|
using ClosedXML.Excel;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Requests.Import;
|
using AsbCloudApp.Services.Parser;
|
||||||
using AsbCloudApp.Services;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
||||||
|
|
||||||
public abstract class TrajectoryParserService<T> : IParserService<T, TrajectoryParserRequest>
|
public abstract class TrajectoryParserService<T> : IParserService<T>
|
||||||
where T : TrajectoryGeoDto
|
where T : TrajectoryGeoDto
|
||||||
{
|
{
|
||||||
|
private const int HeaderRowsCount = 2;
|
||||||
|
private const int ColumnCount = 6;
|
||||||
|
|
||||||
|
protected abstract string SheetName { get; }
|
||||||
|
|
||||||
protected abstract ValidationResultDto<T> ParseRow(IXLRow row);
|
protected abstract ValidationResultDto<T> ParseRow(IXLRow row);
|
||||||
|
|
||||||
public ParserResultDto<T> Parse(Stream file, TrajectoryParserRequest options)
|
public ParserResultDto<T> Parse(Stream file)
|
||||||
{
|
{
|
||||||
using var workbook = new XLWorkbook(file, XLEventTracking.Disabled);
|
using var workbook = new XLWorkbook(file, XLEventTracking.Disabled);
|
||||||
var trajectoryRows = ParseFileStream(file, options);
|
|
||||||
|
|
||||||
|
var sheet = workbook.Worksheets.FirstOrDefault(ws =>
|
||||||
|
ws.Name.ToLower().Trim() == SheetName.ToLower().Trim())
|
||||||
|
?? throw new FileFormatException($"Книга excel не содержит листа {SheetName}.");
|
||||||
|
|
||||||
|
var trajectoryRows = sheet.Parse(ParseRow, ColumnCount, HeaderRowsCount);
|
||||||
return trajectoryRows;
|
return trajectoryRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParserResultDto<T> ParseFileStream(Stream stream, TrajectoryParserRequest options)
|
|
||||||
{
|
|
||||||
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
|
||||||
return ParseWorkbook(workbook, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ParserResultDto<T> ParseWorkbook(IXLWorkbook workbook, TrajectoryParserRequest options)
|
|
||||||
{
|
|
||||||
var sheetTrajectory = workbook.Worksheets.FirstOrDefault(ws =>
|
|
||||||
ws.Name.ToLower().Trim() == options.SheetName.ToLower().Trim());
|
|
||||||
if (sheetTrajectory is null)
|
|
||||||
throw new FileFormatException($"Книга excel не содержит листа {options.SheetName}.");
|
|
||||||
var trajectoryRows = ParseSheet(sheetTrajectory, options);
|
|
||||||
return trajectoryRows;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ParserResultDto<T> ParseSheet(IXLWorksheet sheet, TrajectoryParserRequest options)
|
|
||||||
{
|
|
||||||
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 6)
|
|
||||||
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
|
|
||||||
|
|
||||||
var count = sheet.RowsUsed().Count() - options.HeaderRowsCount;
|
|
||||||
|
|
||||||
if (count > 1024)
|
|
||||||
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк.");
|
|
||||||
|
|
||||||
if (count <= 0)
|
|
||||||
throw new FileFormatException($"Лист {sheet.Name} некорректного формата либо пустой");
|
|
||||||
|
|
||||||
var trajectoryRows = new List<ValidationResultDto<T>>(count);
|
|
||||||
var parseErrors = new List<string>();
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
var row = sheet.Row(1 + i + options.HeaderRowsCount);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var trajectoryRow = ParseRow(row);
|
|
||||||
trajectoryRows.Add(trajectoryRow);
|
|
||||||
}
|
|
||||||
catch (FileFormatException ex)
|
|
||||||
{
|
|
||||||
parseErrors.Add(ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parseErrors.Any())
|
|
||||||
throw new FileFormatException(string.Join("\r\n", parseErrors));
|
|
||||||
|
|
||||||
return new ParserResultDto<T>
|
|
||||||
{
|
|
||||||
Item = trajectoryRows
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -6,6 +6,8 @@ namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
|
|||||||
|
|
||||||
public class TrajectoryPlanParserService : TrajectoryParserService<TrajectoryGeoPlanDto>
|
public class TrajectoryPlanParserService : TrajectoryParserService<TrajectoryGeoPlanDto>
|
||||||
{
|
{
|
||||||
|
protected override string SheetName => "Плановая траектория";
|
||||||
|
|
||||||
protected override ValidationResultDto<TrajectoryGeoPlanDto> ParseRow(IXLRow row)
|
protected override ValidationResultDto<TrajectoryGeoPlanDto> ParseRow(IXLRow row)
|
||||||
{
|
{
|
||||||
var trajectoryRow = new TrajectoryGeoPlanDto
|
var trajectoryRow = new TrajectoryGeoPlanDto
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AsbCloudApp.Data.Trajectory;
|
using AsbCloudApp.Data.Trajectory;
|
||||||
using AsbCloudApp.Requests.Import;
|
|
||||||
using AsbCloudInfrastructure.Services;
|
using AsbCloudInfrastructure.Services;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -10,20 +9,6 @@ public class TrajectoryParserTest
|
|||||||
{
|
{
|
||||||
private const string UsingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates";
|
private const string UsingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates";
|
||||||
|
|
||||||
private readonly TrajectoryParserRequest planTrajectoryParserOptions = new()
|
|
||||||
{
|
|
||||||
IdParserService = ParserServiceFactory.IdTrajectoryPlanParserService,
|
|
||||||
SheetName = "Плановая траектория",
|
|
||||||
HeaderRowsCount = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly TrajectoryParserRequest factTrajectoryParserOptions = new()
|
|
||||||
{
|
|
||||||
IdParserService = ParserServiceFactory.IdTrajectoryFactManualParserService,
|
|
||||||
SheetName = "Фактическая траектория",
|
|
||||||
HeaderRowsCount = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly ParserServiceFactory parserServiceFactory = new();
|
private static readonly ParserServiceFactory parserServiceFactory = new();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -35,9 +20,8 @@ public class TrajectoryParserTest
|
|||||||
if (stream is null)
|
if (stream is null)
|
||||||
Assert.Fail("Файла для импорта не существует");
|
Assert.Fail("Файла для импорта не существует");
|
||||||
|
|
||||||
var parserService = parserServiceFactory.Create<TrajectoryGeoPlanDto, TrajectoryParserRequest>(
|
var parserService = parserServiceFactory.GetParser<TrajectoryGeoPlanDto>(ParserServiceFactory.IdTrajectoryPlanParserService);
|
||||||
planTrajectoryParserOptions.IdParserService);
|
var trajectoryRows = parserService.Parse(stream);
|
||||||
var trajectoryRows = parserService.Parse(stream, planTrajectoryParserOptions);
|
|
||||||
|
|
||||||
Assert.Equal(3, trajectoryRows.Item.Count());
|
Assert.Equal(3, trajectoryRows.Item.Count());
|
||||||
}
|
}
|
||||||
@ -51,9 +35,8 @@ public class TrajectoryParserTest
|
|||||||
if (stream is null)
|
if (stream is null)
|
||||||
Assert.Fail("Файла для импорта не существует");
|
Assert.Fail("Файла для импорта не существует");
|
||||||
|
|
||||||
var parserService = parserServiceFactory.Create<TrajectoryGeoFactDto, TrajectoryParserRequest>(
|
var parserService = parserServiceFactory.GetParser<TrajectoryGeoFactDto>(ParserServiceFactory.IdTrajectoryFactManualParserService);
|
||||||
factTrajectoryParserOptions.IdParserService);
|
var trajectoryRows = parserService.Parse(stream);
|
||||||
var trajectoryRows = parserService.Parse(stream, factTrajectoryParserOptions);
|
|
||||||
|
|
||||||
Assert.Equal(4, trajectoryRows.Item.Count());
|
Assert.Equal(4, trajectoryRows.Item.Count());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user