Skip to content

Commit 29cf446

Browse files
committed
Merge branch 'develop'
2 parents 1639e64 + cd4f7c8 commit 29cf446

File tree

13 files changed

+340
-350
lines changed

13 files changed

+340
-350
lines changed

docs/child-pipeline.md

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
layout: default
3+
title: Child Pipelines
4+
nav_order: 5
5+
---
6+
7+
# Child Piplelines
8+
9+
The `PipelineFactory` library allows you to use pipelines together. Since pipelines are just functions, they can be used
10+
as input to other pipelines. This allows you to create complex data processing flows by reusing and chaining together
11+
multiple pipelines.
12+
13+
Here's an example of how to use pipelines together:
14+
15+
16+
```csharp
17+
var pipeline2 = PipelineFactory
18+
.Start<string>()
19+
.Pipe( ( ctx, arg ) => $"{arg} again!" )
20+
.Build();
21+
22+
var pipeline1 = PipelineFactory
23+
.Start<string>()
24+
.Pipe( ( ctx, arg ) => $"hello {arg}" )
25+
.PipeAsync( pipeline2 )
26+
.Build();
27+
28+
var result = await pipeline1( new PipelineContext(), "you" );
29+
30+
Assert.AreEqual( "hello you again!", result );
31+
```
32+

docs/childPipeline.md

-7
This file was deleted.

docs/execution.md renamed to docs/command-pattern.md

+6-57
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,10 @@
11
---
22
layout: default
3-
title: Execution
4-
nav_order: 2
3+
title: Commands
4+
nav_order: 6
55
---
66

7-
# Execution
8-
9-
| Method | Description
10-
| ---------- | -----------
11-
| Call | Execute a `void` step that does not transform the pipeline output.
12-
| CallAsync | Asynchronously execute a `void` step that does not transform the pipeline output.
13-
| Pipe | Execute a step that transforms the pipeline output.
14-
| PipeAsync | Asynchronously execute a step that transforms the pipeline output.
15-
16-
## Flow Control
17-
18-
| Method | Description
19-
| ---------- | -----------
20-
| Cancel | Cancels the pipeline after the current step.
21-
| CancelWith | Cancels the pipeline with a value, after the current step.
22-
| Pipe | Pipes a child pipeline with optional middlewares.
23-
| PipeIf | Conditionally pipes a child pipeline with optional middlewares.
24-
| Call | Calls a child pipeline with optional middlewares.
25-
| CallIf | Conditionally calls a child pipeline with optional middlewares.
26-
| ForEach | Enumerates a collection pipeline input.
27-
| Reduce | Transforms an enumerable pipeline input.
28-
29-
## Parallel Flow
30-
31-
| Method | Description
32-
| ---------- | -----------
33-
| WaitAll | Waits for concurrent pipelines to complete.
34-
35-
## Middleware
36-
37-
| Method | Description
38-
| ---------- | -----------
39-
| Hook | Applies middleware to each step in the pipeline.
40-
| Wrap | Wraps the middleware around the preceeding steps.
41-
42-
## Building and Executing Pipelines
43-
44-
Pipelines are built using `PipelineFactory`. Once built, a pipeline is just an async function that takes a `PipelineContext` and
45-
an optional input value as parameters, and returns a result.
46-
47-
```csharp
48-
var command = PipelineFactory
49-
.Start<string>()
50-
.Pipe( ( ctx, arg ) => $"hello {arg}" )
51-
.Build();
52-
53-
var result = await command( new PipelineContext(), "pipeline" );
54-
55-
Assert.AreEqual( "hello pipeline", result );
56-
```
57-
58-
## Command Pattern
7+
# Command Pattern
598

609
`ICommand*` interfaces and `Command*` base classes provide a lightweight pattern for constructing injectable commands built
6110
around pipelines and middleware.
@@ -66,7 +15,7 @@ an optional input value as parameters, and returns a result.
6615
| ICommandFunction&lt;TOutput&gt; | CommandFunction&lt;TOutput&gt; | A command that takes no input and returns an output
6716
| ICommandProcedure&lt;TInput&gt; | CommandProcedure&lt;TInput&gt; | A command that takes an input and returns void
6817

