From 82650b1cfb402ade60e1cd17041b8af8efcf5af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Mon, 29 Jan 2024 15:03:53 +0500 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D1=8B=20?= =?UTF-8?q?=D0=BF=D0=B0=D1=80=D1=81=D0=B8=D0=BD=D0=B3=D0=B0=20=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=B5=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Сделан рефакторинг сервисов парсинга траекторий 2. Добавлена фабрика создания парсеров 3. Рефакторинг тестов --- AsbCloudInfrastructure/DependencyInjection.cs | 4 +- .../Services/ParserServiceFactory.cs | 30 +++++++ .../TrajectoryFactManualParserService.cs | 30 ------- .../Import/TrajectoryParserService.cs | 78 ------------------- .../Import/TrajectoryPlanParserService.cs | 33 -------- .../TrajectoryFactManualParserService.cs | 28 +++++++ .../Parser/TrajectoryParserService.cs | 78 +++++++++++++++++++ .../Parser/TrajectoryPlanParserService.cs | 29 +++++++ .../Trajectory/TrajectoryImportTest.cs | 48 ------------ .../Trajectory/TrajectoryParserTest.cs | 60 ++++++++++++++ 10 files changed, 228 insertions(+), 190 deletions(-) create mode 100644 AsbCloudInfrastructure/Services/ParserServiceFactory.cs delete mode 100644 AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryFactManualParserService.cs delete mode 100644 AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryParserService.cs delete mode 100644 AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryPlanParserService.cs create mode 100644 AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParserService.cs create mode 100644 AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParserService.cs create mode 100644 AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParserService.cs delete mode 100644 AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryImportTest.cs create mode 100644 AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 0e88a972..eec917a7 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -30,7 +30,6 @@ using AsbCloudInfrastructure.Services.SAUB; using AsbCloudInfrastructure.Services.Subsystems; using AsbCloudInfrastructure.Services.Trajectory; using AsbCloudInfrastructure.Services.Trajectory.Export; -using AsbCloudInfrastructure.Services.Trajectory.Import; using AsbCloudInfrastructure.Services.WellOperationImport; using AsbCloudInfrastructure.Services.WellOperationImport.FileParser; using AsbCloudInfrastructure.Services.WellOperationService; @@ -45,6 +44,7 @@ using AsbCloudDb.Model.DailyReports.Blocks.TimeBalance; using AsbCloudDb.Model.WellSections; using AsbCloudInfrastructure.Services.ProcessMaps; using AsbCloudApp.Data.ProcessMapPlan; +using AsbCloudInfrastructure.Services.Trajectory.Parser; namespace AsbCloudInfrastructure { @@ -325,6 +325,8 @@ namespace AsbCloudInfrastructure services.AddTransient, ProcessMapPlanService>(); services.AddTransient(); + + services.AddSingleton(); return services; } diff --git a/AsbCloudInfrastructure/Services/ParserServiceFactory.cs b/AsbCloudInfrastructure/Services/ParserServiceFactory.cs new file mode 100644 index 00000000..17f3ed23 --- /dev/null +++ b/AsbCloudInfrastructure/Services/ParserServiceFactory.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using AsbCloudApp.Data; +using AsbCloudApp.Requests.Import; +using AsbCloudApp.Services; +using AsbCloudInfrastructure.Services.Trajectory.Parser; + +namespace AsbCloudInfrastructure.Services; + +public class ParserServiceFactory +{ + public const int IdTrajectoryFactManualParserService = 1; + public const int IdTrajectoryPlanParserService = 2; + + private readonly IDictionary> parsers = new Dictionary> + { + { IdTrajectoryPlanParserService, () => new TrajectoryPlanParserService() }, + { IdTrajectoryFactManualParserService, () => new TrajectoryFactManualParserService() } + }; + + public IParserService Create(int idImportService) + where TDto : class, IId + where TOptions : ParserOptionsRequestBase + { + var parser = parsers[idImportService].Invoke(); + + return parser as IParserService + ?? throw new ArgumentNullException(nameof(idImportService), "Не удалось распознать файл"); + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryFactManualParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryFactManualParserService.cs deleted file mode 100644 index be08e12e..00000000 --- a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryFactManualParserService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using AsbCloudApp.Data.Trajectory; -using ClosedXML.Excel; - -namespace AsbCloudInfrastructure.Services.Trajectory.Import -{ - - public class TrajectoryFactManualParserService : TrajectoryParserService - { - public override string templateFileName { get; } = "TrajectoryFactManualTemplate.xlsx"; - public override string usingTemplateFile { get; } = "AsbCloudInfrastructure.Services.Trajectory.Templates"; - public override string sheetName { get; } = "Фактическая траектория"; - public override int headerRowsCount { get; } = 2; - - protected override TrajectoryGeoFactDto ParseRow(IXLRow row) - { - var trajectoryRow = new TrajectoryGeoFactDto - { - WellboreDepth = row.Cell(1).GetCellValue(), - ZenithAngle = row.Cell(2).GetCellValue(), - AzimuthGeo = row.Cell(3).GetCellValue(), - AzimuthMagnetic = row.Cell(4).GetCellValue(), - VerticalDepth = row.Cell(5).GetCellValue(), - Comment = row.Cell(6).GetCellValue() - }; - //TODO: Добавить валидацию модели IValidatableObject - return trajectoryRow; - } - } -} - diff --git a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryParserService.cs deleted file mode 100644 index c67bc409..00000000 --- a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryParserService.cs +++ /dev/null @@ -1,78 +0,0 @@ -using AsbCloudApp.Data.Trajectory; -using ClosedXML.Excel; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace AsbCloudInfrastructure.Services.Trajectory.Import -{ - public abstract class TrajectoryParserService - where T : TrajectoryGeoDto - { - public abstract string templateFileName { get; } - public abstract string usingTemplateFile { get; } - public abstract string sheetName { get; } - public abstract int headerRowsCount { get; } - - protected abstract T ParseRow(IXLRow row); - - public IEnumerable Import(Stream stream) - { - using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); - var trajectoryRows = ParseFileStream(stream); - - return trajectoryRows; - } - - - private IEnumerable ParseFileStream(Stream stream) - { - using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); - return ParseWorkbook(workbook); - } - - private IEnumerable ParseWorkbook(IXLWorkbook workbook) - { - var sheetTrajectory = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetName); - if (sheetTrajectory is null) - throw new FileFormatException($"Книга excel не содержит листа {sheetName}."); - var trajectoryRows = ParseSheet(sheetTrajectory); - return trajectoryRows; - } - - private IEnumerable ParseSheet(IXLWorksheet sheet) - { - if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 6) - throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов."); - - var count = sheet.RowsUsed().Count() - headerRowsCount; - - if (count > 1024) - throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк."); - - if (count <= 0) - throw new FileFormatException($"Лист {sheet.Name} некорректного формата либо пустой"); - - var trajectoryRows = new List(count); - var parseErrors = new List(); - for (int i = 0; i < count; i++) - { - var row = sheet.Row(1 + i + 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 trajectoryRows; - } - } -} diff --git a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryPlanParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryPlanParserService.cs deleted file mode 100644 index 00f3f197..00000000 --- a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryPlanParserService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using AsbCloudApp.Data.Trajectory; -using ClosedXML.Excel; - -namespace AsbCloudInfrastructure.Services.Trajectory.Import -{ - - public class TrajectoryPlanParserService : TrajectoryParserService - { - public override string templateFileName { get; } = "TrajectoryPlanTemplate.xlsx"; - public override string usingTemplateFile { get; } = "AsbCloudInfrastructure.Services.Trajectory.Templates"; - public override string sheetName { get; } = "Плановая траектория"; - public override int headerRowsCount { get; } = 2; - - protected override TrajectoryGeoPlanDto ParseRow(IXLRow row) - { - var trajectoryRow = new TrajectoryGeoPlanDto - { - WellboreDepth = row.Cell(1).GetCellValue(), - ZenithAngle = row.Cell(2).GetCellValue(), - AzimuthGeo = row.Cell(3).GetCellValue(), - AzimuthMagnetic = row.Cell(4).GetCellValue(), - VerticalDepth = row.Cell(5).GetCellValue(), - Radius = row.Cell(6).GetCellValue(), - Comment = row.Cell(7).GetCellValue() - }; - - //TODO: Добавить валидацию модели IValidatableObject - return trajectoryRow; - } - } - -} - diff --git a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParserService.cs new file mode 100644 index 00000000..6a3a89cc --- /dev/null +++ b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParserService.cs @@ -0,0 +1,28 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.Trajectory; +using ClosedXML.Excel; + +namespace AsbCloudInfrastructure.Services.Trajectory.Parser; + +public class TrajectoryFactManualParserService : TrajectoryParserService +{ + protected override ValidationResultDto ParseRow(IXLRow row) + { + var trajectoryRow = new TrajectoryGeoFactDto + { + WellboreDepth = row.Cell(1).GetCellValue(), + ZenithAngle = row.Cell(2).GetCellValue(), + AzimuthGeo = row.Cell(3).GetCellValue(), + AzimuthMagnetic = row.Cell(4).GetCellValue(), + VerticalDepth = row.Cell(5).GetCellValue(), + Comment = row.Cell(6).GetCellValue() + }; + + //TODO: Добавить валидацию модели + + return new ValidationResultDto + { + Item = trajectoryRow + }; + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParserService.cs new file mode 100644 index 00000000..6b5177fe --- /dev/null +++ b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParserService.cs @@ -0,0 +1,78 @@ +using AsbCloudApp.Data.Trajectory; +using ClosedXML.Excel; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using AsbCloudApp.Data; +using AsbCloudApp.Requests.Import; +using AsbCloudApp.Services; + +namespace AsbCloudInfrastructure.Services.Trajectory.Parser; + +public abstract class TrajectoryParserService : IParserService + where T : TrajectoryGeoDto +{ + protected abstract ValidationResultDto ParseRow(IXLRow row); + + public ParserResultDto Parse(Stream file, TrajectoryParserRequest options) + { + using var workbook = new XLWorkbook(file, XLEventTracking.Disabled); + var trajectoryRows = ParseFileStream(file, options); + + return trajectoryRows; + } + + private ParserResultDto ParseFileStream(Stream stream, TrajectoryParserRequest options) + { + using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled); + return ParseWorkbook(workbook, options); + } + + private ParserResultDto 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 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>(count); + var parseErrors = new List(); + 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 + { + Item = trajectoryRows + }; + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParserService.cs new file mode 100644 index 00000000..6b4654fd --- /dev/null +++ b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParserService.cs @@ -0,0 +1,29 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Data.Trajectory; +using ClosedXML.Excel; + +namespace AsbCloudInfrastructure.Services.Trajectory.Parser; + +public class TrajectoryPlanParserService : TrajectoryParserService +{ + protected override ValidationResultDto ParseRow(IXLRow row) + { + var trajectoryRow = new TrajectoryGeoPlanDto + { + WellboreDepth = row.Cell(1).GetCellValue(), + ZenithAngle = row.Cell(2).GetCellValue(), + AzimuthGeo = row.Cell(3).GetCellValue(), + AzimuthMagnetic = row.Cell(4).GetCellValue(), + VerticalDepth = row.Cell(5).GetCellValue(), + Radius = row.Cell(6).GetCellValue(), + Comment = row.Cell(7).GetCellValue() + }; + + //TODO: Добавить валидацию модели + + return new ValidationResultDto + { + Item = trajectoryRow + }; + } +} \ No newline at end of file diff --git a/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryImportTest.cs b/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryImportTest.cs deleted file mode 100644 index e6763582..00000000 --- a/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryImportTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -using AsbCloudInfrastructure.Services.Trajectory.Import; -using System.Linq; -using Xunit; - -namespace AsbCloudWebApi.Tests.Services.Trajectory -{ - public class TrajectoryImportTest - { - private readonly TrajectoryPlanParserService trajectoryPlanImportService; - private readonly TrajectoryFactManualParserService trajectoryFactManualImportService; - - private string usingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates"; - - public TrajectoryImportTest() - { - trajectoryPlanImportService = new TrajectoryPlanParserService(); - trajectoryFactManualImportService = new TrajectoryFactManualParserService(); - } - - [Fact] - public void Import_trajectory_plan() - { - var stream = System.Reflection.Assembly.GetExecutingAssembly() - .GetManifestResourceStream($"{usingTemplateFile}.TrajectoryPlanTemplate.xlsx"); - - if (stream is null) - Assert.Fail("Файла для импорта не существует"); - - var trajectoryRows = trajectoryPlanImportService.Import(stream); - - Assert.Equal(3, trajectoryRows.Count()); - } - - [Fact] - public void Import_trajectory_fact_manual() - { - var stream = System.Reflection.Assembly.GetExecutingAssembly() - .GetManifestResourceStream($"{usingTemplateFile}.TrajectoryFactManualTemplate.xlsx"); - - if (stream is null) - Assert.Fail("Файла для импорта не существует"); - - var trajectoryRows = trajectoryFactManualImportService.Import(stream); - - Assert.Equal(4, trajectoryRows.Count()); - } - } -} diff --git a/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs b/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs new file mode 100644 index 00000000..0da13a71 --- /dev/null +++ b/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs @@ -0,0 +1,60 @@ +using System.Linq; +using AsbCloudApp.Data.Trajectory; +using AsbCloudApp.Requests.Import; +using AsbCloudInfrastructure.Services; +using Xunit; + +namespace AsbCloudWebApi.Tests.Services.Trajectory; + +public class TrajectoryParserTest +{ + 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(); + + [Fact] + public void Parse_trajectory_plan() + { + var stream = System.Reflection.Assembly.GetExecutingAssembly() + .GetManifestResourceStream($"{UsingTemplateFile}.TrajectoryPlanTemplate.xlsx"); + + if (stream is null) + Assert.Fail("Файла для импорта не существует"); + + var parserService = parserServiceFactory.Create( + planTrajectoryParserOptions.IdParserService); + var trajectoryRows = parserService.Parse(stream, planTrajectoryParserOptions); + + Assert.Equal(3, trajectoryRows.Item.Count()); + } + + [Fact] + public void Parse_trajectory_fact_manual() + { + var stream = System.Reflection.Assembly.GetExecutingAssembly() + .GetManifestResourceStream($"{UsingTemplateFile}.TrajectoryFactManualTemplate.xlsx"); + + if (stream is null) + Assert.Fail("Файла для импорта не существует"); + + var parserService = parserServiceFactory.Create( + factTrajectoryParserOptions.IdParserService); + var trajectoryRows = parserService.Parse(stream, factTrajectoryParserOptions); + + Assert.Equal(4, trajectoryRows.Item.Count()); + } +} \ No newline at end of file