Skip to content

Commit 3ffbbbe

Browse files
feat(spanner): add support for Proto Columns (#9315)
* feat(spanner): add support for Proto Columns (#6886) * feat(spanner): Adding support for Proto Message and Proto Enum * feat(spanner): Add license header to new files * code refactoring and additional checks * nit: code changes * go.mod update to prevent failing builds * go.mod update to prevent failing builds * go.mod and build_samples.sh update to prevent failing builds * revert back grpc version * revert back changes * Using standard Singers example, refactoring redundant code * code and proto refactoring * Add proto_type_fqn for Proto Message and Proto Enum * code refactoring * go mod tidy: go.mod and go.sum version updates * add changes to support compatibility between Int64 and Enum & compatibility between Bytes and Proto * Revert "go mod tidy: go.mod and go.sum version updates" This reverts commit 484b00c. * add Integration Tests for Proto Message, Proto Enum, compatibility tests * code refactoring * code refactoring * add unit tests for nil proto types * Add error when nil proto message or nil enum is passed * feat(spanner): add support for handling null value in Proto columns (#6954) * feat(spanner): add support for handling null value in Proto columns * code refactor: get protoTypeFqn from user defined nil types * code refactoring * code refactoring * code refactoring * code refactoring * Add tests for MarshalJSON and UnmarshalJSON methods * refactoring test file * code refactoring * feat(spanner): add support for Array of Proto columns (#7014) * feat(spanner): add support for array of proto columns * refactoring comments and added negative test cases while reading array of protos * change decoding logic of handling array of proto columns * feat(spanner): add support for handling null values in array of proto columns (#7042) * feat(spanner): add support for handling null values in Array of Proto Columns * add comments for code readability * nit: change in error message * feat(spanner): Modify configuration for integration test and add license header (#7059) * feat(spanner): update go-genproto dependency (#7066) * feat(spanner): support for enum columns as keys, index and integration tests (#7091) * feat(spanner): support for proto columns as primary key and tests for parameterized queries, primary key and indexes * feat(spanner): close read-only transaction to prevent session leak * feat(spanner): update table schema to have GPK on proto field * feat(spanner): add proto changes to support proto columns feature * feat(spanner): remove gen-proto dep overwrite for proto column support * feat(spanner): remove gen-proto dep overwrite from kokoro build * feat(spanner): reset array of proto, enum when null from database (#7176) * feat(spanner): reset array of proto, enum when null from database * feat(spanner): fix license header to fix vet.sh build * feat(spanner): fix proto generated file to fix vet.sh build * feat(spanner): organize imports to fix vet.sh build * feat(spanner): golint changes to fix vet.sh build * feat(spanner): add support for Proto column DDL (#7292) * feat(spanner): add proto changes for Proto Columns DDL support * feat(spanner): add Proto descriptor file and integration tests for Proto DDL feature * feat(spanner): skip pg tests and code refactoring for proto ddl * feat(spanner): rename NewDatabaseAdminRESTClient to NewDatabaseAdminClient due to visibility label issue fix * feat(spanner): remove hardcoded cloud-devel host * feat(spanner): remove hardcoded project id * feat(spanner): revert autogenerated code * feat(spanner): just to validate integration tests running * feat(spanner): change copyright year * feat(spanner): set project id for integration tests * feat(spanner): use jsoniter instead of json for marshal and unmarshal * feat(spanner): revert presubmit.sh changes * chore(spanner): run integration tests in presubmit * chore(spanner): revert presubmit.sh changes * feat(spanner): fix json --------- Co-authored-by: rahul2393 <[email protected]>
1 parent aaf7fa2 commit 3ffbbbe

File tree

9 files changed

+1549
-25
lines changed

9 files changed

+1549
-25
lines changed

spanner/integration_test.go

+567
Large diffs are not rendered by default.

spanner/key.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"cloud.google.com/go/civil"
2626
sppb "cloud.google.com/go/spanner/apiv1/spannerpb"
2727
"google.golang.org/grpc/codes"
28+
"google.golang.org/protobuf/reflect/protoreflect"
2829
proto3 "google.golang.org/protobuf/types/known/structpb"
2930
)
3031

@@ -58,6 +59,7 @@ import (
5859
// - string and NullString are mapped to Cloud Spanner's STRING type.
5960
// - time.Time and NullTime are mapped to Cloud Spanner's TIMESTAMP type.
6061
// - civil.Date and NullDate are mapped to Cloud Spanner's DATE type.
62+
// - protoreflect.Enum and NullProtoEnum are mapped to Cloud Spanner's ENUM type.
6163
type Key []interface{}
6264

6365
// errInvdKeyPartType returns error for unsupported key part type.
@@ -83,7 +85,7 @@ func keyPartValue(part interface{}) (pb *proto3.Value, err error) {
8385
pb, _, err = encodeValue(int64(v))
8486
case uint32:
8587
pb, _, err = encodeValue(int64(v))
86-
case int64, float64, float32, NullInt64, NullFloat64, NullFloat32, bool, NullBool, []byte, string, NullString, time.Time, civil.Date, NullTime, NullDate, big.Rat, NullNumeric:
88+
case int64, float64, float32, NullInt64, NullFloat64, NullFloat32, bool, NullBool, []byte, string, NullString, time.Time, civil.Date, NullTime, NullDate, big.Rat, NullNumeric, protoreflect.Enum, NullProtoEnum:
8789
pb, _, err = encodeValue(v)
8890
case Encoder:
8991
part, err = v.EncodeSpanner()
@@ -138,7 +140,7 @@ func (key Key) String() string {
138140

139141
func (key Key) elemString(b *bytes.Buffer, part interface{}) {
140142
switch v := part.(type) {
141-
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, float32, float64, bool:
143+
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, float32, float64, bool, protoreflect.Enum:
142144
// Use %v to print numeric types and bool.
143145
fmt.Fprintf(b, "%v", v)
144146
case string:
@@ -149,7 +151,7 @@ func (key Key) elemString(b *bytes.Buffer, part interface{}) {
149151
} else {
150152
fmt.Fprint(b, nullString)
151153
}
152-
case NullInt64, NullFloat64, NullBool, NullNumeric:
154+
case NullInt64, NullFloat64, NullBool, NullNumeric, NullProtoEnum:
153155
// The above types implement fmt.Stringer.
154156
fmt.Fprintf(b, "%s", v)
155157
case NullString, NullDate, NullTime:

spanner/key_test.go

+11
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"cloud.google.com/go/civil"
2626
sppb "cloud.google.com/go/spanner/apiv1/spannerpb"
27+
pb "cloud.google.com/go/spanner/testdata/protos"
2728
proto3 "google.golang.org/protobuf/types/known/structpb"
2829
)
2930

@@ -244,6 +245,16 @@ func TestKey(t *testing.T) {
244245
wantProto: nil,
245246
wantStr: `(error)`,
246247
},
248+
{
249+
k: Key{pb.Genre_ROCK},
250+
wantProto: listValueProto(stringProto("3")),
251+
wantStr: "(ROCK)",
252+
},
253+
{
254+
k: Key{NullProtoEnum{pb.Genre_FOLK, true}},
255+
wantProto: listValueProto(stringProto("2")),
256+
wantStr: "(FOLK)",
257+
},
247258
} {
248259
if got := test.k.String(); got != test.wantStr {
249260
t.Errorf("%v.String() = %v, want %v", test.k, got, test.wantStr)

spanner/protoutils.go

+19
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424

2525
"cloud.google.com/go/civil"
2626
sppb "cloud.google.com/go/spanner/apiv1/spannerpb"
27+
"google.golang.org/protobuf/proto"
28+
"google.golang.org/protobuf/reflect/protoreflect"
2729
proto3 "google.golang.org/protobuf/types/known/structpb"
2830
)
2931

@@ -144,3 +146,20 @@ func structType(fields ...*sppb.StructType_Field) *sppb.Type {
144146
func nullProto() *proto3.Value {
145147
return &proto3.Value{Kind: &proto3.Value_NullValue{NullValue: proto3.NullValue_NULL_VALUE}}
146148
}
149+
150+
func protoMessageType(fqn string) *sppb.Type {
151+
return &sppb.Type{Code: sppb.TypeCode_PROTO, ProtoTypeFqn: fqn}
152+
}
153+
154+
func protoEnumType(fqn string) *sppb.Type {
155+
return &sppb.Type{Code: sppb.TypeCode_ENUM, ProtoTypeFqn: fqn}
156+
}
157+
158+
func protoMessageProto(m proto.Message) *proto3.Value {
159+
var b, _ = proto.Marshal(m)
160+
return &proto3.Value{Kind: &proto3.Value_StringValue{StringValue: base64.StdEncoding.EncodeToString(b)}}
161+
}
162+
163+
func protoEnumProto(e protoreflect.Enum) *proto3.Value {
164+
return &proto3.Value{Kind: &proto3.Value_StringValue{StringValue: strconv.FormatInt(int64(e.Number()), 10)}}
165+
}
251 Bytes
Binary file not shown.

spanner/testdata/protos/singer.pb.go

+258
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

spanner/testdata/protos/singer.proto

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
Copyright 2024 Google LLC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
syntax = "proto2";
18+
19+
package spanner.examples.music;
20+
option go_package = "./protos";
21+
22+
message SingerInfo {
23+
optional int64 singer_id = 1;
24+
optional string birth_date = 2;
25+
optional string nationality = 3;
26+
optional Genre genre = 4;
27+
}
28+
29+
enum Genre {
30+
POP = 0;
31+
JAZZ = 1;
32+
FOLK = 2;
33+
ROCK = 3;
34+
}

0 commit comments

Comments
 (0)