69-
#### Example 1
18+
## Example 1
7019
Example of a command that takes an input and produces an output.
7120

7221
```csharp
@@ -103,7 +52,7 @@ Example of a command that takes an input and produces an output.
10352
}
10453
```
10554

106-
#### Example 2
55+
## Example 2
10756
Example of a command that takes no input and produces an output.
10857

10958
```csharp
@@ -140,7 +89,7 @@ Example of a command that takes no input and produces an output.
14089
}
14190
```
14291

143-
#### Example 3
92+
## Example 3
14493
Example of a command that takes an input and produces no output.
14594

14695
```csharp
File renamed without changes.

docs/docs.projitems

+4-3
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
<Import_RootNamespace>docs</Import_RootNamespace>
1010
</PropertyGroup>
1111
<ItemGroup>
12-
<None Include="$(MSBuildThisFileDirectory)childPipeline.md" />
13-
<None Include="$(MSBuildThisFileDirectory)dependencyInjection.md" />
14-
<None Include="$(MSBuildThisFileDirectory)execution.md" />
12+
<None Include="$(MSBuildThisFileDirectory)child-pipeline.md" />
13+
<None Include="$(MSBuildThisFileDirectory)dependency-injection.md" />
14+
<None Include="$(MSBuildThisFileDirectory)command-pattern.md" />
15+
<None Include="$(MSBuildThisFileDirectory)syntax.md" />
1516
<None Include="$(MSBuildThisFileDirectory)index.md" />
1617
<None Include="$(MSBuildThisFileDirectory)middleware.md" />
1718
<None Include="$(MSBuildThisFileDirectory)_config.yml" />

docs/index.md

+45-134
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: Hyperbee Pipeline
44
nav_order: 1
55
---
66

7-
# Hyperbee.Pipeline
7+
# Hyperbee Pipeline
88

99
`Hyperbee.Pipeline` allows you to construct asynchronous fluent pipelines in .NET. A pipeline, in this context, refers to a
1010
sequence of data processing elements arranged in series, where the output of one element serves as the input for the subsequent
@@ -25,63 +25,42 @@ Some key features are:
2525
* Early returns and cancellation
2626
* Child pipelines
2727

28+
## Why Use Pipelines
2829

29-
```csharp
30-
// Takes a string and returns a number
31-
var question = PipelineFactory
32-
.Start<string>()
33-
.PipeIf((ctx, arg) => arg == "Adams", builder => builder
34-
.Pipe((ctx, arg) => 42)
35-
.Cancel()
36-
)
37-
.Pipe((ctx, arg) => 0)
38-
.Build();
30+
Pipelines provide a structured approach to managing complex processes, promoting [SOLID](https://en.wikipedia.org/wiki/SOLID)
31+
principles, including Inversion of Control (IoC) and Separation of Concerns (SoC). They enable composability, making it easier
32+
to build, test, and maintain your code. By extending the benefits of middleware and request-response pipelines throughout your
33+
application, you achieve greater modularity, scalability, and flexibility. This is especially critical in domains such as
34+
healthcare, compliance auditing, identity and roles, and high-security environments where clear boundaries and responsibilities
35+
are essential. Hyperbee.Pipeline ensures that the advantages of pipelines and middleware are not abandoned at the controller
36+
implementation, addressing a common gap in many frameworks. By using a functional approach, Hyperbee.Pipeline ensures that your
37+
pipelines are not only robust and maintainable but also highly adaptable to changing requirements.
3938

40-
var answer1 = await question(new PipelineContext(), "Adams");
41-
Assert.AreEqual(42, answer1);
4239

43-
var answer2 = await question(new PipelineContext(), "Smith");
44-
Assert.AreEqual(0, answer2);
45-
```
40+
## Getting Started
4641

47-
## Hook
42+
To get started with Hyperbee.Pipeline, refer to the documentation for detailed instructions and examples.
4843

49-
The `Hook` and `HookAsync` methods allow you to add a hook that is called for every statement in the pipeline. This hook takes the current context, the current argument, and a delegate to the next part of the pipeline. It can manipulate the argument before and after calling the next part of the pipeline.
44+
Install via NuGet:
5045

51-
Here's an example of how to use `HookAsync`:
52-
53-
```csharp
54-
var command = PipelineFactory
55-
.Start<string>()
56-
.HookAsync( async ( ctx, arg, next ) => await next( ctx, arg + "{" ) + "}" )
57-
.Pipe( ( ctx, arg ) => arg + "1" )
58-
.Pipe( ( ctx, arg ) => arg + "2" )
59-
.Build();
60-
61-
var result = await command( new PipelineContext() );
62-
63-
Assert.AreEqual( "{1}{2}", result );
46+
```bash
47+
dotnet add package Hyperbee.Pipeline
6448
```
6549

66-
## Wrap
50+
## Building and Executing Pipelines
6751

68-
The `Wrap` and `WrapAsync` method allows you to wrap a part of the pipeline. This is useful when you want to apply a transformation to only a part of the pipeline.
69-
70-
Here’s an example of how to use `WrapAsync`:
52+
Pipelines are built using `PipelineFactory`. Once built, a pipeline is just an async function that takes a `PipelineContext` and
53+
an optional input value as parameters, and returns a result.
7154

7255
```csharp
73-
var command = PipelineFactory
74-
.Start<string>()
75-
.Pipe( ( ctx, arg ) => arg + "1" )
76-
.Pipe( ( ctx, arg ) => arg + "2" )
77-
.WrapAsync( async ( ctx, arg, next ) => await next( ctx, arg + "{" ) + "}" )
78-
.Pipe( ( ctx, arg ) => arg + "3" )
79-
.Build();
56+
var command = PipelineFactory
57+
.Start<string>()
58+
.Pipe( ( ctx, arg ) => $"hello {arg}" )
59+
.Build();
8060

81-
var result = await command( new PipelineContext() );
82-
83-
Assert.AreEqual( "{12}3", result );
61+
var result = await command( new PipelineContext(), "pipeline" );
8462

63+
Assert.AreEqual( "hello pipeline", result );
8564
```
8665

8766
## Dependency Injection
@@ -110,110 +89,42 @@ services.AddPipeline( (factoryServices, rootProvider) =>
11089
} );
11190
```
11291

113-
## Advanced Features
114-
115-
The `PipelineFactory` library provides a variety of helper methods that allow you to customize the behavior of your pipelines. These methods provide powerful functionality for manipulating data as it passes through the pipeline.
116-
117-
### Reduce
118-
119-
The `Reduce` and `ReduceAsync` methods allow you to reduce a sequence of elements to a single value. You can specify a reducer function that defines how the elements should be combined, and a builder function that creates the pipeline for processing the elements.
120-
121-
### WaitAll
122-
123-
The `WaitAll` method allows you to wait for all pipelines to complete before continuing. You can specify a set of builders that create the pipelines to wait for, a reducer function that combines the results of the pipelines.
124-
125-
```csharp
126-
var count = 0;
127-
128-
var command = PipelineFactory
129-
.Start<int>()
130-
.WaitAll( builders => builders.Create(
131-
builder => builder.Pipe( ( ctx, arg ) => Interlocked.Increment( ref count ) ),
132-
builder => builder.Pipe( ( ctx, arg ) => Interlocked.Increment( ref count ) )
133-
),
134-
reducer: ( ctx, arg, results ) => { return arg + results.Sum( x => (int) x.Result ); }
135-
)
136-
.Build();
137-
138-
var result = await command( new PipelineContext() );
139-
140-
Assert.AreEqual( 2, count );
141-
Assert.AreEqual( 3, result );
142-
```
143-
144-
### PipeIf
145-
146-
The `PipeIf` method allows you to conditionally add a step to the pipeline. You can specify a condition function that determines whether the step should be added, a builder function that creates the step, and an optional flag indicating whether middleware should be inherited.
92+
## Pipeline of Pipelines
14793

148-
### ForEach and ForEachAsync
94+
The `PipelineFactory` library allows you to use pipelines together. Since pipelines are just functions, they can be used
95+
as input to other pipelines. This allows you to create complex data processing flows by reusing and chaining together
96+
multiple pipelines.
14997

150-
The `ForEach` and `ForEachAsync` methods allow you to apply a pipeline to each element in a sequence. You can specify a builder function that creates the pipeline for processing the elements.
98+
Here's an example of how to use pipelines together:
15199

152100
```csharp
153-
var count = 0;
154-
155-
var command = PipelineFactory
101+
var pipeline2 = PipelineFactory
156102
.Start<string>()
157-
.Pipe( ( ctx, arg ) => arg.Split( ' ' ) )
158-
.ForEach<string>( builder => builder
159-
.Pipe( ( ctx, arg ) => count += 10 )
160-
)
161-
.Pipe( ( ctx, arg ) => count += 5 )
103+
.Pipe( ( ctx, arg ) => $"{arg} again!" )
162104
.Build();
163105

