blob: 6a105af4ffcc02562479cf445137e007b0e1154c [file] [log] [blame]
Don Newton379ae252019-04-01 12:17:06 -04001// Copyright (C) MongoDB, Inc. 2017-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7package internal
8
9import (
10 "fmt"
11)
12
13// WrappedError represents an error that contains another error.
14type WrappedError interface {
15 // Message gets the basic message of the error.
16 Message() string
17 // Inner gets the inner error if one exists.
18 Inner() error
19}
20
21// RolledUpErrorMessage gets a flattened error message.
22func RolledUpErrorMessage(err error) string {
23 if wrappedErr, ok := err.(WrappedError); ok {
24 inner := wrappedErr.Inner()
25 if inner != nil {
26 return fmt.Sprintf("%s: %s", wrappedErr.Message(), RolledUpErrorMessage(inner))
27 }
28
29 return wrappedErr.Message()
30 }
31
32 return err.Error()
33}
34
35//UnwrapError attempts to unwrap the error down to its root cause.
36func UnwrapError(err error) error {
37
38 switch tErr := err.(type) {
39 case WrappedError:
40 return UnwrapError(tErr.Inner())
41 case *multiError:
42 return UnwrapError(tErr.errors[0])
43 }
44
45 return err
46}
47
48// WrapError wraps an error with a message.
49func WrapError(inner error, message string) error {
50 return &wrappedError{message, inner}
51}
52
53// WrapErrorf wraps an error with a message.
54func WrapErrorf(inner error, format string, args ...interface{}) error {
55 return &wrappedError{fmt.Sprintf(format, args...), inner}
56}
57
58// MultiError combines multiple errors into a single error. If there are no errors,
59// nil is returned. If there is 1 error, it is returned. Otherwise, they are combined.
60func MultiError(errors ...error) error {
61
62 // remove nils from the error list
63 var nonNils []error
64 for _, e := range errors {
65 if e != nil {
66 nonNils = append(nonNils, e)
67 }
68 }
69
70 switch len(nonNils) {
71 case 0:
72 return nil
73 case 1:
74 return nonNils[0]
75 default:
76 return &multiError{
77 message: "multiple errors encountered",
78 errors: nonNils,
79 }
80 }
81}
82
83type multiError struct {
84 message string
85 errors []error
86}
87
88func (e *multiError) Message() string {
89 return e.message
90}
91
92func (e *multiError) Error() string {
93 result := e.message
94 for _, e := range e.errors {
95 result += fmt.Sprintf("\n %s", e)
96 }
97 return result
98}
99
100func (e *multiError) Errors() []error {
101 return e.errors
102}
103
104type wrappedError struct {
105 message string
106 inner error
107}
108
109func (e *wrappedError) Message() string {
110 return e.message
111}
112
113func (e *wrappedError) Error() string {
114 return RolledUpErrorMessage(e)
115}
116
117func (e *wrappedError) Inner() error {
118 return e.inner
119}