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