fix(spanner): pointer type custom struct decoder (#12496) · googleapis/google-cloud-go@ac3cafb · GitHub | Latest TMZ Celebrity News & Gossip | Watch TMZ Live
Skip to content

Commit ac3cafb

Browse files
authored
fix(spanner): pointer type custom struct decoder (#12496)
1 parent 91d03e3 commit ac3cafb

File tree

2 files changed

+54
-7
lines changed

2 files changed

+54
-7
lines changed

spanner/row_test.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,6 +2279,7 @@ func TestSelectAll(t *testing.T) {
22792279
Col1 int64
22802280
COL2 float64
22812281
Col3 CustomType[string]
2282+
Col4 *CustomType[string]
22822283
}
22832284

22842285
type testStructWithTag struct {
@@ -2451,7 +2452,7 @@ func TestSelectAll(t *testing.T) {
24512452
},
24522453
},
24532454
{
2454-
name: "success: using destination with custom type with custom decoder with some null columns",
2455+
name: "success: using destination with custom type with custom decoder with some null columns and pointer decoder",
24552456
args: args{
24562457
destination: &[]*testStructWithCustom{},
24572458
mock: newMockIterator(
@@ -2460,32 +2461,35 @@ func TestSelectAll(t *testing.T) {
24602461
{Name: "Col1", Type: intType()},
24612462
{Name: "Col2", Type: floatType()},
24622463
{Name: "Col3", Type: stringType()},
2464+
{Name: "Col4", Type: stringType()},
24632465
},
2464-
[]*proto3.Value{intProto(3), floatProto(3.3), stringProto("value3")},
2466+
[]*proto3.Value{intProto(3), floatProto(3.3), stringProto("value3"), stringProto("test3")},
24652467
},
24662468
&Row{
24672469
[]*sppb.StructType_Field{
24682470
{Name: "Col1", Type: intType()},
24692471
{Name: "Col2", Type: floatType()},
24702472
{Name: "Col3", Type: stringType()},
2473+
{Name: "Col4", Type: stringType()},
24712474
},
2472-
[]*proto3.Value{intProto(1), floatProto(1.1), nullProto()},
2475+
[]*proto3.Value{intProto(1), floatProto(1.1), nullProto(), nullProto()},
24732476
},
24742477
&Row{
24752478
[]*sppb.StructType_Field{
24762479
{Name: "Col1", Type: intType()},
24772480
{Name: "Col2", Type: floatType()},
24782481
{Name: "Col3", Type: stringType()},
2482+
{Name: "Col4", Type: stringType()},
24792483
},
2480-
[]*proto3.Value{intProto(2), floatProto(2.2), stringProto("value2")},
2484+
[]*proto3.Value{intProto(2), floatProto(2.2), stringProto("value2"), stringProto("test2")},
24812485
},
24822486
iterator.Done,
24832487
),
24842488
},
24852489
want: &[]*testStructWithCustom{
2486-
{Col1: 3, COL2: 3.3, Col3: CustomType[string]{"value3"}},
2487-
{Col1: 1, COL2: 1.1, Col3: CustomType[string]{}},
2488-
{Col1: 2, COL2: 2.2, Col3: CustomType[string]{"value2"}},
2490+
{Col1: 3, COL2: 3.3, Col3: CustomType[string]{"value3"}, Col4: &CustomType[string]{"test3"}},
2491+
{Col1: 1, COL2: 1.1, Col3: CustomType[string]{}, Col4: nil},
2492+
{Col1: 2, COL2: 2.2, Col3: CustomType[string]{"value2"}, Col4: &CustomType[string]{"test2"}},
24892493
},
24902494
},
24912495
{

spanner/value.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,41 @@ func parseNullTime(v *proto3.Value, p *NullTime, code sppb.TypeCode, isNull bool
14161416
return nil
14171417
}
14181418

1419+
// tryDecodePointerToDecoder attempts to decode a **T where *T implements Decoder
1420+
// Returns (handled, error) - handled=true if this case was processed
1421+
func tryDecodePointerToDecoder(ptr interface{}, t *sppb.Type, v *proto3.Value, isNull bool) (bool, error) {
1422+
rv := reflect.ValueOf(ptr)
1423+
if rv.Kind() != reflect.Ptr || rv.Type().Elem().Kind() != reflect.Ptr {
1424+
return false, nil
1425+
}
1426+
1427+
elemType := rv.Type().Elem().Elem()
1428+
if !reflect.PointerTo(elemType).Implements(reflect.TypeOf((*Decoder)(nil)).Elem()) {
1429+
return false, nil
1430+
}
1431+
1432+
if isNull {
1433+
rv.Elem().Set(reflect.Zero(rv.Elem().Type()))
1434+
return true, nil
1435+
}
1436+
1437+
// Create a new instance of the underlying type
1438+
newInstance := reflect.New(elemType)
1439+
if decodedVal, ok := newInstance.Interface().(Decoder); ok {
1440+
x, err := getGenericValue(t, v)
1441+
if err != nil {
1442+
return true, err
1443+
}
1444+
if err := decodedVal.DecodeSpanner(x); err != nil {
1445+
return true, err
1446+
}
1447+
rv.Elem().Set(newInstance)
1448+
return true, nil
1449+
}
1450+
1451+
return false, nil
1452+
}
1453+
14191454
// decodeValue decodes a protobuf Value into a pointer to a Go value, as
14201455
// specified by sppb.Type.
14211456
func decodeValue(v *proto3.Value, t *sppb.Type, ptr interface{}, opts ...DecodeOptions) error {
@@ -2470,6 +2505,10 @@ func decodeValue(v *proto3.Value, t *sppb.Type, ptr interface{}, opts ...DecodeO
24702505
}
24712506
return decodedVal.DecodeSpanner(x)
24722507
}
2508+
// Check if the pointer is a pointer to a pointer, and if the underlying type implements Decoder
2509+
if handled, err := tryDecodePointerToDecoder(ptr, t, v, isNull); handled {
2510+
return err
2511+
}
24732512
if p == nil {
24742513
return errNilDst(p)
24752514
}
@@ -2721,6 +2760,10 @@ func decodeValue(v *proto3.Value, t *sppb.Type, ptr interface{}, opts ...DecodeO
27212760
}
27222761
return decodedVal.DecodeSpanner(x)
27232762
}
2763+
// Check if the pointer is a pointer to a pointer, and if the underlying type implements Decoder
2764+
if handled, err := tryDecodePointerToDecoder(ptr, t, v, isNull); handled {
2765+
return err
2766+
}
27242767

27252768
// Check if the pointer is a variant of a base type.
27262769
decodableType := getDecodableSpannerType(ptr, true)

0 commit comments

Comments
 (0)

TMZ Celebrity News – Breaking Stories, Videos & Gossip

Looking for the latest TMZ celebrity news? You've come to the right place. From shocking Hollywood scandals to exclusive videos, TMZ delivers it all in real time.

Whether it’s a red carpet slip-up, a viral paparazzi moment, or a legal drama involving your favorite stars, TMZ news is always first to break the story. Stay in the loop with daily updates, insider tips, and jaw-dropping photos.

🎥 Watch TMZ Live

TMZ Live brings you daily celebrity news and interviews straight from the TMZ newsroom. Don’t miss a beat—watch now and see what’s trending in Hollywood.