use std::collections::HashMap;
use crate::gnostic::openapi::v3::Operation;
use crate::google::api::{FieldBehavior, HttpRule, ResourceDescriptor, ResourceReference};
use crate::parsing::http::HttpPattern;
use crate::parsing::types::{BaseType, UnifiedType};
#[derive(Debug, Default)]
pub struct CodeGenMetadata {
pub messages: HashMap<String, MessageInfo>,
pub enums: HashMap<String, EnumInfo>,
pub services: HashMap<String, ServiceInfo>,
}
impl CodeGenMetadata {
pub fn get_message_fields(&self, type_name: &str) -> Vec<MessageField> {
self.messages
.get(type_name)
.map(|msg| msg.fields.clone())
.unwrap_or_default()
}
pub fn resource_from_singular(&self, name: &str) -> Option<&ResourceDescriptor> {
self.messages.values().find_map(|info| {
info.resource_descriptor
.as_ref()
.filter(|r| r.singular == name)
})
}
pub fn resource_from_plural(&self, name: &str) -> Option<&ResourceDescriptor> {
self.messages.values().find_map(|info| {
info.resource_descriptor
.as_ref()
.filter(|r| r.plural == name)
})
}
pub fn get_resource_descriptor(&self, type_name: &str) -> Option<&ResourceDescriptor> {
if let Some(descriptor) = self
.messages
.get(type_name)
.and_then(|info| info.resource_descriptor.as_ref())
{
return Some(descriptor);
}
self.messages.iter().find_map(|(key, info)| {
let simple = key.rfind('.').map(|i| &key[i + 1..]).unwrap_or(key);
if simple == type_name {
info.resource_descriptor.as_ref()
} else {
None
}
})
}
}
#[derive(Debug, Clone)]
pub struct MessageInfo {
pub name: String,
pub fields: Vec<MessageField>,
pub resource_descriptor: Option<ResourceDescriptor>,
pub documentation: Option<String>,
}
#[derive(Debug, Clone)]
pub struct MessageField {
pub name: String,
pub unified_type: UnifiedType,
pub documentation: Option<String>,
pub oneof_variants: Option<Vec<OneofVariant>>,
pub field_behavior: Vec<FieldBehavior>,
pub is_sensitive: bool,
pub resource_reference: Option<ResourceReference>,
}
#[derive(Debug, Clone)]
pub struct OneofVariant {
pub field_name: String, pub variant_name: String, pub field_type: UnifiedType, pub documentation: Option<String>,
}
impl OneofVariant {
pub fn is_int32(&self) -> bool {
matches!(self.field_type.base_type, BaseType::Int32)
}
}
#[derive(Debug, Clone)]
pub struct EnumInfo {
pub name: String,
pub values: Vec<EnumValue>,
pub documentation: Option<String>,
}
#[derive(Debug, Clone)]
pub struct EnumValue {
pub name: String,
pub number: i32,
pub documentation: Option<String>,
}
#[derive(Debug, Clone)]
pub struct ServiceInfo {
pub name: String,
pub package: String,
pub documentation: Option<String>,
pub methods: Vec<MethodMetadata>,
}
#[derive(Debug, Clone)]
pub struct MethodMetadata {
pub service_name: String,
pub method_name: String,
pub input_type: String,
pub output_type: String,
pub operation: Option<Operation>,
pub http_rule: HttpRule,
pub http_pattern: HttpPattern,
pub documentation: Option<String>,
}
impl MethodMetadata {
pub fn http_method(&self) -> Option<&str> {
use crate::google::api::http_rule::Pattern;
self.http_rule.pattern.as_ref().map(|p| match p {
Pattern::Get(_) => "GET",
Pattern::Post(_) => "POST",
Pattern::Put(_) => "PUT",
Pattern::Delete(_) => "DELETE",
Pattern::Patch(_) => "PATCH",
Pattern::Custom(c) => c.kind.as_str(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_service_based_method_structure() {
let mut codegen_metadata = CodeGenMetadata {
messages: HashMap::new(),
services: HashMap::new(),
enums: HashMap::new(),
};
let mut service_info = ServiceInfo {
name: "TestService".to_string(),
package: "test.v1".to_string(),
documentation: Some("Test service documentation".to_string()),
methods: Vec::new(),
};
let http_rule = crate::google::api::HttpRule {
pattern: Some(crate::google::api::http_rule::Pattern::Get(
"/test".to_string(),
)),
..Default::default()
};
let method = MethodMetadata {
service_name: "TestService".to_string(),
method_name: "TestMethod".to_string(),
input_type: ".test.TestRequest".to_string(),
output_type: ".test.TestResponse".to_string(),
operation: None,
http_pattern: crate::parsing::http::HttpPattern::parse("/test"),
http_rule,
documentation: Some("Test method documentation".to_string()),
};
service_info.methods.push(method);
codegen_metadata
.services
.insert("TestService".to_string(), service_info);
let service = codegen_metadata.services.get("TestService").unwrap();
assert_eq!(service.name, "TestService");
assert_eq!(service.methods.len(), 1);
assert_eq!(service.methods[0].method_name, "TestMethod");
}
}