From f4496e6ea06d61eb8d50c0c54aef37831c3beeb0 Mon Sep 17 00:00:00 2001 From: DLillard0 <565570086@qq.com> Date: Mon, 16 Dec 2024 17:50:18 +0800 Subject: [PATCH] feat: link config support proto paths --- generated/.tailcallrc.schema.json | 10 ++++++ src/core/config/directives/link.rs | 5 +++ src/core/config/reader.rs | 8 ++++- src/core/generator/generator.rs | 1 + src/core/grpc/data_loader_request.rs | 1 + src/core/grpc/protobuf.rs | 48 ++++++++++++++++++++++++++++ src/core/grpc/request_template.rs | 1 + 7 files changed, 73 insertions(+), 1 deletion(-) diff --git a/generated/.tailcallrc.schema.json b/generated/.tailcallrc.schema.json index 62a29551d1..55fbf80df1 100644 --- a/generated/.tailcallrc.schema.json +++ b/generated/.tailcallrc.schema.json @@ -269,6 +269,16 @@ "meta": { "description": "Additional metadata pertaining to the linked resource." }, + "proto_paths": { + "description": "The proto paths to be used when resolving dependencies. Only valid when [`Link::type_of`] is [`LinkType::Protobuf`]", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, "src": { "description": "The source of the link. It can be a URL or a path to a file. If a path is provided, it is relative to the file that imports the link.", "type": "string" diff --git a/src/core/config/directives/link.rs b/src/core/config/directives/link.rs index 5063812a2f..e045caf98c 100644 --- a/src/core/config/directives/link.rs +++ b/src/core/config/directives/link.rs @@ -93,4 +93,9 @@ pub struct Link { /// Additional metadata pertaining to the linked resource. #[serde(default, skip_serializing_if = "is_default")] pub meta: Option, + /// + /// The proto paths to be used when resolving dependencies. + /// Only valid when [`Link::type_of`] is [`LinkType::Protobuf`] + #[serde(default, skip_serializing_if = "is_default")] + pub proto_paths: Option>, } diff --git a/src/core/config/reader.rs b/src/core/config/reader.rs index 675c6a9d42..5240e658e8 100644 --- a/src/core/config/reader.rs +++ b/src/core/config/reader.rs @@ -79,7 +79,13 @@ impl ConfigReader { }); } LinkType::Protobuf => { - let meta = self.proto_reader.read(path, None).await?; + let proto_paths = link.proto_paths.as_ref().map(|paths| { + paths + .iter() + .map(|p| Self::resolve_path(p, parent_dir)) + .collect::>() + }); + let meta = self.proto_reader.read(path, proto_paths.as_deref()).await?; extensions.add_proto(meta); } LinkType::Script => { diff --git a/src/core/generator/generator.rs b/src/core/generator/generator.rs index 98cb81515e..5bcee1f556 100644 --- a/src/core/generator/generator.rs +++ b/src/core/generator/generator.rs @@ -99,6 +99,7 @@ impl Generator { type_of: LinkType::Protobuf, headers: None, meta: None, + proto_paths: None, }); Ok(config) } diff --git a/src/core/grpc/data_loader_request.rs b/src/core/grpc/data_loader_request.rs index 1f49188d6f..7ee4bba124 100644 --- a/src/core/grpc/data_loader_request.rs +++ b/src/core/grpc/data_loader_request.rs @@ -74,6 +74,7 @@ mod tests { type_of: LinkType::Protobuf, headers: None, meta: None, + proto_paths: None, }]); let method = GrpcMethod { package: "greetings".to_string(), diff --git a/src/core/grpc/protobuf.rs b/src/core/grpc/protobuf.rs index 979b7afb2f..36ebdffebd 100644 --- a/src/core/grpc/protobuf.rs +++ b/src/core/grpc/protobuf.rs @@ -254,6 +254,18 @@ pub mod tests { use crate::core::config::{Config, Field, Grpc, Link, LinkType, Resolver, Type}; pub async fn get_proto_file(path: &str) -> Result { + get_proto_file_with_config(path, LinkConfig::default()).await + } + + #[derive(Default)] + pub struct LinkConfig { + proto_paths: Option>, + } + + pub async fn get_proto_file_with_config( + path: &str, + link_config: LinkConfig, + ) -> Result { let runtime = crate::core::runtime::test::init(None); let reader = ConfigReader::init(runtime); @@ -268,6 +280,7 @@ pub mod tests { type_of: LinkType::Protobuf, headers: None, meta: None, + proto_paths: link_config.proto_paths, }]); let method = GrpcMethod { package: id, service: "a".to_owned(), name: "b".to_owned() }; @@ -395,6 +408,41 @@ pub mod tests { Ok(()) } + #[tokio::test] + async fn news_proto_file_with_proto_paths() -> Result<()> { + let grpc_method = GrpcMethod::try_from("news.NewsService.GetNews").unwrap(); + + let path: &str = protobuf::NEWS_PROTO_PATHS; + let proto_paths = Some(vec![Path::new(path) + .ancestors() + .nth(2) + .unwrap() + .to_string_lossy() + .to_string()]); + let file = ProtobufSet::from_proto_file( + get_proto_file_with_config(path, LinkConfig { proto_paths }).await?, + )?; + let service = file.find_service(&grpc_method)?; + let operation = service.find_operation(&grpc_method)?; + + let input = operation.convert_input(r#"{ "id": 1 }"#)?; + + assert_eq!(input, b"\0\0\0\0\x02\x08\x01"); + + let output = b"\0\0\0\x005\x08\x01\x12\x06Note 1\x1a\tContent 1\"\x0cPost image 1"; + + let parsed = operation.convert_output::(output)?; + + assert_eq!( + serde_json::to_value(parsed)?, + json!({ + "id": 1, "title": "Note 1", "body": "Content 1", "postImage": "Post image 1", "status": "PUBLISHED" + }) + ); + + Ok(()) + } + #[tokio::test] async fn oneof_proto_file() -> Result<()> { let grpc_method = GrpcMethod::try_from("oneof.OneOfService.GetOneOf").unwrap(); diff --git a/src/core/grpc/request_template.rs b/src/core/grpc/request_template.rs index b1cb5653e4..4643c5965f 100644 --- a/src/core/grpc/request_template.rs +++ b/src/core/grpc/request_template.rs @@ -160,6 +160,7 @@ mod tests { type_of: LinkType::Protobuf, headers: None, meta: None, + proto_paths: None, }]); let method = GrpcMethod { package: id.to_string(),