Skip to content

Commit

Permalink
Async support for When builder predicates (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
andreas-antoniou-cko authored and ben-foster-cko committed May 8, 2019
1 parent 9237fbe commit f196549
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 81 deletions.
23 changes: 23 additions & 0 deletions src/Flo/Builder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,29 @@ public TBuilder When(
});
}

public TBuilder When(
Func<TIn, Task<bool>> predicate,
Func<TIn, Func<TIn, Task<TOut>>, Func<TIn, Task<TOut>>, Task<TOut>> handler,
Action<TBuilder> configurePipeline)
{
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
if (handler == null) throw new ArgumentNullException(nameof(handler));
if (configurePipeline == null) throw new ArgumentNullException(nameof(configurePipeline));

return Add(async (input, next) =>
{
var doInvoke = await predicate.Invoke(input);
if (doInvoke)
{
var builder = CreateBuilder();
configurePipeline(builder);
return await handler.Invoke(input, builder.Build(), next);
}

return await next.Invoke(input);
});
}

protected abstract TBuilder CreateBuilder();

public TBuilder Final(Func<TIn, Task<TOut>> handler)
Expand Down
18 changes: 18 additions & 0 deletions src/Flo/OutputPipelineBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,24 @@ public OutputPipelineBuilder<TIn, TOut> When(
configurePipeline);
}

public OutputPipelineBuilder<TIn, TOut> When(
Func<TIn, Task<bool>> predicate,
Action<OutputPipelineBuilder<TIn, TOut>> configurePipeline,
Func<TOut, bool> continueIf = null)
{
return When(predicate, async (input, innerPipeline, next) =>
{
var result = await innerPipeline.Invoke(input);

// Continue on to the parent pipeline if the continueIf output predicate matches
if ((continueIf ?? DefaultContinuation).Invoke(result))
return await next.Invoke(input);

return result;
},
configurePipeline);
}

protected override OutputPipelineBuilder<TIn, TOut> CreateBuilder() => new OutputPipelineBuilder<TIn, TOut>(ServiceProvider);
}
}
12 changes: 12 additions & 0 deletions src/Flo/PipelineBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ public PipelineBuilder<T> When(
configurePipeline);
}

public PipelineBuilder<T> When(
Func<T, Task<bool>> predicate,
Action<PipelineBuilder<T>> configurePipeline)
{
return When(predicate, async (input, innerPipeline, next) =>
{
input = await innerPipeline.Invoke(input);
return await next.Invoke(input);
},
configurePipeline);
}

protected override PipelineBuilder<T> CreateBuilder() => new PipelineBuilder<T>(ServiceProvider);
}
}
70 changes: 69 additions & 1 deletion test/Flo.Tests/OutputPipelineBuilderWhenTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@ async Task it_ignores_the_handler_if_the_predicate_returns_false()
result.ShouldBe(0);
}

async Task it_ignores_the_handler_if_the_async_predicate_returns_false()
{
var pipeline = Pipeline.Build<string, int>(cfg =>
cfg.When(input => Task.FromResult(input == "hello world"),
builder => builder.Add((input, next) =>
{
return Task.FromResult(input.Length);
})
)
);

var result = await pipeline.Invoke("hello");
result.ShouldBe(0);
}

async Task it_executes_the_handler_if_the_predicate_returns_true()
{
var pipeline = Pipeline.Build<string, int>(cfg =>
Expand All @@ -36,7 +51,22 @@ async Task it_executes_the_handler_if_the_predicate_returns_true()
var result = await pipeline.Invoke("hello world");
result.ShouldBe(11);
}


async Task it_executes_the_handler_if_the_async_predicate_returns_true()
{
var pipeline = Pipeline.Build<string, int>(cfg =>
cfg.When(input => Task.FromResult(input == "hello world"),
builder => builder.Add((input, next) =>
{
return Task.FromResult(input.Length);
})
)
);

var result = await pipeline.Invoke("hello world");
result.ShouldBe(11);
}

async Task it_continues_to_parent_pipeline_if_child_pipeline_returns_default_value()
{
var pipeline = Pipeline.Build<TestContext, TestContext>(cfg =>
Expand All @@ -56,6 +86,25 @@ async Task it_continues_to_parent_pipeline_if_child_pipeline_returns_default_val
result.ShouldContainKey("Test");
}

async Task it_continues_to_parent_pipeline_if_child_pipeline_returns_default_value_with_async_predicate()
{
var pipeline = Pipeline.Build<TestContext, TestContext>(cfg =>
cfg.When(input => Task.FromResult(true),
builder => builder.Add((ctx, next) =>
{
return Task.FromResult(default(TestContext));
})
)
.Final(ctx => {
ctx.Add("Test", "TestValue");
return Task.FromResult(ctx);
})
);

var result = await pipeline.Invoke(new TestContext());
result.ShouldContainKey("Test");
}

async Task it_does_not_continue_to_parent_pipeline_if_child_pipeline_returns_value()
{
var pipeline = Pipeline.Build<TestContext, TestContext>(cfg =>
Expand All @@ -74,5 +123,24 @@ async Task it_does_not_continue_to_parent_pipeline_if_child_pipeline_returns_val
var result = await pipeline.Invoke(new TestContext());
result.ShouldNotContainKey("Test");
}

async Task it_does_not_continue_to_parent_pipeline_if_child_pipeline_returns_value_with_async_predicate()
{
var pipeline = Pipeline.Build<TestContext, TestContext>(cfg =>
cfg.When(input => Task.FromResult(true),
builder => builder.Add((ctx, next) =>
{
return Task.FromResult(ctx);
})
)
.Final(ctx => {
ctx.Add("Test", "TestValue");
return Task.FromResult(ctx);
})
);

var result = await pipeline.Invoke(new TestContext());
result.ShouldNotContainKey("Test");
}
}
}
Loading

0 comments on commit f196549

Please sign in to comment.