164-
await command( new PipelineContext(), "e f" );
165-
166-
Assert.AreEqual( count, 25 );
167-
```
168-
169-
### Call and CallAsync
170-
171-
The `Call` and `CallAsync` methods allow you to add a procedure to the pipeline. You can think of these as `Action<T>` and `Pipe` like `Func<T>`.
172-
173-
In this example notice that `arg + 9` is not returned from the use of `Call`
174-
175-
```csharp
176-
var callResult = string.Empty;
177-
178-
var command = PipelineFactory
106+
var pipeline1 = PipelineFactory
179107
.Start<string>()
180-
.Pipe( ( ctx, arg ) => arg + "1" )
181-
.Pipe( ( ctx, arg ) => arg + "2" )
182-
.Call( builder => builder
183-
.Call( ( ctx, arg ) => callResult = arg + "3" )
184-
.Pipe( ( ctx, arg ) => arg + "9" )
185-
)
186-
.Pipe( ( ctx, arg ) => arg + "4" )
108+
.Pipe( ( ctx, arg ) => $"hello {arg}" )
109+
.PipeAsync( pipeline2 )
187110
.Build();
188111

189-
var result = await command( new PipelineContext() );
112+
var result = await pipeline1( new PipelineContext(), "you" );
190113

191-
Assert.AreEqual( "124", result );
192-
Assert.AreEqual( "123", callResult );
114+
Assert.AreEqual( "hello you again!", result );
193115
```
194116

195-
### Chaining Child Pipelines
117+
## Conditional Flow and Advanced Features
196118

197-
The `PipelineFactory` library allows you to chain pipelines together. Since pipelines are just functions, they can be used as input to other pipelines. This allows you to create complex data processing flows by reusing and chaining together multiple pipelines.
119+
The `PipelineFactory` library provides a variety of builders that allow you to customize the behavior of your pipelines.
120+
These methods provide powerful functionality for manipulating data as it passes through the pipeline.
198121

199-
Here's an example of how to chain pipelines together:
200-
201-
```csharp
202-
var command2 = PipelineFactory
203-
.Start<string>()
204-
.Pipe( ( ctx, arg ) => $"{arg} again!" )
205-
.Build();
206-
207-
var command1 = PipelineFactory
208-
.Start<string>()
209-
.Pipe( ( ctx, arg ) => $"hello {arg}" )
210-
.PipeAsync( command2 )
211-
.Build();
212-
213-
var result = await command1( new PipelineContext(), "pipeline" );
214-
215-
Assert.AreEqual( "hello pipeline again!", result );
216-
```
122+
- Functions
123+
- Procedures
124+
- Conditional Flow
125+
- Iterators
126+
- Reduce
127+
- Parallel execution
217128

218129
## Credits
219130

0 commit comments

Comments
 (0)