Skip to content

Commit

Permalink
Merge branch 'main' into feat/jq-template-hybrid
Browse files Browse the repository at this point in the history
  • Loading branch information
karatakis authored Dec 5, 2024
2 parents 9cb72ee + 23223b8 commit c8087c1
Show file tree
Hide file tree
Showing 14 changed files with 448 additions and 380 deletions.
7 changes: 5 additions & 2 deletions src/cli/generator/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ pub enum Source<Status = UnResolved> {
Proto {
src: Location<Status>,
url: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "connectRPC")]
connect_rpc: Option<bool>,
},
Config {
src: Location<Status>,
Expand Down Expand Up @@ -217,9 +220,9 @@ impl Source<UnResolved> {
is_mutation,
})
}
Source::Proto { src, url } => {
Source::Proto { src, url, connect_rpc } => {
let resolved_path = src.into_resolved(parent_dir);
Ok(Source::Proto { src: resolved_path, url })
Ok(Source::Proto { src: resolved_path, url, connect_rpc })
}
Source::Config { src } => {
let resolved_path = src.into_resolved(parent_dir);
Expand Down
4 changes: 2 additions & 2 deletions src/cli/generator/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,13 @@ impl Generator {
headers: headers.into_btree_map(),
});
}
Source::Proto { src, url } => {
Source::Proto { src, url, connect_rpc } => {
let path = src.0;
let mut metadata = proto_reader.read(&path).await?;
if let Some(relative_path_to_proto) = to_relative_path(output_dir, &path) {
metadata.path = relative_path_to_proto;
}
input_samples.push(Input::Proto { metadata, url });
input_samples.push(Input::Proto { metadata, url, connect_rpc });
}
Source::Config { src } => {
let path = src.0;
Expand Down
1 change: 1 addition & 0 deletions src/core/config/transformer/ambiguous_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ mod tests {
.inputs(vec![Input::Proto {
metadata: ProtoMetadata { descriptor_set: set, path: news_proto.to_string() },
url,
connect_rpc: None,
}])
.generate(false)?;

Expand Down
7 changes: 6 additions & 1 deletion src/core/config/transformer/flatten_single_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@ impl Transform for FlattenSingleField {
fn transform(&self, mut config: Self::Value) -> Valid<Self::Value, Self::Error> {
let origin_config = config.clone();

for ty in config.types.values_mut() {
let input_types = config.input_types();

for (ty_name, ty) in config.types.iter_mut() {
if input_types.contains(ty_name) {
continue;
}
for (field_name, field) in ty.fields.iter_mut() {
let mut visited_types = HashSet::<String>::new();
if let Some(path) = get_single_field_path(
Expand Down
2 changes: 1 addition & 1 deletion src/core/config/transformer/preset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl Preset {
Self {
merge_type: 0.0,
tree_shake: false,
infer_type_names: false,
infer_type_names: true,
unwrap_single_field_types: true,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ schema @server @upstream {
query: Query
}

type Bar {
input Bar {
a: Int
}

input Input {
a: Bar
}

type Connection {
user: User
}
Expand All @@ -28,6 +32,7 @@ type NotSingleMiddle {
}

type Query @addField(name: "foo", path: ["foo", "bar", "a"]) {
a(input: Input!): Empty
foo: Foo @omit
not_single: NotSingle
not_single_middle: NotSingleMiddle
Expand Down
15 changes: 12 additions & 3 deletions src/core/generator/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use tailcall_valid::Validator;
use url::Url;

use super::from_proto::from_proto;
use super::proto::connect_rpc::ConnectRPC;
use super::{FromJsonGenerator, NameGenerator, RequestSample, PREFIX};
use crate::core::config::{self, Config, ConfigModule, Link, LinkType};
use crate::core::http::Method;
Expand Down Expand Up @@ -42,6 +43,7 @@ pub enum Input {
Proto {
url: String,
metadata: ProtoMetadata,
connect_rpc: Option<bool>,
},
Config {
schema: String,
Expand Down Expand Up @@ -133,9 +135,14 @@ impl Generator {
config = config
.merge_right(self.generate_from_json(&type_name_generator, &[req_sample])?);
}
Input::Proto { metadata, url } => {
config =
config.merge_right(self.generate_from_proto(metadata, &self.query, url)?);
Input::Proto { metadata, url, connect_rpc } => {
let proto_config = self.generate_from_proto(metadata, &self.query, url)?;
let proto_config = if connect_rpc == &Some(true) {
ConnectRPC.transform(proto_config).to_result()?
} else {
proto_config
};
config = config.merge_right(proto_config);
}
}
}
Expand Down Expand Up @@ -264,6 +271,7 @@ pub mod test {
path: "../../../tailcall-fixtures/fixtures/protobuf/news.proto".to_string(),
},
url: "http://localhost:50051".to_string(),
connect_rpc: None,
}])
.generate(false)?;

Expand Down Expand Up @@ -317,6 +325,7 @@ pub mod test {
path: "../../../tailcall-fixtures/fixtures/protobuf/news.proto".to_string(),
},
url: "http://localhost:50051".to_string(),
connect_rpc: None,
};

// Config input
Expand Down
175 changes: 175 additions & 0 deletions src/core/generator/proto/connect_rpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use tailcall_valid::Valid;

use crate::core::config::{Config, Grpc, Http, Resolver, ResolverSet};
use crate::core::Transform;

pub struct ConnectRPC;

impl Transform for ConnectRPC {
type Value = Config;
type Error = String;

fn transform(&self, mut config: Self::Value) -> Valid<Self::Value, Self::Error> {
for type_ in config.types.values_mut() {
for field_ in type_.fields.values_mut() {
let new_resolvers = field_
.resolvers
.0
.iter()
.map(|resolver| match resolver {
Resolver::Grpc(grpc) => Resolver::Http(Http::from(grpc.clone())),
other => other.clone(),
})
.collect();

field_.resolvers = ResolverSet(new_resolvers);
}
}

Valid::succeed(config)
}
}

impl From<Grpc> for Http {
fn from(grpc: Grpc) -> Self {
let url = grpc.url;
let body = grpc.body.or_else(|| {
// if body isn't present while transforming the resolver, we need to provide an
// empty object.
Some(serde_json::Value::Object(serde_json::Map::new()))
});

// remove the last
// method: package.service.method
// remove the method from the end.
let parts = grpc.method.split(".").collect::<Vec<_>>();
let method = parts[..parts.len() - 1].join(".").to_string();
let endpoint = parts[parts.len() - 1].to_string();

let new_url = format!("{}/{}/{}", url, method, endpoint);
let headers = grpc.headers;
let batch_key = grpc.batch_key;
let dedupe = grpc.dedupe;
let select = grpc.select;
let on_response_body = grpc.on_response_body;

Self {
url: new_url,
body: body.map(|b| b.to_string()),
method: crate::core::http::Method::POST,
headers,
batch_key,
dedupe,
select,
on_response_body,
..Default::default()
}
}
}

#[cfg(test)]
mod tests {
use serde_json::{json, Value};

use super::*;
use crate::core::config::KeyValue;

#[test]
fn test_grpc_to_http_basic_conversion() {
let grpc = Grpc {
url: "http://localhost:8080".to_string(),
method: "package.service.method".to_string(),
body: Some(json!({"key": "value"})),
headers: Default::default(),
batch_key: Default::default(),
dedupe: Default::default(),
select: Default::default(),
on_response_body: Default::default(),
};

let http = Http::from(grpc);

assert_eq!(http.url, "http://localhost:8080/package.service/method");
assert_eq!(http.method, crate::core::http::Method::POST);
assert_eq!(http.body, Some(r#"{"key":"value"}"#.to_string()));
}

#[test]
fn test_grpc_to_http_empty_body() {
let grpc = Grpc {
url: "http://localhost:8080".to_string(),
method: "package.service.method".to_string(),
body: Default::default(),
headers: Default::default(),
batch_key: Default::default(),
dedupe: Default::default(),
select: Default::default(),
on_response_body: Default::default(),
};

let http = Http::from(grpc);

assert_eq!(http.body, Some("{}".to_string()));
}

#[test]
fn test_grpc_to_http_with_headers() {
let grpc = Grpc {
url: "http://localhost:8080".to_string(),
method: "a.b.c".to_string(),
body: None,
headers: vec![KeyValue { key: "X-Foo".to_string(), value: "bar".to_string() }],
batch_key: Default::default(),
dedupe: Default::default(),
select: Default::default(),
on_response_body: Default::default(),
};

let http = Http::from(grpc);

assert_eq!(http.url, "http://localhost:8080/a.b/c");
assert_eq!(
http.headers
.iter()
.find(|h| h.key == "X-Foo")
.unwrap()
.value,
"bar".to_string()
);
}

#[test]
fn test_grpc_to_http_all_fields() {
let grpc = Grpc {
url: "http://localhost:8080".to_string(),
method: "package.service.method".to_string(),
body: Some(json!({"key": "value"})),
headers: vec![KeyValue { key: "X-Foo".to_string(), value: "bar".to_string() }],
batch_key: vec!["batch_key_value".to_string()],
dedupe: Some(true),
select: Some(Value::String("select_value".to_string())),
on_response_body: Some("on_response_body_value".to_string()),
};

let http = Http::from(grpc);

assert_eq!(http.url, "http://localhost:8080/package.service/method");
assert_eq!(http.method, crate::core::http::Method::POST);
assert_eq!(http.body, Some(r#"{"key":"value"}"#.to_string()));
assert_eq!(
http.headers
.iter()
.find(|h| h.key == "X-Foo")
.unwrap()
.value,
"bar".to_string()
);
assert_eq!(http.batch_key, vec!["batch_key_value".to_string()]);
assert_eq!(http.dedupe, Some(true));
assert_eq!(http.select, Some(Value::String("select_value".to_string())));
assert_eq!(
http.on_response_body,
Some("on_response_body_value".to_string())
);
}
}
1 change: 1 addition & 0 deletions src/core/generator/proto/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod comments_builder;
pub mod connect_rpc;
pub mod path_builder;
pub mod path_field;
Loading

0 comments on commit c8087c1

Please sign in to comment.