Fix flattening of serde_json::Value
				
					
				
			It should behave similarly to flattening a `Map<String,Value>` in that it allows any properties
This commit is contained in:
		
							parent
							
								
									faf15e7859
								
							
						
					
					
						commit
						705aba1cef
					
				
					 3 changed files with 76 additions and 46 deletions
				
			
		|  | @ -176,7 +176,15 @@ pub fn apply_inner_validation(schema: &mut Schema, f: fn(&mut Schema) -> ()) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn flatten(schema: &mut Schema, other: Schema) { | pub fn flatten(schema: &mut Schema, other: Schema) { | ||||||
|     if let Value::Object(obj2) = other.to_value() { |     match other.try_to_object() { | ||||||
|  |         Err(false) => {} | ||||||
|  |         Err(true) => { | ||||||
|  |             schema | ||||||
|  |                 .ensure_object() | ||||||
|  |                 .entry("additionalProperties") | ||||||
|  |                 .or_insert(true.into()); | ||||||
|  |         } | ||||||
|  |         Ok(obj2) => { | ||||||
|             let obj1 = schema.ensure_object(); |             let obj1 = schema.ensure_object(); | ||||||
| 
 | 
 | ||||||
|             for (key, value2) in obj2 { |             for (key, value2) in obj2 { | ||||||
|  | @ -184,32 +192,8 @@ pub fn flatten(schema: &mut Schema, other: Schema) { | ||||||
|                     Entry::Vacant(vacant) => { |                     Entry::Vacant(vacant) => { | ||||||
|                         vacant.insert(value2); |                         vacant.insert(value2); | ||||||
|                     } |                     } | ||||||
|                 Entry::Occupied(mut occupied) => { |                     Entry::Occupied(occupied) => { | ||||||
|                         match occupied.key().as_str() { |                         match occupied.key().as_str() { | ||||||
|                         // This special "type" handling can probably be removed once the enum variant `with`/`schema_with` behaviour is fixed
 |  | ||||||
|                         "type" => match (occupied.get_mut(), value2) { |  | ||||||
|                             (Value::Array(a1), Value::Array(mut a2)) => { |  | ||||||
|                                 a2.retain(|v2| !a1.contains(v2)); |  | ||||||
|                                 a1.extend(a2); |  | ||||||
|                             } |  | ||||||
|                             (v1, Value::Array(mut a2)) => { |  | ||||||
|                                 if !a2.contains(v1) { |  | ||||||
|                                     a2.push(std::mem::take(v1)); |  | ||||||
|                                     *occupied.get_mut() = Value::Array(a2); |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             (Value::Array(a1), v2) => { |  | ||||||
|                                 if !a1.contains(&v2) { |  | ||||||
|                                     a1.push(v2); |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             (v1, v2) => { |  | ||||||
|                                 if v1 != &v2 { |  | ||||||
|                                     *occupied.get_mut() = |  | ||||||
|                                         Value::Array(vec![std::mem::take(v1), v2]); |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                         }, |  | ||||||
|                             "required" => { |                             "required" => { | ||||||
|                                 if let Value::Array(a1) = occupied.into_mut() { |                                 if let Value::Array(a1) = occupied.into_mut() { | ||||||
|                                     if let Value::Array(a2) = value2 { |                                     if let Value::Array(a2) = value2 { | ||||||
|  | @ -232,4 +216,5 @@ pub fn flatten(schema: &mut Schema, other: Schema) { | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								schemars/tests/expected/flattened_value.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								schemars/tests/expected/flattened_value.json
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | { | ||||||
|  |   "$schema": "https://json-schema.org/draft/2020-12/schema", | ||||||
|  |   "title": "FlattenValue", | ||||||
|  |   "type": "object", | ||||||
|  |   "properties": { | ||||||
|  |     "flag": { | ||||||
|  |       "type": "boolean" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "required": [ | ||||||
|  |     "flag" | ||||||
|  |   ], | ||||||
|  |   "additionalProperties": true | ||||||
|  | } | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
| mod util; | mod util; | ||||||
| use schemars::JsonSchema; | use schemars::JsonSchema; | ||||||
|  | use serde_json::Value; | ||||||
|  | use std::collections::BTreeMap; | ||||||
| use util::*; | use util::*; | ||||||
| 
 | 
 | ||||||
| #[allow(dead_code)] | #[allow(dead_code)] | ||||||
|  | @ -53,5 +55,34 @@ fn test_flat_schema() -> TestResult { | ||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_flattened_schema() -> TestResult { | fn test_flattened_schema() -> TestResult { | ||||||
|  |     // intentionally using the same file as test_flat_schema, as the schema should be identical
 | ||||||
|     test_default_generated_schema::<Deep1>("flatten") |     test_default_generated_schema::<Deep1>("flatten") | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #[allow(dead_code)] | ||||||
|  | #[derive(JsonSchema)] | ||||||
|  | struct FlattenValue { | ||||||
|  |     flag: bool, | ||||||
|  |     #[serde(flatten)] | ||||||
|  |     value: Value, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[allow(dead_code)] | ||||||
|  | #[derive(JsonSchema)] | ||||||
|  | #[schemars(rename = "FlattenValue")] | ||||||
|  | struct FlattenMap { | ||||||
|  |     flag: bool, | ||||||
|  |     #[serde(flatten)] | ||||||
|  |     value: BTreeMap<String, Value>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn test_flattened_value() -> TestResult { | ||||||
|  |     test_default_generated_schema::<FlattenValue>("flattened_value") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn test_flattened_map() -> TestResult { | ||||||
|  |     // intentionally using the same file as test_flattened_value, as the schema should be identical
 | ||||||
|  |     test_default_generated_schema::<FlattenMap>("flattened_value") | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Graham Esau
						Graham Esau