Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.2.0] - 2025-04-25

### Added

- Added unconditional branch with local payload method overload
- New `BranchWithLocalPayload` method that doesn't require a condition parameter and always executes
- Supports both callback-style API and fluent API patterns: `.BranchWithLocalPayload(localPayloadFactory, branch => { ... })`

## [2.1.0] - 2025-04-21

### Added
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<Description>A .NET library for building robust, functional workflows and processing pipelines.</Description>

<!-- Version information -->
<Version>2.1.0</Version>
<Version>2.2.0</Version>

<!-- Source linking -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
Expand Down
46 changes: 46 additions & 0 deletions Zooper.Bee.Tests/BranchWithLocalPayloadTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,4 +408,50 @@ public async Task BranchWithLocalPayload_UnconditionalBranch_AlwaysExecutes()
result.Right.ProcessingResult.Should().Be("Processed with default customization");
result.Right.CustomizationDetails.Should().Be("Default customization");
}

[Fact]
public async Task BranchWithLocalPayload_UnconditionalBranchFluentApi_AlwaysExecutes()
{
// Arrange
var workflow = new WorkflowBuilder<ProductRequest, ProductPayload, ProductResult, ProductError>(
request => new ProductPayload(request.Id, request.Name, request.Price, request.NeedsCustomProcessing),
payload => new ProductResult(
payload.Id, payload.Name, payload.FinalPrice,
payload.ProcessingResult, payload.CustomizationDetails)
)
.BranchWithLocalPayload(
// Local payload factory only (no condition parameter)
_ => new CustomizationPayload(
AvailableOptions: new[] { "Default Option" },
SelectedOptions: new[] { "Default Option" },
CustomizationCost: 5.00m,
CustomizationDetails: "Default customization (fluent API)"
),
// Use callback pattern instead of fluent API
branch => branch.Do((mainPayload, localPayload) =>
{
var updatedMainPayload = mainPayload with
{
FinalPrice = mainPayload.Price + localPayload.CustomizationCost,
CustomizationDetails = localPayload.CustomizationDetails,
ProcessingResult = "Processed with fluent API"
};

return Either<ProductError, (ProductPayload, CustomizationPayload)>.FromRight(
(updatedMainPayload, localPayload));
})
)
.Build();

var request = new ProductRequest(1001, "Test Product", 100.00m, false);

// Act
var result = await workflow.Execute(request);

// Assert
result.IsRight.Should().BeTrue();
result.Right.FinalPrice.Should().Be(105.00m); // 100 + 5
result.Right.ProcessingResult.Should().Be("Processed with fluent API");
result.Right.CustomizationDetails.Should().Be("Default customization (fluent API)");
}
}
15 changes: 15 additions & 0 deletions Zooper.Bee/WorkflowBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,21 @@ public WorkflowBuilder<TRequest, TPayload, TSuccess, TError> BranchWithLocalPayl
return this;
}

/// <summary>
/// Creates a branch in the workflow with a local payload that always executes.
/// This is a convenience method for organizing related activities.
/// </summary>
/// <typeparam name="TLocalPayload">The type of the local branch payload</typeparam>
/// <param name="localPayloadFactory">The factory function that creates the local payload</param>
/// <returns>A branch builder that allows adding activities to the branch</returns>
public BranchWithLocalPayloadBuilder<TRequest, TPayload, TLocalPayload, TSuccess, TError> BranchWithLocalPayload<TLocalPayload>(
Func<TPayload, TLocalPayload> localPayloadFactory)
{
var branch = new BranchWithLocalPayload<TPayload, TLocalPayload, TError>(_ => true, localPayloadFactory);
_branchesWithLocalPayload.Add(branch);
return new BranchWithLocalPayloadBuilder<TRequest, TPayload, TLocalPayload, TSuccess, TError>(this, branch);
}

/// <summary>
/// Creates a branch in the workflow with a local payload that always executes.
/// This is a convenience method for organizing related activities.
Expand Down