github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/internal/xerrors/issues.go (about)

     1  package xerrors
     2  
     3  import (
     4  	"errors"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
     9  	"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Issue"
    10  
    11  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
    12  )
    13  
    14  type issues []*Ydb_Issue.IssueMessage
    15  
    16  func (ii issues) String() string {
    17  	if len(ii) == 0 {
    18  		return ""
    19  	}
    20  	b := xstring.Buffer()
    21  	defer b.Free()
    22  	b.WriteByte('[')
    23  	for i, m := range ii {
    24  		if i != 0 {
    25  			b.WriteByte(',')
    26  		}
    27  		b.WriteByte('{')
    28  		if p := m.GetPosition(); p != nil {
    29  			if file := p.GetFile(); file != "" {
    30  				b.WriteString(file)
    31  				b.WriteByte(':')
    32  			}
    33  			b.WriteString(strconv.Itoa(int(p.GetRow())))
    34  			b.WriteByte(':')
    35  			b.WriteString(strconv.Itoa(int(p.GetColumn())))
    36  			b.WriteString(" => ")
    37  		}
    38  		if code := m.GetIssueCode(); code != 0 {
    39  			b.WriteByte('#')
    40  			b.WriteString(strconv.Itoa(int(code)))
    41  			b.WriteByte(' ')
    42  		}
    43  		b.WriteByte('\'')
    44  		b.WriteString(strings.TrimSuffix(m.GetMessage(), "."))
    45  		b.WriteByte('\'')
    46  		if len(m.GetIssues()) > 0 {
    47  			b.WriteByte(' ')
    48  			b.WriteString(issues(m.GetIssues()).String())
    49  		}
    50  		b.WriteByte('}')
    51  	}
    52  	b.WriteByte(']')
    53  
    54  	return b.String()
    55  }
    56  
    57  // NewWithIssues returns error which contains child issues
    58  func NewWithIssues(text string, issues ...error) error {
    59  	err := &withIssuesError{
    60  		reason: text,
    61  	}
    62  	for i := range issues {
    63  		if issues[i] != nil {
    64  			err.issues = append(err.issues, issues[i])
    65  		}
    66  	}
    67  
    68  	return err
    69  }
    70  
    71  type withIssuesError struct {
    72  	reason string
    73  	issues []error
    74  }
    75  
    76  func (e *withIssuesError) isYdbError() {}
    77  
    78  func (e *withIssuesError) Error() string {
    79  	b := xstring.Buffer()
    80  	defer b.Free()
    81  	if len(e.reason) > 0 {
    82  		b.WriteString(e.reason)
    83  		b.WriteString(", issues: [")
    84  	} else {
    85  		b.WriteString("multiple errors: [")
    86  	}
    87  	for i, issue := range e.issues {
    88  		if i != 0 {
    89  			b.WriteString(", ")
    90  		}
    91  		b.WriteString(issue.Error())
    92  	}
    93  	b.WriteString("]")
    94  
    95  	return b.String()
    96  }
    97  
    98  func (e *withIssuesError) As(target interface{}) bool {
    99  	for _, err := range e.issues {
   100  		if As(err, target) {
   101  			return true
   102  		}
   103  	}
   104  
   105  	return false
   106  }
   107  
   108  func (e *withIssuesError) Is(target error) bool {
   109  	for _, err := range e.issues {
   110  		if Is(err, target) {
   111  			return true
   112  		}
   113  	}
   114  
   115  	return false
   116  }
   117  
   118  func (e *withIssuesError) Unwrap() []error {
   119  	return e.issues
   120  }
   121  
   122  // Issue struct
   123  type Issue struct {
   124  	Message  string
   125  	Code     uint32
   126  	Severity uint32
   127  }
   128  
   129  type IssueIterator []*Ydb_Issue.IssueMessage
   130  
   131  func (it IssueIterator) Len() int {
   132  	return len(it)
   133  }
   134  
   135  func (it IssueIterator) Get(i int) (issue Issue, nested IssueIterator) {
   136  	x := it[i]
   137  	if xs := x.GetIssues(); len(xs) > 0 {
   138  		nested = IssueIterator(xs)
   139  	}
   140  
   141  	return Issue{
   142  		Message:  x.GetMessage(),
   143  		Code:     x.GetIssueCode(),
   144  		Severity: x.GetSeverity(),
   145  	}, nested
   146  }
   147  
   148  func IterateByIssues(err error, it func(message string, code Ydb.StatusIds_StatusCode, severity uint32)) {
   149  	var o *operationError
   150  	if !errors.As(err, &o) {
   151  		return
   152  	}
   153  	iterate(o.Issues(), it)
   154  }
   155  
   156  func iterate(
   157  	issues []*Ydb_Issue.IssueMessage,
   158  	it func(message string, code Ydb.StatusIds_StatusCode, severity uint32),
   159  ) {
   160  	for _, issue := range issues {
   161  		it(issue.GetMessage(), Ydb.StatusIds_StatusCode(issue.GetIssueCode()), issue.GetSeverity())
   162  		iterate(issue.GetIssues(), it)
   163  	}
   164  }