-
Notifications
You must be signed in to change notification settings - Fork 0
/
detail.go
148 lines (126 loc) · 3.11 KB
/
detail.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2022 Dmytro Nozdrin. All rights reserved.
// Use of this source code is governed by the MIT License
// that can be found in the LICENSE file.
package errdetail
import (
"errors"
)
// Detail represents a set of optional fields which provide more
// information about a parent error.
type Detail struct {
field string
description string
code string
domain string
reason string
meta Meta
filled bool
}
type Meta map[string]interface{}
// Field is a Detail field getter.
func (d *Detail) Field() string {
return d.field
}
// Description is a Detail description getter.
func (d *Detail) Description() string {
return d.description
}
// Code is a Detail code getter.
func (d *Detail) Code() string {
return d.code
}
// Domain is a Detail domain getter.
// Domain stands here for a specified sphere of activity or knowledge.
func (d *Detail) Domain() string {
return d.domain
}
// Reason is a Detail reason getter.
func (d *Detail) Reason() string {
return d.reason
}
// Meta is a Detail arbitrary data getter.
func (d *Detail) Meta() Meta {
return d.meta
}
// NewDetail represents a Detail constructor.
func NewDetail(opts ...Option) Detail {
var detail Detail
for i := range opts {
opts[i](&detail)
}
return detail
}
// Option is a function type for Detail fields' setters.
type Option func(*Detail)
// WithField is an option for Detail constructs that sets field name
// and marks the detail as not empty.
func WithField(field string) Option {
return func(d *Detail) {
d.field = field
if d.field != "" {
d.filled = true
}
}
}
// WithDescription is an option for Detail constructs that sets
// description and marks the detail as not empty.
func WithDescription(description string) Option {
return func(d *Detail) {
d.description = description
if d.description != "" {
d.filled = true
}
}
}
// WithCode is an option for Detail constructs that sets code
// and marks the detail as not empty.
func WithCode(code string) Option {
return func(d *Detail) {
d.code = code
if d.code != "" {
d.filled = true
}
}
}
// WithDomain is an option for Detail constructs that sets an error
// domain and marks the detail as not empty. Domain stands here for
// a specified sphere of activity or knowledge.
func WithDomain(domain string) Option {
return func(d *Detail) {
d.domain = domain
if d.domain != "" {
d.filled = true
}
}
}
// WithReason is an option for Detail constructs that sets an error
// reason and marks the detail as not empty.
func WithReason(reason string) Option {
return func(d *Detail) {
d.reason = reason
if d.reason != "" {
d.filled = true
}
}
}
// WithMeta is an option for Detail constructs that sets an error
// arbitrary data and marks the detail as not empty.
func WithMeta(meta Meta) Option {
return func(d *Detail) {
d.meta = meta
if d.meta != nil {
d.filled = true
}
}
}
type detailed interface {
Details() []Detail
}
// ExtractDetails extracts details from an error, if any. Otherwise, returns nil.
func ExtractDetails(err error) []Detail {
var d detailed
if errors.As(err, &d) {
return d.Details()
}
return nil
}