Skip to content

Commit

Permalink
Merge pull request #149 from textileio/asutula/find-improvements
Browse files Browse the repository at this point in the history
Use reflect api to improve find api, more tests
  • Loading branch information
asutula committed Dec 6, 2019
2 parents de8c298 + 4c90621 commit af2a2eb
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 25 deletions.
26 changes: 22 additions & 4 deletions api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"reflect"

ma "github.com/multiformats/go-multiaddr"
"github.com/textileio/go-textile-core/crypto/symmetric"
Expand Down Expand Up @@ -159,10 +160,10 @@ func (c *Client) ModelHas(storeID, modelName string, entityIDs ...string) (bool,
}

// ModelFind finds records by query
func (c *Client) ModelFind(storeID, modelName string, query es.JSONQuery) ([][]byte, error) {
func (c *Client) ModelFind(storeID, modelName string, query es.JSONQuery, dummySlice interface{}) (interface{}, error) {
queryBytes, err := json.Marshal(query)
if err != nil {
return [][]byte{}, err
return nil, err
}
req := &pb.ModelFindRequest{
StoreID: storeID,
Expand All @@ -171,9 +172,9 @@ func (c *Client) ModelFind(storeID, modelName string, query es.JSONQuery) ([][]b
}
resp, err := c.client.ModelFind(c.ctx, req)
if err != nil {
return [][]byte{}, err
return nil, err
}
return resp.GetEntities(), nil
return processFindReply(resp, dummySlice)
}

// ModelFindByID finds a record by id
Expand Down Expand Up @@ -241,6 +242,23 @@ func (c *Client) Listen(storeID, modelName, entityID string) (<-chan ListenEvent
return channel, cancel
}

func processFindReply(reply *pb.ModelFindReply, dummySlice interface{}) (interface{}, error) {
sliceType := reflect.TypeOf(dummySlice)
elementType := sliceType.Elem().Elem()
length := len(reply.GetEntities())
results := reflect.MakeSlice(sliceType, length, length)
for i, result := range reply.GetEntities() {
target := reflect.New(elementType).Interface()
err := json.Unmarshal(result, target)
if err != nil {
return nil, err
}
val := results.Index(i)
val.Set(reflect.ValueOf(target))
}
return results.Interface(), nil
}

func marshalItems(items []interface{}) ([]string, error) {
values := make([]string, len(items))
for i, item := range items {
Expand Down
59 changes: 50 additions & 9 deletions api/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,18 +200,11 @@ func TestModelFind(t *testing.T) {
},
}

jsonResults, err := client.ModelFind(storeID, modelName, q)
rawResults, err := client.ModelFind(storeID, modelName, q, []*Person{})
if err != nil {
t.Fatalf("failed to find: %v", err)
}
results := make([]*Person, len(jsonResults))
for i, jsonResult := range jsonResults {
person := &Person{}
if err := json.Unmarshal(jsonResult, person); err != nil {
t.Fatalf("failed to unmarshal json result: %v", err)
}
results[i] = person
}
results := rawResults.([]*Person)
if len(results) != 1 {
t.Fatalf("expected 1 result, but got %v", len(results))
}
Expand Down Expand Up @@ -286,6 +279,30 @@ func TestReadTransaction(t *testing.T) {
if !reflect.DeepEqual(foundPerson, person) {
t.Fatal("txn model found by id does't equal the original")
}

q := es.JSONQuery{
Ands: []es.JSONCriterion{
es.JSONCriterion{
FieldPath: "lastName",
Operation: es.Eq,
Value: es.JSONValue{
String: &person.LastName,
},
},
},
}

rawResults, err := txn.Find(q, []*Person{})
if err != nil {
t.Fatalf("failed to find: %v", err)
}
results := rawResults.([]*Person)
if len(results) != 1 {
t.Fatalf("expected 1 result, but got %v", len(results))
}
if !reflect.DeepEqual(results[0], person) {
t.Fatal("model found by query does't equal the original")
}
}

func TestWriteTransaction(t *testing.T) {
Expand Down Expand Up @@ -342,6 +359,30 @@ func TestWriteTransaction(t *testing.T) {
t.Fatalf("txn model found by id does't equal the original")
}

q := es.JSONQuery{
Ands: []es.JSONCriterion{
es.JSONCriterion{
FieldPath: "lastName",
Operation: es.Eq,
Value: es.JSONValue{
String: &existingPerson.LastName,
},
},
},
}

rawResults, err := txn.Find(q, []*Person{})
if err != nil {
t.Fatalf("failed to find: %v", err)
}
results := rawResults.([]*Person)
if len(results) != 1 {
t.Fatalf("expected 1 result, but got %v", len(results))
}
if !reflect.DeepEqual(results[0], existingPerson) {
t.Fatal("model found by query does't equal the original")
}

existingPerson.Age = 99
err = txn.Save(existingPerson)
if err != nil {
Expand Down
12 changes: 6 additions & 6 deletions api/client/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,25 +69,25 @@ func (t *ReadTransaction) FindByID(entityID string, entity interface{}) error {
}

// Find finds entities by query
func (t *ReadTransaction) Find(query es.JSONQuery) ([][]byte, error) {
func (t *ReadTransaction) Find(query es.JSONQuery, dummySlice interface{}) (interface{}, error) {
queryBytes, err := json.Marshal(query)
if err != nil {
return [][]byte{}, err
return nil, err
}
innerReq := &pb.ModelFindRequest{QueryJSON: queryBytes}
option := &pb.ReadTransactionRequest_ModelFindRequest{ModelFindRequest: innerReq}
var resp *pb.ReadTransactionReply
if err = t.client.Send(&pb.ReadTransactionRequest{Option: option}); err != nil {
return [][]byte{}, err
return nil, err
}
if resp, err = t.client.Recv(); err != nil {
return [][]byte{}, err
return nil, err
}
switch x := resp.GetOption().(type) {
case *pb.ReadTransactionReply_ModelFindReply:
return x.ModelFindReply.GetEntities(), nil
return processFindReply(x.ModelFindReply, dummySlice)
default:
return [][]byte{}, fmt.Errorf("ReadTransactionReply.Option has unexpected type %T", x)
return nil, fmt.Errorf("ReadTransactionReply.Option has unexpected type %T", x)
}
}

Expand Down
12 changes: 6 additions & 6 deletions api/client/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,25 @@ func (t *WriteTransaction) FindByID(entityID string, entity interface{}) error {
}

// Find finds entities by query
func (t *WriteTransaction) Find(query es.JSONQuery) ([][]byte, error) {
func (t *WriteTransaction) Find(query es.JSONQuery, dummySlice interface{}) (interface{}, error) {
queryBytes, err := json.Marshal(query)
if err != nil {
return [][]byte{}, err
return nil, err
}
innerReq := &pb.ModelFindRequest{QueryJSON: queryBytes}
option := &pb.WriteTransactionRequest_ModelFindRequest{ModelFindRequest: innerReq}
if err = t.client.Send(&pb.WriteTransactionRequest{Option: option}); err != nil {
return [][]byte{}, err
return nil, err
}
var resp *pb.WriteTransactionReply
if resp, err = t.client.Recv(); err != nil {
return [][]byte{}, err
return nil, err
}
switch x := resp.GetOption().(type) {
case *pb.WriteTransactionReply_ModelFindReply:
return x.ModelFindReply.GetEntities(), nil
return processFindReply(x.ModelFindReply, dummySlice)
default:
return [][]byte{}, fmt.Errorf("WriteTransactionReply.Option has unexpected type %T", x)
return nil, fmt.Errorf("WriteTransactionReply.Option has unexpected type %T", x)
}
}

Expand Down

0 comments on commit af2a2eb

Please sign in to comment.