Skip to content

Commit 87e4e48

Browse files
committed
refactor(errors): move typed key and value handling to a new file for better organization and maintainability
1 parent fc7625a commit 87e4e48

File tree

2 files changed

+76
-75
lines changed

2 files changed

+76
-75
lines changed

errors.go

Lines changed: 0 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,6 @@ import (
99
"log/slog"
1010
)
1111

12-
// TypedKey represents a type-safe key for error values
13-
type TypedKey[T any] struct {
14-
name string
15-
}
16-
17-
// NewTypedKey creates a new typed key with the given name
18-
func NewTypedKey[T any](name string) TypedKey[T] {
19-
return TypedKey[T]{name: name}
20-
}
21-
22-
// String returns the string representation of the key for debugging
23-
func (k TypedKey[T]) String() string {
24-
return k.name
25-
}
26-
27-
// Name returns the name of the key
28-
func (k TypedKey[T]) Name() string {
29-
return k.name
30-
}
31-
3212
type Option func(*Error)
3313

3414
// Value sets key and value to the error
@@ -52,18 +32,6 @@ func ID(id string) Option {
5232
}
5333
}
5434

55-
// TypedValue sets typed key and value to the error
56-
func TypedValue[T any](key TypedKey[T], value T) Option {
57-
return func(err *Error) {
58-
err.typedValues[key.name] = value
59-
}
60-
}
61-
62-
// TV is alias of TypedValue
63-
func TV[T any](key TypedKey[T], value T) Option {
64-
return TypedValue(key, value)
65-
}
66-
6735
// Tag sets tag to the error
6836
func Tag(t tag) Option {
6937
return func(err *Error) {
@@ -114,15 +82,6 @@ func Values(err error) map[string]any {
11482
return nil
11583
}
11684

117-
// TypedValues returns map of key and value that is set by TypedValue. All wrapped goerr.Error typed key and values will be merged. Key and values of wrapped error is overwritten by upper goerr.Error.
118-
func TypedValues(err error) map[string]any {
119-
if e := Unwrap(err); e != nil {
120-
return e.TypedValues()
121-
}
122-
123-
return nil
124-
}
125-
12685
// Tags returns list of tags that is set by WithTags. All wrapped goerr.Error tags will be merged. Tags of wrapped error is overwritten by upper goerr.Error.
12786
func Tags(err error) []string {
12887
if e := Unwrap(err); e != nil {
@@ -343,40 +302,6 @@ func (x *Error) TypedValues() map[string]any {
343302
return typedValues
344303
}
345304

346-
// GetTypedValue returns value associated with the typed key from the error. It searches through the error chain.
347-
func GetTypedValue[T any](err error, key TypedKey[T]) (T, bool) {
348-
if e := Unwrap(err); e != nil {
349-
return getTypedValueFromError(e, key)
350-
}
351-
352-
var zero T
353-
return zero, false
354-
}
355-
356-
func getTypedValueFromError[T any](err *Error, key TypedKey[T]) (T, bool) {
357-
// Search in current error's typed values
358-
if value, ok := err.typedValues[key.name]; ok {
359-
// Key found at this level. This is the definitive value.
360-
// Check if the type matches.
361-
if typedValue, ok := value.(T); ok {
362-
return typedValue, true
363-
}
364-
// Type does not match. Do not search deeper for this key.
365-
var zero T
366-
return zero, false
367-
}
368-
369-
// Key not found at this level. Search in wrapped errors recursively.
370-
if cause := err.Unwrap(); cause != nil {
371-
if wrappedErr := Unwrap(cause); wrappedErr != nil {
372-
return getTypedValueFromError(wrappedErr, key)
373-
}
374-
}
375-
376-
var zero T
377-
return zero, false
378-
}
379-
380305
func (x *Error) mergedValues() values {
381306
merged := make(values)
382307

typed_values.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package goerr
2+
3+
// TypedKey represents a type-safe key for error values
4+
type TypedKey[T any] struct {
5+
name string
6+
}
7+
8+
// NewTypedKey creates a new typed key with the given name
9+
func NewTypedKey[T any](name string) TypedKey[T] {
10+
return TypedKey[T]{name: name}
11+
}
12+
13+
// String returns the string representation of the key for debugging
14+
func (k TypedKey[T]) String() string {
15+
return k.name
16+
}
17+
18+
// Name returns the name of the key
19+
func (k TypedKey[T]) Name() string {
20+
return k.name
21+
}
22+
23+
// TypedValue sets typed key and value to the error
24+
func TypedValue[T any](key TypedKey[T], value T) Option {
25+
return func(err *Error) {
26+
err.typedValues[key.name] = value
27+
}
28+
}
29+
30+
// TV is alias of TypedValue
31+
func TV[T any](key TypedKey[T], value T) Option {
32+
return TypedValue(key, value)
33+
}
34+
35+
// TypedValues returns map of key and value that is set by TypedValue. All wrapped goerr.Error typed key and values will be merged. Key and values of wrapped error is overwritten by upper goerr.Error.
36+
func TypedValues(err error) map[string]any {
37+
if e := Unwrap(err); e != nil {
38+
return e.TypedValues()
39+
}
40+
41+
return nil
42+
}
43+
44+
// GetTypedValue returns value associated with the typed key from the error. It searches through the error chain.
45+
func GetTypedValue[T any](err error, key TypedKey[T]) (T, bool) {
46+
if e := Unwrap(err); e != nil {
47+
return getTypedValueFromError(e, key)
48+
}
49+
50+
var zero T
51+
return zero, false
52+
}
53+
54+
func getTypedValueFromError[T any](err *Error, key TypedKey[T]) (T, bool) {
55+
// Search in current error's typed values
56+
if value, ok := err.typedValues[key.name]; ok {
57+
// Key found at this level. This is the definitive value.
58+
// Check if the type matches.
59+
if typedValue, ok := value.(T); ok {
60+
return typedValue, true
61+
}
62+
// Type does not match. Do not search deeper for this key.
63+
var zero T
64+
return zero, false
65+
}
66+
67+
// Key not found at this level. Search in wrapped errors recursively.
68+
if cause := err.Unwrap(); cause != nil {
69+
if wrappedErr := Unwrap(cause); wrappedErr != nil {
70+
return getTypedValueFromError(wrappedErr, key)
71+
}
72+
}
73+
74+
var zero T
75+
return zero, false
76+
}

0 commit comments

Comments
 (0)