Skip to content

Commit d6aa335

Browse files
authored
Merge pull request #1844 from adamreese/feat/sdk-go-redis-v2
ref(sdk/go): Refactor the Redis Go SDK to be more idiomatic
2 parents a79cddf + 43f61a9 commit d6aa335

File tree

3 files changed

+207
-89
lines changed

3 files changed

+207
-89
lines changed

redis/internals.go

Lines changed: 76 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,48 @@ package redis
66
import "C"
77
import (
88
"errors"
9+
"fmt"
910
"unsafe"
1011
)
1112

13+
// argumentKind represents a type of a argument for executing a Redis command.
14+
type argumentKind uint8
15+
16+
const (
17+
argumentKindInt argumentKind = iota
18+
argumentKindBinary
19+
)
20+
21+
// argument represents an argument for a Redis command.
22+
type argument struct {
23+
kind argumentKind
24+
val any
25+
}
26+
27+
func createParameter(x any) (*argument, error) {
28+
var p argument
29+
switch v := x.(type) {
30+
case int:
31+
p.kind = argumentKindInt
32+
p.val = int64(v)
33+
case int32:
34+
p.kind = argumentKindInt
35+
p.val = int64(v)
36+
case int64:
37+
p.kind = argumentKindInt
38+
p.val = v
39+
case string:
40+
p.kind = argumentKindBinary
41+
p.val = []byte(v)
42+
case []byte:
43+
p.kind = argumentKindBinary
44+
p.val = v
45+
default:
46+
return &p, fmt.Errorf("unsupported parameter type: %T", x)
47+
}
48+
return &p, nil
49+
}
50+
1251
//export spin_redis_handle_redis_message
1352
func handleRedisMessage(payload *C.spin_redis_payload_t) C.spin_redis_error_t {
1453
bytes := C.GoBytes(unsafe.Pointer(payload.ptr), C.int(payload.len))
@@ -68,7 +107,7 @@ func del(addr string, keys []string) (int64, error) {
68107
return int64(cpayload), toErr(err)
69108
}
70109

71-
func sadd(addr string, key string, values []string) (int64, error) {
110+
func sadd(addr, key string, values []string) (int64, error) {
72111
caddr := redisStr(addr)
73112
ckey := redisStr(key)
74113
cvalues := redisListStr(values)
@@ -79,7 +118,7 @@ func sadd(addr string, key string, values []string) (int64, error) {
79118
return int64(cpayload), toErr(err)
80119
}
81120

82-
func smembers(addr string, key string) ([]string, error) {
121+
func smembers(addr, key string) ([]string, error) {
83122
caddr := redisStr(addr)
84123
ckey := redisStr(key)
85124

@@ -89,7 +128,7 @@ func smembers(addr string, key string) ([]string, error) {
89128
return fromRedisListStr(&cpayload), toErr(err)
90129
}
91130

92-
func srem(addr string, key string, values []string) (int64, error) {
131+
func srem(addr, key string, values []string) (int64, error) {
93132
caddr := redisStr(addr)
94133
ckey := redisStr(key)
95134
cvalues := redisListStr(values)
@@ -100,33 +139,7 @@ func srem(addr string, key string, values []string) (int64, error) {
100139
return int64(cpayload), toErr(err)
101140
}
102141

103-
type RedisParameterKind uint8
104-
105-
const (
106-
RedisParameterKindInt64 = iota
107-
RedisParameterKindBinary
108-
)
109-
110-
type RedisParameter struct {
111-
Kind RedisParameterKind
112-
Val interface{}
113-
}
114-
115-
type RedisResultKind uint8
116-
117-
const (
118-
RedisResultKindNil = iota
119-
RedisResultKindStatus
120-
RedisResultKindInt64
121-
RedisResultKindBinary
122-
)
123-
124-
type RedisResult struct {
125-
Kind RedisResultKind
126-
Val interface{}
127-
}
128-
129-
func execute(addr string, command string, arguments []RedisParameter) ([]RedisResult, error) {
142+
func execute(addr, command string, arguments []*argument) ([]*Result, error) {
130143
caddr := redisStr(addr)
131144
ccommand := redisStr(command)
132145
carguments := redisListParameter(arguments)
@@ -142,8 +155,10 @@ func redisStr(x string) C.outbound_redis_string_t {
142155
}
143156

144157
func redisListStr(xs []string) C.outbound_redis_list_string_t {
145-
var cxs []C.outbound_redis_string_t
146-
158+
if len(xs) == 0 {
159+
return C.outbound_redis_list_string_t{}
160+
}
161+
cxs := make([]C.outbound_redis_string_t, 0, len(xs))
147162
for i := 0; i < len(xs); i++ {
148163
cxs = append(cxs, redisStr(xs[i]))
149164
}
@@ -152,62 +167,63 @@ func redisListStr(xs []string) C.outbound_redis_list_string_t {
152167

153168
func fromRedisListStr(list *C.outbound_redis_list_string_t) []string {
154169
listLen := int(list.len)
155-
var result []string
170+
result := make([]string, 0, listLen)
156171

157172
slice := unsafe.Slice(list.ptr, listLen)
158173
for i := 0; i < listLen; i++ {
159-
string := slice[i]
160-
result = append(result, C.GoStringN(string.ptr, C.int(string.len)))
174+
str := slice[i]
175+
result = append(result, C.GoStringN(str.ptr, C.int(str.len)))
161176
}
162-
163177
return result
164178
}
165179

166-
func redisParameter(x RedisParameter) C.outbound_redis_redis_parameter_t {
167-
180+
func redisParameter(x *argument) C.outbound_redis_redis_parameter_t {
168181
var ret C.outbound_redis_redis_parameter_t
169-
switch x.Kind {
170-
case RedisParameterKindInt64:
171-
*(*C.int64_t)(unsafe.Pointer(&ret.val)) = x.Val.(int64)
172-
case RedisParameterKindBinary:
173-
value := x.Val.([]byte)
182+
switch x.kind {
183+
case argumentKindInt:
184+
*(*C.int64_t)(unsafe.Pointer(&ret.val)) = x.val.(int64)
185+
case argumentKindBinary:
186+
value := x.val.([]byte)
174187
payload := C.outbound_redis_payload_t{ptr: &value[0], len: C.size_t(len(value))}
175188
*(*C.outbound_redis_payload_t)(unsafe.Pointer(&ret.val)) = payload
176189
}
177-
ret.tag = C.uint8_t(x.Kind)
190+
ret.tag = C.uint8_t(x.kind)
178191
return ret
179192
}
180193

181-
func redisListParameter(xs []RedisParameter) C.outbound_redis_list_redis_parameter_t {
182-
var cxs []C.outbound_redis_redis_parameter_t
194+
func redisListParameter(xs []*argument) C.outbound_redis_list_redis_parameter_t {
195+
if len(xs) == 0 {
196+
return C.outbound_redis_list_redis_parameter_t{}
197+
}
183198

199+
cxs := make([]C.outbound_redis_redis_parameter_t, 0, len(xs))
184200
for i := 0; i < len(xs); i++ {
185201
cxs = append(cxs, redisParameter(xs[i]))
186202
}
187203
return C.outbound_redis_list_redis_parameter_t{ptr: &cxs[0], len: C.size_t(len(cxs))}
188204
}
189205

190-
func fromRedisResult(result *C.outbound_redis_redis_result_t) RedisResult {
191-
var val interface{}
192-
switch result.tag {
193-
case 0: val = nil
194-
case 1: {
195-
string := (*C.outbound_redis_string_t)(unsafe.Pointer(&result.val))
196-
val = C.GoStringN(string.ptr, C.int(string.len))
197-
}
198-
case 2: val = int64(*(*C.int64_t)(unsafe.Pointer(&result.val)))
199-
case 3: {
206+
func fromRedisResult(result *C.outbound_redis_redis_result_t) *Result {
207+
var val any
208+
switch ResultKind(result.tag) {
209+
case ResultKindNil:
210+
val = nil
211+
case ResultKindStatus:
212+
str := (*C.outbound_redis_string_t)(unsafe.Pointer(&result.val))
213+
val = C.GoStringN(str.ptr, C.int(str.len))
214+
case ResultKindInt64:
215+
val = int64(*(*C.int64_t)(unsafe.Pointer(&result.val)))
216+
case ResultKindBinary:
200217
payload := (*C.outbound_redis_payload_t)(unsafe.Pointer(&result.val))
201218
val = C.GoBytes(unsafe.Pointer(payload.ptr), C.int(payload.len))
202219
}
203-
}
204220

205-
return RedisResult{Kind: RedisResultKind(result.tag), Val: val}
221+
return &Result{Kind: ResultKind(result.tag), Val: val}
206222
}
207223

208-
func fromRedisListResult(list *C.outbound_redis_list_redis_result_t) []RedisResult {
224+
func fromRedisListResult(list *C.outbound_redis_list_redis_result_t) []*Result {
209225
listLen := int(list.len)
210-
var result []RedisResult
226+
result := make([]*Result, 0, listLen)
211227

212228
slice := unsafe.Slice(list.ptr, listLen)
213229
for i := 0; i < listLen; i++ {

redis/internals_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package redis
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestCreateParameter(t *testing.T) {
9+
tests := []struct {
10+
in any
11+
want argumentKind
12+
}{
13+
{in: "a", want: argumentKindBinary},
14+
{in: []byte("b"), want: argumentKindBinary},
15+
{in: 1, want: argumentKindInt},
16+
{in: int64(2), want: argumentKindInt},
17+
{in: int32(3), want: argumentKindInt},
18+
}
19+
20+
for _, tc := range tests {
21+
p, err := createParameter(tc.in)
22+
if err != nil {
23+
t.Error(err)
24+
}
25+
if p.kind != tc.want {
26+
t.Errorf("want %s, got %s", tc.want, p.kind)
27+
}
28+
}
29+
}
30+
31+
func TestRedisListString(t *testing.T) {
32+
list := []string{"a", "b", "c"}
33+
34+
rlist := redisListStr(list)
35+
got := fromRedisListStr(&rlist)
36+
37+
if !reflect.DeepEqual(list, got) {
38+
t.Errorf("want %s, got %s", list, got)
39+
}
40+
}

0 commit comments

Comments
 (0)