zerr: sequence: changed into interface for future proofing

This commit is contained in:
Tigor Hutasuhut 2024-08-27 17:08:52 +07:00
parent dba226c1c1
commit ab159d9426
6 changed files with 89 additions and 33 deletions

View file

@ -27,7 +27,7 @@ type Err struct {
id string
logger Logger
notifier Notifier
sequence *Sequence
sequence Sequence
}
// Join implements Error.
@ -215,7 +215,7 @@ func (mu *Err) Notify(ctx context.Context, opts ...zoptions.NotifyOption) Error
}
// Sequence returns the state of the error sequence.
func (mu *Err) Sequence() *Sequence {
func (mu *Err) Sequence() Sequence {
return mu.sequence
}

View file

@ -18,9 +18,11 @@ func (er *Err) WriteBuilder(w io.Writer) {
return
}
var previous string
if err := er.sequence.Outer(); err != nil && !err.IsMulti() {
if parent := er.sequence.Parent(); parent != nil {
if err := parent.Error(); err != nil && !err.IsMulti() {
previous = err.GetMessage()
}
}
current := strings.TrimPrefix(er.message, previous)
if current != "" {
if previous != "" {

View file

@ -85,7 +85,9 @@ type Error interface {
Notify(ctx context.Context, opts ...zoptions.NotifyOption) Error
// Sequence returns the state of the error sequence.
Sequence() *Sequence
//
// Sequence must not be nil.
Sequence() Sequence
// IsMulti returns true if the error is a multiple error.
IsMulti() bool

View file

@ -9,24 +9,50 @@ import "iter"
// When wrapping errors, the wrapping error
// will be the parent of the wrapped Error
// if the wrapped Error is a zerr.Error.
type Sequence struct {
parent *Sequence
children []*Sequence
type Sequence interface {
// WrapBy prepends the next Sequence to the current Sequence.
WrapBy(parent Sequence)
// Parent returns the parent Sequence.
// Return nil if this Sequence is Root.
Parent() Sequence
// Root returns the outermost Sequence in the sequence.
//
// Returns self if current Sequence is the outermost.
Root() Sequence
// IsRoot checks if the Sequence is the outermost Sequence in the sequence.
IsRoot() bool
// Error returns the Error in the sequence.
Error() Error
// Iter returns an iterator to traverse Errors in the sequence.
Iter() iter.Seq[Error]
// AppendChild appends a child Sequence to the current Sequence.
AppendChild(child Sequence)
}
type sequence struct {
parent Sequence
children []Sequence
err Error
}
// WrapBy prepends the next Sequence to the current Sequence.
func (se *Sequence) WrapBy(parent *Sequence) {
parent.children = append(parent.children, se)
func (se *sequence) WrapBy(parent Sequence) {
parent.AppendChild(se)
se.parent = parent
}
// Outer returns the error that wraps this Error.
// Return nil if this Error is not wrapped
// or wrapping outer is not a zerr.Error.
func (se *Sequence) Outer() Error {
func (se *sequence) AppendChild(child Sequence) {
se.children = append(se.children, child)
}
func (se *sequence) Parent() Sequence {
if se.parent != nil {
return se.parent.err
return se.parent
}
return nil
}
@ -34,21 +60,23 @@ func (se *Sequence) Outer() Error {
// Root returns the outermost Error in the sequence.
//
// Returns self if there is no outermost.
func (se *Sequence) Root() *Sequence {
root := se
for root.parent != nil {
root = root.parent
}
func (se *sequence) Root() Sequence {
var root Sequence = se
for {
if root.Parent() == nil {
return root
}
root = root.Parent()
}
}
// IsRoot checks if the Error is the outermost Error in the sequence.
func (se *Sequence) IsRoot() bool {
func (se *sequence) IsRoot() bool {
return se.parent == nil
}
// Error returns the Error in the sequence.
func (se *Sequence) Error() Error {
func (se *sequence) Error() Error {
return se.err
}
@ -64,7 +92,7 @@ func (se *Sequence) Error() Error {
// // e is zerr.Error
// // do something with e
// }
func (se *Sequence) Iter() iter.Seq[Error] {
func (se *sequence) Iter() iter.Seq[Error] {
return func(yield func(Error) bool) {
if se.err != nil && !yield(se.err) {
return

View file

@ -7,19 +7,20 @@ import (
"gitlab.bareksa.com/backend/zen/core/zoptions"
)
type WrapInitialInput struct {
Error error
type WrapInput struct {
Errors []error
Message string
PC uintptr
Time time.Time
Logger Logger
Notifier Notifier
Details []any
}
type Wrapper interface {
// Wrap creates a zerr.Error with inputs
// generated by global entry points.
Wrap(input WrapInitialInput) Error
Wrap(input WrapInput) Error
}
type Logger interface {
@ -30,12 +31,35 @@ type Notifier interface {
NotifyError(ctx context.Context, err Error, opts ...zoptions.NotifyOption)
}
type WrapperFunc func(input WrapInitialInput) Error
type WrapperFunc func(input WrapInput) Error
func (wr WrapperFunc) Wrap(input WrapInitialInput) Error {
func (wr WrapperFunc) Wrap(input WrapInput) Error {
return wr(input)
}
var DefaultWrapper Wrapper = WrapperFunc(func(input WrapInitialInput) Error {
panic("not implemented")
var DefaultWrapper Wrapper = WrapperFunc(func(input WrapInput) Error {
e := &Err{
message: input.Message,
errs: input.Errors,
caller: input.PC,
time: input.Time,
logger: input.Logger,
notifier: input.Notifier,
details: input.Details,
}
e.sequence = &sequence{err: e}
for _, err := range input.Errors {
if err, ok := err.(Error); ok {
err.Sequence().WrapBy(e.sequence)
}
}
return e
})
func Wrap(input WrapInput) Error {
return DefaultWrapper.Wrap(input)
}
func SetDefaultWrapper(w Wrapper) {
DefaultWrapper = w
}

4
go.mod
View file

@ -6,6 +6,8 @@ require (
connectrpc.com/connect v1.16.2
connectrpc.com/grpcreflect v1.2.0
github.com/fatih/color v1.17.0
github.com/mattn/go-isatty v0.0.20
github.com/pborman/indent v1.2.1
github.com/tidwall/pretty v1.2.1
golang.org/x/net v0.23.0
google.golang.org/protobuf v1.34.2
@ -13,8 +15,6 @@ require (
require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pborman/indent v1.2.1 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
)