use crate::database::object::*; use serde::{Deserialize, Serialize}; use serde_json::Value; #[derive(Debug, Clone, Serialize, Default)] pub struct Schema { #[serde(flatten)] pub obj: SchemaObject, #[serde(skip)] pub always_fail: bool, } impl std::ops::Deref for Schema { type Target = SchemaObject; fn deref(&self) -> &Self::Target { &self.obj } } impl std::ops::DerefMut for Schema { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.obj } } impl Schema { /// Returns true if the schema acts purely as a type pointer (composition without overriding constraints) pub fn is_proxy(&self) -> bool { self.obj.properties.is_none() && self.obj.pattern_properties.is_none() && self.obj.additional_properties.is_none() && self.obj.required.is_none() && self.obj.dependencies.is_none() && self.obj.items.is_none() && self.obj.prefix_items.is_none() && self.obj.contains.is_none() && self.obj.format.is_none() && self.obj.enum_.is_none() && self.obj.const_.is_none() && self.obj.cases.is_none() && self.obj.one_of.is_none() && self.obj.not.is_none() && self.obj.family.is_none() } } impl<'de> Deserialize<'de> for Schema { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let v: Value = Deserialize::deserialize(deserializer)?; if let Some(b) = v.as_bool() { let mut obj = SchemaObject::default(); if b { obj.extensible = Some(true); } return Ok(Schema { obj, always_fail: !b, }); } let mut obj: SchemaObject = serde_json::from_value(v.clone()).map_err(serde::de::Error::custom)?; // If a schema is effectively empty (except for potentially carrying an ID), // it functions as a boolean `true` schema in Draft2020 which means it should not // restrict additional properties natively let is_empty = obj.type_.is_none() && obj.properties.is_none() && obj.pattern_properties.is_none() && obj.additional_properties.is_none() && obj.required.is_none() && obj.dependencies.is_none() && obj.items.is_none() && obj.prefix_items.is_none() && obj.contains.is_none() && obj.format.is_none() && obj.enum_.is_none() && obj.const_.is_none() && obj.cases.is_none() && obj.one_of.is_none() && obj.not.is_none() && obj.family.is_none(); if is_empty && obj.extensible.is_none() { obj.extensible = Some(true); } Ok(Schema { obj, always_fail: false, }) } }