Skip to content

Commit a79cddf

Browse files
authored
Merge pull request #1845 from adamreese/feat/sdk-go-kv-v2
feat(sdk/go): Refactor the key/value Go SDK to be more idiomatic
2 parents 6fce595 + 1fb3cec commit a79cddf

File tree

5 files changed

+140
-131
lines changed

5 files changed

+140
-131
lines changed

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ GENERATED_OUTBOUND_HTTP = http/wasi-outbound-http.c http/wasi-outbound-http.h
4444
GENERATED_SPIN_HTTP = http/spin-http.c http/spin-http.h
4545
GENERATED_OUTBOUND_REDIS = redis/outbound-redis.c redis/outbound-redis.h
4646
GENERATED_SPIN_REDIS = redis/spin-redis.c redis/spin-redis.h
47-
GENERATED_KEY_VALUE = key_value/key-value.c key_value/key-value.h
47+
GENERATED_KEY_VALUE = kv/key-value.c kv/key-value.h
4848
GENERATED_SQLITE = sqlite/sqlite.c sqlite/sqlite.h
4949
GENERATED_LLM = llm/llm.c llm/llm.h
5050
GENERATED_OUTBOUND_MYSQL = mysql/outbound-mysql.c mysql/outbound-mysql.h
@@ -54,7 +54,7 @@ SDK_VERSION_SOURCE_FILE = sdk_version/sdk-version-go-template.c
5454

5555
# NOTE: Please update this list if you add a new directory to the SDK:
5656
SDK_VERSION_DEST_FILES = config/sdk-version-go.c http/sdk-version-go.c \
57-
key_value/sdk-version-go.c redis/sdk-version-go.c \
57+
kv/sdk-version-go.c redis/sdk-version-go.c \
5858
sqlite/sdk-version-go.c llm/sdk-version-go.c
5959

6060
# NOTE: To generate the C bindings you need to install a forked version of wit-bindgen.
@@ -90,7 +90,7 @@ $(GENERATED_SPIN_REDIS):
9090
wit-bindgen c --export ../../wit/ephemeral/spin-redis.wit --out-dir ./redis
9191

9292
$(GENERATED_KEY_VALUE):
93-
wit-bindgen c --import ../../wit/ephemeral/key-value.wit --out-dir ./key_value
93+
wit-bindgen c --import ../../wit/ephemeral/key-value.wit --out-dir ./kv
9494

9595
$(GENERATED_SQLITE):
9696
wit-bindgen c --import ../../wit/ephemeral/sqlite.wit --out-dir ./sqlite

key_value/key-value.go

Lines changed: 0 additions & 128 deletions
This file was deleted.
File renamed without changes.
File renamed without changes.

kv/kv.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// Package kv provides access to key value stores within Spin
2+
// components.
3+
package kv
4+
5+
// #include "key-value.h"
6+
import "C"
7+
import (
8+
"errors"
9+
"fmt"
10+
"unsafe"
11+
)
12+
13+
// Store is the Key/Value backend storage.
14+
type Store struct {
15+
name string
16+
active bool
17+
ptr C.key_value_store_t
18+
}
19+
20+
// OpenStore creates a new instance of Store and opens a connection.
21+
func OpenStore(name string) (*Store, error) {
22+
s := &Store{name: name}
23+
if err := s.open(); err != nil {
24+
return nil, err
25+
}
26+
return s, nil
27+
}
28+
29+
// Close terminates the connection to Store.
30+
func (s *Store) Close() {
31+
if s.active {
32+
C.key_value_close(C.uint32_t(s.ptr))
33+
}
34+
s.active = false
35+
}
36+
37+
// Get retrieves a value from Store.
38+
func (s *Store) Get(key string) ([]byte, error) {
39+
ckey := toCStr(key)
40+
var ret C.key_value_expected_list_u8_error_t
41+
C.key_value_get(C.uint32_t(s.ptr), &ckey, &ret)
42+
if ret.is_err {
43+
return nil, toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
44+
}
45+
list := (*C.key_value_list_u8_t)(unsafe.Pointer(&ret.val))
46+
return C.GoBytes(unsafe.Pointer(list.ptr), C.int(list.len)), nil
47+
}
48+
49+
// Delete removes a value from Store.
50+
func (s *Store) Delete(key string) error {
51+
ckey := toCStr(key)
52+
var ret C.key_value_expected_unit_error_t
53+
C.key_value_delete(C.uint32_t(s.ptr), &ckey, &ret)
54+
if ret.is_err {
55+
return toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
56+
}
57+
return nil
58+
}
59+
60+
// Set creates a new key/value in Store.
61+
func (s *Store) Set(key string, value []byte) error {
62+
ckey := toCStr(key)
63+
cbytes := toCBytes(value)
64+
var ret C.key_value_expected_unit_error_t
65+
C.key_value_set(C.uint32_t(s.ptr), &ckey, &cbytes, &ret)
66+
if ret.is_err {
67+
return toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
68+
}
69+
return nil
70+
}
71+
72+
// Exists checks if a key exists within Store.
73+
func (s *Store) Exists(key string) (bool, error) {
74+
ckey := toCStr(key)
75+
var ret C.key_value_expected_bool_error_t
76+
C.key_value_exists(C.uint32_t(s.ptr), &ckey, &ret)
77+
if ret.is_err {
78+
return false, toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
79+
}
80+
return *(*bool)(unsafe.Pointer(&ret.val)), nil
81+
}
82+
83+
func (s *Store) open() error {
84+
if s.active {
85+
return nil
86+
}
87+
cname := toCStr(s.name)
88+
var ret C.key_value_expected_store_error_t
89+
C.key_value_open(&cname, &ret)
90+
if ret.is_err {
91+
return toErr((*C.key_value_error_t)(unsafe.Pointer(&ret.val)))
92+
}
93+
s.ptr = *(*C.key_value_store_t)(unsafe.Pointer(&ret.val))
94+
s.active = true
95+
return nil
96+
}
97+
98+
func toCBytes(x []byte) C.key_value_list_u8_t {
99+
return C.key_value_list_u8_t{ptr: (*C.uint8_t)(unsafe.Pointer(&x[0])), len: C.size_t(len(x))}
100+
}
101+
102+
func toCStr(x string) C.key_value_string_t {
103+
return C.key_value_string_t{ptr: C.CString(x), len: C.size_t(len(x))}
104+
}
105+
106+
func fromCStrList(list *C.key_value_list_string_t) []string {
107+
var result []string
108+
109+
listLen := int(list.len)
110+
slice := unsafe.Slice(list.ptr, listLen)
111+
for i := 0; i < listLen; i++ {
112+
str := slice[i]
113+
result = append(result, C.GoStringN(str.ptr, C.int(str.len)))
114+
}
115+
116+
return result
117+
}
118+
119+
func toErr(err *C.key_value_error_t) error {
120+
switch err.tag {
121+
case 0:
122+
return errors.New("store table full")
123+
case 1:
124+
return errors.New("no such store")
125+
case 2:
126+
return errors.New("access denied")
127+
case 3:
128+
return errors.New("invalid store")
129+
case 4:
130+
return errors.New("no such key")
131+
case 5:
132+
str := (*C.key_value_string_t)(unsafe.Pointer(&err.val))
133+
return fmt.Errorf("io error: %s", C.GoStringN(str.ptr, C.int(str.len)))
134+
default:
135+
return fmt.Errorf("unrecognized error: %v", err.tag)
136+
}
137+
}

0 commit comments

Comments
 (0)