Skip to content

Commit

Permalink
Merge pull request #191 from mercari/support-null-value
Browse files Browse the repository at this point in the history
Support null value
  • Loading branch information
goccy authored Jun 5, 2024
2 parents a85a173 + 836f108 commit 5d164ce
Show file tree
Hide file tree
Showing 17 changed files with 1,539 additions and 1,356 deletions.
744 changes: 397 additions & 347 deletions _examples/02_simple/federation/federation.pb.go

Large diffs are not rendered by default.

171 changes: 128 additions & 43 deletions _examples/02_simple/federation/federation_grpc_federation.pb.go

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion _examples/02_simple/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,10 @@ func TestFederation(t *testing.T) {
BoolWrapperValue: &wrapperspb.BoolValue{
Value: true,
},
Hello: "hello\nworld",
Hello: "hello\nworld",
NullTimestamp: nil,
NullTimestamp2: nil,
NullTimestamp3: nil,
}, cmpopts.IgnoreUnexported(
federation.GetPostResponse{},
federation.Post{},
Expand Down
5 changes: 5 additions & 0 deletions _examples/02_simple/proto/federation/federation.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package federation;

import "google/protobuf/any.proto";
import "google/protobuf/wrappers.proto";
import "google/protobuf/timestamp.proto";
import "grpc/federation/federation.proto";
import "post/post.proto";
import "user/user.proto";
Expand Down Expand Up @@ -38,6 +39,7 @@ message GetPostResponse {
def { name: "sorted_values" by: "[4, 1, 3, 2].sortAsc(v, v)" }
def { name: "sorted_items" by: "[user.Item{location:user.Item.Location{addr1:'a'}}, user.Item{location:user.Item.Location{addr1:'b'}}].sortDesc(v, v.location.addr1)" }
def { name: "map_value" by : "{1: 'a', 2: 'b', 3: 'c'}" }
def { name: "null_value" by: "null" }
};
Post post = 1 [(grpc.federation.field).by = "post"];
string str = 2 [(grpc.federation.field).string = "hello"];
Expand Down Expand Up @@ -66,6 +68,9 @@ message GetPostResponse {
google.protobuf.StringValue string_wrapper_value = 25 [(grpc.federation.field).by = "google.protobuf.StringValue{value: 'hello'}"];
google.protobuf.BytesValue bytes_wrapper_value = 26 [(grpc.federation.field).by = "google.protobuf.BytesValue{value: bytes('world')}"];
string hello = 27 [(grpc.federation.field).by = "'hello\\nworld'"];
google.protobuf.Timestamp null_timestamp = 28 [(grpc.federation.field).by = "null"];
google.protobuf.Timestamp null_timestamp2 = 29 [(grpc.federation.field).by = "null_value"];
google.protobuf.Timestamp null_timestamp3 = 30 [(grpc.federation.field).by = "true ? null : google.protobuf.Timestamp{}"];
}

message A {
Expand Down
976 changes: 493 additions & 483 deletions _examples/17_error_handler/grpc/federation/generator.pb.go

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion generator/code_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@ func toCELTypeDeclare(t *resolver.Type) string {
}

func (f *File) toTypeText(t *resolver.Type) string {
if t == nil {
if t == nil || t.IsNull {
return "any"
}
if t.OneofField != nil {
Expand Down Expand Up @@ -2829,6 +2829,9 @@ func toCELNativeType(t *resolver.Type) string {
cloned.Repeated = false
return fmt.Sprintf("grpcfed.CELListType(%s)", toCELNativeType(cloned))
}
if t.IsNull {
return "grpcfed.CELNullType"
}
switch t.Kind {
case types.Double, types.Float:
return "grpcfed.CELDoubleType"
Expand Down
1 change: 1 addition & 0 deletions grpc/federation/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ var (
CELObjectType = cel.ObjectType
CELListType = cel.ListType
CELMapType = cel.MapType
CELNullType = cel.NullType
NewCELListType = types.NewListType
NewCELObjectType = types.NewObjectType
)
Expand Down
6 changes: 6 additions & 0 deletions grpc/federation/cel.go
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,12 @@ func EvalCEL(ctx context.Context, req *EvalCELRequest) (any, error) {
}
out = opt.GetValue()
}
if _, ok := out.(celtypes.Null); ok {
if req.OutType == nil {
return nil, nil
}
return reflect.Zero(req.OutType).Interface(), nil
}
if req.OutType != nil {
return out.ConvertToNative(req.OutType)
}
Expand Down
1 change: 1 addition & 0 deletions grpc/federation/generator/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,7 @@ func (d *decoder) toType(t *plugin.Type) (*resolver.Type, error) {
return &resolver.Type{
Kind: d.toTypeKind(t.GetKind()),
Repeated: t.GetRepeated(),
IsNull: t.GetIsNull(),
Message: msg,
Enum: enum,
OneofField: oneofField,
Expand Down
1 change: 1 addition & 0 deletions grpc/federation/generator/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ func (e *encoder) toType(t *resolver.Type) *plugin.Type {
ret := &plugin.Type{
Kind: e.toTypeKind(t.Kind),
Repeated: t.Repeated,
IsNull: t.IsNull,
}
switch {
case t.Message != nil:
Expand Down
949 changes: 479 additions & 470 deletions grpc/federation/generator/plugin/generator.pb.go

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions proto/grpc/federation/generator.proto
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,11 @@ enum TypeKind {
message Type {
TypeKind kind = 1;
bool repeated = 2;
bool is_null = 3;
oneof ref {
string message_id = 3;
string enum_id = 4;
string oneof_field_id = 5;
string message_id = 4;
string enum_id = 5;
string oneof_field_id = 6;
}
}

Expand Down
5 changes: 5 additions & 0 deletions resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3390,6 +3390,8 @@ func (r *Resolver) fromCELType(ctx *context, typ *cel.Type) (*Type, error) {
return &Type{Kind: types.Enum, Enum: enum}, nil
}
return r.fromCELType(ctx, param)
case celtypes.NullTypeKind:
return NullType, nil
}

return nil, fmt.Errorf("unknown type %s is required", typ.TypeName())
Expand Down Expand Up @@ -3932,6 +3934,9 @@ func isDifferentType(from, to *Type) bool {
if from.IsNumber() && to.IsNumber() {
return false
}
if from.IsNull && (to.Repeated || to.Kind == types.Message || to.Kind == types.Bytes) {
return false
}
return from.Kind != to.Kind
}

Expand Down
3 changes: 3 additions & 0 deletions resolver/type_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ func typeConversionDecls(fromType, toType *Type, convertedFQDNMap map[string]str
if fromType == nil || toType == nil {
return nil
}
if fromType.IsNull || toType.IsNull {
return nil
}
if !requiredTypeConversion(fromType, toType) {
return nil
}
Expand Down
3 changes: 3 additions & 0 deletions resolver/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ type MessageDependencyGraphNode struct {

type Type struct {
Kind types.Kind
IsNull bool
Repeated bool
Message *Message
Enum *Enum
Expand All @@ -358,6 +359,7 @@ func (t *Type) Clone() *Type {
return &Type{
Kind: t.Kind,
Repeated: t.Repeated,
IsNull: t.IsNull,
Message: t.Message,
Enum: t.Enum,
OneofField: t.OneofField,
Expand Down Expand Up @@ -484,6 +486,7 @@ var (
BytesType = &Type{Kind: types.Bytes}
EnumType = &Type{Kind: types.Enum}
EnvType = &Type{Kind: types.String}
NullType = &Type{IsNull: true}
DoubleRepeatedType = &Type{Kind: types.Double, Repeated: true}
FloatRepeatedType = &Type{Kind: types.Float, Repeated: true}
Int32RepeatedType = &Type{Kind: types.Int32, Repeated: true}
Expand Down
2 changes: 1 addition & 1 deletion types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (k Kind) ToString() string {
case Sint64:
return "sint64"
}
return ""
return "null"
}

func ToKind(s string) Kind {
Expand Down
11 changes: 4 additions & 7 deletions validator/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,6 @@ testdata/invalid_message_name.proto:53:17: "post.Invalid" message does not exist
testdata/invalid_message_name.proto:54:17: undefined message specified
54: name: "post.Invalid"
^
testdata/invalid_message_name.proto:63:47: unknown type null_type is required
63: User user = 4 [(grpc.federation.field).by = "user1"];
^
`},
{file: "invalid_nested_message_name.proto", expected: `
testdata/invalid_nested_message_name.proto:36:31: "federation.Invalid1" message does not exist
Expand All @@ -442,12 +439,12 @@ testdata/invalid_nested_message_name.proto:42:33: "federation.Invalid2" message
testdata/invalid_nested_message_name.proto:42:41: undefined message specified
42: { name: "c1" message: { name: "Invalid2" } }
^
testdata/invalid_nested_message_name.proto:45:51: unknown type null_type is required
testdata/invalid_nested_message_name.proto:45:7: cannot convert type automatically: field type is "string" but specified value type is "null"
45: string c1 = 1 [(grpc.federation.field).by = "c1"];
^
testdata/invalid_nested_message_name.proto:47:49: unknown type null_type is required
^
testdata/invalid_nested_message_name.proto:47:5: cannot convert type automatically: field type is "string" but specified value type is "null"
47: string b1 = 1 [(grpc.federation.field).by = "b1"];
^
^
`},
{file: "invalid_message_argument.proto", expected: `
testdata/invalid_message_argument.proto:51:19: ERROR: <input>:1:11: type 'string' does not support field selection
Expand Down

0 comments on commit 5d164ce

Please sign in to comment.