1use std::collections::HashMap;
2
3use crate::gnostic::openapi::v3::Operation;
4use crate::google::api::{FieldBehavior, HttpRule, ResourceDescriptor, ResourceReference};
5use crate::parsing::http::HttpPattern;
6use crate::parsing::types::UnifiedType;
7use crate::utils::last_segment;
8
9#[derive(Debug, Default)]
11pub struct CodeGenMetadata {
12 pub messages: HashMap<String, MessageInfo>,
13 pub enums: HashMap<String, EnumInfo>,
14 pub services: HashMap<String, ServiceInfo>,
15}
16
17impl CodeGenMetadata {
18 pub fn get_message_fields(&self, type_name: &str) -> Vec<MessageField> {
20 self.messages
21 .get(type_name)
22 .map(|msg| msg.fields.clone())
23 .unwrap_or_default()
24 }
25
26 pub fn resource_from_singular(&self, name: &str) -> Option<&ResourceDescriptor> {
28 self.messages.values().find_map(|info| {
29 info.resource_descriptor
30 .as_ref()
31 .filter(|r| r.singular == name)
32 })
33 }
34
35 pub fn resource_from_plural(&self, name: &str) -> Option<&ResourceDescriptor> {
37 self.messages.values().find_map(|info| {
38 info.resource_descriptor
39 .as_ref()
40 .filter(|r| r.plural == name)
41 })
42 }
43
44 pub fn get_resource_descriptor(&self, type_name: &str) -> Option<&ResourceDescriptor> {
46 if let Some(descriptor) = self
48 .messages
49 .get(type_name)
50 .and_then(|info| info.resource_descriptor.as_ref())
51 {
52 return Some(descriptor);
53 }
54
55 self.messages.iter().find_map(|(key, info)| {
57 if last_segment(key) == type_name {
58 info.resource_descriptor.as_ref()
59 } else {
60 None
61 }
62 })
63 }
64}
65
66#[derive(Debug, Clone)]
68pub struct MessageInfo {
69 pub name: String,
70 pub fields: Vec<MessageField>,
71 pub resource_descriptor: Option<ResourceDescriptor>,
72 pub documentation: Option<String>,
73}
74
75#[derive(Debug, Clone)]
77pub struct MessageField {
78 pub name: String,
79 pub json_name: Option<String>,
81 pub response_header: Option<String>,
83 pub request_header: Option<String>,
85 pub emit_unpopulated: bool,
87 pub raw_body: bool,
89 pub unified_type: UnifiedType,
91 pub documentation: Option<String>,
92 pub oneof_variants: Option<Vec<OneofVariant>>,
94 pub field_behavior: Vec<FieldBehavior>,
96 pub is_sensitive: bool,
99 pub resource_reference: Option<ResourceReference>,
106}
107
108#[derive(Debug, Clone)]
110pub struct OneofVariant {
111 pub field_name: String, pub variant_name: String, pub field_type: UnifiedType, pub documentation: Option<String>,
115}
116
117#[derive(Debug, Clone)]
119pub struct EnumInfo {
120 pub name: String,
121 pub values: Vec<EnumValue>,
122 pub documentation: Option<String>,
123}
124
125#[derive(Debug, Clone)]
127pub struct EnumValue {
128 pub name: String,
129 pub number: i32,
130 pub documentation: Option<String>,
131}
132
133#[derive(Debug, Clone)]
135pub struct ServiceInfo {
136 pub name: String,
137 pub package: String,
139 pub documentation: Option<String>,
140 pub methods: Vec<MethodMetadata>,
141}
142
143#[derive(Debug, Clone)]
145pub struct MethodMetadata {
146 pub service_name: String,
147 pub method_name: String,
148 pub input_type: String,
149 pub output_type: String,
150 pub operation: Option<Operation>,
151 pub http_rule: HttpRule,
152 pub http_pattern: HttpPattern,
154 pub documentation: Option<String>,
155 pub server_streaming: bool,
157}
158
159impl MethodMetadata {
160 pub fn http_method(&self) -> Option<&str> {
162 use crate::google::api::http_rule::Pattern;
163 self.http_rule.pattern.as_ref().map(|p| match p {
164 Pattern::Get(_) => "GET",
165 Pattern::Post(_) => "POST",
166 Pattern::Put(_) => "PUT",
167 Pattern::Delete(_) => "DELETE",
168 Pattern::Patch(_) => "PATCH",
169 Pattern::Custom(c) => c.kind.as_str(),
170 })
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_service_based_method_structure() {
180 let mut codegen_metadata = CodeGenMetadata {
181 messages: HashMap::new(),
182 services: HashMap::new(),
183 enums: HashMap::new(),
184 };
185
186 let mut service_info = ServiceInfo {
188 name: "TestService".to_string(),
189 package: "test.v1".to_string(),
190 documentation: Some("Test service documentation".to_string()),
191 methods: Vec::new(),
192 };
193
194 let http_rule = crate::google::api::HttpRule {
196 pattern: Some(crate::google::api::http_rule::Pattern::Get(
197 "/test".to_string(),
198 )),
199 ..Default::default()
200 };
201
202 let method = MethodMetadata {
203 service_name: "TestService".to_string(),
204 method_name: "TestMethod".to_string(),
205 input_type: ".test.TestRequest".to_string(),
206 output_type: ".test.TestResponse".to_string(),
207 server_streaming: false,
208 operation: None,
209 http_pattern: crate::parsing::http::HttpPattern::parse("/test"),
210 http_rule,
211 documentation: Some("Test method documentation".to_string()),
212 };
213 service_info.methods.push(method);
214
215 codegen_metadata
216 .services
217 .insert("TestService".to_string(), service_info);
218
219 let service = codegen_metadata.services.get("TestService").unwrap();
221 assert_eq!(service.name, "TestService");
222 assert_eq!(service.methods.len(), 1);
223 assert_eq!(service.methods[0].method_name, "TestMethod");
224 }
225}