apcore_toolkit/
schema_utils.rs1use std::collections::HashMap;
7
8use serde_json::Value;
9
10pub fn enrich_schema_descriptions(
18 schema: &Value,
19 param_descriptions: &HashMap<String, String>,
20 overwrite: bool,
21) -> Value {
22 if param_descriptions.is_empty() {
23 return schema.clone();
24 }
25
26 match schema.get("properties") {
27 Some(p) if p.is_object() => p,
28 _ => return schema.clone(),
29 };
30
31 let mut result = schema.clone();
32
33 if let Some(result_props) = result.get_mut("properties").and_then(|p| p.as_object_mut()) {
34 for (name, desc) in param_descriptions {
35 if let Some(prop) = result_props.get_mut(name) {
36 if let Some(prop_obj) = prop.as_object_mut() {
37 if overwrite || !prop_obj.contains_key("description") {
38 prop_obj.insert("description".to_string(), Value::String(desc.clone()));
39 }
40 }
41 }
42 }
43 }
44
45 result
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use serde_json::json;
52
53 #[test]
54 fn test_enrich_adds_missing_descriptions() {
55 let schema = json!({
56 "type": "object",
57 "properties": {
58 "name": {"type": "string"},
59 "age": {"type": "integer"}
60 }
61 });
62 let mut descs = HashMap::new();
63 descs.insert("name".into(), "The user's name".into());
64 descs.insert("age".into(), "The user's age".into());
65
66 let result = enrich_schema_descriptions(&schema, &descs, false);
67 assert_eq!(
68 result["properties"]["name"]["description"],
69 "The user's name"
70 );
71 assert_eq!(result["properties"]["age"]["description"], "The user's age");
72 }
73
74 #[test]
75 fn test_enrich_preserves_existing_descriptions() {
76 let schema = json!({
77 "type": "object",
78 "properties": {
79 "name": {"type": "string", "description": "Original"}
80 }
81 });
82 let mut descs = HashMap::new();
83 descs.insert("name".into(), "New description".into());
84
85 let result = enrich_schema_descriptions(&schema, &descs, false);
86 assert_eq!(result["properties"]["name"]["description"], "Original");
87 }
88
89 #[test]
90 fn test_enrich_overwrites_when_flag_set() {
91 let schema = json!({
92 "type": "object",
93 "properties": {
94 "name": {"type": "string", "description": "Original"}
95 }
96 });
97 let mut descs = HashMap::new();
98 descs.insert("name".into(), "Overwritten".into());
99
100 let result = enrich_schema_descriptions(&schema, &descs, true);
101 assert_eq!(result["properties"]["name"]["description"], "Overwritten");
102 }
103
104 #[test]
105 fn test_enrich_empty_descriptions_returns_original() {
106 let schema = json!({"type": "object", "properties": {"a": {"type": "string"}}});
107 let descs = HashMap::new();
108 let result = enrich_schema_descriptions(&schema, &descs, false);
109 assert_eq!(result, schema);
110 }
111
112 #[test]
113 fn test_enrich_no_properties_returns_original() {
114 let schema = json!({"type": "string"});
115 let mut descs = HashMap::new();
116 descs.insert("x".into(), "desc".into());
117 let result = enrich_schema_descriptions(&schema, &descs, false);
118 assert_eq!(result, schema);
119 }
120
121 #[test]
122 fn test_enrich_ignores_unknown_params() {
123 let schema = json!({
124 "type": "object",
125 "properties": {"name": {"type": "string"}}
126 });
127 let mut descs = HashMap::new();
128 descs.insert("unknown_field".into(), "desc".into());
129 let result = enrich_schema_descriptions(&schema, &descs, false);
130 assert!(!result["properties"]
131 .as_object()
132 .unwrap()
133 .contains_key("unknown_field"));
134 }
135
136 #[test]
137 fn test_enrich_does_not_mutate_original() {
138 let schema = json!({
139 "type": "object",
140 "properties": {
141 "name": {"type": "string"},
142 "age": {"type": "integer"}
143 }
144 });
145 let original = schema.clone();
146 let mut descs = HashMap::new();
147 descs.insert("name".into(), "A name".into());
148 descs.insert("age".into(), "An age".into());
149
150 let result = enrich_schema_descriptions(&schema, &descs, false);
151 assert_eq!(result["properties"]["name"]["description"], "A name");
153 assert_eq!(schema, original, "original schema must not be mutated");
155 assert!(
156 schema["properties"]["name"]
157 .as_object()
158 .unwrap()
159 .get("description")
160 .is_none(),
161 "original should not have description added"
162 );
163 }
164
165 #[test]
166 fn test_enrich_partial_match() {
167 let schema = json!({
169 "type": "object",
170 "properties": {
171 "name": {"type": "string"},
172 "email": {"type": "string"}
173 }
174 });
175 let mut descs = HashMap::new();
176 descs.insert("name".into(), "User name".into());
177 descs.insert("nonexistent".into(), "Should be ignored".into());
178
179 let result = enrich_schema_descriptions(&schema, &descs, false);
180 assert_eq!(result["properties"]["name"]["description"], "User name");
182 assert!(
184 result["properties"]["email"]
185 .as_object()
186 .unwrap()
187 .get("description")
188 .is_none(),
189 "email should not get a description"
190 );
191 assert!(
193 !result["properties"]
194 .as_object()
195 .unwrap()
196 .contains_key("nonexistent"),
197 "nonexistent param should not appear in properties"
198 );
199 }
200}