vika_cli/generator/
query_keys.rs1use crate::generator::swagger_parser::OperationInfo;
2use crate::generator::utils::to_camel_case;
3use serde::Serialize;
4
5#[derive(Debug, Clone, Serialize)]
7pub struct QueryKeyContext {
8 pub module_name: String,
9 pub spec_name: Option<String>,
10 pub keys: Vec<QueryKeyEntry>,
11}
12
13#[derive(Debug, Clone, Serialize)]
15pub struct QueryKeyEntry {
16 pub key_name: String,
17 pub has_params: bool,
18 pub param_list: String, pub param_names: String, }
21
22pub fn generate_query_keys(
24 operations: &[OperationInfo],
25 module_name: &str,
26 spec_name: Option<&str>,
27) -> QueryKeyContext {
28 let mut keys = Vec::new();
29
30 for op_info in operations {
31 let key_name = if let Some(operation_id) = &op_info.operation.operation_id {
33 to_camel_case(operation_id)
34 } else {
35 generate_key_name_from_path(&op_info.path, &op_info.method)
36 };
37
38 let mut params = Vec::new();
40 let mut param_names = Vec::new();
41
42 for param_ref in &op_info.operation.parameters {
44 if let openapiv3::ReferenceOr::Item(openapiv3::Parameter::Path {
45 parameter_data, ..
46 }) = param_ref
47 {
48 let param_type = extract_param_type(parameter_data);
49 params.push(format!("{}: {}", parameter_data.name, param_type));
50 param_names.push(parameter_data.name.clone());
51 }
52 }
53
54 let is_query = matches!(op_info.method.to_uppercase().as_str(), "GET" | "HEAD");
56 let mut query_fields = Vec::new();
57 if is_query {
58 for param_ref in &op_info.operation.parameters {
59 if let openapiv3::ReferenceOr::Item(openapiv3::Parameter::Query {
60 parameter_data,
61 ..
62 }) = param_ref
63 {
64 let param_type = extract_param_type(parameter_data);
65 query_fields.push(format!("{}?: {}", parameter_data.name, param_type));
66 }
67 }
68 }
69
70 if !query_fields.is_empty() {
72 let query_type = format!("{{ {} }}", query_fields.join(", "));
73 params.push(format!("query?: {}", query_type));
74 param_names.push("query".to_string());
75 }
76
77 let has_params = !params.is_empty();
78 let param_list = params.join(", ");
79 let param_names_str = param_names.join(", ");
80
81 keys.push(QueryKeyEntry {
82 key_name,
83 has_params,
84 param_list,
85 param_names: param_names_str,
86 });
87 }
88
89 QueryKeyContext {
90 module_name: module_name.to_string(),
91 spec_name: spec_name.map(|s| s.to_string()),
92 keys,
93 }
94}
95
96fn generate_key_name_from_path(path: &str, method: &str) -> String {
98 let path_parts: Vec<&str> = path
99 .trim_start_matches('/')
100 .split('/')
101 .filter(|p| !p.starts_with('{'))
102 .collect();
103
104 let method_upper = method.to_uppercase();
105 let method_prefix = match method_upper.as_str() {
106 "GET" => "get",
107 "POST" => "create",
108 "PUT" => "update",
109 "DELETE" => "delete",
110 "PATCH" => "patch",
111 _ => {
112 return to_camel_case(&method.to_lowercase());
113 }
114 };
115
116 let base_name = if path_parts.is_empty() {
117 method_prefix.to_string()
118 } else {
119 let resource_name = if path_parts.len() > 1 {
120 path_parts.last().unwrap_or(&"")
121 } else {
122 path_parts.first().unwrap_or(&"")
123 };
124
125 if resource_name.ends_with('s') && path.contains('{') {
126 let singular = &resource_name[..resource_name.len() - 1];
127 format!("{}{}ById", method_prefix, to_pascal_case(singular))
128 } else if path.contains('{') {
129 format!("{}{}ById", method_prefix, to_pascal_case(resource_name))
130 } else {
131 format!("{}{}", method_prefix, to_pascal_case(resource_name))
132 }
133 };
134
135 to_camel_case(&base_name)
136}
137
138fn extract_param_type(parameter_data: &openapiv3::ParameterData) -> String {
140 match ¶meter_data.format {
141 openapiv3::ParameterSchemaOrContent::Schema(schema_ref) => {
142 match schema_ref {
143 openapiv3::ReferenceOr::Item(schema) => match &schema.schema_kind {
144 openapiv3::SchemaKind::Type(type_) => match type_ {
145 openapiv3::Type::String(_) => "string".to_string(),
146 openapiv3::Type::Number(_) => "number".to_string(),
147 openapiv3::Type::Integer(_) => "number".to_string(),
148 openapiv3::Type::Boolean(_) => "boolean".to_string(),
149 openapiv3::Type::Array(_) => "string[]".to_string(),
150 openapiv3::Type::Object(_) => "string".to_string(),
151 },
152 _ => "string".to_string(),
153 },
154 openapiv3::ReferenceOr::Reference { reference } => {
155 if let Some(ref_name) = reference.strip_prefix("#/components/schemas/") {
157 crate::generator::utils::to_pascal_case(ref_name)
158 } else {
159 "string".to_string()
160 }
161 }
162 }
163 }
164 _ => "string".to_string(),
165 }
166}
167
168fn to_pascal_case(s: &str) -> String {
170 crate::generator::utils::to_pascal_case(s)
171}