diff --git a/DESIGN.md b/DESIGN.md index f89d13f..3c32964 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -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 @@ -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) ``` diff --git a/README.md b/README.md index 773904e..aef3bea 100644 --- a/README.md +++ b/README.md @@ -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", + }), ) ``` diff --git a/errors.go b/errors.go index 4b93c21..b7c2f92 100644 --- a/errors.go +++ b/errors.go @@ -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) { diff --git a/errors_test.go b/errors_test.go index d8dd400..67cea83 100644 --- a/errors_test.go +++ b/errors_test.go @@ -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)) @@ -115,6 +116,7 @@ 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 @@ -122,7 +124,7 @@ var _ = Describe("Errors", func() { 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")) } @@ -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))