Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The variadic options would be the following one

* `WithDetail`/`WithDetailf`: provide a message that details the error
* `WithProperty`: provide a key/value pair for additional informations (filename, path, username, ... )
* `WithProperties`: provide multiple properties at once
* `WithIdentifier`: used to provide an identifer, it could be concatenated with other idenfier from previous calls from subfunctions (See example below for clarity)
* `CausedBy`: used to trace a root error

Expand All @@ -35,6 +36,7 @@ Signature could be as follow
errors.WithDetail(string)
errors.WithDetailf(string, ...any)
errors.WithProperty(string, any)
errors.WithProperties(map[string]any)
errors.WithIdentifier(uint32)
errors.CausedBy(err error)
```
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,13 @@ err3 := errors.Wrap(ErrRequestFailed,
errors.WithProperty("status_code", 500),
)

// Multiple properties (one option per property)
// Multiple properties
err4 := errors.Wrap(ErrDatabaseError,
errors.WithProperty("host", "localhost"),
errors.WithProperty("port", 5432),
errors.WithProperty("database", "myapp"),
errors.WithProperties(map[string]any{
"host": "localhost",
"port": 5432,
"database": "myapp",
}),
)
```

Expand Down
10 changes: 10 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ func WithProperty(key string, value any) Option {
}
}

// WithProperties sets multiple properties for the error.
func WithProperties(properties map[string]any) Option {
if properties == nil {
return func(c *opts) {}
}
return func(c *opts) {
maps.Copy(c.Properties, properties)
}
}

// CausedBy sets the underlying cause of this error.
func CausedBy(err error) Option {
return func(c *opts) {
Expand Down
11 changes: 8 additions & 3 deletions errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,14 @@ var _ = Describe("Errors", func() {
WithIdentifier(1001),
WithDetail("This is a test error"),
WithProperty("type", "fake"),
WithProperties(map[string]any{"key1": "value1", "key2": "value2"}),
)
var err *Error
if ok := errors.As(e, &err); ok {
Expect(err.Title).To(Equal("unknown error"))
Expect(err.Identifier).To(Equal([]uint32{1001}))
Expect(err.Details).To(Equal([]string{"This is a test error"}))
Expect(err.Properties).To(Equal(map[string]any{"type": "fake"}))
Expect(err.Properties).To(Equal(map[string]any{"key2": "value2", "type": "fake", "key1": "value1"}))
Expect(err.Cause).To(Equal(&causeError{error: errTest}))
Expect(err.stack[0].File).To(ContainSubstring("errors_test.go"))
Expect(err.stack[0].Line).To(BeNumerically(">", 0))
Expand Down Expand Up @@ -115,14 +116,15 @@ var _ = Describe("Errors", func() {
e = Wrap(ErrNotFound,
WithDetail("File not found in the session"),
WithProperty("File", "test.txt"),
WithProperties(map[string]any{"key1": "value1", "key2": "value2"}),
WithIdentifier(1001),
)
var err *Error
if ok := errors.As(e, &err); ok {
Expect(err.Title).To(Equal("not found"))
Expect(err.Identifier).To(Equal([]uint32{1001}))
Expect(err.Details).To(Equal([]string{"File not found in the session"}))
Expect(err.Properties).To(Equal(map[string]any{"File": "test.txt"}))
Expect(err.Properties).To(Equal(map[string]any{"File": "test.txt", "key1": "value1", "key2": "value2"}))
Expect(err.Cause).To(BeNil())
Expect(err.stack[0].File).To(ContainSubstring("errors_test.go"))
}
Expand All @@ -149,13 +151,16 @@ var _ = Describe("Errors", func() {
WithIdentifier(1001),
WithDetail("custom client role is 'Reader'"),
WithProperty("ClientID", "1234567890"),
WithProperties(map[string]any{"key1": "value1", "key2": "value2"}),
)
var err *Error
if ok := errors.As(e, &err); ok {
Expect(err.Title).To(Equal("not found"))
Expect(err.Identifier).To(Equal([]uint32{1, 1001}))
Expect(err.Details).To(Equal([]string{"File not found in the session", "custom client role is 'Reader'"}))
Expect(err.Properties).To(Equal(map[string]any{"File": "test.txt", "User": "john.doe", "ClientID": "1234567890"}))
Expect(err.Properties).To(Equal(map[string]any{
"key1": "value1", "key2": "value2", "File": "test.txt", "User": "john.doe", "ClientID": "1234567890",
}))
Expect(err.Cause).To(BeNil())
Expect(err.stack[0].File).To(ContainSubstring("errors_test.go"))
Expect(err.stack[0].Line).To(BeNumerically(">", 0))
Expand Down