graphrag_core/graph/incremental/
mod.rs1mod helpers;
30mod manager;
31mod store;
32mod types;
33
34pub use helpers::*;
35pub use manager::*;
36pub use store::*;
37pub use types::*;
38
39#[cfg(test)]
43#[allow(unused_imports)]
44use {
45 crate::core::{Entity, EntityId, KnowledgeGraph, Relationship},
46 chrono::Utc,
47 std::collections::{HashMap, HashSet},
48 std::sync::Arc,
49 std::time::Duration,
50};
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn test_update_id_generation() {
58 let id1 = UpdateId::new();
59 let id2 = UpdateId::new();
60 assert_ne!(id1.as_str(), id2.as_str());
61 }
62
63 #[test]
64 fn test_transaction_id_generation() {
65 let tx1 = TransactionId::new();
66 let tx2 = TransactionId::new();
67 assert_ne!(tx1.as_str(), tx2.as_str());
68 }
69
70 #[test]
71 fn test_change_record_creation() {
72 let entity = Entity::new(
73 EntityId::new("test".to_string()),
74 "Test Entity".to_string(),
75 "Person".to_string(),
76 0.9,
77 );
78
79 let config = IncrementalConfig::default();
80 let graph = KnowledgeGraph::new();
81 let manager = IncrementalGraphManager::new(graph, config);
82
83 let change = manager.create_change_record(
84 ChangeType::EntityAdded,
85 Operation::Insert,
86 ChangeData::Entity(entity.clone()),
87 Some(entity.id.clone()),
88 None,
89 );
90
91 assert_eq!(change.change_type, ChangeType::EntityAdded);
92 assert_eq!(change.operation, Operation::Insert);
93 assert_eq!(change.entity_id, Some(entity.id));
94 }
95
96 #[test]
97 fn test_conflict_resolver_creation() {
98 let resolver = ConflictResolver::new(ConflictStrategy::KeepExisting);
99 assert!(matches!(resolver.strategy, ConflictStrategy::KeepExisting));
100 }
101
102 #[test]
103 fn test_incremental_config_default() {
104 let config = IncrementalConfig::default();
105 assert_eq!(config.max_change_log_size, 10000);
106 assert_eq!(config.batch_size, 100);
107 assert!(config.enable_monitoring);
108 }
109
110 #[test]
111 fn test_statistics_creation() {
112 let stats = IncrementalStatistics::empty();
113 assert_eq!(stats.total_updates, 0);
114 assert_eq!(stats.entities_added, 0);
115 assert_eq!(stats.average_update_time_ms, 0.0);
116 }
117
118 #[cfg(feature = "incremental")]
119 #[cfg(feature = "incremental")]
120 #[test]
121 fn test_batch_processor_creation() {
122 let processor = BatchProcessor::new(100, Duration::from_millis(500), 10);
123 let metrics = processor.get_metrics();
124 assert_eq!(metrics.total_batches_processed, 0);
125 }
126
127 #[cfg(feature = "incremental")]
128 #[tokio::test]
129 async fn test_selective_invalidation() {
130 let invalidation = SelectiveInvalidation::new();
131
132 let region = CacheRegion {
133 region_id: "test_region".to_string(),
134 entity_ids: [EntityId::new("entity1".to_string())].into_iter().collect(),
135 relationship_types: ["KNOWS".to_string()].into_iter().collect(),
136 document_ids: HashSet::new(),
137 last_modified: Utc::now(),
138 };
139
140 invalidation.register_cache_region(region);
141
142 let entity = Entity::new(
143 EntityId::new("entity1".to_string()),
144 "Entity 1".to_string(),
145 "Person".to_string(),
146 0.9,
147 );
148
149 let ent_id_for_log = entity.id.clone();
150 let change = ChangeRecord {
151 change_id: UpdateId::new(),
152 timestamp: Utc::now(),
153 change_type: ChangeType::EntityUpdated,
154 entity_id: Some(ent_id_for_log),
155 document_id: None,
156 operation: Operation::Update,
157 data: ChangeData::Entity(entity),
158 metadata: HashMap::new(),
159 };
160
161 let strategies = invalidation.invalidate_for_changes(&[change]);
162 assert!(!strategies.is_empty());
163 }
164
165 #[cfg(feature = "incremental")]
166 #[test]
167 fn test_conflict_resolver_merge() {
168 let resolver = ConflictResolver::new(ConflictStrategy::Merge);
169
170 let entity1 = Entity::new(
171 EntityId::new("entity1".to_string()),
172 "Entity 1".to_string(),
173 "Person".to_string(),
174 0.8,
175 );
176
177 let entity2 = Entity::new(
178 EntityId::new("entity1".to_string()),
179 "Entity 1 Updated".to_string(),
180 "Person".to_string(),
181 0.9,
182 );
183
184 let merged = resolver.merge_entities(&entity1, &entity2).unwrap();
185 assert_eq!(merged.confidence, 0.9); assert_eq!(merged.name, "Entity 1 Updated");
187 }
188
189 #[test]
190 fn test_graph_statistics_creation() {
191 let stats = GraphStatistics {
192 node_count: 100,
193 edge_count: 150,
194 average_degree: 3.0,
195 max_degree: 10,
196 connected_components: 1,
197 clustering_coefficient: 0.3,
198 last_updated: Utc::now(),
199 };
200
201 assert_eq!(stats.node_count, 100);
202 assert_eq!(stats.edge_count, 150);
203 }
204
205 #[test]
206 fn test_consistency_report_creation() {
207 let report = ConsistencyReport {
208 is_consistent: true,
209 orphaned_entities: vec![],
210 broken_relationships: vec![],
211 missing_embeddings: vec![],
212 validation_time: Utc::now(),
213 issues_found: 0,
214 };
215
216 assert!(report.is_consistent);
217 assert_eq!(report.issues_found, 0);
218 }
219
220 #[test]
221 fn test_change_event_creation() {
222 let event = ChangeEvent {
223 event_id: UpdateId::new(),
224 event_type: ChangeEventType::EntityUpserted,
225 entity_id: Some(EntityId::new("entity1".to_string())),
226 timestamp: Utc::now(),
227 metadata: HashMap::new(),
228 };
229
230 assert!(matches!(event.event_type, ChangeEventType::EntityUpserted));
231 assert!(event.entity_id.is_some());
232 }
233}