Skip to content

Commit 2bfc80d

Browse files
authored
Merge pull request #4 from zooper-lib/feature/branch-method
Added new branch method without the need for a condition
2 parents 5caac39 + 55fcff3 commit 2bfc80d

4 files changed

Lines changed: 70 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.2.0] - 2025-04-25
9+
10+
### Added
11+
12+
- Added unconditional branch with local payload method overload
13+
- New `BranchWithLocalPayload` method that doesn't require a condition parameter and always executes
14+
- Supports both callback-style API and fluent API patterns: `.BranchWithLocalPayload(localPayloadFactory, branch => { ... })`
15+
816
## [2.1.0] - 2025-04-21
917

1018
### Added

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<Description>A .NET library for building robust, functional workflows and processing pipelines.</Description>
1414

1515
<!-- Version information -->
16-
<Version>2.1.0</Version>
16+
<Version>2.2.0</Version>
1717

1818
<!-- Source linking -->
1919
<PublishRepositoryUrl>true</PublishRepositoryUrl>

Zooper.Bee.Tests/BranchWithLocalPayloadTests.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,4 +408,50 @@ public async Task BranchWithLocalPayload_UnconditionalBranch_AlwaysExecutes()
408408
result.Right.ProcessingResult.Should().Be("Processed with default customization");
409409
result.Right.CustomizationDetails.Should().Be("Default customization");
410410
}
411+
412+
[Fact]
413+
public async Task BranchWithLocalPayload_UnconditionalBranchFluentApi_AlwaysExecutes()
414+
{
415+
// Arrange
416+
var workflow = new WorkflowBuilder<ProductRequest, ProductPayload, ProductResult, ProductError>(
417+
request => new ProductPayload(request.Id, request.Name, request.Price, request.NeedsCustomProcessing),
418+
payload => new ProductResult(
419+
payload.Id, payload.Name, payload.FinalPrice,
420+
payload.ProcessingResult, payload.CustomizationDetails)
421+
)
422+
.BranchWithLocalPayload(
423+
// Local payload factory only (no condition parameter)
424+
_ => new CustomizationPayload(
425+
AvailableOptions: new[] { "Default Option" },
426+
SelectedOptions: new[] { "Default Option" },
427+
CustomizationCost: 5.00m,
428+
CustomizationDetails: "Default customization (fluent API)"
429+
),
430+
// Use callback pattern instead of fluent API
431+
branch => branch.Do((mainPayload, localPayload) =>
432+
{
433+
var updatedMainPayload = mainPayload with
434+
{
435+
FinalPrice = mainPayload.Price + localPayload.CustomizationCost,
436+
CustomizationDetails = localPayload.CustomizationDetails,
437+
ProcessingResult = "Processed with fluent API"
438+
};
439+
440+
return Either<ProductError, (ProductPayload, CustomizationPayload)>.FromRight(
441+
(updatedMainPayload, localPayload));
442+
})
443+
)
444+
.Build();
445+
446+
var request = new ProductRequest(1001, "Test Product", 100.00m, false);
447+
448+
// Act
449+
var result = await workflow.Execute(request);
450+
451+
// Assert
452+
result.IsRight.Should().BeTrue();
453+
result.Right.FinalPrice.Should().Be(105.00m); // 100 + 5
454+
result.Right.ProcessingResult.Should().Be("Processed with fluent API");
455+
result.Right.CustomizationDetails.Should().Be("Default customization (fluent API)");
456+
}
411457
}

Zooper.Bee/WorkflowBuilder.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,21 @@ public WorkflowBuilder<TRequest, TPayload, TSuccess, TError> BranchWithLocalPayl
282282
return this;
283283
}
284284

285+
/// <summary>
286+
/// Creates a branch in the workflow with a local payload that always executes.
287+
/// This is a convenience method for organizing related activities.
288+
/// </summary>
289+
/// <typeparam name="TLocalPayload">The type of the local branch payload</typeparam>
290+
/// <param name="localPayloadFactory">The factory function that creates the local payload</param>
291+
/// <returns>A branch builder that allows adding activities to the branch</returns>
292+
public BranchWithLocalPayloadBuilder<TRequest, TPayload, TLocalPayload, TSuccess, TError> BranchWithLocalPayload<TLocalPayload>(
293+
Func<TPayload, TLocalPayload> localPayloadFactory)
294+
{
295+
var branch = new BranchWithLocalPayload<TPayload, TLocalPayload, TError>(_ => true, localPayloadFactory);
296+
_branchesWithLocalPayload.Add(branch);
297+
return new BranchWithLocalPayloadBuilder<TRequest, TPayload, TLocalPayload, TSuccess, TError>(this, branch);
298+
}
299+
285300
/// <summary>
286301
/// Creates a branch in the workflow with a local payload that always executes.
287302
/// This is a convenience method for organizing related activities.

0 commit comments

Comments
 (0)