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:
Graham Esau 2024-08-12 21:39:41 +01:00
parent faf15e7859
commit 705aba1cef
3 changed files with 76 additions and 46 deletions

View file

@ -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) {
} }
} }
} }
}
} }

View 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
}

View file

@ -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")
}