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
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import "github.com/go-coldbrew/data-builder"

## Index

- [Constants](<#constants>)
- [Variables](<#variables>)
- [func AddResultToCtx\(ctx context.Context, r Result\) context.Context](<#AddResultToCtx>)
- [func BuildGraph\(executionPlan Plan, format, file string\) error](<#BuildGraph>)
Expand All @@ -29,6 +30,14 @@ import "github.com/go-coldbrew/data-builder"
- [func \(r Result\) Get\(obj any\) any](<#Result.Get>)


## Constants

<a name="SupportPackageIsVersion1"></a>SupportPackageIsVersion1 is a compile\-time assertion constant. Downstream packages reference this to enforce version compatibility.

```go
const SupportPackageIsVersion1 = true
```

## Variables

<a name="ErrInvalidBuilder"></a>
Expand Down Expand Up @@ -80,7 +89,7 @@ AddResultToCtx adds the given result object to context
this function should ideally only be used in your tests and/or for debugging modification made to Result obj will NOT persist

<a name="BuildGraph"></a>
## func [BuildGraph](<https://github.com/go-coldbrew/data-builder/blob/main/plan.go#L305>)
## func [BuildGraph](<https://github.com/go-coldbrew/data-builder/blob/main/plan.go#L319>)

```go
func BuildGraph(executionPlan Plan, format, file string) error
Expand All @@ -100,7 +109,7 @@ GetFromResult allows builders to access data built by other builders
this function enables optional access to data, your code should not rely on values being present, if you have explicit dependency please add them to your function parameters

<a name="IsValidBuilder"></a>
## func [IsValidBuilder](<https://github.com/go-coldbrew/data-builder/blob/main/databuilder.go#L90>)
## func [IsValidBuilder](<https://github.com/go-coldbrew/data-builder/blob/main/databuilder.go#L94>)

```go
func IsValidBuilder(builder any) error
Expand All @@ -109,7 +118,7 @@ func IsValidBuilder(builder any) error
IsValidBuilder checks if the given function is valid or not

<a name="MaxPlanParallelism"></a>
## func [MaxPlanParallelism](<https://github.com/go-coldbrew/data-builder/blob/main/plan.go#L317>)
## func [MaxPlanParallelism](<https://github.com/go-coldbrew/data-builder/blob/main/plan.go#L331>)

```go
func MaxPlanParallelism(pl Plan) (uint, error)
Expand Down Expand Up @@ -284,7 +293,7 @@ welcome to singapore
</details>

<a name="New"></a>
### func [New](<https://github.com/go-coldbrew/data-builder/blob/main/databuilder.go#L174>)
### func [New](<https://github.com/go-coldbrew/data-builder/blob/main/databuilder.go#L178>)

```go
func New() DataBuilder
Expand Down Expand Up @@ -378,7 +387,7 @@ GetResultFromCtx gives access to result object at this point in execution
this function should ideally only be used in your tests and/or for debugging modification made to Result obj may or may not persist

<a name="Result.Get"></a>
### func \(Result\) [Get](<https://github.com/go-coldbrew/data-builder/blob/main/plan.go#L233>)
### func \(Result\) [Get](<https://github.com/go-coldbrew/data-builder/blob/main/plan.go#L247>)

```go
func (r Result) Get(obj any) any
Expand Down
19 changes: 15 additions & 4 deletions plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package databuilder
import (
"context"
"errors"
"fmt"
"reflect"
"strconv"
"sync"
Expand Down Expand Up @@ -141,7 +142,12 @@ func processWork(ctx context.Context, w work) {
}
o.outputs = fn.Call(args)
if len(o.outputs) > 1 && !o.outputs[1].IsNil() {
span.SetError(o.outputs[1].Interface().(error)) // nolint: errcheck
secondReturn := o.outputs[1].Interface()
if errVal, ok := secondReturn.(error); ok {
span.SetError(errVal) //nolint:errcheck
} else {
span.SetError(fmt.Errorf("builder %s: second return value is not an error (type %T)", w.builder.Name, secondReturn)) //nolint:errcheck
}
Comment thread
ankurs marked this conversation as resolved.
}
w.out <- o
}
Expand Down Expand Up @@ -171,15 +177,20 @@ func doWorkAndGetResult(ctx context.Context, builders []*builder, dataMap map[st
errs := make([]error, 0)
for o := range outChan {
if o.err != nil {
// error occured, return it back and stop processing
// error occurred, return it back and stop processing
return o.err
}
outputs := o.outputs
// we should only ever have two outputs
// 0-> data, 1-> error
if !outputs[1].IsNil() {
// error occured, add it to the list of errors and continue processing
errs = append(errs, outputs[1].Interface().(error))
// error occurred, add it to the list of errors and continue processing
secondReturn := outputs[1].Interface()
if errVal, ok := secondReturn.(error); ok {
errs = append(errs, errVal)
} else {
errs = append(errs, fmt.Errorf("builder %s: second return value is not an error (type %T)", o.builder.Name, secondReturn))
}
continue
}
// add result
Expand Down
15 changes: 15 additions & 0 deletions plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,21 @@ func TestPlanRunPartialSuccess(t *testing.T) {
goleak.VerifyNone(t)
}

func TestPlanRun_ErrorFlowWithCommaOk(t *testing.T) {
// Verify that the comma-ok type assertion guards in processWork and
// doWorkAndGetResult correctly propagate errors from builders.
d := testNew(t)
err := d.AddBuilders(DBTestFuncErr)
assert.NoError(t, err)
executionPlan, err := d.Compile(TestStruct1{})
assert.NotNil(t, executionPlan)
assert.NoError(t, err)

_, err = executionPlan.Run(context.Background(), TestStruct1{Value: "test"})
assert.ErrorContains(t, err, "encountered an error")
goleak.VerifyNone(t)
}

func ExamplePlan() {
b := New()
err := b.AddBuilders(DBTestFunc, DBTestFunc4)
Expand Down
Loading