1use oxirs_core::OxirsError;
199use serde::{Deserialize, Serialize};
200use thiserror::Error;
201use tracing::{debug, info, span, Level};
202
203pub mod adaptive_query_optimizer;
204pub mod advanced_query;
205pub mod annotation_aggregation;
206pub mod annotation_lifecycle;
207pub mod annotation_paths;
208pub mod annotation_profile;
209pub mod annotations;
210pub mod backup_restore;
211pub mod bloom_filter;
212pub mod cache;
213pub mod cli;
214pub mod cluster_scaling;
215pub mod compact_annotation_storage;
216pub mod compatibility;
217pub mod compliance;
218pub mod compliance_reporting;
219pub mod cryptographic_provenance;
220pub mod distributed;
221pub mod docs;
222pub mod enhanced_errors;
223pub mod execution;
224pub mod functions;
225pub mod governance;
226pub mod gpu_acceleration;
227pub mod graph_diff;
228pub mod graphql_star;
229pub mod hdt_star;
230pub mod index;
231pub mod jit_query_engine;
232pub mod kg_embeddings;
233pub mod lsm_annotation_store;
234pub mod materialized_views;
235pub mod memory_efficient_store;
236pub mod migration_tools;
237pub mod ml_embedding_pipeline;
238pub mod ml_sparql_optimizer;
239pub mod model;
240pub mod monitoring;
241pub mod parallel_query;
242pub mod parser;
243pub mod production;
244pub mod profiling;
245pub mod property_graph_bridge;
246pub mod quantum_sparql_optimizer;
247pub mod query;
248pub mod query_optimizer;
249pub mod quoted_graph;
250pub mod rdf_star_formats;
251pub mod reasoning;
252pub mod reification;
253pub mod reification_bridge;
254pub mod security_audit;
255pub mod semantics;
256pub mod serialization;
257pub mod serializer;
258pub mod shacl_star;
259pub mod sparql;
260pub mod sparql_enhanced;
261pub mod sparql_star_bind_values;
262pub mod sparql_star_extended;
263pub mod storage;
264pub mod storage_integration;
265pub mod store;
266pub mod streaming_query;
267pub mod temporal_versioning;
268pub mod testing_utilities;
269pub mod tiered_storage;
270pub mod troubleshooting;
271pub mod trust_scoring;
272pub mod validation_framework;
273pub mod w3c_compliance;
274pub mod reification_mapper;
276pub mod write_ahead_log;
277
278pub mod triple_reifier;
280
281pub mod provenance_tracker;
283
284pub mod rdf_patch;
286
287pub mod quoted_triple_store;
289
290pub mod annotation_graph;
292
293pub mod rdf_star_serializer;
295
296pub mod star_pattern_matcher;
298
299pub mod star_normalizer;
301
302pub mod star_query_rewriter;
304
305pub mod triple_diff;
308
309pub mod star_statistics;
311
312pub mod graph_merger;
314
315pub use enhanced_errors::{
317 EnhancedError, EnhancedResult, ErrorAggregator, ErrorCategory, ErrorContext, ErrorSeverity,
318 WithErrorContext,
319};
320pub use model::*;
321pub use store::StarStore;
322pub use troubleshooting::{DiagnosticAnalyzer, MigrationAssistant, TroubleshootingGuide};
323
324#[derive(Debug, Error)]
326#[error("Parse error: {message}")]
327pub struct ParseErrorDetails {
328 pub message: String,
329 pub line: Option<usize>,
330 pub column: Option<usize>,
331 pub input_fragment: Option<String>,
332 pub expected: Option<String>,
333 pub suggestion: Option<String>,
334}
335
336#[derive(Debug, Error)]
338pub enum StarError {
339 #[error("Invalid quoted triple: {message}")]
340 InvalidQuotedTriple {
341 message: String,
342 context: Option<String>,
343 suggestion: Option<String>,
344 },
345 #[error("Parse error in RDF-star format: {0}")]
346 ParseError(#[from] Box<ParseErrorDetails>),
347 #[error("Serialization error: {message}")]
348 SerializationError {
349 message: String,
350 format: Option<String>,
351 context: Option<String>,
352 },
353 #[error("SPARQL-star query error: {message}")]
354 QueryError {
355 message: String,
356 query_fragment: Option<String>,
357 position: Option<usize>,
358 suggestion: Option<String>,
359 },
360 #[error("Core RDF error: {0}")]
361 CoreError(#[from] OxirsError),
362 #[error("Reification error: {message}")]
363 ReificationError {
364 message: String,
365 reification_strategy: Option<String>,
366 context: Option<String>,
367 },
368 #[error("Invalid term type for RDF-star context: {message}")]
369 InvalidTermType {
370 message: String,
371 term_type: Option<String>,
372 expected_types: Option<Vec<String>>,
373 suggestion: Option<String>,
374 },
375 #[error("Nesting depth exceeded: maximum depth {max_depth} reached")]
376 NestingDepthExceeded {
377 max_depth: usize,
378 current_depth: usize,
379 context: Option<String>,
380 },
381 #[error("Format not supported: {format}")]
382 UnsupportedFormat {
383 format: String,
384 available_formats: Vec<String>,
385 },
386 #[error("Configuration error: {message}")]
387 ConfigurationError {
388 message: String,
389 parameter: Option<String>,
390 valid_range: Option<String>,
391 },
392 #[error("Internal error: {message}")]
393 InternalError {
394 message: String,
395 context: Option<String>,
396 },
397}
398
399pub type StarResult<T> = std::result::Result<T, StarError>;
401
402impl StarError {
403 pub fn invalid_quoted_triple(message: impl Into<String>) -> Self {
405 Self::InvalidQuotedTriple {
406 message: message.into(),
407 context: None,
408 suggestion: None,
409 }
410 }
411
412 pub fn parse_error(message: impl Into<String>) -> Self {
414 Self::ParseError(Box::new(ParseErrorDetails {
415 message: message.into(),
416 line: None,
417 column: None,
418 input_fragment: None,
419 expected: None,
420 suggestion: None,
421 }))
422 }
423
424 pub fn serialization_error(message: impl Into<String>) -> Self {
426 Self::SerializationError {
427 message: message.into(),
428 format: None,
429 context: None,
430 }
431 }
432
433 pub fn query_error(message: impl Into<String>) -> Self {
435 Self::QueryError {
436 message: message.into(),
437 query_fragment: None,
438 position: None,
439 suggestion: None,
440 }
441 }
442
443 pub fn reification_error(message: impl Into<String>) -> Self {
445 Self::ReificationError {
446 message: message.into(),
447 reification_strategy: None,
448 context: None,
449 }
450 }
451
452 pub fn invalid_term_type(message: impl Into<String>) -> Self {
454 Self::InvalidTermType {
455 message: message.into(),
456 term_type: None,
457 expected_types: None,
458 suggestion: None,
459 }
460 }
461
462 pub fn nesting_depth_exceeded(
464 max_depth: usize,
465 current_depth: usize,
466 context: Option<String>,
467 ) -> Self {
468 Self::NestingDepthExceeded {
469 max_depth,
470 current_depth,
471 context,
472 }
473 }
474
475 pub fn configuration_error(message: impl Into<String>) -> Self {
477 Self::ConfigurationError {
478 message: message.into(),
479 parameter: None,
480 valid_range: None,
481 }
482 }
483
484 pub fn internal_error(message: impl Into<String>) -> Self {
486 Self::InternalError {
487 message: message.into(),
488 context: None,
489 }
490 }
491
492 pub fn lock_error(context: impl Into<String>) -> Self {
494 Self::InternalError {
495 message: "Lock poisoned".to_string(),
496 context: Some(context.into()),
497 }
498 }
499
500 pub fn unsupported_format(format: impl Into<String>, available: Vec<String>) -> Self {
502 Self::UnsupportedFormat {
503 format: format.into(),
504 available_formats: available,
505 }
506 }
507
508 pub fn recovery_suggestions(&self) -> Vec<String> {
510 let mut suggestions = Vec::new();
511
512 match self {
513 Self::NestingDepthExceeded { max_depth, .. } => {
514 suggestions.push(format!(
515 "Consider increasing max_nesting_depth beyond {max_depth}"
516 ));
517 suggestions.push("Check for circular references in quoted triples".to_string());
518 }
519 Self::UnsupportedFormat {
520 available_formats, ..
521 } => {
522 suggestions.push(format!(
523 "Supported formats: {}",
524 available_formats.join(", ")
525 ));
526 }
527 Self::ConfigurationError {
528 valid_range: Some(range),
529 ..
530 } => {
531 suggestions.push(format!("Valid range: {range}"));
532 }
533 Self::ConfigurationError {
534 valid_range: None, ..
535 } => {}
536 _ => {}
537 }
538
539 suggestions
540 }
541
542 pub fn resource_error(message: impl Into<String>) -> Self {
544 Self::ConfigurationError {
545 message: message.into(),
546 parameter: Some("resource".to_string()),
547 valid_range: None,
548 }
549 }
550
551 pub fn processing_error(message: impl Into<String>) -> Self {
553 Self::ConfigurationError {
554 message: message.into(),
555 parameter: Some("processing".to_string()),
556 valid_range: None,
557 }
558 }
559}
560
561#[derive(Debug, Clone, Serialize, Deserialize)]
563pub struct StarConfig {
564 pub max_nesting_depth: usize,
566 pub enable_reification_fallback: bool,
568 pub strict_mode: bool,
570 pub enable_sparql_star: bool,
572 pub buffer_size: usize,
574 pub max_parse_errors: Option<usize>,
576}
577
578impl Default for StarConfig {
579 fn default() -> Self {
580 Self {
581 max_nesting_depth: 10,
582 enable_reification_fallback: true,
583 strict_mode: false,
584 enable_sparql_star: true,
585 buffer_size: 8192,
586 max_parse_errors: Some(100),
587 }
588 }
589}
590
591#[derive(Debug, Clone, Default, Serialize, Deserialize)]
593pub struct StarStatistics {
594 pub quoted_triples_count: usize,
596 pub max_nesting_encountered: usize,
598 pub reified_triples_count: usize,
600 pub sparql_star_queries_count: usize,
602 pub processing_time_us: u64,
604}
605
606pub fn init_star_system(config: StarConfig) -> StarResult<()> {
608 let span = span!(Level::INFO, "init_star_system");
609 let _enter = span.enter();
610
611 info!("Initializing OxiRS RDF-star system");
612 debug!("Configuration: {:?}", config);
613
614 if config.max_nesting_depth == 0 {
616 return Err(StarError::ConfigurationError {
617 message: "Max nesting depth must be greater than 0".to_string(),
618 parameter: Some("max_nesting_depth".to_string()),
619 valid_range: Some("1..=1000".to_string()),
620 });
621 }
622
623 if config.buffer_size == 0 {
624 return Err(StarError::ConfigurationError {
625 message: "Buffer size must be greater than 0".to_string(),
626 parameter: Some("buffer_size".to_string()),
627 valid_range: Some("1..=1048576".to_string()),
628 });
629 }
630
631 if config.max_nesting_depth > 1000 {
633 return Err(StarError::ConfigurationError {
634 message: "Max nesting depth is too large and may cause performance issues".to_string(),
635 parameter: Some("max_nesting_depth".to_string()),
636 valid_range: Some("1..=1000".to_string()),
637 });
638 }
639
640 info!("RDF-star system initialized successfully");
641 Ok(())
642}
643
644pub fn validate_nesting_depth(term: &StarTerm, max_depth: usize) -> StarResult<()> {
646 fn check_depth(term: &StarTerm, current_depth: usize, max_depth: usize) -> StarResult<usize> {
647 match term {
648 StarTerm::QuotedTriple(triple) => {
649 if current_depth >= max_depth {
650 return Err(StarError::InvalidQuotedTriple {
651 message: format!(
652 "Nesting depth {current_depth} exceeds maximum {max_depth}"
653 ),
654 context: None,
655 suggestion: None,
656 });
657 }
658
659 let subj_depth = check_depth(&triple.subject, current_depth + 1, max_depth)?;
660 let pred_depth = check_depth(&triple.predicate, current_depth + 1, max_depth)?;
661 let obj_depth = check_depth(&triple.object, current_depth + 1, max_depth)?;
662
663 Ok(subj_depth.max(pred_depth).max(obj_depth))
664 }
665 _ => Ok(current_depth),
666 }
667 }
668
669 check_depth(term, 0, max_depth)?;
670 Ok(())
671}
672
673pub const VERSION: &str = env!("CARGO_PKG_VERSION");
675
676pub mod dev_tools {
711 use super::*;
712 use std::collections::HashMap;
713
714 #[derive(Debug, Clone, PartialEq)]
716 pub enum DetectedFormat {
717 TurtleStar,
718 NTriplesStar,
719 TrigStar,
720 NQuadsStar,
721 Unknown,
722 }
723
724 pub fn detect_format(content: &str) -> DetectedFormat {
726 let content = content.trim();
727
728 if content.contains("GRAPH") || content.contains("{") && content.contains("}") {
730 return DetectedFormat::TrigStar;
731 }
732
733 let lines: Vec<&str> = content
735 .lines()
736 .filter(|line| !line.trim().is_empty() && !line.trim().starts_with('#'))
737 .collect();
738 if !lines.is_empty() {
739 let first_line = lines[0].trim();
740 let terms: Vec<&str> = first_line.split_whitespace().collect();
741 if terms.len() >= 4 && first_line.ends_with('.') {
742 return DetectedFormat::NQuadsStar;
743 }
744 }
745
746 if content.contains("<<") && content.contains(">>") {
748 if content.contains("@prefix") || content.contains("PREFIX") {
750 return DetectedFormat::TurtleStar;
751 }
752 return DetectedFormat::NTriplesStar;
754 }
755
756 if content.contains("@prefix") || content.contains("@base") {
758 return DetectedFormat::TurtleStar;
759 }
760
761 DetectedFormat::Unknown
762 }
763
764 pub fn validate_content(content: &str, config: &StarConfig) -> ValidationResult {
766 let mut result = ValidationResult::new();
767
768 result.detected_format = detect_format(content);
770
771 let quoted_count = content.matches("<<").count();
773 result.quoted_triple_count = quoted_count;
774
775 if quoted_count > 10000 && !config.enable_reification_fallback {
777 result.warnings.push("Large number of quoted triples detected. Consider enabling reification fallback for better performance.".to_string());
778 }
779
780 let max_nesting = find_max_nesting_depth(content);
782 result.max_nesting_depth = max_nesting;
783
784 if max_nesting > config.max_nesting_depth {
785 result.errors.push(format!(
786 "Nesting depth {} exceeds configured maximum {}",
787 max_nesting, config.max_nesting_depth
788 ));
789 }
790
791 check_syntax_issues(content, &mut result);
793
794 result
795 }
796
797 #[derive(Debug, Clone)]
799 pub struct ValidationResult {
800 pub detected_format: DetectedFormat,
801 pub quoted_triple_count: usize,
802 pub max_nesting_depth: usize,
803 pub errors: Vec<String>,
804 pub warnings: Vec<String>,
805 pub suggestions: Vec<String>,
806 pub line_errors: HashMap<u32, String>,
807 }
808
809 impl ValidationResult {
810 fn new() -> Self {
811 Self {
812 detected_format: DetectedFormat::Unknown,
813 quoted_triple_count: 0,
814 max_nesting_depth: 0,
815 errors: Vec::new(),
816 warnings: Vec::new(),
817 suggestions: Vec::new(),
818 line_errors: HashMap::new(),
819 }
820 }
821
822 pub fn is_valid(&self) -> bool {
824 self.errors.is_empty()
825 }
826
827 pub fn summary(&self) -> String {
829 let mut summary = String::new();
830 summary.push_str(&format!("Format: {:?}\n", self.detected_format));
831 summary.push_str(&format!("Quoted triples: {}\n", self.quoted_triple_count));
832 summary.push_str(&format!("Max nesting depth: {}\n", self.max_nesting_depth));
833
834 if !self.errors.is_empty() {
835 summary.push_str(&format!("Errors: {}\n", self.errors.len()));
836 }
837
838 if !self.warnings.is_empty() {
839 summary.push_str(&format!("Warnings: {}\n", self.warnings.len()));
840 }
841
842 summary
843 }
844 }
845
846 fn find_max_nesting_depth(content: &str) -> usize {
847 let mut max_depth: usize = 0;
848 let mut current_depth: i32 = 0;
849
850 for ch in content.chars() {
851 match ch {
852 '<' => {
853 current_depth += 1;
855 }
856 '>' => {
857 current_depth = current_depth.saturating_sub(1);
858 }
859 _ => {}
860 }
861 max_depth = max_depth.max((current_depth / 2).max(0) as usize); }
863
864 max_depth
865 }
866
867 fn check_syntax_issues(content: &str, result: &mut ValidationResult) {
868 let lines: Vec<&str> = content.lines().collect();
869
870 for (line_num, line) in lines.iter().enumerate() {
871 let line_num = line_num as u32 + 1;
872 let trimmed = line.trim();
873
874 if trimmed.is_empty() || trimmed.starts_with('#') {
876 continue;
877 }
878
879 let open_count = trimmed.matches("<<").count();
881 let close_count = trimmed.matches(">>").count();
882
883 if open_count != close_count {
884 result.line_errors.insert(
885 line_num,
886 format!(
887 "Unmatched quoted triple brackets: {open_count} << vs {close_count} >>"
888 ),
889 );
890 }
891
892 if (result.detected_format == DetectedFormat::NTriplesStar
894 || result.detected_format == DetectedFormat::NQuadsStar)
895 && !trimmed.ends_with('.')
896 && !trimmed.starts_with('@')
897 && !trimmed.starts_with("PREFIX")
898 {
899 result.warnings.push(format!(
900 "Line {line_num}: Missing period at end of statement"
901 ));
902 }
903 }
904 }
905
906 pub struct StarProfiler {
908 start_time: std::time::Instant,
909 operation_times: HashMap<String, u64>,
910 }
911
912 impl StarProfiler {
913 pub fn new() -> Self {
914 Self {
915 start_time: std::time::Instant::now(),
916 operation_times: HashMap::new(),
917 }
918 }
919
920 pub fn time_operation<F, R>(&mut self, name: &str, operation: F) -> R
921 where
922 F: FnOnce() -> R,
923 {
924 let start = std::time::Instant::now();
925 let result = operation();
926 let duration = start.elapsed().as_micros() as u64;
927 self.operation_times.insert(name.to_string(), duration);
928 result
929 }
930
931 pub fn get_stats(&self) -> HashMap<String, u64> {
932 self.operation_times.clone()
933 }
934
935 pub fn total_time(&self) -> u64 {
936 self.start_time.elapsed().as_micros() as u64
937 }
938 }
939
940 impl Default for StarProfiler {
941 fn default() -> Self {
942 Self::new()
943 }
944 }
945
946 pub fn generate_diagnostic_report(content: &str, config: &StarConfig) -> String {
948 let validation = validate_content(content, config);
949 let mut report = String::new();
950
951 report.push_str("=== RDF-star Diagnostic Report ===\n\n");
952 report.push_str(&validation.summary());
953
954 if !validation.errors.is_empty() {
955 report.push_str("\nErrors:\n");
956 for (i, error) in validation.errors.iter().enumerate() {
957 report.push_str(&format!(" {}. {}\n", i + 1, error));
958 }
959 }
960
961 if !validation.warnings.is_empty() {
962 report.push_str("\nWarnings:\n");
963 for (i, warning) in validation.warnings.iter().enumerate() {
964 report.push_str(&format!(" {}. {}\n", i + 1, warning));
965 }
966 }
967
968 if !validation.suggestions.is_empty() {
969 report.push_str("\nSuggestions:\n");
970 for (i, suggestion) in validation.suggestions.iter().enumerate() {
971 report.push_str(&format!(" {}. {}\n", i + 1, suggestion));
972 }
973 }
974
975 if !validation.line_errors.is_empty() {
976 report.push_str("\nLine-specific issues:\n");
977 let mut sorted_lines: Vec<_> = validation.line_errors.iter().collect();
978 sorted_lines.sort_by_key(|(line, _)| *line);
979
980 for (line, error) in sorted_lines {
981 report.push_str(&format!(" Line {line}: {error}\n"));
982 }
983 }
984
985 report
986 }
987}
988
989#[cfg(test)]
990mod tests {
991 use super::*;
992
993 #[test]
994 fn test_config_default() {
995 let config = StarConfig::default();
996 assert_eq!(config.max_nesting_depth, 10);
997 assert!(config.enable_reification_fallback);
998 assert!(!config.strict_mode);
999 assert!(config.enable_sparql_star);
1000 }
1001
1002 #[test]
1003 fn test_nesting_depth_validation() {
1004 let simple_term = StarTerm::iri("http://example.org/test").unwrap();
1005 assert!(validate_nesting_depth(&simple_term, 5).is_ok());
1006
1007 let inner_triple = StarTriple::new(
1009 StarTerm::iri("http://example.org/s").unwrap(),
1010 StarTerm::iri("http://example.org/p").unwrap(),
1011 StarTerm::iri("http://example.org/o").unwrap(),
1012 );
1013 let nested_term = StarTerm::quoted_triple(inner_triple);
1014 assert!(validate_nesting_depth(&nested_term, 5).is_ok());
1015 assert!(validate_nesting_depth(&nested_term, 0).is_err());
1016 }
1017}