32
32
import com .google .cloud .spanner .spi .v1 .SpannerRpc ;
33
33
import com .google .cloud .spanner .v1 .stub .SpannerStubSettings ;
34
34
import com .google .common .annotations .VisibleForTesting ;
35
+ import com .google .common .base .Preconditions ;
35
36
import com .google .common .collect .AbstractIterator ;
36
37
import com .google .common .collect .ImmutableMap ;
37
38
import com .google .common .collect .Lists ;
38
39
import com .google .common .util .concurrent .Uninterruptibles ;
40
+ import com .google .protobuf .AbstractMessage ;
39
41
import com .google .protobuf .ByteString ;
42
+ import com .google .protobuf .InvalidProtocolBufferException ;
40
43
import com .google .protobuf .ListValue ;
44
+ import com .google .protobuf .ProtocolMessageEnum ;
41
45
import com .google .protobuf .Value .KindCase ;
42
46
import com .google .spanner .v1 .PartialResultSet ;
43
47
import com .google .spanner .v1 .ResultSetMetadata ;
65
69
import java .util .concurrent .Executor ;
66
70
import java .util .concurrent .LinkedBlockingQueue ;
67
71
import java .util .concurrent .TimeUnit ;
72
+ import java .util .function .Function ;
68
73
import java .util .logging .Level ;
69
74
import java .util .logging .Logger ;
70
75
import javax .annotation .Nullable ;
@@ -391,6 +396,14 @@ private Object writeReplace() {
391
396
case JSON :
392
397
builder .set (fieldName ).to (Value .json ((String ) value ));
393
398
break ;
399
+ case PROTO :
400
+ builder
401
+ .set (fieldName )
402
+ .to (Value .protoMessage ((ByteArray ) value , fieldType .getProtoTypeFqn ()));
403
+ break ;
404
+ case ENUM :
405
+ builder .set (fieldName ).to (Value .protoEnum ((Long ) value , fieldType .getProtoTypeFqn ()));
406
+ break ;
394
407
case PG_JSONB :
395
408
builder .set (fieldName ).to (Value .pgJsonb ((String ) value ));
396
409
break ;
@@ -410,6 +423,7 @@ private Object writeReplace() {
410
423
builder .set (fieldName ).toBoolArray ((Iterable <Boolean >) value );
411
424
break ;
412
425
case INT64 :
426
+ case ENUM :
413
427
builder .set (fieldName ).toInt64Array ((Iterable <Long >) value );
414
428
break ;
415
429
case FLOAT64 :
@@ -431,6 +445,7 @@ private Object writeReplace() {
431
445
builder .set (fieldName ).toPgJsonbArray ((Iterable <String >) value );
432
446
break ;
433
447
case BYTES :
448
+ case PROTO :
434
449
builder .set (fieldName ).toBytesArray ((Iterable <ByteArray >) value );
435
450
break ;
436
451
case TIMESTAMP :
@@ -496,6 +511,7 @@ private static Object decodeValue(Type fieldType, com.google.protobuf.Value prot
496
511
checkType (fieldType , proto , KindCase .BOOL_VALUE );
497
512
return proto .getBoolValue ();
498
513
case INT64 :
514
+ case ENUM :
499
515
checkType (fieldType , proto , KindCase .STRING_VALUE );
500
516
return Long .parseLong (proto .getStringValue ());
501
517
case FLOAT64 :
@@ -510,6 +526,7 @@ private static Object decodeValue(Type fieldType, com.google.protobuf.Value prot
510
526
checkType (fieldType , proto , KindCase .STRING_VALUE );
511
527
return proto .getStringValue ();
512
528
case BYTES :
529
+ case PROTO :
513
530
checkType (fieldType , proto , KindCase .STRING_VALUE );
514
531
return ByteArray .fromBase64 (proto .getStringValue ());
515
532
case TIMESTAMP :
@@ -547,7 +564,8 @@ private static Struct decodeStructValue(Type structType, ListValue structValue)
547
564
static Object decodeArrayValue (Type elementType , ListValue listValue ) {
548
565
switch (elementType .getCode ()) {
549
566
case INT64 :
550
- // For int64/float64 types, use custom containers. These avoid wrapper object
567
+ case ENUM :
568
+ // For int64/float64/enum types, use custom containers. These avoid wrapper object
551
569
// creation for non-null arrays.
552
570
return new Int64Array (listValue );
553
571
case FLOAT64 :
@@ -562,6 +580,7 @@ static Object decodeArrayValue(Type elementType, ListValue listValue) {
562
580
case TIMESTAMP :
563
581
case DATE :
564
582
case STRUCT :
583
+ case PROTO :
565
584
return Lists .transform (
566
585
listValue .getValuesList (), input -> decodeValue (elementType , input ));
567
586
default :
@@ -597,6 +616,30 @@ public boolean isNull(int columnIndex) {
597
616
return rowData .get (columnIndex ) == null ;
598
617
}
599
618
619
+ @ Override
620
+ protected <T extends AbstractMessage > T getProtoMessageInternal (int columnIndex , T message ) {
621
+ Preconditions .checkNotNull (
622
+ message ,
623
+ "Proto message may not be null. Use MyProtoClass.getDefaultInstance() as a parameter value." );
624
+ try {
625
+ return (T )
626
+ message
627
+ .toBuilder ()
628
+ .mergeFrom (((ByteArray ) rowData .get (columnIndex )).toByteArray ())
629
+ .build ();
630
+ } catch (InvalidProtocolBufferException e ) {
631
+ throw SpannerExceptionFactory .asSpannerException (e );
632
+ }
633
+ }
634
+
635
+ @ Override
636
+ protected <T extends ProtocolMessageEnum > T getProtoEnumInternal (
637
+ int columnIndex , Function <Integer , ProtocolMessageEnum > method ) {
638
+ Preconditions .checkNotNull (
639
+ method , "Method may not be null. Use 'MyProtoEnum::forNumber' as a parameter value." );
640
+ return (T ) method .apply ((int ) getLongInternal (columnIndex ));
641
+ }
642
+
600
643
@ Override
601
644
protected boolean getBooleanInternal (int columnIndex ) {
602
645
return (Boolean ) rowData .get (columnIndex );
@@ -658,6 +701,8 @@ protected Value getValueInternal(int columnIndex) {
658
701
return Value .bool (isNull ? null : getBooleanInternal (columnIndex ));
659
702
case INT64 :
660
703
return Value .int64 (isNull ? null : getLongInternal (columnIndex ));
704
+ case ENUM :
705
+ return Value .protoEnum (getLongInternal (columnIndex ), columnType .getProtoTypeFqn ());
661
706
case NUMERIC :
662
707
return Value .numeric (isNull ? null : getBigDecimalInternal (columnIndex ));
663
708
case PG_NUMERIC :
@@ -672,6 +717,8 @@ protected Value getValueInternal(int columnIndex) {
672
717
return Value .pgJsonb (isNull ? null : getPgJsonbInternal (columnIndex ));
673
718
case BYTES :
674
719
return Value .bytes (isNull ? null : getBytesInternal (columnIndex ));
720
+ case PROTO :
721
+ return Value .protoMessage (getBytesInternal (columnIndex ), columnType .getProtoTypeFqn ());
675
722
case TIMESTAMP :
676
723
return Value .timestamp (isNull ? null : getTimestampInternal (columnIndex ));
677
724
case DATE :
@@ -699,6 +746,12 @@ protected Value getValueInternal(int columnIndex) {
699
746
return Value .pgJsonbArray (isNull ? null : getPgJsonbListInternal (columnIndex ));
700
747
case BYTES :
701
748
return Value .bytesArray (isNull ? null : getBytesListInternal (columnIndex ));
749
+ case PROTO :
750
+ return Value .protoMessageArray (
751
+ isNull ? null : getBytesListInternal (columnIndex ), elementType .getProtoTypeFqn ());
752
+ case ENUM :
753
+ return Value .protoEnumArray (
754
+ isNull ? null : getLongListInternal (columnIndex ), elementType .getProtoTypeFqn ());
702
755
case TIMESTAMP :
703
756
return Value .timestampArray (isNull ? null : getTimestampListInternal (columnIndex ));
704
757
case DATE :
@@ -778,6 +831,52 @@ protected List<String> getJsonListInternal(int columnIndex) {
778
831
return Collections .unmodifiableList ((List <String >) rowData .get (columnIndex ));
779
832
}
780
833
834
+ @ Override
835
+ @ SuppressWarnings ("unchecked" ) // We know ARRAY<PROTO> produces a List<ByteArray>.
836
+ protected <T extends AbstractMessage > List <T > getProtoMessageListInternal (
837
+ int columnIndex , T message ) {
838
+ Preconditions .checkNotNull (
839
+ message ,
840
+ "Proto message may not be null. Use MyProtoClass.getDefaultInstance() as a parameter value." );
841
+
842
+ List <ByteArray > bytesArray = (List <ByteArray >) rowData .get (columnIndex );
843
+
844
+ try {
845
+ List <T > protoMessagesList = new ArrayList <>(bytesArray .size ());
846
+ for (ByteArray protoMessageBytes : bytesArray ) {
847
+ if (protoMessageBytes == null ) {
848
+ protoMessagesList .add (null );
849
+ } else {
850
+ protoMessagesList .add (
851
+ (T ) message .toBuilder ().mergeFrom (protoMessageBytes .toByteArray ()).build ());
852
+ }
853
+ }
854
+ return protoMessagesList ;
855
+ } catch (InvalidProtocolBufferException e ) {
856
+ throw SpannerExceptionFactory .asSpannerException (e );
857
+ }
858
+ }
859
+
860
+ @ Override
861
+ @ SuppressWarnings ("unchecked" ) // We know ARRAY<ENUM> produces a List<Long>.
862
+ protected <T extends ProtocolMessageEnum > List <T > getProtoEnumListInternal (
863
+ int columnIndex , Function <Integer , ProtocolMessageEnum > method ) {
864
+ Preconditions .checkNotNull (
865
+ method , "Method may not be null. Use 'MyProtoEnum::forNumber' as a parameter value." );
866
+
867
+ List <Long > enumIntArray = (List <Long >) rowData .get (columnIndex );
868
+ List <T > protoEnumList = new ArrayList <>(enumIntArray .size ());
869
+ for (Long enumIntValue : enumIntArray ) {
870
+ if (enumIntValue == null ) {
871
+ protoEnumList .add (null );
872
+ } else {
873
+ protoEnumList .add ((T ) method .apply (enumIntValue .intValue ()));
874
+ }
875
+ }
876
+
877
+ return protoEnumList ;
878
+ }
879
+
781
880
@ Override
782
881
@ SuppressWarnings ("unchecked" ) // We know ARRAY<JSONB> produces a List<String>.
783
882
protected List <String > getPgJsonbListInternal (int columnIndex ) {
@@ -1310,6 +1409,17 @@ protected String getStringInternal(int columnIndex) {
1310
1409
return currRow ().getStringInternal (columnIndex );
1311
1410
}
1312
1411
1412
+ @ Override
1413
+ protected <T extends AbstractMessage > T getProtoMessageInternal (int columnIndex , T message ) {
1414
+ return currRow ().getProtoMessageInternal (columnIndex , message );
1415
+ }
1416
+
1417
+ @ Override
1418
+ protected <T extends ProtocolMessageEnum > T getProtoEnumInternal (
1419
+ int columnIndex , Function <Integer , ProtocolMessageEnum > method ) {
1420
+ return currRow ().getProtoEnumInternal (columnIndex , method );
1421
+ }
1422
+
1313
1423
@ Override
1314
1424
protected String getJsonInternal (int columnIndex ) {
1315
1425
return currRow ().getJsonInternal (columnIndex );
@@ -1395,6 +1505,18 @@ protected List<ByteArray> getBytesListInternal(int columnIndex) {
1395
1505
return currRow ().getBytesListInternal (columnIndex );
1396
1506
}
1397
1507
1508
+ @ Override
1509
+ protected <T extends AbstractMessage > List <T > getProtoMessageListInternal (
1510
+ int columnIndex , T message ) {
1511
+ return currRow ().getProtoMessageListInternal (columnIndex , message );
1512
+ }
1513
+
1514
+ @ Override
1515
+ protected <T extends ProtocolMessageEnum > List <T > getProtoEnumListInternal (
1516
+ int columnIndex , Function <Integer , ProtocolMessageEnum > method ) {
1517
+ return currRow ().getProtoEnumListInternal (columnIndex , method );
1518
+ }
1519
+
1398
1520
@ Override
1399
1521
protected List <Timestamp > getTimestampListInternal (int columnIndex ) {
1400
1522
return currRow ().getTimestampListInternal (columnIndex );
0 commit comments