1 package emperror 2 3 // multiError aggregates multiple errors into a single value. 4 // 5 // While ErrorCollection is only an interface for listing errors, 6 // multiError actually implements the error interface so it can be returned as an error. 7 type multiError struct { 8 errors []error 9 msg string 10 } 11 12 // Error implements the error interface. 13 func (e *multiError) Error() string { 14 if e.msg != "" { 15 return e.msg 16 } 17 18 return "Multiple errors happened" 19 } 20 21 // Errors returns the list of wrapped errors. 22 func (e *multiError) Errors() []error { 23 return e.errors 24 } 25 26 // SingleWrapMode defines how MultiErrorBuilder behaves when there is only one error in the list. 27 type SingleWrapMode int 28 29 // These constants cause MultiErrorBuilder to behave as described if there is only one error in the list. 30 const ( 31 AlwaysWrap SingleWrapMode = iota // Always return a MultiError. 32 ReturnSingle // Return the single error. 33 ) 34 35 // MultiErrorBuilder provides an interface for aggregating errors and exposing them as a single value. 36 type MultiErrorBuilder struct { 37 errors []error 38 39 Message string 40 SingleWrapMode SingleWrapMode 41 } 42 43 // NewMultiErrorBuilder returns a new MultiErrorBuilder. 44 func NewMultiErrorBuilder() *MultiErrorBuilder { 45 return &MultiErrorBuilder{ 46 SingleWrapMode: AlwaysWrap, 47 } 48 } 49 50 // Add adds an error to the list. 51 // 52 // Calling this method concurrently is not safe. 53 func (b *MultiErrorBuilder) Add(err error) { 54 // Do not add nil values. 55 if err == nil { 56 return 57 } 58 59 b.errors = append(b.errors, err) 60 } 61 62 // ErrOrNil returns a MultiError the builder aggregates a list of errors, 63 // or returns nil if the list of errors is empty. 64 // 65 // It is useful to avoid checking if there are any errors added to the list. 66 func (b *MultiErrorBuilder) ErrOrNil() error { 67 // No errors added, return nil. 68 if len(b.errors) == 0 { 69 return nil 70 } 71 72 // Return a single error when there is only one and the builder is told to do so. 73 if len(b.errors) == 1 && b.SingleWrapMode == ReturnSingle { 74 return b.errors[0] 75 } 76 77 return &multiError{b.errors, b.Message} 78 } 79