176 lines
5.6 KiB
Rust
176 lines
5.6 KiB
Rust
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<crate::drop::Error>,
|
|
) {
|
|
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<String> = 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);
|
|
}
|
|
}
|