Skip to content

Commit

Permalink
fix(grpc): config generation for optional fields (#2042)
Browse files Browse the repository at this point in the history
  • Loading branch information
meskill authored May 31, 2024
1 parent 3363240 commit 0f27a09
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 11 deletions.
11 changes: 10 additions & 1 deletion src/core/generator/from_proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ impl Context {

let label = field.label().as_str_name().to_lowercase();
cfg_field.list = label.contains("repeated");
cfg_field.required = label.contains("required") || cfg_field.list;
// required only applicable for proto2
cfg_field.required = label.contains("required");

if let Some(type_name) = &field.type_name {
// check that current field is map.
Expand Down Expand Up @@ -396,4 +397,12 @@ mod test {
insta::assert_snapshot!(config);
Ok(())
}

#[test]
fn test_optional_fields() -> Result<()> {
let set = compile_protobuf(&[protobuf::OPTIONAL])?;
let config = from_proto(&[set], "Query")?.to_sdl();

Check failure on line 404 in src/core/generator/from_proto.rs

View workflow job for this annotation

GitHub Actions / Run Formatter and Lint Check

cannot find function `from_proto` in this scope

Check failure on line 404 in src/core/generator/from_proto.rs

View workflow job for this annotation

GitHub Actions / Micro Benchmarks

cannot find function `from_proto` in this scope

Check failure on line 404 in src/core/generator/from_proto.rs

View workflow job for this annotation

GitHub Actions / Micro Benchmarks

cannot find function `from_proto` in this scope
insta::assert_snapshot!(config);
Ok(())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ input greetings_a__b__HelloRequest @tag(id: "greetings_a.b.HelloRequest") {
}

input news__MultipleNewsId @tag(id: "news.MultipleNewsId") {
ids: [news__NewsId]!
ids: [news__NewsId]
}

input news__NewsId @tag(id: "news.NewsId") {
Expand Down Expand Up @@ -64,5 +64,5 @@ type news__News @tag(id: "news.News") {
}

type news__NewsList @tag(id: "news.NewsList") {
news: [news__News]!
news: [news__News]
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type News @tag(id: "News") {
}

type NewsList @tag(id: "NewsList") {
news: [News]!
news: [News]
}

type Query {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ schema @server @upstream {
}

input map__MapRequest @tag(id: "map.MapRequest") {
map: JSON!
map: JSON
}

type Query {
map__MapService__GetMap(mapRequest: map__MapRequest!): map__MapResponse! @grpc(body: "{{.args.mapRequest}}", method: "map.MapService.GetMap")
}

type map__MapResponse @tag(id: "map.MapResponse") {
map: JSON!
map: JSON
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ input google__protobuf__TimestampInput @tag(id: "google.protobuf.Timestamp") {
}

input movies__MovieInput @tag(id: "movies.Movie") {
cast: [String]!
cast: [String]
duration: google__protobuf__DurationInput
genre: movies__GenreInput
name: String
Expand Down Expand Up @@ -70,7 +70,7 @@ type google__protobuf__Timestamp @tag(id: "google.protobuf.Timestamp") {
}

type movies__Movie @tag(id: "movies.Movie") {
cast: [String]!
cast: [String]
duration: google__protobuf__Duration
genre: movies__Genre
name: String
Expand All @@ -80,5 +80,5 @@ type movies__Movie @tag(id: "movies.Movie") {
}

type movies__MoviesResult @tag(id: "movies.MoviesResult") {
result: [movies__Movie]!
result: [movies__Movie]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
source: src/core/generator/from_proto.rs
expression: config
---
schema @server @upstream {
query: Query
}

input type__Type @tag(id: "type.Type") {
id: Int
idOpt: Int
nested: type__Type__Nested
nestedOpt: type__Type__Nested
nestedRep: [type__Type__Nested]
num: [Float]
str: String
strOpt: String
}

input type__Type__Nested @tag(id: "type.Type.Nested") {
id: Int
idOpt: Int
num: [Float]
str: String
strOpt: String
}

enum type__Status {
FIRST
SECOND
UNSPECIFIED
}

type Query {
type__TypeService__Get(type: type__Type!): type__Type! @grpc(body: "{{.args.type}}", method: "type.TypeService.Get")
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ type person__Person @tag(id: "person.Person") {
email: String
id: Int!
name: String!
phone: [person__PhoneNumber]!
stringMap: JSON!
phone: [person__PhoneNumber]
stringMap: JSON
}

type person__PhoneNumber @tag(id: "person.PhoneNumber") {
Expand Down
33 changes: 33 additions & 0 deletions src/core/grpc/protobuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,4 +458,37 @@ pub mod tests {

Ok(())
}

#[tokio::test]
async fn optional_proto_file() -> Result<()> {
let grpc_method = GrpcMethod::try_from("type.TypeService.Get").unwrap();

let file = ProtobufSet::from_proto_file(get_proto_file(protobuf::OPTIONAL).await?)?;
let service = file.find_service(&grpc_method)?;
let operation = service.find_operation(&grpc_method)?;

let input = operation.convert_input(r#"{ }"#)?;

assert_eq!(input, b"\0\0\0\0\0");

let output = b"\0\0\0\0\0";

let parsed = operation.convert_output::<serde_json::Value>(output)?;

assert_eq!(
serde_json::to_value(parsed)?,
json!({"id": 0, "str": "", "num": [], "nestedRep": []})
);

let output = b"\0\0\0\0\x03\x92\x03\0";

let parsed = operation.convert_output::<serde_json::Value>(output)?;

assert_eq!(
serde_json::to_value(parsed)?,
json!({"id": 0, "str": "", "num": [], "nestedRep": [], "nested": {"id": 0, "str": "", "num": []}})
);

Ok(())
}
}
32 changes: 32 additions & 0 deletions tailcall-fixtures/fixtures/protobuf/optional.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
syntax = "proto3";

package type;

enum Status {
UNSPECIFIED = 0;
FIRST = 1;
SECOND = 2;
}

message Type {
message Nested {
int32 id = 1;
string str = 2;
optional int32 id_opt = 3;
optional string str_opt = 4;
repeated float num = 5;
}

int32 id = 1;
string str = 2;
optional int32 id_opt = 3;
optional string str_opt = 4;
repeated float num = 5;
Nested nested = 50;
optional Nested nested_opt = 51;
repeated Nested nested_rep = 52;
}

service TypeService {
rpc Get(Type) returns (Type) {}
}

1 comment on commit 0f27a09

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running 30s test @ http://localhost:8000/graphql

4 threads and 100 connections

Thread Stats Avg Stdev Max +/- Stdev
Latency 6.67ms 3.01ms 82.21ms 72.06%
Req/Sec 3.80k 192.59 4.34k 91.75%

453166 requests in 30.01s, 2.27GB read

Requests/sec: 15101.19

Transfer/sec: 77.51MB

Please sign in to comment.