From 1a7d5ea44e4839f463a2cfc377cf1cfc5868d0da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Cs=C3=A1nyi?= Date: Sun, 15 Sep 2024 19:10:39 +0200 Subject: [PATCH] feat: CRUD operations for Filetype (#8) * tmp * tmp * impl --- Backend.sln.DotSettings | 7 +- Backend.sln.DotSettings.user | 14 +--- .../DocumentDomain.Spec.csproj | 4 +- .../Scenario/Filetype/AddFiletypeScenario.cs | 42 ++++++++++ ...AddFiletypeScenarioInputValidatorShould.cs | 59 +++++++++++++ ...eteFiletypeScenarioInputValidatorShould.cs | 27 ++++++ .../Filetype/DeleteFiletypeScenarioShould.cs | 61 ++++++++++++++ ...ditFiletypeScenarioInputValidatorShould.cs | 63 ++++++++++++++ .../Filetype/EditFiletypeScenarioShould.cs | 46 ++++++++++ ...iletypeByIdScenarioInputValidatorShould.cs | 27 ++++++ .../Filetype/GetFiletypeByIdScenarioShould.cs | 63 ++++++++++++++ .../Filetype/GetFiletypesScenarioShould.cs | 32 +++++++ .../Operations/Scenario/ScenarioBaseTest.cs | 83 +++++++++++++++++++ DocumentDomain/DocumentDomain.csproj | 2 +- DocumentDomain/Entity/Filetype.cs | 9 ++ .../Database/DocumentDomainDbContext.cs | 2 + .../Database/FiletypeConfiguration.cs | 18 ++++ .../Infrastructure/Mappers/FiletypeMapper.cs | 47 +++++++++++ .../Scenarios/Filetype/AddFiletypeScenario.cs | 76 +++++++++++++++++ .../AddFiletypeScenarioInputValidator.cs | 54 ++++++++++++ .../Filetype/DeleteFiletypeScenario.cs | 62 ++++++++++++++ .../DeleteFiletypeScenarioInputValidator.cs | 14 ++++ .../Filetype/EditFiletypeScenario.cs | 77 +++++++++++++++++ .../EditFiletypeScenarioInputValidator.cs | 53 ++++++++++++ .../Filetype/GetFiletypeByIdScenario.cs | 68 +++++++++++++++ .../GetFiletypeByIdScenarioInputValidator.cs | 14 ++++ .../Filetype/GetFiletypesScenario.cs | 43 ++++++++++ Tools/Tools.csproj | 2 +- 28 files changed, 1054 insertions(+), 15 deletions(-) create mode 100644 DocumentDomain.Spec/Operations/Scenario/Filetype/AddFiletypeScenario.cs create mode 100644 DocumentDomain.Spec/Operations/Scenario/Filetype/AddFiletypeScenarioInputValidatorShould.cs create mode 100644 DocumentDomain.Spec/Operations/Scenario/Filetype/DeleteFiletypeScenarioInputValidatorShould.cs create mode 100644 DocumentDomain.Spec/Operations/Scenario/Filetype/DeleteFiletypeScenarioShould.cs create mode 100644 DocumentDomain.Spec/Operations/Scenario/Filetype/EditFiletypeScenarioInputValidatorShould.cs create mode 100644 DocumentDomain.Spec/Operations/Scenario/Filetype/EditFiletypeScenarioShould.cs create mode 100644 DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypeByIdScenarioInputValidatorShould.cs create mode 100644 DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypeByIdScenarioShould.cs create mode 100644 DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypesScenarioShould.cs create mode 100644 DocumentDomain/Entity/Filetype.cs create mode 100644 DocumentDomain/Infrastructure/Database/FiletypeConfiguration.cs create mode 100644 DocumentDomain/Infrastructure/Mappers/FiletypeMapper.cs create mode 100644 DocumentDomain/Operations/Scenarios/Filetype/AddFiletypeScenario.cs create mode 100644 DocumentDomain/Operations/Scenarios/Filetype/AddFiletypeScenarioInputValidator.cs create mode 100644 DocumentDomain/Operations/Scenarios/Filetype/DeleteFiletypeScenario.cs create mode 100644 DocumentDomain/Operations/Scenarios/Filetype/DeleteFiletypeScenarioInputValidator.cs create mode 100644 DocumentDomain/Operations/Scenarios/Filetype/EditFiletypeScenario.cs create mode 100644 DocumentDomain/Operations/Scenarios/Filetype/EditFiletypeScenarioInputValidator.cs create mode 100644 DocumentDomain/Operations/Scenarios/Filetype/GetFiletypeByIdScenario.cs create mode 100644 DocumentDomain/Operations/Scenarios/Filetype/GetFiletypeByIdScenarioInputValidator.cs create mode 100644 DocumentDomain/Operations/Scenarios/Filetype/GetFiletypesScenario.cs diff --git a/Backend.sln.DotSettings b/Backend.sln.DotSettings index 2d0bdc6..876a763 100644 --- a/Backend.sln.DotSettings +++ b/Backend.sln.DotSettings @@ -58,11 +58,16 @@ UseExplicitType UseExplicitType UseExplicitType + CoverNewAndOutdated False True + True Enable Enable + OnlyMarkers True True True - True \ No newline at end of file + True + Never + False \ No newline at end of file diff --git a/Backend.sln.DotSettings.user b/Backend.sln.DotSettings.user index 436937e..56c982f 100644 --- a/Backend.sln.DotSettings.user +++ b/Backend.sln.DotSettings.user @@ -5,15 +5,9 @@ False /Users/andrascsanyi/Library/Caches/JetBrains/Rider2024.2/resharper-host/temp/Rider/vAny/CoverageData/_Backend.1702169323/Snapshot/snapshot.utdcvr - <SessionState ContinuousTestingIsOn="True" ContinuousTestingMode="3" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <Solution /> -</SessionState> - <SessionState ContinuousTestingIsOn="True" ContinuousTestingMode="2" Name="Continuous Testing" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <Solution /> -</SessionState> - <SessionState ContinuousTestingIsOn="True" ContinuousTestingMode="3" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + + <SessionState ContinuousTestingIsOn="True" ContinuousTestingMode="3" IsActive="True" Name="Continuous Testing" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <Solution /> </SessionState> - <SessionState ContinuousTestingMode="0" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <Solution /> -</SessionState> \ No newline at end of file + + \ No newline at end of file diff --git a/DocumentDomain.Spec/DocumentDomain.Spec.csproj b/DocumentDomain.Spec/DocumentDomain.Spec.csproj index 9622fce..366b5e2 100644 --- a/DocumentDomain.Spec/DocumentDomain.Spec.csproj +++ b/DocumentDomain.Spec/DocumentDomain.Spec.csproj @@ -10,7 +10,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -31,7 +31,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/DocumentDomain.Spec/Operations/Scenario/Filetype/AddFiletypeScenario.cs b/DocumentDomain.Spec/Operations/Scenario/Filetype/AddFiletypeScenario.cs new file mode 100644 index 0000000..5ab6d45 --- /dev/null +++ b/DocumentDomain.Spec/Operations/Scenario/Filetype/AddFiletypeScenario.cs @@ -0,0 +1,42 @@ +namespace DocumentDomain.Spec.Operations.Scenario.Filetype; + +using EncyclopediaGalactica.BusinessLogic.Contracts; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; +using FluentAssertions; +using LanguageExt; + +public class AddFiletypeScenario : ScenarioBaseTest +{ + [Theory] + [ClassData(typeof(AddFiletypeScenarioInputValidationInvalidInputData))] + public async Task ReturnErrorResult_WhenInputIsInvalid(FiletypeInput input) + { + Either result = await AddFiletypeScenario.ExecuteAsync( + new AddFiletypeScenarioContext(Guid.NewGuid(), input)); + result.IsLeft.Should().BeTrue(); + result.IsRight.Should().BeFalse(); + result.IfLeft(er => + { + er.CorrelationId.Should().NotBeEmpty(); + er.ErrorMessage.Should().NotBeEmpty(); + }); + } + + [Fact] + public async Task ReturnFiletypeResult_WhenOperationIsSuccessful() + { + Either result = await AddFiletypeScenario.ExecuteAsync( + new AddFiletypeScenarioContext(Guid.NewGuid(), + new FiletypeInput { Id = 0, Name = "asdd", Description = "asd", FileExtension = "asd" })); + result.IsLeft.Should().BeFalse(); + result.IsRight.Should().BeTrue(); + result.IfRight(r => + { + r.Id.Should().BeGreaterOrEqualTo(1); + r.Name.Should().Be("asdd"); + r.Description.Should().Be("asd"); + r.FileExtension.Should().Be("asd"); + }); + } +} \ No newline at end of file diff --git a/DocumentDomain.Spec/Operations/Scenario/Filetype/AddFiletypeScenarioInputValidatorShould.cs b/DocumentDomain.Spec/Operations/Scenario/Filetype/AddFiletypeScenarioInputValidatorShould.cs new file mode 100644 index 0000000..5b7e037 --- /dev/null +++ b/DocumentDomain.Spec/Operations/Scenario/Filetype/AddFiletypeScenarioInputValidatorShould.cs @@ -0,0 +1,59 @@ +namespace DocumentDomain.Spec.Operations.Scenario.Filetype; + +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using EncyclopediaGalactica.BusinessLogic.Contracts; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; +using FluentAssertions; +using FluentValidation.Results; + +public class AddFiletypeScenarioInputValidatorShould +{ + private AddFiletypeScenarioInputValidator validator = new(); + + [Theory] + [ClassData(typeof(AddFiletypeScenarioInputValidationInvalidInputData))] + public void ShowInvalidState_WhenInputIsInvalid(FiletypeInput input) + { + ValidationResult result = validator.Validate(input); + result.IsValid.Should().BeFalse(); + result.Errors.Should().NotBeEmpty(); + } + + [Fact] + public void ShowValidState_WhenInputIsValid() + { + ValidationResult validationResult = validator.Validate( + new FiletypeInput { Id = 0, Name = "asd", Description = "asd", FileExtension = "asd" }); + validationResult.IsValid.Should().BeTrue(); + validationResult.Errors.Should().BeEmpty(); + } +} + +[ExcludeFromCodeCoverage] +public class AddFiletypeScenarioInputValidationInvalidInputData : IEnumerable +{ + public IEnumerator GetEnumerator() + { + yield return new object[] { new FiletypeInput { Id = 1, Name = "asd", Description = "asd", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 0, Name = null, Description = "asd", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 0, Name = string.Empty, Description = "asd", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 0, Name = " ", Description = "asd", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 0, Name = "as", Description = "asd", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 0, Name = " as ", Description = "asd", FileExtension = "asd" } }; + + yield return new object[] { new FiletypeInput { Id = 1, Name = "asd", Description = null, FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 0, Name = "asd", Description = string.Empty, FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 0, Name = "asd", Description = " ", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 0, Name = "asd", Description = "as", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 0, Name = "asd", Description = " as ", FileExtension = "asd" } }; + + yield return new object[] { new FiletypeInput { Id = 0, Name = "asd", Description = "asd", FileExtension = null } }; + yield return new object[] { new FiletypeInput { Id = 0, Name = "asd", Description = "asd", FileExtension = string.Empty } }; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} \ No newline at end of file diff --git a/DocumentDomain.Spec/Operations/Scenario/Filetype/DeleteFiletypeScenarioInputValidatorShould.cs b/DocumentDomain.Spec/Operations/Scenario/Filetype/DeleteFiletypeScenarioInputValidatorShould.cs new file mode 100644 index 0000000..bd1c0ac --- /dev/null +++ b/DocumentDomain.Spec/Operations/Scenario/Filetype/DeleteFiletypeScenarioInputValidatorShould.cs @@ -0,0 +1,27 @@ +namespace DocumentDomain.Spec.Operations.Scenario.Filetype; + +using EncyclopediaGalactica.BusinessLogic.Contracts; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; +using FluentAssertions; +using FluentValidation.Results; + +public class DeleteFiletypeScenarioInputValidatorShould +{ + private DeleteFiletypeScenarioInputValidator validator = new(); + + [Fact] + public void ShowInvalidState_WhenTheInputIsInvalid() + { + ValidationResult result = validator.Validate(new FiletypeInput { Id = 0 }); + result.IsValid.Should().BeFalse(); + result.Errors.Should().NotBeEmpty(); + } + + [Fact] + public void ShowValidState_WhenTheInputIsValid() + { + ValidationResult result = validator.Validate(new FiletypeInput { Id = 1 }); + result.IsValid.Should().BeTrue(); + result.Errors.Should().BeEmpty(); + } +} \ No newline at end of file diff --git a/DocumentDomain.Spec/Operations/Scenario/Filetype/DeleteFiletypeScenarioShould.cs b/DocumentDomain.Spec/Operations/Scenario/Filetype/DeleteFiletypeScenarioShould.cs new file mode 100644 index 0000000..59dcf0a --- /dev/null +++ b/DocumentDomain.Spec/Operations/Scenario/Filetype/DeleteFiletypeScenarioShould.cs @@ -0,0 +1,61 @@ +namespace DocumentDomain.Spec.Operations.Scenario.Filetype; + +using EncyclopediaGalactica.BusinessLogic.Contracts; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; +using FluentAssertions; +using LanguageExt; + +public class DeleteFiletypeScenarioShould : ScenarioBaseTest +{ + [Fact] + public async Task ReturnErrorResult_WhenInputIsInvalid() + { + Either result = await DeleteFiletypeScenario.ExecuteAsync( + new DeleteFiletypeScenarioContext(Guid.NewGuid(), + new FiletypeInput { Id = 0 })); + result.IsLeft.Should().BeTrue(); + result.IsRight.Should().BeFalse(); + result.IfLeft(er => + { + er.CorrelationId.Should().NotBeEmpty(); + er.ErrorMessage.Should().NotBeEmpty(); + }); + } + + [Fact] + public async Task ReturnErrorResult_WhenNoSuchEntity() + { + Either result = await DeleteFiletypeScenario.ExecuteAsync( + new DeleteFiletypeScenarioContext(Guid.NewGuid(), + new FiletypeInput { Id = 190 })); + result.IsLeft.Should().BeTrue(); + result.IsRight.Should().BeFalse(); + result.IfLeft(er => + { + er.CorrelationId.Should().NotBeEmpty(); + er.ErrorMessage.Should().NotBeEmpty(); + }); + } + + [Fact] + public async Task ReturnFiletypeResult_WhenTheOperationIsSuccessful() + { + FiletypeInput delete = null; + Either data = await AddFiletypeScenario.ExecuteAsync( + new AddFiletypeScenarioContext(Guid.NewGuid(), new FiletypeInput + { + Id = 0, Name = "asd", Description = "asd", FileExtension = "asd" + })); + data.IsRight.Should().BeTrue(); + data.IsLeft.Should().BeFalse(); + data.IfRight(res => delete = new FiletypeInput { Id = res.Id }); + + Either result = await DeleteFiletypeScenario.ExecuteAsync( + new DeleteFiletypeScenarioContext(Guid.NewGuid(), delete!)); + + result.IsLeft.Should().BeFalse(); + result.IsRight.Should().BeTrue(); + result.IfRight(r => { r.Id.Should().Be(0); }); + } +} \ No newline at end of file diff --git a/DocumentDomain.Spec/Operations/Scenario/Filetype/EditFiletypeScenarioInputValidatorShould.cs b/DocumentDomain.Spec/Operations/Scenario/Filetype/EditFiletypeScenarioInputValidatorShould.cs new file mode 100644 index 0000000..b40596d --- /dev/null +++ b/DocumentDomain.Spec/Operations/Scenario/Filetype/EditFiletypeScenarioInputValidatorShould.cs @@ -0,0 +1,63 @@ +namespace DocumentDomain.Spec.Operations.Scenario.Filetype; + +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using EncyclopediaGalactica.BusinessLogic.Contracts; +using EncyclopediaGalactica.DocumentDomain.Entity; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; +using FluentAssertions; +using FluentValidation.Results; + +public class EditFiletypeScenarioInputValidatorShould +{ + private EditFiletypeScenarioInputValidator _validator = new(); + + + [Theory] + [ClassData(typeof(EditFiletypeScenarioInputValidatorInvalidInputData))] + public void ShowsInvalidResult_WhenInputIsInvalid(FiletypeInput filetypeInput) + { + ValidationResult result = _validator.Validate(filetypeInput); + result.IsValid.Should().BeFalse(); + result.Errors.Should().NotBeEmpty(); + } + + [Fact] + public void ShowsValidResult_WhenInputIsValid() + { + ValidationResult result = _validator.Validate(new FiletypeInput + { + Id = 1, + Name = "asd", + Description = "asd", + FileExtension = "asd" + }); + result.IsValid.Should().BeTrue(); + result.Errors.Should().BeEmpty(); + } +} + +[ExcludeFromCodeCoverage] +public class EditFiletypeScenarioInputValidatorInvalidInputData : IEnumerable +{ + public IEnumerator GetEnumerator() + { + yield return new object[] { new FiletypeInput { Id = 0, Name = "asd", Description = "asd", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = null, Description = "asd", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = string.Empty, Description = "asd", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = " ", Description = "asd", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = " as ", Description = "asd", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = "asd", Description = null, FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = "asd", Description = string.Empty, FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = "asd", Description = " ", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = "asd", Description = " as ", FileExtension = "asd" } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = "asd", Description = "asd", FileExtension = null } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = "asd", Description = "asd", FileExtension = string.Empty } }; + yield return new object[] { new FiletypeInput { Id = 1, Name = "asd", Description = "asd", FileExtension = " " } }; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} \ No newline at end of file diff --git a/DocumentDomain.Spec/Operations/Scenario/Filetype/EditFiletypeScenarioShould.cs b/DocumentDomain.Spec/Operations/Scenario/Filetype/EditFiletypeScenarioShould.cs new file mode 100644 index 0000000..0bd57fd --- /dev/null +++ b/DocumentDomain.Spec/Operations/Scenario/Filetype/EditFiletypeScenarioShould.cs @@ -0,0 +1,46 @@ +namespace DocumentDomain.Spec.Operations.Scenario.Filetype; + +using System.Diagnostics.CodeAnalysis; +using EncyclopediaGalactica.BusinessLogic.Contracts; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; +using FluentAssertions; +using LanguageExt; + +public class EditFiletypeScenarioShould : ScenarioBaseTest +{ + [Theory] + [ClassData(typeof(EditFiletypeScenarioInputValidatorInvalidInputData))] + public async Task ReturnErrorResult_WhenOperationFails(FiletypeInput input) + { + Either result = await EditFiletypeScenario.ExecuteAsync( + new EditFiletypeScenarioContext(Guid.NewGuid(), input)); + + result.IsRight.Should().BeFalse(); + result.IsLeft.Should().BeTrue(); + result.IfLeft(er => + { + er.CorrelationId.Should().NotBeEmpty(); + er.ErrorMessage.Should().NotBeEmpty(); + }); + } + + [Fact] + public async Task ReturnErrorResult_WhenThereIsNoSuchEntity() + { + Either result = await EditFiletypeScenario.ExecuteAsync( + new EditFiletypeScenarioContext(Guid.NewGuid(), new FiletypeInput { Id = 1000 })); + + result.IsRight.Should().BeFalse(); + result.IsLeft.Should().BeTrue(); + result.IfLeft(er => + { + er.CorrelationId.Should().NotBeEmpty(); + er.ErrorMessage.Should().NotBeEmpty(); + }); + } + + public async Task ReturnFiletypeResult_WhenOperationIsSuccessful() + { + } +} \ No newline at end of file diff --git a/DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypeByIdScenarioInputValidatorShould.cs b/DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypeByIdScenarioInputValidatorShould.cs new file mode 100644 index 0000000..7740fb6 --- /dev/null +++ b/DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypeByIdScenarioInputValidatorShould.cs @@ -0,0 +1,27 @@ +namespace DocumentDomain.Spec.Operations.Scenario.Filetype; + +using EncyclopediaGalactica.BusinessLogic.Contracts; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; +using FluentAssertions; +using FluentValidation.Results; + +public class GetFiletypeByIdScenarioInputValidatorShould +{ + private GetFiletypeByIdScenarioInputValidator validator = new(); + + [Fact] + public void ReturnInvalidState_WhenInputIsInvalid() + { + ValidationResult result = validator.Validate(new FiletypeInput { Id = 0 }); + result.IsValid.Should().BeFalse(); + result.Errors.Should().NotBeEmpty(); + } + + [Fact] + public void ReturnValidState_WhenInputIsValid() + { + ValidationResult result = validator.Validate(new FiletypeInput { Id = 1 }); + result.IsValid.Should().BeTrue(); + result.Errors.Should().BeEmpty(); + } +} \ No newline at end of file diff --git a/DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypeByIdScenarioShould.cs b/DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypeByIdScenarioShould.cs new file mode 100644 index 0000000..ac73fec --- /dev/null +++ b/DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypeByIdScenarioShould.cs @@ -0,0 +1,63 @@ +namespace DocumentDomain.Spec.Operations.Scenario.Filetype; + +using EncyclopediaGalactica.BusinessLogic.Contracts; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; +using FluentAssertions; +using LanguageExt; + +public class GetFiletypeByIdScenarioShould : ScenarioBaseTest +{ + [Fact] + public async Task ReturnErrorResult_WhenInputIdInvalid() + { + Either result = await GetFiletypeByIdScenario.ExecuteAsync( + new GetFiletypeByIdScenarioContext(Guid.NewGuid(), new FiletypeInput { Id = 0 })); + result.IsLeft.Should().BeTrue(); + result.IsRight.Should().BeFalse(); + result.IfLeft(e => + { + e.CorrelationId.Should().NotBeEmpty(); + e.ErrorMessage.Should().NotBeEmpty(); + }); + } + + [Fact] + public async Task ReturnErrorResult_WhenThereIsNoSuchEntity() + { + Either result = await GetFiletypeByIdScenario.ExecuteAsync( + new GetFiletypeByIdScenarioContext(Guid.NewGuid(), new FiletypeInput { Id = 190 })); + result.IsLeft.Should().BeTrue(); + result.IsRight.Should().BeFalse(); + result.IfLeft(e => + { + e.CorrelationId.Should().NotBeEmpty(); + e.ErrorMessage.Should().NotBeEmpty(); + }); + } + + [Fact] + public async Task ReturnFiletypeResult_WhenOperationIsSuccessful() + { + FiletypeInput d = new FiletypeInput { Id = 0, Name = "asd", Description = "asd", FileExtension = "asd" }; + Either data = await AddFiletypeScenario.ExecuteAsync( + new AddFiletypeScenarioContext(Guid.NewGuid(), d)); + data.IsLeft.Should().BeFalse(); + data.IsRight.Should().BeTrue(); + + FiletypeInput query = null; + data.IfRight(d => query = new FiletypeInput { Id = d.Id, Name = d.Name, Description = d.Description, FileExtension = d.FileExtension }); + Either result = await GetFiletypeByIdScenario.ExecuteAsync( + new GetFiletypeByIdScenarioContext(Guid.NewGuid(), query!)); + + result.IsLeft.Should().BeFalse(); + result.IsRight.Should().BeTrue(); + result.IfRight(res => + { + res.Id.Should().Be(query!.Id); + res.Name.Should().Be(query!.Name); + res.Description.Should().Be(query!.Description); + res.FileExtension.Should().Be(query!.FileExtension); + }); + } +} \ No newline at end of file diff --git a/DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypesScenarioShould.cs b/DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypesScenarioShould.cs new file mode 100644 index 0000000..22e923a --- /dev/null +++ b/DocumentDomain.Spec/Operations/Scenario/Filetype/GetFiletypesScenarioShould.cs @@ -0,0 +1,32 @@ +namespace DocumentDomain.Spec.Operations.Scenario.Filetype; + +using EncyclopediaGalactica.BusinessLogic.Contracts; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; +using FluentAssertions; +using LanguageExt; +using Xunit.Abstractions; + +public class GetFiletypesScenarioShould(ITestOutputHelper _testOutputHelper) : ScenarioBaseTest +{ + [Fact] + public async Task ReturnEmptyList_WhenThereIsNoData() + { + Either> result = await GetFiletypesScenario.ExecuteAsync( + new GetFiletypesScenarioContext(Guid.NewGuid())); + result.IsLeft.Should().BeFalse(); + result.IsRight.Should().BeTrue(); + result.IfRight(r => r.Should().BeEmpty()); + } + + [Fact] + public async Task ReturnList() + { + await SeedAndForgetFiletypes(10, _testOutputHelper); + Either> result = await GetFiletypesScenario.ExecuteAsync( + new GetFiletypesScenarioContext(Guid.NewGuid())); + result.IsLeft.Should().BeFalse(); + result.IsRight.Should().BeTrue(); + result.IfRight(r => r.Should().HaveCount(10)); + } +} \ No newline at end of file diff --git a/DocumentDomain.Spec/Operations/Scenario/ScenarioBaseTest.cs b/DocumentDomain.Spec/Operations/Scenario/ScenarioBaseTest.cs index c5622d5..836da0e 100644 --- a/DocumentDomain.Spec/Operations/Scenario/ScenarioBaseTest.cs +++ b/DocumentDomain.Spec/Operations/Scenario/ScenarioBaseTest.cs @@ -11,12 +11,14 @@ namespace DocumentDomain.Spec.Operations.Scenario; using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios; using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Application; using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.DocumentType; +using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; using EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Relation; using FluentValidation; using LanguageExt; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using Xunit.Abstractions; public class ScenarioBaseTest : IDisposable { @@ -51,8 +53,14 @@ public class ScenarioBaseTest : IDisposable protected GetRelationsScenario GetRelationsScenario; protected GetRelationByIdScenario GetRelationByIdScenario; protected DeleteRelationScenario DeleteRelationScenario; + protected EditFiletypeScenario EditFiletypeScenario; + protected AddFiletypeScenario AddFiletypeScenario; + protected DeleteFiletypeScenario DeleteFiletypeScenario; + protected GetFiletypeByIdScenario GetFiletypeByIdScenario; + protected GetFiletypesScenario GetFiletypesScenario; private RelationMapper _relationMapper; + protected ScenarioBaseTest() { InitializeDbContext(); @@ -96,6 +104,44 @@ protected ScenarioBaseTest() InitializeGetRelationsScenario(); InitializeGetRelationByIdScenario(); InitializeDeleteRelationScenario(); + + InitializeEditfiletypeScenario(); + InitializeAddFiletypeScenario(); + InitializeDeleteFiletypeScenario(); + InitializeGetFiletypeByIdScenario(); + InitialzeGetFiletypesScenario(); + } + + private void InitialzeGetFiletypesScenario() + { + GetFiletypesScenario = new GetFiletypesScenario(_dbContextOptions); + } + + private void InitializeGetFiletypeByIdScenario() + { + GetFiletypeByIdScenario = new GetFiletypeByIdScenario( + new GetFiletypeByIdScenarioInputValidator(), _dbContextOptions); + } + + private void InitializeDeleteFiletypeScenario() + { + DeleteFiletypeScenario = new DeleteFiletypeScenario( + new DeleteFiletypeScenarioInputValidator(), _dbContextOptions); + } + + private void InitializeAddFiletypeScenario() + { + AddFiletypeScenario = new AddFiletypeScenario( + new AddFiletypeScenarioInputValidator(), + _dbContextOptions); + } + + + private void InitializeEditfiletypeScenario() + { + EditFiletypeScenario = new EditFiletypeScenario( + new EditFiletypeScenarioInputValidator(), + _dbContextOptions); } private void InitializeDeleteRelationScenario() @@ -322,4 +368,41 @@ protected async Task> SeedRelations(int v) return result; } + + protected async Task SeedAndForgetFiletypes(int v, ITestOutputHelper testOutputHelper) + { + for (int i = 0; i < v; i++) + { + Either r = await AddFiletypeScenario.ExecuteAsync( + new AddFiletypeScenarioContext(Guid.NewGuid(), new FiletypeInput + { + Id = 0, Name = $"name{i}", Description = $"desc{i}", + FileExtension = $"fileextension{i}" + })); + r.IfLeft(e => testOutputHelper.WriteLine(e.ErrorMessage)); + } + } + + protected async Task> SeedFiletypes(int v) + { + Dictionary result = new(); + if (v == 0) + { + return result; + } + + for (int i = 0; i <= v; i++) + { + Either r = await AddFiletypeScenario.ExecuteAsync( + new AddFiletypeScenarioContext(Guid.NewGuid(), new FiletypeInput + { + Id = 0, Name = $"name{i}", Description = $"desc{i}", + FileExtension = $"fileextension{i}" + })); + r.IfLeft(e => Console.WriteLine(e.ErrorMessage)); + r.IfRight(r => result.Add(r.Id, r)); + } + + return result; + } } \ No newline at end of file diff --git a/DocumentDomain/DocumentDomain.csproj b/DocumentDomain/DocumentDomain.csproj index b601fab..a7474c5 100644 --- a/DocumentDomain/DocumentDomain.csproj +++ b/DocumentDomain/DocumentDomain.csproj @@ -9,7 +9,7 @@ - + diff --git a/DocumentDomain/Entity/Filetype.cs b/DocumentDomain/Entity/Filetype.cs new file mode 100644 index 0000000..e95ad87 --- /dev/null +++ b/DocumentDomain/Entity/Filetype.cs @@ -0,0 +1,9 @@ +namespace EncyclopediaGalactica.DocumentDomain.Entity; + +public class Filetype +{ + public long Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string FileExtension { get; set; } +} \ No newline at end of file diff --git a/DocumentDomain/Infrastructure/Database/DocumentDomainDbContext.cs b/DocumentDomain/Infrastructure/Database/DocumentDomainDbContext.cs index 1836b12..b445d65 100644 --- a/DocumentDomain/Infrastructure/Database/DocumentDomainDbContext.cs +++ b/DocumentDomain/Infrastructure/Database/DocumentDomainDbContext.cs @@ -17,6 +17,7 @@ public DocumentDomainDbContext(DbContextOptions options) : base(options) public DbSet DocumentStructureNodes => Set(); public DbSet Relations => Set(); public DbSet Applications => Set(); + public DbSet Filetypes => Set(); public DbSet DocumentTypes => Set(); @@ -27,5 +28,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.ApplyConfigurationsFromAssembly(typeof(RelationConfiguration).Assembly); modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationConfiguration).Assembly); modelBuilder.ApplyConfigurationsFromAssembly(typeof(DocumentTypeConfiguration).Assembly); + modelBuilder.ApplyConfigurationsFromAssembly(typeof(FiletypeConfiguration).Assembly); } } \ No newline at end of file diff --git a/DocumentDomain/Infrastructure/Database/FiletypeConfiguration.cs b/DocumentDomain/Infrastructure/Database/FiletypeConfiguration.cs new file mode 100644 index 0000000..e2ff004 --- /dev/null +++ b/DocumentDomain/Infrastructure/Database/FiletypeConfiguration.cs @@ -0,0 +1,18 @@ +namespace EncyclopediaGalactica.DocumentDomain.Infrastructure.Database; + +using Entity; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +public class FiletypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("filetype"); + builder.HasKey(k => k.Id); + builder.Property(p => p.Id).HasColumnName("id"); + builder.Property(p => p.Name).HasColumnName("name"); + builder.Property(p => p.Description).HasColumnName("description"); + builder.Property(p => p.FileExtension).HasColumnName("fileextension"); + } +} \ No newline at end of file diff --git a/DocumentDomain/Infrastructure/Mappers/FiletypeMapper.cs b/DocumentDomain/Infrastructure/Mappers/FiletypeMapper.cs new file mode 100644 index 0000000..c650d63 --- /dev/null +++ b/DocumentDomain/Infrastructure/Mappers/FiletypeMapper.cs @@ -0,0 +1,47 @@ +namespace EncyclopediaGalactica.DocumentDomain.Infrastructure.Mappers; + +using BusinessLogic.Contracts; +using Entity; + +public static class FiletypeMapper +{ + public static Filetype MapToFiletypeEntity(this FiletypeInput filetypeInput) + { + return new Filetype + { + Id = filetypeInput.Id, + Name = filetypeInput.Name, + Description = filetypeInput.Description, + FileExtension = filetypeInput.FileExtension + }; + } + + public static FiletypeResult MapToFiletypeResult(this Filetype filetype) + { + return new FiletypeResult + { + Id = filetype.Id, + Name = filetype.Name, + Description = filetype.Description, + FileExtension = filetype.FileExtension + }; + } + + public static List MapToFiletypeResultList(this List filetypes) + { + List result = new(); + if (!filetypes.Any()) + { + return result; + } + + filetypes.ForEach(item => result.Add(new FiletypeResult + { + Id = item.Id, + Name = item.Name, + Description = item.Description, + FileExtension = item.FileExtension + })); + return result; + } +} \ No newline at end of file diff --git a/DocumentDomain/Operations/Scenarios/Filetype/AddFiletypeScenario.cs b/DocumentDomain/Operations/Scenarios/Filetype/AddFiletypeScenario.cs new file mode 100644 index 0000000..3e51f67 --- /dev/null +++ b/DocumentDomain/Operations/Scenarios/Filetype/AddFiletypeScenario.cs @@ -0,0 +1,76 @@ +namespace EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; + +using System.Text; +using BusinessLogic.Contracts; +using Entity; +using FluentValidation.Results; +using Infrastructure.Database; +using Infrastructure.Mappers; +using LanguageExt; +using Microsoft.EntityFrameworkCore; + +public class AddFiletypeScenario( + AddFiletypeScenarioInputValidator validator, + DbContextOptions dbContextOptions +) +{ + public async Task> ExecuteAsync( + AddFiletypeScenarioContext context, + CancellationToken cancellationToken = default) + { + Either result = + from validatedInput in ValidateInput(context.Payload, context.CorrelationId) + from mappedToEntity in MapToFiletypeEntity(validatedInput, context.CorrelationId) + from savedEntity in SaveToDatabase(mappedToEntity, context.CorrelationId) + from mappedSavedEntity in MapToFiletypeResult(savedEntity, context.CorrelationId) + select mappedSavedEntity; + return result; + } + + private Either MapToFiletypeResult(Filetype filetype, Guid correlationId) + { + return Either.Right(filetype.MapToFiletypeResult()); + } + + private Either SaveToDatabase(Filetype filetype, Guid correlationId) + { + using DocumentDomainDbContext ctx = new(dbContextOptions); + try + { + ctx.Filetypes.Add(filetype); + ctx.SaveChanges(); + return Either.Right(filetype); + } + catch (Exception e) + { + return Either.Left(new ErrorResult(correlationId, e.Message)); + } + } + + private Either MapToFiletypeEntity(FiletypeInput payload, Guid correlationId) + { + return Either.Right(payload.MapToFiletypeEntity()); + } + + private Either ValidateInput(FiletypeInput payload, Guid correlationId) + { + ValidationResult? result = validator.Validate(payload); + if (result.IsValid) + { + return Either.Right(payload); + } + + StringBuilder builder = new(); + result.Errors.ForEach(e => builder.Append($"Property name:") + .Append(' ') + .Append(e.PropertyName) + .Append(' ') + .Append("error:") + .Append(' ') + .Append(e.ErrorMessage) + ); + return Either.Left(new ErrorResult(correlationId, builder.ToString())); + } +} + +public record AddFiletypeScenarioContext(Guid CorrelationId, FiletypeInput Payload); \ No newline at end of file diff --git a/DocumentDomain/Operations/Scenarios/Filetype/AddFiletypeScenarioInputValidator.cs b/DocumentDomain/Operations/Scenarios/Filetype/AddFiletypeScenarioInputValidator.cs new file mode 100644 index 0000000..5a396ca --- /dev/null +++ b/DocumentDomain/Operations/Scenarios/Filetype/AddFiletypeScenarioInputValidator.cs @@ -0,0 +1,54 @@ +namespace EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; + +using BusinessLogic.Contracts; +using Entity; +using FluentValidation; + +public class AddFiletypeScenarioInputValidator : AbstractValidator +{ + public AddFiletypeScenarioInputValidator() + { + RuleFor(r => r.Id) + .Equal(0) + .WithMessage($"The id of {nameof(Filetype)} entity must be zero during creation."); + + RuleFor(r => r.Name) + .NotNull() + .WithMessage($"The name of {nameof(Filetype)} entity must not be null."); + + When(w => w.Name is not null, () => + { + RuleFor(w => w.Name) + .NotEmpty() + .WithMessage($"The name of {nameof(Filetype)} entity must not be empty"); + RuleFor(w => w.Name.Trim().Length) + .GreaterThanOrEqualTo(3) + .WithMessage($"The name length of {nameof(Filetype)} must be equal or greater to 3 chars."); + }); + + RuleFor(r => r.Description) + .NotNull() + .WithMessage($"The description of {nameof(Filetype)} entity must not be null."); + + When(w => w.Description is not null, () => + { + RuleFor(w => w.Description) + .NotEmpty() + .WithMessage($"The description of {nameof(Filetype)} entity must not be empty"); + RuleFor(w => w.Description.Trim().Length) + .GreaterThanOrEqualTo(3) + .WithMessage($"The description length of {nameof(Filetype)} must be equal or greater to 3 chars."); + }); + + RuleFor(r => r.FileExtension) + .NotNull() + .WithMessage($"The filetype extension of {nameof(Filetype)} entity must not be null."); + + When(w => w.FileExtension is not null, () => + { + RuleFor(w => w.FileExtension.Trim()) + .NotEmpty() + .WithMessage($"The filetype extension of {nameof(Filetype)} entity must not be empty"); + }); + } +} \ No newline at end of file diff --git a/DocumentDomain/Operations/Scenarios/Filetype/DeleteFiletypeScenario.cs b/DocumentDomain/Operations/Scenarios/Filetype/DeleteFiletypeScenario.cs new file mode 100644 index 0000000..9b895c5 --- /dev/null +++ b/DocumentDomain/Operations/Scenarios/Filetype/DeleteFiletypeScenario.cs @@ -0,0 +1,62 @@ +namespace EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; + +using System.Text; +using BusinessLogic.Contracts; +using Entity; +using FluentValidation.Results; +using Infrastructure.Database; +using LanguageExt; +using Microsoft.EntityFrameworkCore; + +public class DeleteFiletypeScenario( + DeleteFiletypeScenarioInputValidator validator, + DbContextOptions dbContextOptions) +{ + public async Task> ExecuteAsync( + DeleteFiletypeScenarioContext context, + CancellationToken cancellationToken = default) + { + Either result = + from validatedInput in ValidateInput(context.Payload, context.CorrelationId) + from _ in DeleteFromDatabase(validatedInput, context.CorrelationId, cancellationToken) + select new FiletypeResult(); + return result; + } + + private Either DeleteFromDatabase(FiletypeInput input, Guid correlationId, CancellationToken cancellationToken) + { + using DocumentDomainDbContext ctx = new(dbContextOptions); + try + { + Filetype target = ctx.Filetypes.First(w => w.Id == input.Id); + ctx.Entry(target).State = EntityState.Deleted; + ctx.SaveChanges(); + return Either.Right(new FiletypeResult()); + } + catch (Exception e) + { + return Either.Left(new ErrorResult(correlationId, e.Message)); + } + } + + private Either ValidateInput(FiletypeInput input, Guid correlationId) + { + ValidationResult validationResult = validator.Validate(input); + if (validationResult.IsValid) + { + return Either.Right(input); + } + + StringBuilder builder = new(); + validationResult.Errors.ForEach(e => builder.Append("Property name:") + .Append(' ') + .Append(e.PropertyName) + .Append(' ') + .Append("Error message:") + .Append(' ') + .Append(e.ErrorMessage)); + return Either.Left(new ErrorResult(correlationId, builder.ToString())); + } +} + +public record DeleteFiletypeScenarioContext(Guid CorrelationId, FiletypeInput Payload); \ No newline at end of file diff --git a/DocumentDomain/Operations/Scenarios/Filetype/DeleteFiletypeScenarioInputValidator.cs b/DocumentDomain/Operations/Scenarios/Filetype/DeleteFiletypeScenarioInputValidator.cs new file mode 100644 index 0000000..3b1b1f4 --- /dev/null +++ b/DocumentDomain/Operations/Scenarios/Filetype/DeleteFiletypeScenarioInputValidator.cs @@ -0,0 +1,14 @@ +namespace EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; + +using BusinessLogic.Contracts; +using FluentValidation; + +public class DeleteFiletypeScenarioInputValidator : AbstractValidator +{ + public DeleteFiletypeScenarioInputValidator() + { + RuleFor(r => r.Id) + .GreaterThanOrEqualTo(1) + .WithMessage($"The id of {nameof(Filetype)} entity must be greater or equal to 1."); + } +} \ No newline at end of file diff --git a/DocumentDomain/Operations/Scenarios/Filetype/EditFiletypeScenario.cs b/DocumentDomain/Operations/Scenarios/Filetype/EditFiletypeScenario.cs new file mode 100644 index 0000000..79128a6 --- /dev/null +++ b/DocumentDomain/Operations/Scenarios/Filetype/EditFiletypeScenario.cs @@ -0,0 +1,77 @@ +namespace EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; + +using System.Text; +using BusinessLogic.Contracts; +using Entity; +using FluentValidation.Results; +using Infrastructure.Database; +using Infrastructure.Mappers; +using LanguageExt; +using Microsoft.EntityFrameworkCore; + +public class EditFiletypeScenario( + EditFiletypeScenarioInputValidator validator, + DbContextOptions dbContextOptions) +{ + public async Task> ExecuteAsync( + EditFiletypeScenarioContext context, + CancellationToken cancellationToken = default) + { + Either result = + from validatedInput in ValidateInput(context.Payload, context.CorrelationId) + from mappedInput in MapToFiletype(validatedInput, context.CorrelationId) + from savedEntity in SaveToDatabase(mappedInput, context.CorrelationId) + from mappedResult in MapToFiletypeResult(savedEntity, context.CorrelationId) + select mappedResult; + return result; + } + + private Either MapToFiletypeResult(Filetype filetype, Guid correlationId) + { + return filetype.MapToFiletypeResult(); + } + + private Either SaveToDatabase(Filetype input, Guid correlationId) + { + using DocumentDomainDbContext ctx = new(dbContextOptions); + try + { + Filetype target = ctx.Filetypes.First(f => f.Id == input.Id); + target.Name = input.Name; + target.Description = input.Description; + target.FileExtension = input.FileExtension; + ctx.Entry(target).State = EntityState.Modified; + ctx.SaveChanges(); + return Either.Right(target); + } + catch (Exception e) + { + return Either.Left(new ErrorResult(correlationId, e.Message)); + } + } + + private Either MapToFiletype(FiletypeInput input, Guid correlationId) + { + return Either.Right(input.MapToFiletypeEntity()); + } + + private Either ValidateInput(FiletypeInput input, Guid correlationId) + { + ValidationResult result = validator.Validate(input); + if (result.IsValid) + { + return Either.Right(input); + } + + StringBuilder builder = new(); + result.Errors.ForEach(er => builder + .Append("Property name") + .Append(' ') + .Append($"{er.PropertyName}") + .Append(' ') + .Append($"{er.ErrorMessage}")); + return Either.Left(new ErrorResult(correlationId, builder.ToString())); + } +} + +public record EditFiletypeScenarioContext(Guid CorrelationId, FiletypeInput Payload); \ No newline at end of file diff --git a/DocumentDomain/Operations/Scenarios/Filetype/EditFiletypeScenarioInputValidator.cs b/DocumentDomain/Operations/Scenarios/Filetype/EditFiletypeScenarioInputValidator.cs new file mode 100644 index 0000000..7e47ebd --- /dev/null +++ b/DocumentDomain/Operations/Scenarios/Filetype/EditFiletypeScenarioInputValidator.cs @@ -0,0 +1,53 @@ +namespace EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; + +using BusinessLogic.Contracts; +using FluentValidation; + +public class EditFiletypeScenarioInputValidator : AbstractValidator +{ + public EditFiletypeScenarioInputValidator() + { + RuleFor(r => r.Id) + .GreaterThanOrEqualTo(1) + .WithMessage($"The id of {nameof(FiletypeInput)} entity must be greater or equals to 1."); + + RuleFor(r => r.Name) + .NotNull() + .WithMessage($"The name of {nameof(FiletypeInput)} entity must not be null."); + + When(w => w.Name is not null, () => + { + RuleFor(w => w.Name) + .NotEmpty() + .WithMessage($"The name of {nameof(FiletypeInput)} entity must not be empty"); + RuleFor(w => w.Name.Trim().Length) + .GreaterThanOrEqualTo(3) + .WithMessage($"The name length of {nameof(FiletypeInput)} must be equal or greater to 3 chars."); + }); + + RuleFor(r => r.Description) + .NotNull() + .WithMessage($"The description of {nameof(FiletypeInput)} entity must not be null."); + + When(w => w.Description is not null, () => + { + RuleFor(w => w.Description) + .NotEmpty() + .WithMessage($"The description of {nameof(FiletypeInput)} entity must not be empty"); + RuleFor(w => w.Description.Trim().Length) + .GreaterThanOrEqualTo(3) + .WithMessage($"The description length of {nameof(FiletypeInput)} must be equal or greater to 3 chars."); + }); + + RuleFor(r => r.FileExtension) + .NotNull() + .WithMessage($"The filetype extension of {nameof(FiletypeInput)} entity must not be null."); + + When(w => w.FileExtension is not null, () => + { + RuleFor(w => w.FileExtension.Trim()) + .NotEmpty() + .WithMessage($"The filetype extension of {nameof(FiletypeInput)} entity must not be empty"); + }); + } +} \ No newline at end of file diff --git a/DocumentDomain/Operations/Scenarios/Filetype/GetFiletypeByIdScenario.cs b/DocumentDomain/Operations/Scenarios/Filetype/GetFiletypeByIdScenario.cs new file mode 100644 index 0000000..1b6df66 --- /dev/null +++ b/DocumentDomain/Operations/Scenarios/Filetype/GetFiletypeByIdScenario.cs @@ -0,0 +1,68 @@ +namespace EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; + +using System.Text; +using BusinessLogic.Contracts; +using Entity; +using FluentValidation.Results; +using Infrastructure.Database; +using Infrastructure.Mappers; +using LanguageExt; +using Microsoft.EntityFrameworkCore; + +public class GetFiletypeByIdScenario( + GetFiletypeByIdScenarioInputValidator validator, + DbContextOptions dbContextOptions +) +{ + public async Task> ExecuteAsync( + GetFiletypeByIdScenarioContext context, + CancellationToken cancellationToken = default) + { + Either result = + from validatedInput in ValidateInput(context.Payload, context.CorrelationId) + from foundEntity in FindInDatabase(validatedInput, context.CorrelationId) + from mappedResult in MapToFiletypeResult(foundEntity, context.CorrelationId) + select mappedResult; + return result; + } + + private Either MapToFiletypeResult(Filetype filetype, Guid correlationId) + { + return filetype.MapToFiletypeResult(); + } + + private Either FindInDatabase(FiletypeInput input, Guid correlationId) + { + using DocumentDomainDbContext ctx = new(dbContextOptions); + try + { + Filetype target = ctx.Filetypes.First(w => w.Id == input.Id); + return Either.Right(target); + } + catch (Exception e) + { + return Either.Left(new ErrorResult(correlationId, e.Message)); + } + } + + private Either ValidateInput(FiletypeInput input, Guid correlationId) + { + ValidationResult validationResult = validator.Validate(input); + if (validationResult.IsValid) + { + return Either.Right(input); + } + + StringBuilder builder = new(); + validationResult.Errors.ForEach(err => builder.Append("Property name") + .Append(' ') + .Append(err.PropertyName) + .Append(' ') + .Append("message:") + .Append(' ') + .Append(err.ErrorMessage)); + return Either.Left(new ErrorResult(correlationId, builder.ToString())); + } +} + +public record GetFiletypeByIdScenarioContext(Guid CorrelationId, FiletypeInput Payload); \ No newline at end of file diff --git a/DocumentDomain/Operations/Scenarios/Filetype/GetFiletypeByIdScenarioInputValidator.cs b/DocumentDomain/Operations/Scenarios/Filetype/GetFiletypeByIdScenarioInputValidator.cs new file mode 100644 index 0000000..f64903c --- /dev/null +++ b/DocumentDomain/Operations/Scenarios/Filetype/GetFiletypeByIdScenarioInputValidator.cs @@ -0,0 +1,14 @@ +namespace EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; + +using BusinessLogic.Contracts; +using FluentValidation; + +public class GetFiletypeByIdScenarioInputValidator : AbstractValidator +{ + public GetFiletypeByIdScenarioInputValidator() + { + RuleFor(r => r.Id) + .GreaterThanOrEqualTo(1) + .WithMessage($"The id of {nameof(FiletypeInput)} entity must be greater or equals to 1."); + } +} \ No newline at end of file diff --git a/DocumentDomain/Operations/Scenarios/Filetype/GetFiletypesScenario.cs b/DocumentDomain/Operations/Scenarios/Filetype/GetFiletypesScenario.cs new file mode 100644 index 0000000..f4075cd --- /dev/null +++ b/DocumentDomain/Operations/Scenarios/Filetype/GetFiletypesScenario.cs @@ -0,0 +1,43 @@ +namespace EncyclopediaGalactica.DocumentDomain.Operations.Scenarios.Filetype; + +using BusinessLogic.Contracts; +using Entity; +using Infrastructure.Database; +using Infrastructure.Mappers; +using LanguageExt; +using Microsoft.EntityFrameworkCore; + +public class GetFiletypesScenario(DbContextOptions dbContextOptions) +{ + public async Task>> ExecuteAsync( + GetFiletypesScenarioContext context, + CancellationToken cancellationToken = default) + { + Either> result = + from filetypes in FetchFromDatabase(context.CorrelationId, cancellationToken) + from mappedResult in MapToFiletypeResultList(filetypes, context.CorrelationId) + select mappedResult; + return result; + } + + private Either> MapToFiletypeResultList(List filetypes, Guid correlationId) + { + return filetypes.MapToFiletypeResultList(); + } + + private Either> FetchFromDatabase(Guid correlationId, CancellationToken cancellationToken) + { + using DocumentDomainDbContext ctx = new(dbContextOptions); + try + { + List result = ctx.Filetypes.ToList(); + return Either>.Right(result); + } + catch (Exception e) + { + return Either>.Left(new ErrorResult(correlationId, e.Message)); + } + } +} + +public record GetFiletypesScenarioContext(Guid CorrelationId); \ No newline at end of file diff --git a/Tools/Tools.csproj b/Tools/Tools.csproj index 53555eb..e5bf951 100644 --- a/Tools/Tools.csproj +++ b/Tools/Tools.csproj @@ -13,7 +13,7 @@ - +