Skip to content

Commit

Permalink
fix(datastore): Handle loading nil values (#8544)
Browse files Browse the repository at this point in the history
* fix(datastore): Handle loading nil values
  • Loading branch information
bhshkh committed Sep 18, 2023
1 parent 0c97c14 commit 25dbb9c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 4 deletions.
28 changes: 28 additions & 0 deletions datastore/integration_test.go
Expand Up @@ -342,6 +342,34 @@ func TestIntegration_ListValues(t *testing.T) {
}
}

func TestIntegration_PutGetUntypedNil(t *testing.T) {
ctx := context.Background()
client := newTestClient(ctx, t)
defer client.Close()

type X struct {
I interface{} `json:"i"`
}

putX := &X{
I: nil,
}
key, err := client.Put(ctx, IncompleteKey("X", nil), putX)
if err != nil {
t.Fatalf("client.Put got: %v, want: nil", err)
}

getX := &X{}
err = client.Get(ctx, key, getX)
if err != nil {
t.Fatalf("client.Get got: %v, want: nil", err)
}

if !reflect.DeepEqual(getX, putX) {
t.Fatalf("got: %v, want: %v", getX, putX)
}
}

func TestIntegration_GetMulti(t *testing.T) {
ctx := context.Background()
client := newTestClient(ctx, t)
Expand Down
14 changes: 10 additions & 4 deletions datastore/load.go
Expand Up @@ -302,11 +302,17 @@ func setVal(v reflect.Value, p Property) (s string) {
return fmt.Sprintf("%v is unsettable", v.Type())
}

rpValue := reflect.ValueOf(pValue)
if !rpValue.Type().AssignableTo(v.Type()) {
return fmt.Sprintf("%q is not assignable to %q", rpValue.Type(), v.Type())
// When retrieved property value is untyped nil, its type cannot be determined
// So, set v to zero value of its datatype
if pValue == nil {
v.Set(reflect.Zero(v.Type()))
} else {
rpValue := reflect.ValueOf(pValue)
if !rpValue.Type().AssignableTo(v.Type()) {
return fmt.Sprintf("%q is not assignable to %q", rpValue.Type(), v.Type())
}
v.Set(rpValue)
}
v.Set(rpValue)

case reflect.Ptr:
// v must be a pointer to either a Key, an Entity, or one of the supported basic types.
Expand Down
21 changes: 21 additions & 0 deletions datastore/load_test.go
Expand Up @@ -1290,6 +1290,27 @@ func TestLoadNull(t *testing.T) {
}
}

func TestLoadNilInterface(t *testing.T) {
type WithAny struct {
AnyField interface{}
}

withAny1 := &WithAny{}
err := loadEntityProto(withAny1, &pb.Entity{
Key: keyToProto(testKey0),
Properties: map[string]*pb.Value{
"AnyField": {ValueType: &pb.Value_NullValue{}},
},
})
if err != nil {
t.Fatalf("loadEntityProto got: %v, want: nil", err)
}

if withAny1.AnyField != nil {
t.Fatalf("got: %v, want: nil", withAny1.AnyField)
}
}

type KeyLoaderEnt struct {
A int
K *Key
Expand Down

0 comments on commit 25dbb9c

Please sign in to comment.