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

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