From 609371c03cb23ccfc7e9e9bb7c6c284b2988e9db Mon Sep 17 00:00:00 2001 From: Alex Groleau Date: Tue, 14 Apr 2026 09:36:04 -0400 Subject: [PATCH] fixed drop errors for database initialization --- src/database/mod.rs | 41 ++++++++++++++++++++++++++++++----------- src/database/schema.rs | 8 ++++---- src/drop.rs | 3 ++- src/lib.rs | 2 +- src/merger/mod.rs | 6 +++--- src/queryer/mod.rs | 8 ++++---- src/tests/mod.rs | 2 +- src/tests/runner.rs | 2 +- src/validator/mod.rs | 6 +++--- 9 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/database/mod.rs b/src/database/mod.rs index 1cc8ec6..e32ed6c 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -60,10 +60,14 @@ impl Database { db.enums.insert(def.name.clone(), def); } Err(e) => { + let name = item.get("name").and_then(|v| v.as_str()).unwrap_or("unknown"); 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(), + message: format!("Failed to parse database enum '{}': {}", name, e), + details: crate::drop::ErrorDetails { + context: Some(serde_json::json!(name)), + ..Default::default() + }, }); } } @@ -77,10 +81,14 @@ impl Database { db.types.insert(def.name.clone(), def); } Err(e) => { + let name = item.get("name").and_then(|v| v.as_str()).unwrap_or("unknown"); 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(), + message: format!("Failed to parse database type '{}': {}", name, e), + details: crate::drop::ErrorDetails { + context: Some(serde_json::json!(name)), + ..Default::default() + }, }); } } @@ -98,10 +106,14 @@ impl Database { } } Err(e) => { + let constraint = item.get("constraint").and_then(|v| v.as_str()).unwrap_or("unknown"); 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(), + message: format!("Failed to parse database relation '{}': {}", constraint, e), + details: crate::drop::ErrorDetails { + context: Some(serde_json::json!(constraint)), + ..Default::default() + }, }); } } @@ -115,10 +127,14 @@ impl Database { db.puncs.insert(def.name.clone(), def); } Err(e) => { + let name = item.get("name").and_then(|v| v.as_str()).unwrap_or("unknown"); 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(), + message: format!("Failed to parse database punc '{}': {}", name, e), + details: crate::drop::ErrorDetails { + context: Some(serde_json::json!(name)), + ..Default::default() + }, }); } } @@ -135,7 +151,10 @@ impl Database { errors.push(crate::drop::Error { code: "DATABASE_SCHEMA_PARSE_FAILED".to_string(), message: format!("Failed to parse database schema key '{}': {}", key, e), - details: crate::drop::ErrorDetails::default(), + details: crate::drop::ErrorDetails { + context: Some(serde_json::json!(key)), + ..Default::default() + }, }); } } @@ -282,7 +301,7 @@ impl Database { // 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(), + path: Some(path.to_string()), ..Default::default() }; if let Some(sid) = schema_id { @@ -381,7 +400,7 @@ impl Database { // and forces a clean structural error for the architect. if !resolved { let mut details = crate::drop::ErrorDetails { - path: path.to_string(), + path: Some(path.to_string()), context: serde_json::to_value(&matching_rels).ok(), cause: Some("Multiple conflicting constraints found matching prefixes".to_string()), ..Default::default() diff --git a/src/database/schema.rs b/src/database/schema.rs index 3d55224..1ba2b62 100644 --- a/src/database/schema.rs +++ b/src/database/schema.rs @@ -103,7 +103,7 @@ impl Schema { types ), details: crate::drop::ErrorDetails { - path: path.clone(), + path: Some(path.clone()), schema: Some(root_id.to_string()), ..Default::default() } @@ -427,7 +427,7 @@ impl Schema { code: "AMBIGUOUS_POLYMORPHISM".to_string(), message: format!("oneOf boundaries must map mathematically unique 'type' or 'kind' discriminators, or strictly contain disjoint primitive types."), details: crate::drop::ErrorDetails { - path: path.to_string(), + path: Some(path.to_string()), schema: Some(root_id.to_string()), ..Default::default() } @@ -449,7 +449,7 @@ impl Schema { code: "POLYMORPHIC_COLLISION".to_string(), message: format!("Polymorphic boundary defines multiple candidates mapped to the identical discriminator value '{}'.", val), details: crate::drop::ErrorDetails { - path: path.to_string(), + path: Some(path.to_string()), schema: Some(root_id.to_string()), ..Default::default() } @@ -491,7 +491,7 @@ impl Schema { c, field_name, id ), details: crate::drop::ErrorDetails { - path: path.to_string(), + path: Some(path.to_string()), schema: Some(root_id.to_string()), ..Default::default() }, diff --git a/src/drop.rs b/src/drop.rs index c6e0b11..3300de7 100644 --- a/src/drop.rs +++ b/src/drop.rs @@ -66,7 +66,8 @@ pub struct Error { #[derive(Debug, Serialize, Deserialize, Clone, Default)] pub struct ErrorDetails { - pub path: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub path: Option, #[serde(skip_serializing_if = "Option::is_none")] pub cause: Option, #[serde(skip_serializing_if = "Option::is_none")] diff --git a/src/lib.rs b/src/lib.rs index b509c9a..cbce7ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ fn jspg_failure() -> JsonB { code: "ENGINE_NOT_INITIALIZED".to_string(), message: "JSPG extension has not been initialized via jspg_setup".to_string(), details: crate::drop::ErrorDetails { - path: "".to_string(), + path: None, cause: None, context: None, schema: None, diff --git a/src/merger/mod.rs b/src/merger/mod.rs index 240cd5f..a6fec9b 100644 --- a/src/merger/mod.rs +++ b/src/merger/mod.rs @@ -31,7 +31,7 @@ impl Merger { code: "MERGE_FAILED".to_string(), message: format!("Unknown schema_id: {}", schema_id), details: crate::drop::ErrorDetails { - path: "".to_string(), + path: None, cause: None, context: Some(data), schema: None, @@ -76,7 +76,7 @@ impl Merger { code: final_code, message: final_message, details: crate::drop::ErrorDetails { - path: "".to_string(), + path: None, cause: final_cause, context: None, schema: None, @@ -92,7 +92,7 @@ impl Merger { code: "MERGE_FAILED".to_string(), message: format!("Executor Error in pre-ordered notify: {:?}", e), details: crate::drop::ErrorDetails { - path: "".to_string(), + path: None, cause: None, context: None, schema: None, diff --git a/src/queryer/mod.rs b/src/queryer/mod.rs index 6fad6bb..755f93a 100644 --- a/src/queryer/mod.rs +++ b/src/queryer/mod.rs @@ -33,7 +33,7 @@ impl Queryer { code: "FILTER_PARSE_FAILED".to_string(), message: msg.clone(), details: crate::drop::ErrorDetails { - path: "".to_string(), // filters apply to the root query + path: None, // filters apply to the root query cause: Some(msg), context: filters.cloned(), schema: Some(schema_id.to_string()), @@ -138,7 +138,7 @@ impl Queryer { code: "QUERY_COMPILATION_FAILED".to_string(), message: e.clone(), details: crate::drop::ErrorDetails { - path: "".to_string(), + path: None, cause: Some(e), context: None, schema: Some(schema_id.to_string()), @@ -165,7 +165,7 @@ impl Queryer { code: "QUERY_FAILED".to_string(), message: format!("Expected array from generic query, got: {:?}", other), details: crate::drop::ErrorDetails { - path: "".to_string(), + path: None, cause: Some(format!("Expected array, got {}", other)), context: Some(serde_json::json!([sql])), schema: Some(schema_id.to_string()), @@ -175,7 +175,7 @@ impl Queryer { code: "QUERY_FAILED".to_string(), message: format!("SPI error in queryer: {}", e), details: crate::drop::ErrorDetails { - path: "".to_string(), + path: None, cause: Some(format!("SPI error in queryer: {}", e)), context: Some(serde_json::json!([sql])), schema: Some(schema_id.to_string()), diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 16a7fc3..dfc959b 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -18,7 +18,7 @@ fn test_library_api() { "errors": [{ "code": "ENGINE_NOT_INITIALIZED", "message": "JSPG extension has not been initialized via jspg_setup", - "details": { "path": "" } + "details": {} }] }) ); diff --git a/src/tests/runner.rs b/src/tests/runner.rs index 5d68d04..87bcf7c 100644 --- a/src/tests/runner.rs +++ b/src/tests/runner.rs @@ -86,7 +86,7 @@ pub fn run_test_case(path: &str, suite_idx: usize, case_idx: usize) -> Result<() let error_messages: Vec = drop .errors .iter() - .map(|e| format!("Error {} at path {}: {}", e.code, e.details.path, e.message)) + .map(|e| format!("Error {} at path {}: {}", e.code, e.details.path.as_deref().unwrap_or("/"), e.message)) .collect(); failures.push(format!( "[{}] Cannot run '{}' test '{}': System Setup Compilation structurally failed:\n{}", diff --git a/src/validator/mod.rs b/src/validator/mod.rs index c7a50a2..b07994d 100644 --- a/src/validator/mod.rs +++ b/src/validator/mod.rs @@ -68,7 +68,7 @@ impl Validator { code: e.code, message: e.message, details: crate::drop::ErrorDetails { - path: e.path, + path: Some(e.path), cause: None, context: None, schema: None, @@ -82,7 +82,7 @@ impl Validator { code: e.code, message: e.message, details: crate::drop::ErrorDetails { - path: e.path, + path: Some(e.path), cause: None, context: None, schema: None, @@ -94,7 +94,7 @@ impl Validator { code: "SCHEMA_NOT_FOUND".to_string(), message: format!("Schema {} not found", schema_id), details: crate::drop::ErrorDetails { - path: "/".to_string(), + path: Some("/".to_string()), cause: None, context: None, schema: None,