pub mod edge; pub mod r#enum; pub mod executors; pub mod formats; pub mod page; pub mod punc; pub mod object; pub mod relation; pub mod schema; pub mod r#type; // External mock exports inside the executor sub-folder use r#enum::Enum; use executors::DatabaseExecutor; #[cfg(not(test))] use executors::pgrx::SpiExecutor; #[cfg(test)] use executors::mock::MockExecutor; use punc::Punc; use relation::Relation; use schema::Schema; use serde_json::Value; use std::collections::HashMap; use std::sync::Arc; use r#type::Type; pub struct Database { pub enums: HashMap, pub types: HashMap, pub puncs: HashMap, pub relations: HashMap, pub schemas: HashMap>, pub executor: Box, } impl Database { pub fn new(val: &serde_json::Value) -> (Self, crate::drop::Drop) { let mut db = Self { enums: HashMap::new(), types: HashMap::new(), relations: HashMap::new(), puncs: HashMap::new(), schemas: HashMap::new(), #[cfg(not(test))] executor: Box::new(SpiExecutor::new()), #[cfg(test)] executor: Box::new(MockExecutor::new()), }; let mut errors = Vec::new(); if let Some(arr) = val.get("enums").and_then(|v| v.as_array()) { for item in arr { match serde_json::from_value::(item.clone()) { Ok(def) => { db.enums.insert(def.name.clone(), def); } Err(e) => { errors.push(crate::drop::Error { code: "DATABASE_ENUM_PARSE_FAILED".to_string(), message: format!("Failed to parse database enum: {}", e), details: crate::drop::ErrorDetails::default(), }); } } } } if let Some(arr) = val.get("types").and_then(|v| v.as_array()) { for item in arr { match serde_json::from_value::(item.clone()) { Ok(def) => { db.types.insert(def.name.clone(), def); } Err(e) => { errors.push(crate::drop::Error { code: "DATABASE_TYPE_PARSE_FAILED".to_string(), message: format!("Failed to parse database type: {}", e), details: crate::drop::ErrorDetails::default(), }); } } } } if let Some(arr) = val.get("relations").and_then(|v| v.as_array()) { for item in arr { match serde_json::from_value::(item.clone()) { Ok(def) => { if db.types.contains_key(&def.source_type) && db.types.contains_key(&def.destination_type) { db.relations.insert(def.constraint.clone(), def); } } Err(e) => { errors.push(crate::drop::Error { code: "DATABASE_RELATION_PARSE_FAILED".to_string(), message: format!("Failed to parse database relation: {}", e), details: crate::drop::ErrorDetails::default(), }); } } } } if let Some(arr) = val.get("puncs").and_then(|v| v.as_array()) { for item in arr { match serde_json::from_value::(item.clone()) { Ok(def) => { db.puncs.insert(def.name.clone(), def); } Err(e) => { errors.push(crate::drop::Error { code: "DATABASE_PUNC_PARSE_FAILED".to_string(), message: format!("Failed to parse database punc: {}", e), details: crate::drop::ErrorDetails::default(), }); } } } } if let Some(arr) = val.get("schemas").and_then(|v| v.as_array()) { for (i, item) in arr.iter().enumerate() { match serde_json::from_value::(item.clone()) { Ok(mut schema) => { let id = schema .obj .id .clone() .unwrap_or_else(|| format!("schema_{}", i)); schema.obj.id = Some(id.clone()); db.schemas.insert(id, Arc::new(schema)); } Err(e) => { errors.push(crate::drop::Error { code: "DATABASE_SCHEMA_PARSE_FAILED".to_string(), message: format!("Failed to parse database schema: {}", e), details: crate::drop::ErrorDetails::default(), }); } } } } db.compile(&mut errors); let drop = if errors.is_empty() { crate::drop::Drop::success() } else { crate::drop::Drop::with_errors(errors) }; (db, drop) } /// Override the default executor for unit testing pub fn with_executor(mut self, executor: Box) -> Self { self.executor = executor; self } /// Executes a query expecting a single JSONB array return, representing rows. pub fn query(&self, sql: &str, args: Option>) -> Result { self.executor.query(sql, args) } /// Executes an operation (INSERT, UPDATE, DELETE, or pg_notify) that does not return rows. pub fn execute(&self, sql: &str, args: Option>) -> Result<(), String> { self.executor.execute(sql, args) } /// Returns the current authenticated user's ID pub fn auth_user_id(&self) -> Result { self.executor.auth_user_id() } /// Returns the current transaction timestamp pub fn timestamp(&self) -> Result { self.executor.timestamp() } pub fn compile(&mut self, errors: &mut Vec) { let mut harvested = Vec::new(); for schema_arc in self.schemas.values_mut() { if let Some(s) = std::sync::Arc::get_mut(schema_arc) { s.collect_schemas(None, &mut harvested, errors); } } for (id, schema) in harvested { self.schemas.insert(id, Arc::new(schema)); } self.collect_schemas(errors); // Mathematically evaluate all property inheritances, formats, schemas, and foreign key edges topographically over OnceLocks let mut visited = std::collections::HashSet::new(); for schema_arc in self.schemas.values() { schema_arc.as_ref().compile(self, &mut visited, errors); } } fn collect_schemas(&mut self, errors: &mut Vec) { let mut to_insert = Vec::new(); // Pass 1: Extract all Schemas structurally off top level definitions into the master registry. // Validate every node recursively via string filters natively! for type_def in self.types.values() { for mut schema in type_def.schemas.clone() { schema.collect_schemas(None, &mut to_insert, errors); } } for punc_def in self.puncs.values() { for mut schema in punc_def.schemas.clone() { schema.collect_schemas(None, &mut to_insert, errors); } } for enum_def in self.enums.values() { for mut schema in enum_def.schemas.clone() { schema.collect_schemas(None, &mut to_insert, errors); } } for (id, schema) in to_insert { self.schemas.insert(id, Arc::new(schema)); } } /// Inspects the Postgres pg_constraint relations catalog to securely identify /// the precise Foreign Key connecting a parent and child hierarchy path. pub fn resolve_relation<'a>( &'a self, parent_type: &str, child_type: &str, prop_name: &str, relative_keys: Option<&Vec>, is_array: bool, schema_id: Option<&str>, path: &str, errors: &mut Vec, ) -> Option<(&'a crate::database::relation::Relation, bool)> { // Enforce graph locality by ensuring we don't accidentally crawl to pure structural entity boundaries if parent_type == "entity" && child_type == "entity" { return None; } let p_def = self.types.get(parent_type)?; let c_def = self.types.get(child_type)?; let mut matching_rels = Vec::new(); let mut directions = Vec::new(); // Scour the complete catalog for any Edge matching the inheritance scope of the two objects // This automatically binds polymorphic structures (e.g. recognizing a relationship targeting User // also natively binds instances specifically typed as Person). let mut all_rels: Vec<&crate::database::relation::Relation> = self.relations.values().collect(); all_rels.sort_by(|a, b| a.constraint.cmp(&b.constraint)); for rel in all_rels { let mut is_forward = p_def.hierarchy.contains(&rel.source_type) && c_def.hierarchy.contains(&rel.destination_type); let is_reverse = p_def.hierarchy.contains(&rel.destination_type) && c_def.hierarchy.contains(&rel.source_type); // Structural Cardinality Filtration: // If the schema requires a collection (Array), it is mathematically impossible for a pure // Forward scalar edge (where the parent holds exactly one UUID pointer) to fulfill a One-to-Many request. // Thus, if it's an array, we fully reject pure Forward edges and only accept Reverse edges (or Junction edges). if is_array && is_forward && !is_reverse { is_forward = false; } if is_forward { matching_rels.push(rel); directions.push(true); } else if is_reverse { matching_rels.push(rel); directions.push(false); } } // Abort relation discovery early if no hierarchical inheritance match was found if matching_rels.is_empty() { let mut details = crate::drop::ErrorDetails { path: path.to_string(), ..Default::default() }; if let Some(sid) = schema_id { details.schema = Some(sid.to_string()); } errors.push(crate::drop::Error { code: "EDGE_MISSING".to_string(), message: format!( "No database relation exists between '{}' and '{}' for property '{}'", parent_type, child_type, prop_name ), details, }); return None; } // Ideal State: The objects only share a solitary structural relation, resolving ambiguity instantly. if matching_rels.len() == 1 { return Some((matching_rels[0], directions[0])); } let mut chosen_idx = 0; let mut resolved = false; // Exact Prefix Disambiguation: Determine if the database specifically names this constraint // directly mapping to the JSON Schema property name (e.g., `fk_{child}_{property_name}`) for (i, rel) in matching_rels.iter().enumerate() { if let Some(prefix) = &rel.prefix { if prop_name.starts_with(prefix) || prefix.starts_with(prop_name) || prefix.replace("_", "") == prop_name.replace("_", "") { chosen_idx = i; resolved = true; break; } } } // Complex Subgraph Resolution: The database contains multiple equally explicit foreign key constraints // linking these objects (such as pointing to `source` and `target` in Many-to-Many junction models). if !resolved && relative_keys.is_some() { // Twin Deduction Pass 1: We inspect the exact properties structurally defined inside the compiled payload // to observe which explicit relation arrow the child payload natively consumes. let keys = relative_keys.unwrap(); let mut consumed_rel_idx = None; for (i, rel) in matching_rels.iter().enumerate() { if let Some(prefix) = &rel.prefix { if keys.contains(prefix) { consumed_rel_idx = Some(i); break; // Found the routing edge explicitly consumed by the schema payload } } } // Twin Deduction Pass 2: Knowing which arrow points outbound, we can mathematically deduce its twin // providing the reverse ownership on the same junction boundary must be the incoming Edge to the parent. if let Some(used_idx) = consumed_rel_idx { let used_rel = matching_rels[used_idx]; let mut twin_ids = Vec::new(); for (i, rel) in matching_rels.iter().enumerate() { if i != used_idx && rel.source_type == used_rel.source_type && rel.destination_type == used_rel.destination_type && rel.prefix.is_some() { twin_ids.push(i); } } if twin_ids.len() == 1 { chosen_idx = twin_ids[0]; resolved = true; } } } // Implicit Base Fallback: If no complex explicit paths resolve, but exactly one relation // sits entirely naked (without a constraint prefix), it must be the core structural parent ownership. if !resolved { let mut null_prefix_ids = Vec::new(); for (i, rel) in matching_rels.iter().enumerate() { if rel.prefix.is_none() { null_prefix_ids.push(i); } } if null_prefix_ids.len() == 1 { chosen_idx = null_prefix_ids[0]; resolved = true; } } // If we exhausted all mathematical deduction pathways and STILL cannot isolate a single edge, // we must abort rather than silently guessing. Returning None prevents arbitrary SQL generation // and forces a clean structural error for the architect. if !resolved { let mut details = crate::drop::ErrorDetails { path: path.to_string(), context: serde_json::to_value(&matching_rels).ok(), cause: Some("Multiple conflicting constraints found matching prefixes".to_string()), ..Default::default() }; if let Some(sid) = schema_id { details.schema = Some(sid.to_string()); } errors.push(crate::drop::Error { code: "AMBIGUOUS_TYPE_RELATIONS".to_string(), message: format!( "Ambiguous database relation between '{}' and '{}' for property '{}'", parent_type, child_type, prop_name ), details, }); return None; } Some((matching_rels[chosen_idx], directions[chosen_idx])) } }