boru

boru is a pipeline implementation in kotlin with native coroutine support and custom dsl.

Supports chaining pipeline steps with conditions and branches.

Inspired by @oguzhaneren‘s C# implementation

<dependency>
    <groupId>com.trendyol</groupId>
    <artifactId>boru</artifactId>
    <version>1.0.0</version>
</dependency>

USAGE

Defining Context

Define a context implementing PipelineContext. In this case a simple context that sets and gets a text field

interface PipelineContext {
    val items: Map<Any, Any>
}

class TestDataContext : PipelineContext {
    override val items: MutableMap<Any, Any> = mutableMapOf()

    var intValue: Int = 0

    var text: String?
        get() = items.getOrDefault("Text", null).toString()
        set(value) {
            items["Text"] = value!!
        }
}

Define Pipeline Steps

Implement a pipeline step using TestDataContext

class TestWriterStep(
    private val text: String,
) : PipelineStep<TestDataContext> {

    override suspend fun execute(context: TestDataContext, next: PipelineStepDelegate<TestDataContext>) {
        context.text = text
        next(context)
    }
}

Build Pipeline

fun compose() {
    val pipeline = PipelineBuilder<TestDataContext>()
        .usePipelineStep(TestWriterStep("hello"))
        .build()
    val context = TestDataContext()
}

You can also use lambda functions without defining a pipeline step

fun compose() {
    val pipeline = PipelineBuilder<TestDataContext>()
        .use { context: TestDataContext, next: suspend () -> Unit ->
            context.text = "hello"
            next()
        }
        .build()
    val context = TestDataContext()
}

Or use built-in dsl

fun compose() {
    val pipeline = pipelineBuilder<TestDataContext> {
        use { testDataContext: TestDataContext, next: suspend () -> Unit ->
            context.text = "Hello World"
            next()
        }
    }
}

Conditions and Branching

You can also use conditions when executing steps or branch using map operation

fun compose() {
    val pipeline = pipelineBuilder<TestDataContext> {
        usePipelineStepWhen(TestWriterStep("Hello World")) {
            it.text == "ExecuteStep"
        }
    }
}

Mapping allows you to group multiple steps under one condition.

fun composeMapping() {
    val pipeline = pipelineBuilder<TestDataContext> {
        map({ it.intValue < 3 }) {
            usePipelineStep(TestWriterStep("one"))
            usePipelineStep(TestWriterStep("two"))
        }
        map({ it.intValue == 3 }) {
            usePipelineStep(TestWriterStep("three"))
        }
    }
}

Examples

You can check out other examples

GitHub

https://github.com/Trendyol/boru