Skip to content

Commit

Permalink
Merge pull request #353 from Exca-DK/redis-result-stringer
Browse files Browse the repository at this point in the history
Feat: Human readable results
  • Loading branch information
rueian committed Aug 31, 2023
2 parents c0e2e54 + 3165dfc commit 3f0b61d
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
68 changes: 68 additions & 0 deletions message.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,29 @@ func (r RedisResult) CachePXAT() int64 {
return r.val.CachePXAT()
}

// String returns human-readable representation of RedisResult
func (r *RedisResult) String() string {
v, _ := (*prettyRedisResult)(r).MarshalJSON()
return string(v)
}

type prettyRedisResult RedisResult

// MarshalJSON implements json.Marshaler interface
func (r *prettyRedisResult) MarshalJSON() ([]byte, error) {
type PrettyRedisResult struct {
Error string `json:"Error,omitempty"`
Message *prettyRedisMessage `json:"Message,omitempty"`
}
obj := PrettyRedisResult{}
if r.err != nil {
obj.Error = r.err.Error()
} else {
obj.Message = (*prettyRedisMessage)(&r.val)
}
return json.Marshal(obj)
}

// RedisMessage is a redis response message, it may be a nil response
type RedisMessage struct {
attrs *RedisMessage
Expand Down Expand Up @@ -1236,3 +1259,48 @@ func (m *RedisMessage) approximateSize() (s int) {
}
return
}

// String returns human-readable representation of RedisMessage
func (m *RedisMessage) String() string {
v, _ := (*prettyRedisMessage)(m).MarshalJSON()
return string(v)
}

type prettyRedisMessage RedisMessage

// MarshalJSON implements json.Marshaler interface
func (m *prettyRedisMessage) MarshalJSON() ([]byte, error) {
type PrettyRedisMessage struct {
Type string `json:"Type,omitempty"`
Error string `json:"Error,omitempty"`
Ttl string `json:"TTL,omitempty"`
Value any `json:"Value,omitempty"`
}
org := (*RedisMessage)(m)
strType, ok := typeNames[m.typ]
if !ok {
strType = "unknown"
}
obj := PrettyRedisMessage{Type: strType}
if m.ttl != [7]byte{} {
obj.Ttl = time.UnixMilli(org.CachePXAT()).UTC().String()
}
if err := org.Error(); err != nil {
obj.Error = err.Error()
}
switch m.typ {
case typeFloat, typeBlobString, typeSimpleString, typeVerbatimString, typeBigNumber:
obj.Value = m.string
case typeBool:
obj.Value = m.integer == 1
case typeInteger:
obj.Value = m.integer
case typeMap, typeSet, typeArray:
values := make([]prettyRedisMessage, len(m.values))
for i, value := range m.values {
values[i] = prettyRedisMessage(value)
}
obj.Value = values
}
return json.Marshal(obj)
}
86 changes: 86 additions & 0 deletions message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,40 @@ func TestRedisResult(t *testing.T) {
t.Fatal("CachePXAT <= 0")
}
})

t.Run("Stringer", func(t *testing.T) {
tests := []struct {
input RedisResult
expected string
}{
{
input: RedisResult{
val: RedisMessage{typ: '*', values: []RedisMessage{
{typ: '*', values: []RedisMessage{
{typ: ':', integer: 0},
{typ: ':', integer: 0},
{typ: '*', values: []RedisMessage{ // master
{typ: '+', string: "127.0.3.1"},
{typ: ':', integer: 3},
{typ: '+', string: ""},
}},
}},
}},
},
expected: `{"Message":{"Type":"array","Value":[{"Type":"array","Value":[{"Type":"int64","Value":0},{"Type":"int64","Value":0},{"Type":"array","Value":[{"Type":"simple string","Value":"127.0.3.1"},{"Type":"int64","Value":3},{"Type":"simple string","Value":""}]}]}]}}`,
},
{
input: RedisResult{err: errors.New("foo")},
expected: `{"Error":"foo"}`,
},
}
for _, test := range tests {
msg := test.input.String()
if msg != test.expected {
t.Fatalf("unexpected string. got %v expected %v", msg, test.expected)
}
}
})
}

//gocyclo:ignore
Expand Down Expand Up @@ -1672,4 +1706,56 @@ func TestRedisMessage(t *testing.T) {
t.Fatal("CachePXAT <= 0")
}
})

t.Run("Stringer", func(t *testing.T) {
tests := []struct {
input RedisMessage
expected string
}{
{
input: RedisMessage{typ: '*', values: []RedisMessage{
{typ: '*', values: []RedisMessage{
{typ: ':', integer: 0},
{typ: ':', integer: 0},
{typ: '*', values: []RedisMessage{
{typ: '+', string: "127.0.3.1"},
{typ: ':', integer: 3},
{typ: '+', string: ""},
}},
}},
}},
expected: `{"Type":"array","Value":[{"Type":"array","Value":[{"Type":"int64","Value":0},{"Type":"int64","Value":0},{"Type":"array","Value":[{"Type":"simple string","Value":"127.0.3.1"},{"Type":"int64","Value":3},{"Type":"simple string","Value":""}]}]}]}`,
},
{
input: RedisMessage{typ: '+', string: "127.0.3.1", ttl: [7]byte{97, 77, 74, 61, 138, 1, 0}},
expected: `{"Type":"simple string","TTL":"2023-08-28 17:56:34.273 +0000 UTC","Value":"127.0.3.1"}`,
},
{
input: RedisMessage{typ: '0'},
expected: `{"Type":"unknown"}`,
},
{
input: RedisMessage{typ: typeBool, integer: 1},
expected: `{"Type":"boolean","Value":true}`,
},
{
input: RedisMessage{typ: typeNull},
expected: `{"Type":"null","Error":"redis nil message"}`,
},
{
input: RedisMessage{typ: typeSimpleErr, string: "ERR foo"},
expected: `{"Type":"simple error","Error":"foo"}`,
},
{
input: RedisMessage{typ: typeBlobErr, string: "ERR foo"},
expected: `{"Type":"blob error","Error":"foo"}`,
},
}
for _, test := range tests {
msg := test.input.String()
if msg != test.expected {
t.Fatalf("unexpected string. got %v expected %v", msg, test.expected)
}
}
})
}

0 comments on commit 3f0b61d

Please sign in to comment.