diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 92d305c5..1aaeab0c 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using AsbCloudApp.Data; using AsbCloudApp.Data.DrillTestReport; using AsbCloudApp.Data.Manuals; @@ -46,6 +47,8 @@ using AsbCloudInfrastructure.Services.ProcessMaps; using AsbCloudApp.Data.ProcessMapPlan; using AsbCloudApp.Requests; using AsbCloudInfrastructure.Services.Parser; +using AsbCloudInfrastructure.Services.ProcessMapPlan.Parser; +using AsbCloudInfrastructure.Services.Trajectory.Parser; namespace AsbCloudInfrastructure { @@ -329,8 +332,20 @@ namespace AsbCloudInfrastructure services.AddTransient(); services.AddTransient(); services.AddTransient(); + + + services.AddTransient(serviceProvider => + { + var parsers = new Dictionary> + { + { ParserIds.IdTrajectoryPlanParser, () => new TrajectoryPlanParser(serviceProvider) }, + { ParserIds.IdTrajectoryFactManualParser, () => new TrajectoryFactManualParser(serviceProvider) }, + { ParserIds.IdProcessMapPlanDrillingParser, () => new ProcessMapPlanDrillingParser(serviceProvider) } + }; - services.AddSingleton(); + var factory = new ParserServiceFactory(parsers); + return factory; + }); return services; } diff --git a/AsbCloudInfrastructure/Services/Parser/Cell.cs b/AsbCloudInfrastructure/Services/Parser/Cell.cs new file mode 100644 index 00000000..381ca57b --- /dev/null +++ b/AsbCloudInfrastructure/Services/Parser/Cell.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.IO; +using ClosedXML.Excel; + +namespace AsbCloudInfrastructure.Services.Parser; + +public class Cell +{ + private static IDictionary> converters = new Dictionary>() + { + { typeof(bool), cell => cell.GetBoolean() }, + { typeof(double), cell => cell.GetValue() }, + { typeof(float), cell => cell.GetValue() }, + { typeof(long), cell => cell.GetValue() }, + { typeof(ulong), cell => cell.GetValue() }, + { typeof(int), cell => cell.GetValue() }, + { typeof(uint), cell => cell.GetValue() }, + { typeof(short), cell => cell.GetValue() }, + { typeof(ushort), cell => cell.GetValue() }, + { typeof(string), cell => cell.GetString() }, + + { + typeof(DateTime), cell => + { + if (cell.DataType == XLDataType.DateTime) + return cell.GetDateTime(); + + var stringValue = cell.GetString(); + return DateTime.Parse(stringValue); + } + }, + + { + typeof(DateTimeOffset), cell => + { + var stringValue = cell.GetString(); + return DateTimeOffset.Parse(stringValue); + } + }, + + { + typeof(DateOnly), cell => + { + var stringValue = cell.GetString(); + return DateOnly.Parse(stringValue); + } + }, + + { + typeof(TimeOnly), cell => + { + var stringValue = cell.GetString(); + return TimeOnly.Parse(stringValue); + } + }, + + { + typeof(TimeSpan), cell => + { + if (cell.DataType == XLDataType.TimeSpan) + return cell.GetTimeSpan(); + + var stringValue = cell.GetString(); + return TimeSpan.Parse(stringValue); + } + }, + }; + + private readonly Type type; + + public Cell(int columnNumber, + Type type) + { + ColumnNumber = columnNumber; + this.type = type; + } + + public int ColumnNumber { get; } + + public object? GetValueFromCell(IXLCell cell) + { + try + { + return converters[type].Invoke(cell); + } + catch + { + var message = string.Format(XLExtentions.InvalidValueTemplate, cell.Worksheet.Name, cell.Address.RowNumber, + cell.Address.ColumnNumber); + throw new FileFormatException(message); + } + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/Parser/Data/Cell.cs b/AsbCloudInfrastructure/Services/Parser/Data/Cell.cs deleted file mode 100644 index a70f004e..00000000 --- a/AsbCloudInfrastructure/Services/Parser/Data/Cell.cs +++ /dev/null @@ -1,17 +0,0 @@ -using ClosedXML.Excel; - -namespace AsbCloudInfrastructure.Services.Parser.Data; - -public class Cell -{ - public Cell(int columnNumber, - XLDataType type) - { - ColumnNumber = columnNumber; - Type = type; - } - - public int ColumnNumber { get; } - - public XLDataType Type { get; } -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/Parser/Data/Row.cs b/AsbCloudInfrastructure/Services/Parser/Data/Row.cs deleted file mode 100644 index c66ce1fd..00000000 --- a/AsbCloudInfrastructure/Services/Parser/Data/Row.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; - -namespace AsbCloudInfrastructure.Services.Parser.Data; - -public class Row -{ - public Row(int number, - IDictionary cells) - { - Number = number; - Cells = cells; - } - - public int Number { get; } - - public IDictionary Cells { get; } -} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/Parser/ParserExcelService.cs b/AsbCloudInfrastructure/Services/Parser/ParserExcelService.cs index bb717b56..dabf5d50 100644 --- a/AsbCloudInfrastructure/Services/Parser/ParserExcelService.cs +++ b/AsbCloudInfrastructure/Services/Parser/ParserExcelService.cs @@ -7,7 +7,6 @@ using System.Reflection; using AsbCloudApp.Data; using AsbCloudApp.Requests.ParserOptions; using AsbCloudApp.Services; -using AsbCloudInfrastructure.Services.Parser.Data; using ClosedXML.Excel; using Mapster; @@ -45,27 +44,23 @@ public abstract class ParserExcelService : IParserService ParseRow(IXLRow xlRow) { var cells = Cells.ToDictionary(x => x.Key, x => { var columnNumber = x.Value.ColumnNumber; - var type = x.Value.Type; - var cellValue = xlRow.Cell(columnNumber).GetCellValue(type); - - return (x.Value, cellValue); + var xlCell = xlRow.Cell(columnNumber); + var cellValue = x.Value.GetValueFromCell(xlCell); + return cellValue; }); - var row = new Row(xlRow.RowNumber(), cells); - - return row; + return cells; } - protected virtual TDto BuildDto(Row row) + protected virtual TDto BuildDto(IDictionary row, int rowNumber) { - var propertiesDict = row.Cells.ToDictionary(x => x.Key, x => x.Value.CellValue); - - return propertiesDict.Adapt(); + var dto = row.Adapt(); + return dto; } private ValidationResultDto Validate(TDto dto, int rowNumber) @@ -118,12 +113,13 @@ public abstract class ParserExcelService : IParserService> parsers; - private readonly IServiceScope serviceScope; - public ParserServiceFactory(IServiceProvider serviceProvider) + public ParserServiceFactory(IDictionary> parsers) { - serviceScope = serviceProvider.CreateScope(); - - parsers = new Dictionary> - { - { IdTrajectoryPlanParser, () => new TrajectoryPlanParser(serviceScope.ServiceProvider) }, - { IdTrajectoryFactManualParser, () => new TrajectoryFactManualParser(serviceScope.ServiceProvider) }, - { IdProcessMapPlanDrillingParser, () => new ProcessMapPlanDrillingParser(serviceScope.ServiceProvider) } - }; + this.parsers = parsers; } public IParserService Create(int idParserService) @@ -40,9 +25,4 @@ public class ParserServiceFactory : IDisposable return parserService.Invoke() as IParserService ?? throw new ArgumentNullException(nameof(idParserService), "Ошибка приведения типа"); } - - public void Dispose() - { - serviceScope.Dispose(); - } } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanDrillingParser.cs b/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanDrillingParser.cs index 6af94311..e0073bee 100644 --- a/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanDrillingParser.cs +++ b/AsbCloudInfrastructure/Services/ProcessMapPlan/Parser/ProcessMapPlanDrillingParser.cs @@ -5,8 +5,7 @@ using System.Linq; using AsbCloudApp.Data; using AsbCloudApp.Data.ProcessMapPlan; using AsbCloudApp.Repositories; -using AsbCloudInfrastructure.Services.Parser.Data; -using ClosedXML.Excel; +using AsbCloudInfrastructure.Services.Parser; using Microsoft.Extensions.DependencyInjection; namespace AsbCloudInfrastructure.Services.ProcessMapPlan.Parser; @@ -31,36 +30,36 @@ public class ProcessMapPlanDrillingParser : ProcessMapPlanParser Cells => new Dictionary { - { nameof(ProcessMapPlanDrillingDto.Section), new Cell(ColumnSection, XLDataType.Text) }, - { nameof(ProcessMapPlanDrillingDto.Mode), new Cell(ColumnMode, XLDataType.Text) }, - { nameof(ProcessMapPlanDrillingDto.DepthStart), new Cell(3, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.DepthEnd), new Cell(4, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.DeltaPressurePlan), new Cell(5, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.DeltaPressureLimitMax), new Cell(6, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.AxialLoadPlan), new Cell(7, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.AxialLoadLimitMax), new Cell(8, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.TopDriveTorquePlan), new Cell(9, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.TopDriveTorqueLimitMax), new Cell(10, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.TopDriveSpeedPlan), new Cell(11, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.TopDriveSpeedLimitMax), new Cell(12, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.FlowPlan), new Cell(13, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.FlowLimitMax), new Cell(14, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.RopPlan), new Cell(15, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.UsageSaub), new Cell(16, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.UsageSpin), new Cell(17, XLDataType.Number) }, - { nameof(ProcessMapPlanDrillingDto.Comment), new Cell(18, XLDataType.Text) } + { nameof(ProcessMapPlanDrillingDto.Section), new Cell(ColumnSection, typeof(string)) }, + { nameof(ProcessMapPlanDrillingDto.Mode), new Cell(ColumnMode, typeof(string)) }, + { nameof(ProcessMapPlanDrillingDto.DepthStart), new Cell(3, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.DepthEnd), new Cell(4, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.DeltaPressurePlan), new Cell(5, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.DeltaPressureLimitMax), new Cell(6, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.AxialLoadPlan), new Cell(7, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.AxialLoadLimitMax), new Cell(8, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.TopDriveTorquePlan), new Cell(9, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.TopDriveTorqueLimitMax), new Cell(10, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.TopDriveSpeedPlan), new Cell(11, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.TopDriveSpeedLimitMax), new Cell(12, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.FlowPlan), new Cell(13, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.FlowLimitMax), new Cell(14, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.RopPlan), new Cell(15, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.UsageSaub), new Cell(16, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.UsageSpin), new Cell(17, typeof(double)) }, + { nameof(ProcessMapPlanDrillingDto.Comment), new Cell(18, typeof(string)) } }; - protected override ProcessMapPlanDrillingDto BuildDto(Row row) + protected override ProcessMapPlanDrillingDto BuildDto(IDictionary row, int rowNumber) { - var dto = base.BuildDto(row); + var dto = base.BuildDto(row, rowNumber); var section = sections.FirstOrDefault(s => string.Equals(s.Caption.Trim(), dto.Section?.Trim(), StringComparison.CurrentCultureIgnoreCase)); if (section is null) { - var message = string.Format(XLExtentions.ProblemDetailsTemplate, SheetName, row.Number, ColumnSection, + var message = string.Format(XLExtentions.ProblemDetailsTemplate, SheetName, rowNumber, ColumnSection, "Указана некорректная секция"); throw new FileFormatException(message); } @@ -69,7 +68,7 @@ public class ProcessMapPlanDrillingParser : ProcessMapPlanParser "TrajectoryFactManualTemplate.xlsx"; - protected override IDictionary Cells => new Dictionary() + protected override IDictionary Cells => new Dictionary { - { nameof(TrajectoryGeoFactDto.WellboreDepth), new Cell(1, XLDataType.Number) }, - { nameof(TrajectoryGeoFactDto.ZenithAngle), new Cell(2, XLDataType.Number) }, - { nameof(TrajectoryGeoFactDto.AzimuthGeo), new Cell(3, XLDataType.Number) }, - { nameof(TrajectoryGeoFactDto.AzimuthMagnetic), new Cell(4, XLDataType.Number) }, - { nameof(TrajectoryGeoFactDto.VerticalDepth), new Cell(5, XLDataType.Number) }, - { nameof(TrajectoryGeoFactDto.Comment), new Cell(6, XLDataType.Text) } + { nameof(TrajectoryGeoFactDto.WellboreDepth), new Cell(1, typeof(double)) }, + { nameof(TrajectoryGeoFactDto.ZenithAngle), new Cell(2, typeof(double)) }, + { nameof(TrajectoryGeoFactDto.AzimuthGeo), new Cell(3, typeof(double)) }, + { nameof(TrajectoryGeoFactDto.AzimuthMagnetic), new Cell(4, typeof(double)) }, + { nameof(TrajectoryGeoFactDto.VerticalDepth), new Cell(5, typeof(double)) }, + { nameof(TrajectoryGeoFactDto.Comment), new Cell(6, typeof(string)) } }; } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParser.cs b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParser.cs index 99ec5ae6..b7a03696 100644 --- a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParser.cs +++ b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParser.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; using AsbCloudApp.Data.Trajectory; using AsbCloudApp.Requests.ParserOptions; using AsbCloudInfrastructure.Services.Parser; -using AsbCloudInfrastructure.Services.Parser.Data; -using ClosedXML.Excel; namespace AsbCloudInfrastructure.Services.Trajectory.Parser; @@ -23,12 +21,12 @@ public class TrajectoryPlanParser : ParserExcelService Cells => new Dictionary { - { nameof(TrajectoryGeoPlanDto.WellboreDepth), new Cell(1, XLDataType.Number) }, - { nameof(TrajectoryGeoPlanDto.ZenithAngle), new Cell(2, XLDataType.Number) }, - { nameof(TrajectoryGeoPlanDto.AzimuthGeo), new Cell(3, XLDataType.Number) }, - { nameof(TrajectoryGeoPlanDto.AzimuthMagnetic), new Cell(4, XLDataType.Number) }, - { nameof(TrajectoryGeoPlanDto.VerticalDepth), new Cell(5, XLDataType.Number) }, - { nameof(TrajectoryGeoPlanDto.Radius), new Cell(6, XLDataType.Number) }, - { nameof(TrajectoryGeoPlanDto.Comment), new Cell(7, XLDataType.Text) } + { nameof(TrajectoryGeoPlanDto.WellboreDepth), new Cell(1, typeof(double)) }, + { nameof(TrajectoryGeoPlanDto.ZenithAngle), new Cell(2, typeof(double)) }, + { nameof(TrajectoryGeoPlanDto.AzimuthGeo), new Cell(3, typeof(double)) }, + { nameof(TrajectoryGeoPlanDto.AzimuthMagnetic), new Cell(4, typeof(double)) }, + { nameof(TrajectoryGeoPlanDto.VerticalDepth), new Cell(5, typeof(double)) }, + { nameof(TrajectoryGeoPlanDto.Radius), new Cell(6, typeof(double)) }, + { nameof(TrajectoryGeoPlanDto.Comment), new Cell(7, typeof(string)) } }; } \ No newline at end of file diff --git a/AsbCloudInfrastructure/XLExtentions.cs b/AsbCloudInfrastructure/XLExtentions.cs index 481ea891..927c90a8 100644 --- a/AsbCloudInfrastructure/XLExtentions.cs +++ b/AsbCloudInfrastructure/XLExtentions.cs @@ -8,9 +8,7 @@ namespace AsbCloudInfrastructure; public static class XLExtentions { public const string ProblemDetailsTemplate = "Лист: {0}, Строка: {1}, Столбец: {2}. {3}"; - public const string NotFoundSheetTemplate = "Книга excel не содержит листа {0}"; - public const string InvalidValueTemplate = "Лист: {0}, Строка: {1}, Столбец: {2}. Содержит некорректное значение"; public static IXLWorksheet GetWorksheet(this IXLWorkbook workbook, string sheetName) => @@ -34,29 +32,6 @@ public static class XLExtentions return cell; } - public static object? GetCellValue(this IXLCell cell, XLDataType type) - { - try - { - return type switch - { - XLDataType.Blank => null, - XLDataType.Boolean => cell.Value.GetBoolean(), - XLDataType.Number => cell.Value.GetNumber(), - XLDataType.Text => cell.Value.GetText(), - XLDataType.Error => cell.Value.GetError(), - XLDataType.DateTime => cell.Value.GetDateTime(), - XLDataType.TimeSpan => cell.Value.GetTimeSpan(), - _ => throw new InvalidCastException() - }; - } - catch - { - var message = string.Format(InvalidValueTemplate, cell.Worksheet.Name, cell.Address.RowNumber, cell.Address.ColumnNumber); - throw new FileFormatException(message); - } - } - public static T? GetCellValue(this IXLCell cell) { try diff --git a/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs b/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs index 9e2ebd7e..dcda8a58 100644 --- a/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs +++ b/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs @@ -1,10 +1,7 @@ -using System; -using System.Linq; +using System.Linq; using AsbCloudApp.Data.Trajectory; using AsbCloudApp.Requests.ParserOptions; using AsbCloudInfrastructure.Services.Parser; -using Microsoft.Extensions.DependencyInjection; -using NSubstitute; using Xunit; namespace AsbCloudWebApi.Tests.Services.Trajectory; @@ -12,21 +9,9 @@ namespace AsbCloudWebApi.Tests.Services.Trajectory; public class TrajectoryParserTest { private const string UsingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates"; - - private readonly IServiceProvider serviceProviderMock = Substitute.For(); - private readonly IServiceScope serviceScopeMock = Substitute.For(); - private readonly IServiceScopeFactory serviceScopeFactoryMock = Substitute.For(); private readonly ParserServiceFactory parserServiceFactory; - public TrajectoryParserTest() - { - serviceScopeFactoryMock.CreateScope().Returns(serviceScopeMock); - ((ISupportRequiredService)serviceProviderMock).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactoryMock); - - parserServiceFactory = new ParserServiceFactory(serviceProviderMock); - } - [Fact] public void Parse_trajectory_plan() { @@ -37,7 +22,7 @@ public class TrajectoryParserTest Assert.Fail("Файла для импорта не существует"); var parserService = parserServiceFactory.Create( - ParserServiceFactory.IdTrajectoryPlanParser); + ParserIds.IdTrajectoryPlanParser); var trajectoryRows = parserService.Parse(stream, IParserOptionsRequest.Empty()); @@ -54,7 +39,7 @@ public class TrajectoryParserTest Assert.Fail("Файла для импорта не существует"); var parserService = parserServiceFactory.Create( - ParserServiceFactory.IdTrajectoryFactManualParser); + ParserIds.IdTrajectoryFactManualParser); var trajectoryRows = parserService.Parse(stream, IParserOptionsRequest.Empty()); diff --git a/AsbCloudWebApi/Controllers/ProcessMapPlan/ProcessMapPlanDrillingController.cs b/AsbCloudWebApi/Controllers/ProcessMapPlan/ProcessMapPlanDrillingController.cs index 9e9a7175..ed2e9b35 100644 --- a/AsbCloudWebApi/Controllers/ProcessMapPlan/ProcessMapPlanDrillingController.cs +++ b/AsbCloudWebApi/Controllers/ProcessMapPlan/ProcessMapPlanDrillingController.cs @@ -11,7 +11,7 @@ public class ProcessMapPlanDrillingController : ProcessMapPlanBaseController repository, IWellService wellService, ParserServiceFactory parserFactory) - : base(repository, wellService, parserFactory, ParserServiceFactory.IdProcessMapPlanDrillingParser) + : base(repository, wellService, parserFactory, ParserIds.IdProcessMapPlanDrillingParser) { } diff --git a/AsbCloudWebApi/Controllers/Trajectory/TrajectoryFactManualController.cs b/AsbCloudWebApi/Controllers/Trajectory/TrajectoryFactManualController.cs index 2bc3c769..2317c1ff 100644 --- a/AsbCloudWebApi/Controllers/Trajectory/TrajectoryFactManualController.cs +++ b/AsbCloudWebApi/Controllers/Trajectory/TrajectoryFactManualController.cs @@ -1,6 +1,7 @@ using AsbCloudApp.Data.Trajectory; using AsbCloudApp.Repositories; using AsbCloudApp.Services; +using AsbCloudInfrastructure; using AsbCloudInfrastructure.Services.Parser; using AsbCloudInfrastructure.Services.Trajectory.Export; using Microsoft.AspNetCore.Mvc; @@ -24,7 +25,7 @@ public class TrajectoryFactManualController : TrajectoryEditableController