From 776a442374d84b938bda113eb4ac1b55b8c13d67 Mon Sep 17 00:00:00 2001 From: Alex Groleau Date: Fri, 3 Apr 2026 00:29:44 -0400 Subject: [PATCH] added setup strict mode --- src/database/mod.rs | 12 +++++++----- src/database/schema.rs | 24 ++++++++++++++++++++++-- src/jspg.rs | 19 +++++++++++-------- src/lib.rs | 21 ++++++++------------- src/tests/runner.rs | 9 +++++---- 5 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/database/mod.rs b/src/database/mod.rs index fc1aa11..38133a5 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -38,7 +38,7 @@ pub struct Database { } impl Database { - pub fn new(val: &serde_json::Value) -> Result { + pub fn new(val: &serde_json::Value) -> (Self, crate::drop::Drop) { let mut db = Self { enums: HashMap::new(), types: HashMap::new(), @@ -151,10 +151,12 @@ impl Database { } db.compile(&mut errors); - if !errors.is_empty() { - return Err(crate::drop::Drop::with_errors(errors)); - } - Ok(db) + 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 diff --git a/src/database/schema.rs b/src/database/schema.rs index 28b21fb..0865352 100644 --- a/src/database/schema.rs +++ b/src/database/schema.rs @@ -588,6 +588,8 @@ impl Schema { prop_name, Some(&keys_for_ambiguity), is_array, + self.id.as_deref(), + &format!("/{}", prop_name), errors, ) { schema_edges.insert( @@ -617,6 +619,8 @@ pub(crate) fn resolve_relation<'a>( 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 @@ -661,13 +665,21 @@ pub(crate) fn resolve_relation<'a>( // 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: crate::drop::ErrorDetails::default(), + details, }); return None; } @@ -752,13 +764,21 @@ pub(crate) fn resolve_relation<'a>( // 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(), + ..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: crate::drop::ErrorDetails::default(), + details, }); return None; } diff --git a/src/jspg.rs b/src/jspg.rs index fc616fe..59a467a 100644 --- a/src/jspg.rs +++ b/src/jspg.rs @@ -12,18 +12,21 @@ pub struct Jspg { } impl Jspg { - pub fn new(database_val: &serde_json::Value) -> Result { - let database_instance = Database::new(database_val)?; + pub fn new(database_val: &serde_json::Value) -> (Self, crate::drop::Drop) { + let (database_instance, drop) = Database::new(database_val); let database = Arc::new(database_instance); let validator = Validator::new(database.clone()); let queryer = Queryer::new(database.clone()); let merger = Merger::new(database.clone()); - Ok(Self { - database, - validator, - queryer, - merger, - }) + ( + Self { + database, + validator, + queryer, + merger, + }, + drop, + ) } } diff --git a/src/lib.rs b/src/lib.rs index 129f18e..b509c9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,21 +42,16 @@ fn jspg_failure() -> JsonB { #[cfg_attr(not(test), pg_extern(strict))] pub fn jspg_setup(database: JsonB) -> JsonB { - match crate::jspg::Jspg::new(&database.0) { - Ok(new_jspg) => { - let new_arc = Arc::new(new_jspg); + let (new_jspg, drop) = crate::jspg::Jspg::new(&database.0); + let new_arc = Arc::new(new_jspg); - // 3. ATOMIC SWAP - { - let mut lock = GLOBAL_JSPG.write().unwrap(); - *lock = Some(new_arc); - } - - let drop = crate::drop::Drop::success(); - JsonB(serde_json::to_value(drop).unwrap()) - } - Err(drop) => JsonB(serde_json::to_value(drop).unwrap()), + // 3. ATOMIC SWAP + { + let mut lock = GLOBAL_JSPG.write().unwrap(); + *lock = Some(new_arc); } + + JsonB(serde_json::to_value(drop).unwrap()) } #[cfg_attr(not(test), pg_extern)] diff --git a/src/tests/runner.rs b/src/tests/runner.rs index c64c683..5d68d04 100644 --- a/src/tests/runner.rs +++ b/src/tests/runner.rs @@ -42,10 +42,11 @@ fn get_cached_file(path: &str) -> CompiledSuite { let mut compiled_suites = Vec::new(); for suite in suites { - let db_result = crate::database::Database::new(&suite.database); - let compiled_db = match db_result { - Ok(db) => Ok(Arc::new(db)), - Err(drop) => Err(drop), + let (db, drop) = crate::database::Database::new(&suite.database); + let compiled_db = if drop.errors.is_empty() { + Ok(Arc::new(db)) + } else { + Err(drop) }; compiled_suites.push((suite, Arc::new(compiled_db))); }