diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..f8c883d9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# CA1806: Do not ignore method results +dotnet_diagnostic.CA1806.severity = warning diff --git a/TransactionProcessor.Aggregates.Tests/EstateAggregateTests.cs b/TransactionProcessor.Aggregates.Tests/EstateAggregateTests.cs index 7c260882..3f813615 100644 --- a/TransactionProcessor.Aggregates.Tests/EstateAggregateTests.cs +++ b/TransactionProcessor.Aggregates.Tests/EstateAggregateTests.cs @@ -1,4 +1,5 @@ using Shouldly; +using SimpleResults; using TransactionProcessor.Models.Estate; using TransactionProcessor.Testing; @@ -19,7 +20,6 @@ public void EstateAggregate_Create_IsCreated() { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); aggregate.Create(TestData.EstateName); - aggregate.GenerateReference(); aggregate.AggregateId.ShouldBe(TestData.EstateId); aggregate.EstateName.ShouldBe(TestData.EstateName); @@ -33,45 +33,29 @@ public void EstateAggregate_Create_IsCreated() public void EstateAggregate_Create_InvalidEstateName_ErrorThrown(String estateName) { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); - ArgumentNullException exception = Should.Throw(() => - { - aggregate.Create(estateName); - }); + Result result = aggregate.Create(estateName); - exception.Message.ShouldContain("Estate name must be provided when registering a new estate"); - } - - [Fact] - public void EstateAggregate_Create_EstateAlreadyCreated_NoErrorThrown() - { - EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); - aggregate.Create(TestData.EstateName); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); - Should.NotThrow(() => - { - aggregate.Create(TestData.EstateName); - }); + result.Message.ShouldContain("Estate name must be provided when registering a new estate"); } [Fact] - public void EstateAggregate_GenerateReference_CalledTwice_NoErrorThrown() + public void EstateAggregate_Create_EstateAlreadyCreated_NoErrorThrown() { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); aggregate.Create(TestData.EstateName); - aggregate.GenerateReference(); - Should.NotThrow(() => - { - aggregate.GenerateReference(); - }); + var result = aggregate.Create(TestData.EstateName); + result.IsSuccess.ShouldBeTrue(); } - + [Fact] public void EstateAggregate_GetEstate_NoOperators_EstateIsReturned() { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); aggregate.Create(TestData.EstateName); - aggregate.GenerateReference(); TransactionProcessor.Models.Estate.Estate model = aggregate.GetEstate(); model.EstateId.ShouldBe(TestData.EstateId); @@ -85,7 +69,6 @@ public void EstateAggregate_GetEstate_WithAnOperator_EstateIsReturned() { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); aggregate.Create(TestData.EstateName); - aggregate.GenerateReference(); aggregate.AddOperator(TestData.OperatorId); TransactionProcessor.Models.Estate.Estate model = aggregate.GetEstate(); @@ -104,7 +87,6 @@ public void EstateAggregate_GetEstate_NoSecurityUsers_EstateIsReturned() { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); aggregate.Create(TestData.EstateName); - aggregate.GenerateReference(); TransactionProcessor.Models.Estate.Estate model = aggregate.GetEstate(); model.EstateId.ShouldBe(TestData.EstateId); @@ -119,7 +101,6 @@ public void EstateAggregate_GetEstate_WithASecurityUser_EstateIsReturned() { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); aggregate.Create(TestData.EstateName); - aggregate.GenerateReference(); aggregate.AddSecurityUser(TestData.SecurityUserId,TestData.EstateUserEmailAddress); TransactionProcessor.Models.Estate.Estate model = aggregate.GetEstate(); @@ -153,12 +134,12 @@ public void EstateAggregate_AddOperatorToEstate_EstateNotCreated_ErrorThrown() { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); - InvalidOperationException exception = Should.Throw(() => - { - aggregate.AddOperator(TestData.OperatorId); - }); + Result result = aggregate.AddOperator(TestData.OperatorId); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); - exception.Message.ShouldContain("Estate has not been created"); + result.Message.ShouldContain("Estate has not been created"); } [Fact] @@ -168,12 +149,11 @@ public void EstateAggregate_AddOperatorToEstate_OperatorWithIdAlreadyAdded_Error aggregate.Create(TestData.EstateName); aggregate.AddOperator(TestData.OperatorId); - InvalidOperationException exception = Should.Throw(() => - { - aggregate.AddOperator(TestData.OperatorId); - }); + var result = aggregate.AddOperator(TestData.OperatorId); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); - exception.Message.ShouldContain($"Duplicate operator details are not allowed, an operator already exists on this estate with Id [{TestData.OperatorId}]"); + result.Message.ShouldContain($"Duplicate operator details are not allowed, an operator already exists on this estate with Id [{TestData.OperatorId}]"); } [Fact] @@ -193,12 +173,12 @@ public void EstateAggregate_AddSecurityUserToEstate_EstateNotCreated_ErrorThrown { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); - InvalidOperationException exception = Should.Throw(() => - { - aggregate.AddSecurityUser(TestData.SecurityUserId, TestData.EstateUserEmailAddress); - }); + Result result = aggregate.AddSecurityUser(TestData.SecurityUserId, TestData.EstateUserEmailAddress); - exception.Message.ShouldContain("Estate has not been created"); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + + result.Message.ShouldContain("Estate has not been created"); } [Fact] @@ -220,12 +200,11 @@ public void EstateAggregate_RemoveOperatorFromEstate_EstateNotCreated_ErrorThrow { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); - InvalidOperationException exception = Should.Throw(() => - { - aggregate.RemoveOperator(TestData.OperatorId); - }); + Result result = aggregate.RemoveOperator(TestData.OperatorId); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); - exception.Message.ShouldContain("Estate has not been created"); + result.Message.ShouldContain("Estate has not been created"); } [Fact] @@ -233,13 +212,12 @@ public void EstateAggregate_RemoveOperatorFromEstate_OperatorWithIdNotAlreadyAdd { EstateAggregate aggregate = EstateAggregate.Create(TestData.EstateId); aggregate.Create(TestData.EstateName); + + var result = aggregate.RemoveOperator(TestData.OperatorId); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); - InvalidOperationException exception = Should.Throw(() => - { - aggregate.RemoveOperator(TestData.OperatorId); - }); - - exception.Message.ShouldContain($"Operator not added to this Estate with Id [{TestData.OperatorId}]"); + result.Message.ShouldContain($"Operator not added to this Estate with Id [{TestData.OperatorId}]"); } } } diff --git a/TransactionProcessor.Aggregates/EstateAggregate.cs b/TransactionProcessor.Aggregates/EstateAggregate.cs index b3ec55e3..bb9adfea 100644 --- a/TransactionProcessor.Aggregates/EstateAggregate.cs +++ b/TransactionProcessor.Aggregates/EstateAggregate.cs @@ -1,7 +1,9 @@ using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; using Shared.DomainDrivenDesign.EventSourcing; using Shared.EventStore.Aggregate; using Shared.General; +using SimpleResults; using TransactionProcessor.DomainEvents; using TransactionProcessor.Models.Estate; @@ -9,95 +11,92 @@ namespace TransactionProcessor.Aggregates{ public static class EstateAggregateExtensions{ #region Methods - public static void AddOperator(this EstateAggregate aggregate, + public static Result AddOperator(this EstateAggregate aggregate, Guid operatorId){ - - aggregate.CheckEstateHasBeenCreated(); - aggregate.CheckOperatorHasNotAlreadyBeenCreated(operatorId); + + Result result = aggregate.CheckEstateHasBeenCreated(); + if (result.IsFailed) + return result; + result = aggregate.CheckOperatorHasNotAlreadyBeenCreated(operatorId); + if (result.IsFailed) + return result; EstateDomainEvents.OperatorAddedToEstateEvent operatorAddedToEstateEvent = new EstateDomainEvents.OperatorAddedToEstateEvent(aggregate.AggregateId, operatorId); aggregate.ApplyAndAppend(operatorAddedToEstateEvent); + + return Result.Success(); } - public static void RemoveOperator(this EstateAggregate aggregate, + public static Result RemoveOperator(this EstateAggregate aggregate, Guid operatorId) { - aggregate.CheckEstateHasBeenCreated(); - aggregate.CheckOperatorHasBeenAdded(operatorId); - - EstateDomainEvents.OperatorRemovedFromEstateEvent operatorRemovedFromEstateEvent = - new EstateDomainEvents.OperatorRemovedFromEstateEvent(aggregate.AggregateId, operatorId); + Result result = aggregate.CheckEstateHasBeenCreated(); + if (result.IsFailed) + return result; + result = aggregate.CheckOperatorHasBeenAdded(operatorId); + if (result.IsFailed) + return result; + EstateDomainEvents.OperatorRemovedFromEstateEvent operatorRemovedFromEstateEvent = new(aggregate.AggregateId, operatorId); aggregate.ApplyAndAppend(operatorRemovedFromEstateEvent); + + return Result.Success(); } - public static void AddSecurityUser(this EstateAggregate aggregate, + public static Result AddSecurityUser(this EstateAggregate aggregate, Guid securityUserId, String emailAddress){ - aggregate.CheckEstateHasBeenCreated(); + Result result = aggregate.CheckEstateHasBeenCreated(); + if (result.IsFailed) + return result; - EstateDomainEvents.SecurityUserAddedToEstateEvent securityUserAddedEvent = new EstateDomainEvents.SecurityUserAddedToEstateEvent(aggregate.AggregateId, securityUserId, emailAddress); + EstateDomainEvents.SecurityUserAddedToEstateEvent securityUserAddedEvent = new(aggregate.AggregateId, securityUserId, emailAddress); aggregate.ApplyAndAppend(securityUserAddedEvent); + + return Result.Success(); } - public static void Create(this EstateAggregate aggregate, String estateName){ - Guard.ThrowIfNullOrEmpty(estateName, typeof(ArgumentNullException), "Estate name must be provided when registering a new estate"); + [Pure] + public static Result Create(this EstateAggregate aggregate, String estateName){ + if (String.IsNullOrEmpty(estateName)) + return Result.Invalid("Estate name must be provided when registering a new estate"); // Just return if already created if (aggregate.IsCreated) - return; + return Result.Success(); - EstateDomainEvents.EstateCreatedEvent estateCreatedEvent = new EstateDomainEvents.EstateCreatedEvent(aggregate.AggregateId, estateName); + EstateDomainEvents.EstateCreatedEvent estateCreatedEvent = new(aggregate.AggregateId, estateName); aggregate.ApplyAndAppend(estateCreatedEvent); - } - - public static void GenerateReference(this EstateAggregate aggregate){ - // Just return as we already have a reference allocated - if (String.IsNullOrEmpty(aggregate.EstateReference) == false) - return; - - aggregate.CheckEstateHasBeenCreated(); String reference = $"{aggregate.AggregateId.GetHashCode():X}"; EstateDomainEvents.EstateReferenceAllocatedEvent estateReferenceAllocatedEvent = new EstateDomainEvents.EstateReferenceAllocatedEvent(aggregate.AggregateId, reference); aggregate.ApplyAndAppend(estateReferenceAllocatedEvent); + + return Result.Success(); } + + public static Estate GetEstate(this EstateAggregate aggregate) { + Estate estateModel = new() { EstateId = aggregate.AggregateId, Name = aggregate.EstateName, Reference = aggregate.EstateReference, Operators = [] }; - public static TransactionProcessor.Models.Estate.Estate GetEstate(this EstateAggregate aggregate){ - TransactionProcessor.Models.Estate.Estate estateModel = new TransactionProcessor.Models.Estate.Estate(); - - estateModel.EstateId = aggregate.AggregateId; - estateModel.Name = aggregate.EstateName; - estateModel.Reference = aggregate.EstateReference; - - estateModel.Operators = new List(); - if (aggregate.Operators.Any()){ - - foreach (KeyValuePair @operator in aggregate.Operators){ - estateModel.Operators.Add(new TransactionProcessor.Models.Estate.Operator - { - OperatorId = @operator.Key, - IsDeleted = @operator.Value.IsDeleted, - }); + if (aggregate.Operators.Any()) { + + foreach (KeyValuePair @operator in aggregate.Operators) { + estateModel.Operators.Add(new Operator { OperatorId = @operator.Key, IsDeleted = @operator.Value.IsDeleted, }); } } - estateModel.SecurityUsers = new List(); - if (aggregate.SecurityUsers.Any()){ - - foreach (KeyValuePair securityUser in aggregate.SecurityUsers){ - estateModel.SecurityUsers.Add(new TransactionProcessor.Models.Estate.SecurityUser - { - EmailAddress = securityUser.Value.EmailAddress, - SecurityUserId = securityUser.Key - }); + estateModel.SecurityUsers = new List(); + if (aggregate.SecurityUsers.Any()) { + + foreach (KeyValuePair securityUser in aggregate.SecurityUsers) { + estateModel.SecurityUsers.Add(new SecurityUser { EmailAddress = securityUser.Value.EmailAddress, SecurityUserId = securityUser.Key }); } } @@ -119,10 +118,6 @@ public static void PlayEvent(this EstateAggregate aggregate, EstateDomainEvents. aggregate.EstateReference = domainEvent.EstateReference; } - /// - /// Operators the added to estate event. - /// - /// The domain event. public static void PlayEvent(this EstateAggregate aggregate, EstateDomainEvents.OperatorAddedToEstateEvent domainEvent){ TransactionProcessor.Models.Estate.Operator @operator = new() { IsDeleted = false, @@ -137,30 +132,29 @@ public static void PlayEvent(this EstateAggregate aggregate, EstateDomainEvents. aggregate.Operators[domainEvent.OperatorId].IsDeleted = true; } - private static void CheckEstateHasBeenCreated(this EstateAggregate aggregate){ + private static Result CheckEstateHasBeenCreated(this EstateAggregate aggregate){ if (aggregate.IsCreated == false){ - throw new InvalidOperationException("Estate has not been created"); + return Result.Invalid("Estate has not been created"); } + return Result.Success(); } - private static void CheckOperatorHasNotAlreadyBeenCreated(this EstateAggregate aggregate, - Guid operatorId){ - Boolean operatorRecord = aggregate.Operators.ContainsKey(operatorId); - - if (operatorRecord == true){ - throw new InvalidOperationException($"Duplicate operator details are not allowed, an operator already exists on this estate with Id [{operatorId}]"); + private static Result CheckOperatorHasNotAlreadyBeenCreated(this EstateAggregate aggregate, + Guid operatorId) { + Boolean operatorRecordExists = aggregate.Operators.ContainsKey(operatorId); + if (operatorRecordExists == true) { + return Result.Invalid($"Duplicate operator details are not allowed, an operator already exists on this estate with Id [{operatorId}]"); } + return Result.Success(); } - private static void CheckOperatorHasBeenAdded(this EstateAggregate aggregate, - Guid operatorId) - { - Boolean operatorRecord = aggregate.Operators.ContainsKey(operatorId); - - if (operatorRecord == false) - { - throw new InvalidOperationException($"Operator not added to this Estate with Id [{operatorId}]"); + private static Result CheckOperatorHasBeenAdded(this EstateAggregate aggregate, + Guid operatorId) { + Boolean operatorRecordExists = aggregate.Operators.ContainsKey(operatorId); + if (operatorRecordExists == false) { + return Result.Invalid($"Operator not added to this Estate with Id [{operatorId}]"); } + return Result.Success(); } #endregion diff --git a/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj b/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj index 880f67dd..09cd1fd3 100644 --- a/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj +++ b/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj @@ -2,7 +2,7 @@ net9.0 - Full + None false diff --git a/TransactionProcessor.BusinessLogic/Services/EstateDomainService.cs b/TransactionProcessor.BusinessLogic/Services/EstateDomainService.cs index 4ec0bca2..dde20ef3 100644 --- a/TransactionProcessor.BusinessLogic/Services/EstateDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/EstateDomainService.cs @@ -62,8 +62,9 @@ public async Task CreateEstate(EstateCommands.CreateEstateCommand comman EstateAggregate estateAggregate = estateResult.Data; - estateAggregate.Create(command.RequestDto.EstateName); - estateAggregate.GenerateReference(); + Result stateResult = estateAggregate.Create(command.RequestDto.EstateName); + if (stateResult.IsFailed) + return ResultHelpers.CreateFailure(stateResult); Result saveResult = await this.AggregateService.Save(estateAggregate, cancellationToken); if (saveResult.IsFailed) @@ -90,7 +91,9 @@ public async Task AddOperatorToEstate(EstateCommands.AddOperatorToEstate EstateAggregate estateAggregate = estateResult.Data; - estateAggregate.AddOperator(command.RequestDto.OperatorId); + Result stateResult =estateAggregate.AddOperator(command.RequestDto.OperatorId); + if (stateResult.IsFailed) + return ResultHelpers.CreateFailure(stateResult); Result saveResult = await this.AggregateService.Save(estateAggregate, cancellationToken); if (saveResult.IsFailed) @@ -143,7 +146,9 @@ public async Task CreateEstateUser(EstateCommands.CreateEstateUserComman EstateAggregate estateAggregate = estateResult.Data; - estateAggregate.AddSecurityUser(user.UserId, command.RequestDto.EmailAddress); + Result stateResult = estateAggregate.AddSecurityUser(user.UserId, command.RequestDto.EmailAddress); + if (stateResult.IsFailed) + return ResultHelpers.CreateFailure(stateResult); Result saveResult = await this.AggregateService.Save(estateAggregate, cancellationToken); if (saveResult.IsFailed) @@ -167,7 +172,9 @@ public async Task RemoveOperatorFromEstate(EstateCommands.RemoveOperator EstateAggregate estateAggregate = estateResult.Data; - estateAggregate.RemoveOperator(command.OperatorId); + Result stateResult = estateAggregate.RemoveOperator(command.OperatorId); + if (stateResult.IsFailed) + return ResultHelpers.CreateFailure(stateResult); Result saveResult = await this.AggregateService.Save(estateAggregate, cancellationToken); if (saveResult.IsFailed) diff --git a/TransactionProcessor.DatabaseTests/TransactionProcessor.DatabaseTests.csproj b/TransactionProcessor.DatabaseTests/TransactionProcessor.DatabaseTests.csproj index 2970b6be..7e7f2ecb 100644 --- a/TransactionProcessor.DatabaseTests/TransactionProcessor.DatabaseTests.csproj +++ b/TransactionProcessor.DatabaseTests/TransactionProcessor.DatabaseTests.csproj @@ -5,6 +5,7 @@ enable enable false + None diff --git a/TransactionProcessor.sln b/TransactionProcessor.sln index 7d35f702..b40bf2e7 100644 --- a/TransactionProcessor.sln +++ b/TransactionProcessor.sln @@ -43,6 +43,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionProcessor.Domain EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionProcessor.DatabaseTests", "TransactionProcessor.DatabaseTests\TransactionProcessor.DatabaseTests.csproj", "{33C3AABB-B6A9-40CD-A8E0-3EF8DD38646E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/TransactionProcessor/TransactionProcessor.csproj b/TransactionProcessor/TransactionProcessor.csproj index a5ac1488..a82bda69 100644 --- a/TransactionProcessor/TransactionProcessor.csproj +++ b/TransactionProcessor/TransactionProcessor.csproj @@ -47,7 +47,6 @@ -