leptos_query_rs/devtools/
mod.rs

1use crate::client::{QueryClient, CacheEntry, CacheStats};
2use crate::types::QueryKey;
3use crate::persistence::PersistenceManager;
4use crate::optimistic::{OptimisticManager, OptimisticStats};
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use std::sync::Arc;
8use std::time::{Duration, Instant};
9use parking_lot::RwLock;
10use uuid::Uuid;
11
12/// DevTools configuration
13#[derive(Clone, Debug, Serialize, Deserialize)]
14pub struct DevToolsConfig {
15    /// Whether DevTools are enabled
16    pub enabled: bool,
17    /// Port for the DevTools server (if applicable)
18    pub port: Option<u16>,
19    /// Maximum number of events to keep in history
20    pub max_history: usize,
21    /// Whether to capture performance metrics
22    pub capture_metrics: bool,
23    /// Whether to capture network requests
24    pub capture_network: bool,
25    /// Whether to capture cache operations
26    pub capture_cache: bool,
27}
28
29impl Default for DevToolsConfig {
30    fn default() -> Self {
31        Self {
32            enabled: true,
33            port: Some(3001),
34            max_history: 1000,
35            capture_metrics: true,
36            capture_network: true,
37            capture_cache: true,
38        }
39    }
40}
41
42/// Performance metrics for queries
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct QueryMetrics {
45    /// Query key
46    pub key: QueryKey,
47    /// Total execution time
48    #[serde(with = "duration_serde")]
49    pub total_time: Duration,
50    /// Number of executions
51    pub execution_count: usize,
52    /// Average execution time
53    #[serde(with = "duration_serde")]
54    pub avg_time: Duration,
55    /// Last execution time
56    #[serde(with = "option_instant_serde")]
57    pub last_execution: Option<Instant>,
58    /// Cache hit rate
59    pub cache_hit_rate: f64,
60    /// Error count
61    pub error_count: usize,
62    /// Success count
63    pub success_count: usize,
64    /// Total requests
65    pub total_requests: usize,
66    /// Average response time
67    #[serde(with = "duration_serde")]
68    pub average_response_time: Duration,
69}
70
71impl QueryMetrics {
72    /// Create new metrics for a query
73    pub fn new(key: QueryKey) -> Self {
74        Self {
75            key,
76            total_time: Duration::ZERO,
77            execution_count: 0,
78            avg_time: Duration::ZERO,
79            last_execution: None,
80            cache_hit_rate: 0.0,
81            error_count: 0,
82            success_count: 0,
83            total_requests: 0,
84            average_response_time: Duration::ZERO,
85        }
86    }
87
88    /// Record an execution
89    pub fn record_execution(&mut self, duration: Duration, success: bool) {
90        self.total_time += duration;
91        self.execution_count += 1;
92        self.avg_time = self.total_time / self.execution_count as u32;
93        self.last_execution = Some(Instant::now());
94        self.total_requests += 1;
95        self.average_response_time = self.avg_time;
96        
97        if success {
98            self.success_count += 1;
99        } else {
100            self.error_count += 1;
101        }
102    }
103
104    /// Update cache hit rate
105    pub fn update_cache_hit_rate(&mut self, hits: usize, total: usize) {
106        if total > 0 {
107            self.cache_hit_rate = hits as f64 / total as f64;
108        }
109    }
110}
111
112/// Network request information
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct NetworkRequest {
115    /// Unique request ID
116    pub id: String,
117    /// Query key
118    pub key: QueryKey,
119    /// Request URL
120    pub url: String,
121    /// HTTP method
122    pub method: String,
123    /// Request timestamp
124    #[serde(with = "instant_serde")]
125    pub timestamp: Instant,
126    /// Request duration
127    #[serde(with = "option_duration_serde")]
128    pub duration: Option<Duration>,
129    /// Response status
130    pub status: Option<u16>,
131    /// Error message (if any)
132    pub error: Option<String>,
133    /// Request headers
134    pub headers: HashMap<String, String>,
135    /// Request body
136    pub body: Option<String>,
137    /// Request body size
138    pub body_size: Option<usize>,
139    /// Response body size
140    pub response_size: Option<usize>,
141}
142
143impl NetworkRequest {
144    /// Create a new network request
145    pub fn new(key: QueryKey, url: String, method: String) -> Self {
146        Self {
147            id: Uuid::new_v4().to_string(),
148            key,
149            url,
150            method,
151            timestamp: Instant::now(),
152            duration: None,
153            status: None,
154            error: None,
155            headers: HashMap::new(),
156            body: None,
157            body_size: None,
158            response_size: None,
159        }
160    }
161
162    /// Mark request as completed
163    pub fn complete(&mut self, status: u16, duration: Duration, response_size: Option<usize>) {
164        self.status = Some(status);
165        self.duration = Some(duration);
166        self.response_size = response_size;
167    }
168
169    /// Mark request as failed
170    pub fn fail(&mut self, error: String, duration: Duration) {
171        self.error = Some(error);
172        self.duration = Some(duration);
173    }
174}
175
176/// Cache operation event
177#[derive(Debug, Clone, Serialize, Deserialize)]
178pub enum CacheOperation {
179    /// Cache entry was set
180    Set { key: QueryKey, size: usize, #[serde(with = "instant_serde")] timestamp: Instant },
181    /// Cache entry was retrieved
182    Get { key: QueryKey, hit: bool, #[serde(with = "instant_serde")] timestamp: Instant },
183    /// Cache entry was removed
184    Remove { key: QueryKey, #[serde(with = "instant_serde")] timestamp: Instant },
185    /// Cache was cleared
186    Clear { #[serde(with = "instant_serde")] timestamp: Instant },
187    /// Cache entry expired
188    Expire { key: QueryKey, #[serde(with = "instant_serde")] timestamp: Instant },
189}
190
191/// DevTools event
192#[derive(Debug, Clone, Serialize, Deserialize)]
193pub enum DevToolsEvent {
194    /// Query execution started
195    QueryStart { key: QueryKey, #[serde(with = "instant_serde")] timestamp: Instant },
196    /// Query execution completed
197    QueryComplete { key: QueryKey, success: bool, #[serde(with = "duration_serde")] duration: Duration, #[serde(with = "instant_serde")] timestamp: Instant },
198    /// Cache operation
199    CacheOp { operation: CacheOperation },
200    /// Network request
201    NetworkRequest { request: NetworkRequest },
202    /// Optimistic update
203    OptimisticUpdate { key: QueryKey, update_id: String, #[serde(with = "instant_serde")] timestamp: Instant },
204    /// Optimistic update confirmed
205    OptimisticConfirm { key: QueryKey, update_id: String, #[serde(with = "instant_serde")] timestamp: Instant },
206    /// Optimistic update rolled back
207    OptimisticRollback { key: QueryKey, update_id: String, #[serde(with = "instant_serde")] timestamp: Instant },
208    /// Persistence operation
209    PersistenceOp { operation: String, key: Option<QueryKey>, #[serde(with = "instant_serde")] timestamp: Instant },
210    /// Query error
211    QueryError { key: QueryKey, error: String, #[serde(with = "instant_serde")] timestamp: Instant },
212    /// Cache operation
213    CacheOperation { operation: CacheOperation, #[serde(with = "instant_serde")] timestamp: Instant },
214}
215
216/// DevTools manager
217pub struct DevToolsManager {
218    /// Configuration
219    config: DevToolsConfig,
220    /// Query performance metrics
221    metrics: Arc<RwLock<HashMap<QueryKey, QueryMetrics>>>,
222    /// Network request history
223    network_history: Arc<RwLock<Vec<NetworkRequest>>>,
224    /// Cache operation history
225    cache_history: Arc<RwLock<Vec<CacheOperation>>>,
226    /// Event history
227    event_history: Arc<RwLock<Vec<DevToolsEvent>>>,
228    /// Active queries
229    active_queries: Arc<RwLock<HashMap<QueryKey, Instant>>>,
230}
231
232impl DevToolsManager {
233    /// Create a new DevTools manager
234    pub fn new(config: DevToolsConfig) -> Self {
235        Self {
236            config,
237            metrics: Arc::new(RwLock::new(HashMap::new())),
238            network_history: Arc::new(RwLock::new(Vec::new())),
239            cache_history: Arc::new(RwLock::new(Vec::new())),
240            event_history: Arc::new(RwLock::new(Vec::new())),
241            active_queries: Arc::new(RwLock::new(HashMap::new())),
242        }
243    }
244
245    /// Check if DevTools is enabled
246    pub fn is_enabled(&self) -> bool {
247        self.config.enabled
248    }
249
250    /// Start the DevTools server
251    pub fn start_server(&mut self, address: String) -> Result<DevToolsServer, String> {
252        if !self.config.enabled {
253            return Err("DevTools is not enabled".to_string());
254        }
255
256        // Parse address (e.g., "localhost:3001")
257        let parts: Vec<&str> = address.split(':').collect();
258        if parts.len() != 2 {
259            return Err("Invalid address format. Expected 'host:port'".to_string());
260        }
261
262        let host = parts[0].to_string();
263        let port: u16 = parts[1].parse().map_err(|_| "Invalid port number".to_string())?;
264
265        let manager = Arc::new(DevToolsManager::new(self.config.clone()));
266        let config = DevToolsConfig::default();
267        Ok(DevToolsServer::new(manager, config))
268    }
269
270    /// Record a query execution start
271    pub fn record_query_start(&self, key: &QueryKey) {
272        if !self.config.capture_metrics {
273            return;
274        }
275
276        let mut active = self.active_queries.write();
277        active.insert(key.clone(), Instant::now());
278
279        let event = DevToolsEvent::QueryStart {
280            key: key.clone(),
281            timestamp: Instant::now(),
282        };
283        self.record_event(event);
284    }
285
286    /// Record a query execution completion
287    pub fn record_query_complete(&self, key: &QueryKey, success: bool, duration: Duration) {
288        if !self.config.capture_metrics {
289            return;
290        }
291
292        // Remove from active queries
293        let mut active = self.active_queries.write();
294        active.remove(key);
295
296        // Update metrics
297        let mut metrics = self.metrics.write();
298        let query_metrics = metrics.entry(key.clone()).or_insert_with(|| QueryMetrics::new(key.clone()));
299        query_metrics.record_execution(duration, success);
300
301        let event = DevToolsEvent::QueryComplete {
302            key: key.clone(),
303            success,
304            duration,
305            timestamp: Instant::now(),
306        };
307        self.record_event(event);
308    }
309
310    /// Record a successful query execution (convenience method)
311    pub fn record_query_success(&self, key: &QueryKey, duration: Duration) {
312        self.record_query_complete(key, true, duration);
313    }
314
315    /// Record a query error
316    pub fn record_query_error(&self, key: &QueryKey, error: &crate::retry::QueryError) {
317        if !self.config.capture_metrics {
318            return;
319        }
320
321        // Remove from active queries
322        let mut active = self.active_queries.write();
323        active.remove(key);
324
325        let event = DevToolsEvent::QueryError {
326            key: key.clone(),
327            error: error.to_string(),
328            timestamp: Instant::now(),
329        };
330        self.record_event(event);
331    }
332
333    /// Record a network request
334    pub fn record_network_request(&self, _key: &QueryKey, request: NetworkRequest) {
335        if !self.config.capture_network {
336            return;
337        }
338
339        let mut history = self.network_history.write();
340        history.push(request.clone());
341
342        // Keep only the last N requests
343        if history.len() > self.config.max_history {
344            history.remove(0);
345        }
346
347        let event = DevToolsEvent::NetworkRequest { request };
348        self.record_event(event);
349    }
350
351    /// Record a cache operation
352    pub fn record_cache_operation(&self, operation: CacheOperation, _key: &QueryKey, _data: Option<&impl Serialize>) {
353        if !self.config.capture_cache {
354            return;
355        }
356
357        let mut history = self.cache_history.write();
358        history.push(operation.clone());
359
360        // Keep only the last N operations
361        if history.len() > self.config.max_history {
362            history.remove(0);
363        }
364
365        let event = DevToolsEvent::CacheOperation { operation, timestamp: std::time::Instant::now() };
366        self.record_event(event);
367    }
368
369    /// Record an optimistic update
370    pub fn record_optimistic_update(&self, key: &QueryKey, update_id: &str) {
371        let event = DevToolsEvent::OptimisticUpdate {
372            key: key.clone(),
373            update_id: update_id.to_string(),
374            timestamp: Instant::now(),
375        };
376        self.record_event(event);
377    }
378
379    /// Record an optimistic update confirmation
380    pub fn record_optimistic_confirm(&self, key: &QueryKey, update_id: &str) {
381        let event = DevToolsEvent::OptimisticConfirm {
382            key: key.clone(),
383            update_id: update_id.to_string(),
384            timestamp: Instant::now(),
385        };
386        self.record_event(event);
387    }
388
389    /// Record an optimistic update rollback
390    pub fn record_optimistic_rollback(&self, key: &QueryKey, update_id: &str) {
391        let event = DevToolsEvent::OptimisticRollback {
392            key: key.clone(),
393            update_id: update_id.to_string(),
394            timestamp: Instant::now(),
395        };
396        self.record_event(event);
397    }
398
399    /// Record a persistence operation
400    pub fn record_persistence_operation(&self, operation: &str, key: Option<&QueryKey>) {
401        let event = DevToolsEvent::PersistenceOp {
402            operation: operation.to_string(),
403            key: key.cloned(),
404            timestamp: Instant::now(),
405        };
406        self.record_event(event);
407    }
408
409    /// Record a generic event
410    fn record_event(&self, event: DevToolsEvent) {
411        let mut history = self.event_history.write();
412        history.push(event);
413
414        // Keep only the last N events
415        if history.len() > self.config.max_history {
416            history.remove(0);
417        }
418    }
419
420    /// Get query metrics
421    pub fn get_query_metrics(&self, _key: &QueryKey) -> Option<QueryMetrics> {
422        // For now, return the first metric if any exist
423        let metrics = self.metrics.read();
424        metrics.values().next().cloned()
425    }
426
427    /// Get network request history
428    pub fn get_network_history(&self) -> Vec<NetworkRequest> {
429        let history = self.network_history.read();
430        history.clone()
431    }
432
433    /// Get cache operation history
434    pub fn get_cache_history(&self) -> Vec<CacheOperation> {
435        let history = self.cache_history.read();
436        history.clone()
437    }
438
439    /// Get event history
440    pub fn get_event_history(&self) -> Vec<DevToolsEvent> {
441        let history = self.event_history.read();
442        history.clone()
443    }
444
445    /// Get active queries
446    pub fn get_active_queries(&self) -> Vec<ActiveQuery> {
447        let active = self.active_queries.read();
448        let now = Instant::now();
449        active
450            .iter()
451            .map(|(key, start_time)| ActiveQuery {
452                key: key.clone(),
453                duration: now.duration_since(*start_time),
454            })
455            .collect()
456    }
457
458    /// Get cache statistics
459    pub fn get_cache_stats(&self, client: &QueryClient) -> CacheStats {
460        client.cache_stats()
461    }
462
463    /// Get cache entries
464    pub fn get_cache_entries(&self, client: &QueryClient) -> Vec<(QueryKey, CacheEntry)> {
465        client.get_cache_entries()
466    }
467
468    /// Get optimistic update statistics
469    pub fn get_optimistic_stats(&self, manager: &OptimisticManager<String>) -> OptimisticStats {
470        manager.get_stats()
471    }
472
473    /// Get persistence statistics
474    pub fn get_persistence_stats(&self, manager: &PersistenceManager) -> HashMap<String, usize> {
475        let mut stats = HashMap::new();
476        stats.insert("offline_queue_size".to_string(), manager.get_offline_queue().len());
477        stats.insert("cache_persisted".to_string(), if manager.is_cache_persisted() { 1 } else { 0 });
478        stats
479    }
480
481    /// Clear all history
482    pub fn clear_history(&self) {
483        let mut metrics = self.metrics.write();
484        let mut network = self.network_history.write();
485        let mut cache = self.cache_history.write();
486        let mut events = self.event_history.write();
487        let mut active = self.active_queries.write();
488
489        metrics.clear();
490        network.clear();
491        cache.clear();
492        events.clear();
493        active.clear();
494    }
495
496    /// Export data for external tools
497    pub fn export_data(&self) -> DevToolsExport {
498        DevToolsExport {
499            query_metrics: self.metrics.read().values().cloned().collect(),
500            network_requests: self.get_network_history(),
501            cache_operations: self.get_cache_history(),
502            event_history: self.get_event_history(),
503            active_queries: self.get_active_queries(),
504            timestamp: std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(),
505        }
506    }
507
508    /// Get recent events (last N events)
509    pub fn get_recent_events(&self, count: usize) -> Vec<DevToolsEvent> {
510        let history = self.event_history.read();
511        let start = if history.len() > count {
512            history.len() - count
513        } else {
514            0
515        };
516        history[start..].to_vec()
517    }
518
519    /// Start monitoring (placeholder for real-time monitoring)
520    pub fn start_monitoring(&mut self) {
521        // In a real implementation, this would start a background task
522        // For now, we just ensure monitoring is enabled
523        self.config.enabled = true;
524    }
525
526    /// Stop monitoring
527    pub fn stop_monitoring(&mut self) {
528        // In a real implementation, this would stop the background task
529        // For now, we just disable monitoring
530        self.config.enabled = false;
531    }
532
533    /// Check if monitoring is active
534    pub fn is_monitoring(&self) -> bool {
535        self.config.enabled
536    }
537
538    /// Get performance statistics
539    pub fn get_performance_stats(&self) -> PerformanceStats {
540        let metrics = self.metrics.read();
541        let mut total_queries = 0;
542        let mut total_time = Duration::ZERO;
543        let mut max_time = Duration::ZERO;
544        let mut min_time = Duration::from_secs(u64::MAX);
545
546        for query_metrics in metrics.values() {
547            total_queries += query_metrics.execution_count;
548            total_time += query_metrics.total_time;
549            if query_metrics.total_time > max_time {
550                max_time = query_metrics.total_time;
551            }
552            if query_metrics.total_time < min_time {
553                min_time = query_metrics.total_time;
554            }
555        }
556
557        let average_time = if total_queries > 0 {
558            total_time / total_queries as u32
559        } else {
560            Duration::ZERO
561        };
562
563        PerformanceStats {
564            total_queries,
565            average_response_time: average_time,
566            max_response_time: max_time,
567            min_response_time: if min_time == Duration::from_secs(u64::MAX) { Duration::ZERO } else { min_time },
568        }
569    }
570
571    /// Get error statistics
572    pub fn get_error_stats(&self) -> ErrorStats {
573        let events = self.event_history.read();
574        let mut total_errors = 0;
575        let mut total_events = events.len();
576
577        for event in events.iter() {
578            if matches!(event, DevToolsEvent::QueryError { .. }) {
579                total_errors += 1;
580            }
581        }
582
583        let error_rate = if total_events > 0 {
584            total_errors as f64 / total_events as f64
585        } else {
586            0.0
587        };
588
589        ErrorStats {
590            total_errors,
591            error_rate,
592        }
593    }
594
595    /// Import data from external tools
596    pub fn import_data(&self, data: DevToolsExport) {
597        let mut metrics = self.metrics.write();
598        let mut network = self.network_history.write();
599        let mut cache = self.cache_history.write();
600        let mut events = self.event_history.write();
601
602        // Import metrics
603        for metric in data.query_metrics {
604            metrics.insert(metric.key.clone(), metric);
605        }
606
607        // Import network history
608        network.extend(data.network_requests);
609
610        // Import cache history
611        cache.extend(data.cache_operations);
612
613        // Import event history
614        events.extend(data.event_history);
615    }
616}
617
618/// Active query with duration
619#[derive(Debug, Clone, Serialize, Deserialize)]
620pub struct ActiveQuery {
621    /// Query key
622    pub key: QueryKey,
623    /// Duration since start
624    #[serde(with = "duration_serde")]
625    pub duration: Duration,
626}
627
628/// DevTools data export
629#[derive(Debug, Clone, Serialize, Deserialize)]
630pub struct DevToolsExport {
631    /// Query metrics
632    pub query_metrics: Vec<QueryMetrics>,
633    /// Network request history
634    pub network_requests: Vec<NetworkRequest>,
635    /// Cache operation history
636    pub cache_operations: Vec<CacheOperation>,
637    /// Event history
638    pub event_history: Vec<DevToolsEvent>,
639    /// Active queries
640    pub active_queries: Vec<ActiveQuery>,
641    /// Export timestamp
642    pub timestamp: u64,
643}
644
645/// DevTools server (placeholder for future implementation)
646pub struct DevToolsServer {
647    /// Manager instance
648    #[allow(dead_code)]
649    manager: Arc<DevToolsManager>,
650    /// Server configuration
651    #[allow(dead_code)]
652    config: DevToolsConfig,
653}
654
655impl DevToolsServer {
656    /// Create a new DevTools server
657    pub fn new(manager: Arc<DevToolsManager>, config: DevToolsConfig) -> Self {
658        Self { manager, config }
659    }
660
661    /// Start the DevTools server
662    pub async fn start(&self) -> Result<(), Box<dyn std::error::Error>> {
663        // This would implement an actual HTTP server
664        // For now, just return Ok
665        Ok(())
666    }
667
668    /// Stop the DevTools server
669    pub async fn stop(&self) -> Result<(), Box<dyn std::error::Error>> {
670        Ok(())
671    }
672
673    pub fn port(&self) -> u16 {
674        3001 // Default port
675    }
676
677    pub fn host(&self) -> &str {
678        "localhost" // Default host
679    }
680}
681
682/// Performance statistics
683#[derive(Debug, Clone, Serialize, Deserialize)]
684pub struct PerformanceStats {
685    pub total_queries: usize,
686    pub average_response_time: Duration,
687    pub max_response_time: Duration,
688    pub min_response_time: Duration,
689}
690
691/// Error statistics
692#[derive(Debug, Clone, Serialize, Deserialize)]
693pub struct ErrorStats {
694    pub total_errors: usize,
695    pub error_rate: f64,
696}
697
698#[cfg(test)]
699mod tests {
700    use super::*;
701    use crate::types::QueryKey;
702
703    #[test]
704    fn test_devtools_manager_creation() {
705        let config = DevToolsConfig::default();
706        let manager = DevToolsManager::new(config);
707        
708        let key = QueryKey::new(&["test"]);
709        assert!(manager.get_query_metrics(&key).is_none());
710        assert_eq!(manager.get_network_history().len(), 0);
711        assert_eq!(manager.get_cache_history().len(), 0);
712    }
713
714    #[test]
715    fn test_query_metrics_recording() {
716        let config = DevToolsConfig::default();
717        let manager = DevToolsManager::new(config);
718        
719        let key = QueryKey::from("test");
720        manager.record_query_start(&key);
721        manager.record_query_complete(&key, true, Duration::from_millis(100));
722        
723        let metrics = manager.get_query_metrics(&key);
724        assert!(metrics.is_some());
725        let metrics = metrics.unwrap();
726        assert_eq!(metrics.execution_count, 1);
727        assert_eq!(metrics.success_count, 1);
728    }
729
730    #[test]
731    fn test_network_request_recording() {
732        let config = DevToolsConfig::default();
733        let manager = DevToolsManager::new(config);
734        
735        let key = QueryKey::from("test");
736        let request = NetworkRequest::new(key, "https://api.example.com/data".to_string(), "GET".to_string());
737        let key = QueryKey::new(&["test"]);
738        manager.record_network_request(&key, request);
739        
740        let history = manager.get_network_history();
741        assert_eq!(history.len(), 1);
742        assert_eq!(history[0].method, "GET");
743    }
744
745    #[test]
746    fn test_cache_operation_recording() {
747        let config = DevToolsConfig::default();
748        let manager = DevToolsManager::new(config);
749        
750        let key = QueryKey::from("test");
751        let operation = CacheOperation::Set {
752            key: key.clone(),
753            size: 1024,
754            timestamp: Instant::now(),
755        };
756        let key = QueryKey::new(&["test"]);
757        manager.record_cache_operation(operation, &key, None::<&String>);
758        
759        let history = manager.get_cache_history();
760        assert_eq!(history.len(), 1);
761    }
762
763    #[test]
764    fn test_history_limits() {
765        let mut config = DevToolsConfig::default();
766        config.max_history = 5;
767        let manager = DevToolsManager::new(config);
768        
769        // Add more events than the limit
770        for i in 0..10 {
771            let key = QueryKey::from(format!("test{}", i));
772            manager.record_query_start(&key);
773        }
774        
775        // Should only keep the last 5 events
776        let events = manager.get_event_history();
777        assert_eq!(events.len(), 5);
778    }
779
780    #[test]
781    fn test_export_import() {
782        let config = DevToolsConfig::default();
783        let manager = DevToolsManager::new(config);
784        
785        let key = QueryKey::from("test");
786        manager.record_query_start(&key);
787        manager.record_query_complete(&key, true, Duration::from_millis(100));
788        
789        let export = manager.export_data();
790        assert_eq!(export.query_metrics.len(), 1);
791        
792        // Clear and reimport
793        manager.clear_history();
794        let key = QueryKey::new(&["test"]);
795        assert!(manager.get_query_metrics(&key).is_none());
796        
797        manager.import_data(export);
798        let key = QueryKey::new(&["test"]);
799        assert!(manager.get_query_metrics(&key).is_some());
800    }
801}
802
803/// Serialization helpers for Instant
804mod instant_serde {
805    use serde::{Deserialize, Deserializer, Serialize, Serializer};
806    use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
807
808    pub fn serialize<S>(instant: &Instant, serializer: S) -> Result<S::Ok, S::Error>
809    where
810        S: Serializer,
811    {
812        // Convert Instant to SystemTime for serialization
813        let system_time = SystemTime::now() - instant.elapsed();
814        let duration = system_time.duration_since(UNIX_EPOCH).unwrap_or(Duration::ZERO);
815        duration.serialize(serializer)
816    }
817
818    pub fn deserialize<'de, D>(deserializer: D) -> Result<Instant, D::Error>
819    where
820        D: Deserializer<'de>,
821    {
822        let duration = Duration::deserialize(deserializer)?;
823        let system_time = UNIX_EPOCH + duration;
824        let now = SystemTime::now();
825        let elapsed = now.duration_since(system_time).unwrap_or(Duration::ZERO);
826        Ok(Instant::now() - elapsed)
827    }
828}
829
830/// Serialization helpers for Duration
831mod duration_serde {
832    use serde::{Deserialize, Deserializer, Serialize, Serializer};
833    use std::time::Duration;
834
835    pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
836    where
837        S: Serializer,
838    {
839        duration.as_secs().serialize(serializer)
840    }
841
842    pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
843    where
844        D: Deserializer<'de>,
845    {
846        let secs = u64::deserialize(deserializer)?;
847        Ok(Duration::from_secs(secs))
848    }
849}
850
851/// Serialization helpers for Option<Duration>
852mod option_duration_serde {
853    use serde::{Deserialize, Deserializer, Serialize, Serializer};
854    use std::time::Duration;
855
856    pub fn serialize<S>(duration: &Option<Duration>, serializer: S) -> Result<S::Ok, S::Error>
857    where
858        S: Serializer,
859    {
860        match duration {
861            Some(d) => d.as_secs().serialize(serializer),
862            None => serializer.serialize_none(),
863        }
864    }
865
866    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Duration>, D::Error>
867    where
868        D: Deserializer<'de>,
869    {
870        let secs = Option::<u64>::deserialize(deserializer)?;
871        Ok(secs.map(Duration::from_secs))
872    }
873}
874
875/// Serialization helpers for Option<Instant>
876mod option_instant_serde {
877    use serde::{Deserialize, Deserializer, Serialize, Serializer};
878    use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
879
880    pub fn serialize<S>(instant: &Option<Instant>, serializer: S) -> Result<S::Ok, S::Error>
881    where
882        S: Serializer,
883    {
884        match instant {
885            Some(inst) => {
886                let system_time = SystemTime::now() - inst.elapsed();
887                let duration = system_time.duration_since(UNIX_EPOCH).unwrap_or(Duration::ZERO);
888                duration.serialize(serializer)
889            }
890            None => serializer.serialize_none(),
891        }
892    }
893
894    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Instant>, D::Error>
895    where
896        D: Deserializer<'de>,
897    {
898        let duration = Option::<Duration>::deserialize(deserializer)?;
899        Ok(duration.map(|d| {
900            let system_time = UNIX_EPOCH + d;
901            let now = SystemTime::now();
902            let elapsed = now.duration_since(system_time).unwrap_or(Duration::ZERO);
903            Instant::now() - elapsed
904        }))
905    }
906}