Skip to content

Commit 5d82ac7

Browse files
committed
Initial commit to setup the client
1 parent 48f7c09 commit 5d82ac7

File tree

6 files changed

+206
-0
lines changed

6 files changed

+206
-0
lines changed

pkg/blueprint_client/get_by_id.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package bpc
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"connectrpc.com/connect"
8+
kvv1 "github.com/steady-bytes/draft/api/core/registry/key_value/v1"
9+
kvv1Connect "github.com/steady-bytes/draft/api/core/registry/key_value/v1/v1connect"
10+
"google.golang.org/protobuf/reflect/protoreflect"
11+
"google.golang.org/protobuf/types/known/anypb"
12+
)
13+
14+
func GetById[T protoreflect.ProtoMessage](
15+
ctx context.Context,
16+
client kvv1Connect.KeyValueServiceClient,
17+
id string,
18+
factory func() T) (T, error) {
19+
if id == "" {
20+
return factory(), fmt.Errorf("ID cannot be empty")
21+
}
22+
23+
t := factory()
24+
25+
val, err := anypb.New(*new(T))
26+
if err != nil {
27+
return t, err
28+
}
29+
30+
res, err := client.Get(ctx, connect.NewRequest(&kvv1.GetRequest{
31+
Key: id,
32+
Value: val,
33+
}))
34+
if err != nil {
35+
return t, err
36+
}
37+
38+
if res.Msg == nil || res.Msg.GetValue() == nil {
39+
return t, fmt.Errorf("item with ID %s not found", id)
40+
}
41+
42+
if err := res.Msg.GetValue().UnmarshalTo(t); err != nil {
43+
return t, fmt.Errorf("failed to unmarshal item: %v", err)
44+
}
45+
46+
return t, nil
47+
}

pkg/blueprint_client/go.mod

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module github.com/steady-bytes/bpc/pkg/blueprint_client
2+
3+
go 1.24.0
4+
5+
require (
6+
connectrpc.com/connect v1.18.1
7+
github.com/steady-bytes/draft/api v1.1.0
8+
google.golang.org/protobuf v1.36.7
9+
)
10+
11+
require github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect

pkg/blueprint_client/go.sum

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw=
2+
connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8=
3+
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
4+
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
5+
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
6+
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
7+
github.com/steady-bytes/draft/api v1.1.0 h1:nOPLbpkWrdGAWFz22SPsSO4HR8IlckvUq7ZD5l0jn4A=
8+
github.com/steady-bytes/draft/api v1.1.0/go.mod h1:zwZNNg8uIoQb3OqibvvcdgJPymawy2rUWh6M6Nk43a0=
9+
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
10+
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
11+
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
12+
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
13+
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
14+
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=

pkg/blueprint_client/list.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package bpc
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"connectrpc.com/connect"
8+
kvv1 "github.com/steady-bytes/draft/api/core/registry/key_value/v1"
9+
kvv1Connect "github.com/steady-bytes/draft/api/core/registry/key_value/v1/v1connect"
10+
"google.golang.org/protobuf/reflect/protoreflect"
11+
"google.golang.org/protobuf/types/known/anypb"
12+
)
13+
14+
// list retrieves all items of type T from the key-value store.
15+
// It's understood that the response of this is not limited in size
16+
// so use with caution in production environments.
17+
// Blueprint needs some additional logic to handle pagination or limits.
18+
// I don't think this can actually be improved without Blueprint having
19+
// indexing and pagination capabilities.
20+
func List[T protoreflect.ProtoMessage](ctx context.Context, client kvv1Connect.KeyValueServiceClient, factory func() T) ([]T, error) {
21+
val, err := anypb.New(*new(T))
22+
if err != nil {
23+
return nil, err
24+
}
25+
26+
res, err := client.List(ctx, connect.NewRequest(&kvv1.ListRequest{
27+
Value: val,
28+
}))
29+
if err != nil {
30+
return nil, err
31+
}
32+
33+
if res.Msg == nil || len(res.Msg.GetValues()) == 0 {
34+
return nil, fmt.Errorf("no items found")
35+
}
36+
37+
var items []T
38+
for _, v := range res.Msg.GetValues() {
39+
item := factory()
40+
if err := v.UnmarshalTo(item); err != nil {
41+
return nil, fmt.Errorf("failed to unmarshal item: %v", err)
42+
}
43+
items = append(items, item)
44+
}
45+
46+
return items, nil
47+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package bpc
2+
3+
import (
4+
"context"
5+
6+
kvv1 "github.com/steady-bytes/draft/api/core/registry/key_value/v1"
7+
kvv1Connect "github.com/steady-bytes/draft/api/core/registry/key_value/v1/v1connect"
8+
"google.golang.org/protobuf/reflect/protoreflect"
9+
)
10+
11+
func ListAndFilter[T protoreflect.ProtoMessage](ctx context.Context, client kvv1Connect.KeyValueServiceClient, filter *kvv1.Statement, factory func() T) ([]T, error) {
12+
// This function can be used to list and filter items based on the provided filter.
13+
// For now, it just calls the list function.
14+
items, err := List[T](ctx, client, factory)
15+
if err != nil {
16+
return nil, err
17+
}
18+
19+
// filter items based on the key/value pairs in the filter
20+
filters := filter.GetWhere().(*kvv1.Statement_KeyVal).KeyVal.GetMatch()
21+
22+
// the new slice of T that will hold the filtered items
23+
var filtered []T
24+
25+
// use proto reflect to filter items based on the the key/value pairs in the filter
26+
// NOTE: This is a simple filtering logic that checks if the field value matches the filter value in
27+
// In the request. It's also understood this is no the most efficient way to filter items,
28+
// but it serves as a starting point for filtering logic.
29+
for _, item := range items {
30+
itemValue := item.ProtoReflect()
31+
matched := true
32+
for key, value := range filters {
33+
field := itemValue.Descriptor().Fields().ByName(protoreflect.Name(key))
34+
if field == nil || itemValue.Get(field).String() != value {
35+
matched = false
36+
break
37+
}
38+
}
39+
40+
if matched {
41+
filtered = append(filtered, item)
42+
}
43+
}
44+
45+
return filtered, nil
46+
}

pkg/blueprint_client/save.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package bpc
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"connectrpc.com/connect"
8+
"google.golang.org/protobuf/reflect/protoreflect"
9+
"google.golang.org/protobuf/types/known/anypb"
10+
11+
kvv1 "github.com/steady-bytes/draft/api/core/registry/key_value/v1"
12+
kvv1Connect "github.com/steady-bytes/draft/api/core/registry/key_value/v1/v1connect"
13+
)
14+
15+
func Save[T protoreflect.ProtoMessage](
16+
ctx context.Context,
17+
client kvv1Connect.KeyValueServiceClient,
18+
key string,
19+
item T,
20+
) (T, error) {
21+
if key == "" {
22+
// I am starting to consider that I should make a generic error type for the repository lib
23+
return item, fmt.Errorf("key cannot be empty")
24+
}
25+
26+
val, err := anypb.New(item)
27+
if err != nil {
28+
return item, err
29+
}
30+
31+
req := connect.NewRequest(&kvv1.SetRequest{
32+
Key: key,
33+
Value: val,
34+
})
35+
36+
if _, err := client.Set(ctx, req); err != nil {
37+
return item, err
38+
}
39+
40+
return item, nil
41+
}

0 commit comments

Comments
 (0)