pub mod collection; pub mod edges; pub mod filter; pub mod polymorphism; use crate::database::schema::Schema; impl Schema { pub fn compile( &self, db: &crate::database::Database, root_id: &str, path: String, errors: &mut Vec, ) { if self.obj.compiled_properties.get().is_some() { return; } if let Some(format_str) = &self.obj.format { if let Some(fmt) = crate::database::formats::FORMATS.get(format_str.as_str()) { let _ = self .obj .compiled_format .set(crate::database::object::CompiledFormat::Func(fmt.func)); } } if let Some(pattern_str) = &self.obj.pattern { if let Ok(re) = regex::Regex::new(pattern_str) { let _ = self .obj .compiled_pattern .set(crate::database::object::CompiledRegex(re)); } } if let Some(pattern_props) = &self.obj.pattern_properties { let mut compiled = Vec::new(); for (k, v) in pattern_props { if let Ok(re) = regex::Regex::new(k) { compiled.push((crate::database::object::CompiledRegex(re), v.clone())); } } if !compiled.is_empty() { let _ = self.obj.compiled_pattern_properties.set(compiled); } } let mut props = std::collections::BTreeMap::new(); // 1. Resolve INHERITANCE dependencies first if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &self.obj.type_ { if !crate::database::object::is_primitive_type(t) { if let Some(parent) = db.schemas.get(t) { parent.as_ref().compile(db, t, t.clone(), errors); if let Some(p_props) = parent.obj.compiled_properties.get() { props.extend(p_props.clone()); } } } } if let Some(crate::database::object::SchemaTypeOrArray::Multiple(types)) = &self.obj.type_ { let mut custom_type_count = 0; for t in types { if !crate::database::object::is_primitive_type(t) { custom_type_count += 1; } } if custom_type_count > 1 { errors.push(crate::drop::Error { code: "MULTIPLE_INHERITANCE_PROHIBITED".to_string(), message: format!( "Schema attempts to extend multiple custom object pointers in its type array {:?}. Use 'oneOf' for polymorphism and tagged unions.", types ), details: crate::drop::ErrorDetails { path: Some(path.clone()), schema: Some(root_id.to_string()), ..Default::default() } }); } for t in types { if !crate::database::object::is_primitive_type(t) { if let Some(parent) = db.schemas.get(t) { parent.as_ref().compile(db, t, t.clone(), errors); } } } } // 2. Add local properties if let Some(local_props) = &self.obj.properties { for (k, v) in local_props { props.insert(k.clone(), v.clone()); } } // 3. Add cases conditionally-defined properties recursively if let Some(cases) = &self.obj.cases { for (i, c) in cases.iter().enumerate() { if let Some(child) = &c.when { child.compile(db, root_id, format!("{}/cases/{}/when", path, i), errors); } if let Some(child) = &c.then { child.compile(db, root_id, format!("{}/cases/{}/then", path, i), errors); if let Some(t_props) = child.obj.compiled_properties.get() { props.extend(t_props.clone()); } } if let Some(child) = &c.else_ { child.compile(db, root_id, format!("{}/cases/{}/else", path, i), errors); if let Some(e_props) = child.obj.compiled_properties.get() { props.extend(e_props.clone()); } } } } // 4. Set the OnceLock! let _ = self.obj.compiled_properties.set(props.clone()); let mut names: Vec = props.keys().cloned().collect(); names.sort(); let _ = self.obj.compiled_property_names.set(names); // 5. Compute Edges natively let schema_edges = self.compile_edges(db, root_id, &path, &props, errors); let _ = self.obj.compiled_edges.set(schema_edges); // 5. Build our inline children properties recursively NOW! (Depth-first search) if let Some(local_props) = &self.obj.properties { for (k, child) in local_props { child.compile(db, root_id, format!("{}/{}", path, k), errors); } } if let Some(items) = &self.obj.items { items.compile(db, root_id, format!("{}/items", path), errors); } if let Some(pattern_props) = &self.obj.pattern_properties { for (k, child) in pattern_props { child.compile(db, root_id, format!("{}/{}", path, k), errors); } } if let Some(additional_props) = &self.obj.additional_properties { additional_props.compile( db, root_id, format!("{}/additionalProperties", path), errors, ); } if let Some(one_of) = &self.obj.one_of { for (i, child) in one_of.iter().enumerate() { child.compile(db, root_id, format!("{}/oneOf/{}", path, i), errors); } } if let Some(arr) = &self.obj.prefix_items { for (i, child) in arr.iter().enumerate() { child.compile(db, root_id, format!("{}/prefixItems/{}", path, i), errors); } } if let Some(child) = &self.obj.not { child.compile(db, root_id, format!("{}/not", path), errors); } if let Some(child) = &self.obj.contains { child.compile(db, root_id, format!("{}/contains", path), errors); } self.compile_polymorphism(db, root_id, &path, errors); } }