vectorizer_sdk/
models.rs

1//! Data models for the Vectorizer SDK
2
3use std::collections::HashMap;
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7
8// Re-export hybrid search models
9pub mod hybrid_search;
10pub use hybrid_search::*;
11
12// Re-export graph models
13pub mod graph;
14pub use graph::*;
15
16// Re-export file upload models
17pub mod file_upload;
18pub use file_upload::*;
19
20// ===== CLIENT-SIDE REPLICATION CONFIGURATION =====
21
22/// Read preference for routing read operations.
23/// Similar to MongoDB's read preferences.
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
25#[serde(rename_all = "snake_case")]
26pub enum ReadPreference {
27    /// Route all reads to master
28    Master,
29    /// Route reads to replicas (round-robin)
30    #[default]
31    Replica,
32    /// Route to the node with lowest latency
33    Nearest,
34}
35
36/// Host configuration for master/replica topology.
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct HostConfig {
39    /// Master node URL (receives all write operations)
40    pub master: String,
41    /// Replica node URLs (receive read operations based on read_preference)
42    pub replicas: Vec<String>,
43}
44
45/// Options that can be passed to read operations for per-operation override.
46#[derive(Debug, Clone, Default)]
47pub struct ReadOptions {
48    /// Override the default read preference for this operation
49    pub read_preference: Option<ReadPreference>,
50}
51
52/// Vector similarity metrics
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
54#[serde(rename_all = "snake_case")]
55pub enum SimilarityMetric {
56    /// Cosine similarity
57    #[default]
58    Cosine,
59    /// Euclidean distance
60    Euclidean,
61    /// Dot product
62    DotProduct,
63}
64
65/// Vector representation
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct Vector {
68    /// Unique identifier for the vector
69    pub id: String,
70    /// Vector data as an array of numbers
71    pub data: Vec<f32>,
72    /// Optional metadata associated with the vector
73    pub metadata: Option<HashMap<String, serde_json::Value>>,
74}
75
76/// Collection representation
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct Collection {
79    /// Collection name
80    pub name: String,
81    /// Vector dimension
82    pub dimension: usize,
83    /// Similarity metric used for search (API may return as 'metric')
84    #[serde(alias = "similarity_metric")]
85    pub metric: Option<String>,
86    /// Optional description
87    #[serde(default)]
88    pub description: Option<String>,
89    /// Creation timestamp
90    #[serde(default)]
91    pub created_at: Option<String>,
92    /// Last update timestamp
93    #[serde(default)]
94    pub updated_at: Option<String>,
95    /// Vector count
96    #[serde(default)]
97    pub vector_count: usize,
98    /// Document count
99    #[serde(default)]
100    pub document_count: usize,
101    /// Embedding provider
102    #[serde(default)]
103    pub embedding_provider: Option<String>,
104    /// Indexing status
105    #[serde(default)]
106    pub indexing_status: Option<serde_json::Value>,
107    /// Normalization config
108    #[serde(default)]
109    pub normalization: Option<serde_json::Value>,
110    /// Quantization config
111    #[serde(default)]
112    pub quantization: Option<serde_json::Value>,
113    /// Size info
114    #[serde(default)]
115    pub size: Option<serde_json::Value>,
116}
117
118/// Collection information
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct CollectionInfo {
121    /// Collection name
122    pub name: String,
123    /// Vector dimension
124    pub dimension: usize,
125    /// Similarity metric used for search
126    pub metric: String,
127    /// Number of vectors in the collection
128    #[serde(default)]
129    pub vector_count: usize,
130    /// Number of documents in the collection
131    #[serde(default)]
132    pub document_count: usize,
133    /// Creation timestamp
134    pub created_at: String,
135    /// Last update timestamp
136    pub updated_at: String,
137    /// Indexing status
138    #[serde(default)]
139    pub indexing_status: Option<IndexingStatus>,
140}
141
142/// Indexing status
143#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct IndexingStatus {
145    /// Status
146    pub status: String,
147    /// Progress percentage
148    pub progress: f32,
149    /// Total documents
150    pub total_documents: usize,
151    /// Processed documents
152    pub processed_documents: usize,
153    /// Vector count
154    pub vector_count: usize,
155    /// Estimated time remaining
156    pub estimated_time_remaining: Option<String>,
157    /// Last updated timestamp
158    pub last_updated: String,
159}
160
161/// Search result
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct SearchResult {
164    /// Vector ID
165    pub id: String,
166    /// Similarity score
167    pub score: f32,
168    /// Vector content (if available)
169    pub content: Option<String>,
170    /// Optional metadata
171    pub metadata: Option<HashMap<String, serde_json::Value>>,
172}
173
174/// Search response
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct SearchResponse {
177    /// Search results
178    pub results: Vec<SearchResult>,
179    /// Query time in milliseconds
180    pub query_time_ms: f64,
181}
182
183/// Embedding request
184#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct EmbeddingRequest {
186    /// Text to embed
187    pub text: String,
188    /// Optional model to use for embedding
189    pub model: Option<String>,
190    /// Optional parameters for embedding generation
191    pub parameters: Option<EmbeddingParameters>,
192}
193
194/// Embedding parameters
195#[derive(Debug, Clone, Serialize, Deserialize)]
196pub struct EmbeddingParameters {
197    /// Maximum sequence length
198    pub max_length: Option<usize>,
199    /// Whether to normalize the embedding
200    pub normalize: Option<bool>,
201    /// Optional prefix for the text
202    pub prefix: Option<String>,
203}
204
205/// Embedding response
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct EmbeddingResponse {
208    /// Generated embedding vector
209    pub embedding: Vec<f32>,
210    /// Model used for embedding
211    pub model: String,
212    /// Text that was embedded
213    pub text: String,
214    /// Embedding dimension
215    pub dimension: usize,
216    /// Provider used
217    pub provider: String,
218}
219
220/// Health status
221#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct HealthStatus {
223    /// Service status
224    pub status: String,
225    /// Service version
226    pub version: String,
227    /// Timestamp
228    pub timestamp: String,
229    /// Uptime in seconds
230    pub uptime: Option<u64>,
231    /// Number of collections
232    pub collections: Option<usize>,
233    /// Total number of vectors
234    pub total_vectors: Option<usize>,
235}
236
237/// Collections list response
238#[derive(Debug, Clone, Serialize, Deserialize)]
239pub struct CollectionsResponse {
240    /// List of collections
241    pub collections: Vec<Collection>,
242}
243
244/// Create collection response
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct CreateCollectionResponse {
247    /// Success message
248    pub message: String,
249    /// Collection name
250    pub collection: String,
251}
252
253/// Database statistics
254#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct DatabaseStats {
256    /// Total number of collections
257    pub total_collections: usize,
258    /// Total number of vectors
259    pub total_vectors: usize,
260    /// Total memory estimate in bytes
261    pub total_memory_estimate_bytes: usize,
262    /// Collections information
263    pub collections: Vec<CollectionStats>,
264}
265
266/// Collection statistics
267#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct CollectionStats {
269    /// Collection name
270    pub name: String,
271    /// Number of vectors
272    pub vector_count: usize,
273    /// Vector dimension
274    pub dimension: usize,
275    /// Memory estimate in bytes
276    pub memory_estimate_bytes: usize,
277}
278
279/// Batch text request
280#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct BatchTextRequest {
282    /// Text ID
283    pub id: String,
284    /// Text content
285    pub text: String,
286    /// Optional metadata
287    pub metadata: Option<HashMap<String, String>>,
288}
289
290/// Batch configuration
291#[derive(Debug, Clone, Serialize, Deserialize)]
292pub struct BatchConfig {
293    /// Maximum batch size
294    pub max_batch_size: Option<usize>,
295    /// Number of parallel workers
296    pub parallel_workers: Option<usize>,
297    /// Whether operations should be atomic
298    pub atomic: Option<bool>,
299}
300
301/// Batch insert request
302#[derive(Debug, Clone, Serialize, Deserialize)]
303pub struct BatchInsertRequest {
304    /// Texts to insert
305    pub texts: Vec<BatchTextRequest>,
306    /// Batch configuration
307    pub config: Option<BatchConfig>,
308}
309
310/// Batch response
311#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct BatchResponse {
313    /// Whether the operation was successful
314    pub success: bool,
315    /// Collection name
316    pub collection: String,
317    /// Operation type
318    pub operation: String,
319    /// Total number of operations
320    pub total_operations: usize,
321    /// Number of successful operations
322    pub successful_operations: usize,
323    /// Number of failed operations
324    pub failed_operations: usize,
325    /// Duration in milliseconds
326    pub duration_ms: u64,
327    /// Error messages
328    pub errors: Vec<String>,
329}
330
331/// Batch search query
332#[derive(Debug, Clone, Serialize, Deserialize)]
333pub struct BatchSearchQuery {
334    /// Query text
335    pub query: String,
336    /// Maximum number of results
337    pub limit: Option<usize>,
338    /// Minimum score threshold
339    pub score_threshold: Option<f32>,
340}
341
342/// Batch search request
343#[derive(Debug, Clone, Serialize, Deserialize)]
344pub struct BatchSearchRequest {
345    /// Search queries
346    pub queries: Vec<BatchSearchQuery>,
347    /// Batch configuration
348    pub config: Option<BatchConfig>,
349}
350
351/// Batch search response
352#[derive(Debug, Clone, Serialize, Deserialize)]
353pub struct BatchSearchResponse {
354    /// Whether the operation was successful
355    pub success: bool,
356    /// Collection name
357    pub collection: String,
358    /// Total number of queries
359    pub total_queries: usize,
360    /// Number of successful queries
361    pub successful_queries: usize,
362    /// Number of failed queries
363    pub failed_queries: usize,
364    /// Duration in milliseconds
365    pub duration_ms: u64,
366    /// Search results
367    pub results: Vec<Vec<SearchResult>>,
368    /// Error messages
369    pub errors: Vec<String>,
370}
371
372/// Batch vector update
373#[derive(Debug, Clone, Serialize, Deserialize)]
374pub struct BatchVectorUpdate {
375    /// Vector ID
376    pub id: String,
377    /// New vector data (optional)
378    pub data: Option<Vec<f32>>,
379    /// New metadata (optional)
380    pub metadata: Option<HashMap<String, serde_json::Value>>,
381}
382
383/// Batch update request
384#[derive(Debug, Clone, Serialize, Deserialize)]
385pub struct BatchUpdateRequest {
386    /// Vector updates
387    pub updates: Vec<BatchVectorUpdate>,
388    /// Batch configuration
389    pub config: Option<BatchConfig>,
390}
391
392/// Batch delete request
393#[derive(Debug, Clone, Serialize, Deserialize)]
394pub struct BatchDeleteRequest {
395    /// Vector IDs to delete
396    pub vector_ids: Vec<String>,
397    /// Batch configuration
398    pub config: Option<BatchConfig>,
399}
400
401/// Summarization methods
402#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
403#[serde(rename_all = "snake_case")]
404pub enum SummarizationMethod {
405    /// Extractive summarization
406    #[default]
407    Extractive,
408    /// Keyword summarization
409    Keyword,
410    /// Sentence summarization
411    Sentence,
412    /// Abstractive summarization
413    Abstractive,
414}
415
416/// Summarize text request
417#[derive(Debug, Clone, Serialize, Deserialize)]
418pub struct SummarizeTextRequest {
419    /// Text to summarize
420    pub text: String,
421    /// Summarization method
422    pub method: Option<SummarizationMethod>,
423    /// Maximum summary length
424    pub max_length: Option<usize>,
425    /// Compression ratio
426    pub compression_ratio: Option<f32>,
427    /// Language code
428    pub language: Option<String>,
429}
430
431/// Summarize text response
432#[derive(Debug, Clone, Serialize, Deserialize)]
433pub struct SummarizeTextResponse {
434    /// Summary ID
435    pub summary_id: String,
436    /// Original text
437    pub original_text: String,
438    /// Generated summary
439    pub summary: String,
440    /// Method used
441    pub method: String,
442    /// Original text length
443    pub original_length: usize,
444    /// Summary length
445    pub summary_length: usize,
446    /// Compression ratio
447    pub compression_ratio: f32,
448    /// Language
449    pub language: String,
450    /// Status
451    pub status: String,
452    /// Message
453    pub message: String,
454    /// Metadata
455    pub metadata: HashMap<String, String>,
456}
457
458/// Summarize context request
459#[derive(Debug, Clone, Serialize, Deserialize)]
460pub struct SummarizeContextRequest {
461    /// Context to summarize
462    pub context: String,
463    /// Summarization method
464    pub method: Option<SummarizationMethod>,
465    /// Maximum summary length
466    pub max_length: Option<usize>,
467    /// Compression ratio
468    pub compression_ratio: Option<f32>,
469    /// Language code
470    pub language: Option<String>,
471}
472
473/// Summarize context response
474#[derive(Debug, Clone, Serialize, Deserialize)]
475pub struct SummarizeContextResponse {
476    /// Summary ID
477    pub summary_id: String,
478    /// Original context
479    pub original_context: String,
480    /// Generated summary
481    pub summary: String,
482    /// Method used
483    pub method: String,
484    /// Original context length
485    pub original_length: usize,
486    /// Summary length
487    pub summary_length: usize,
488    /// Compression ratio
489    pub compression_ratio: f32,
490    /// Language
491    pub language: String,
492    /// Status
493    pub status: String,
494    /// Message
495    pub message: String,
496    /// Metadata
497    pub metadata: HashMap<String, String>,
498}
499
500/// Get summary response
501#[derive(Debug, Clone, Serialize, Deserialize)]
502pub struct GetSummaryResponse {
503    /// Summary ID
504    pub summary_id: String,
505    /// Original text
506    pub original_text: String,
507    /// Generated summary
508    pub summary: String,
509    /// Method used
510    pub method: String,
511    /// Original text length
512    pub original_length: usize,
513    /// Summary length
514    pub summary_length: usize,
515    /// Compression ratio
516    pub compression_ratio: f32,
517    /// Language
518    pub language: String,
519    /// Creation timestamp
520    pub created_at: String,
521    /// Metadata
522    pub metadata: HashMap<String, String>,
523    /// Status
524    pub status: String,
525}
526
527/// Summary info
528#[derive(Debug, Clone, Serialize, Deserialize)]
529pub struct SummaryInfo {
530    /// Summary ID
531    pub summary_id: String,
532    /// Method used
533    pub method: String,
534    /// Language
535    pub language: String,
536    /// Original text length
537    pub original_length: usize,
538    /// Summary length
539    pub summary_length: usize,
540    /// Compression ratio
541    pub compression_ratio: f32,
542    /// Creation timestamp
543    pub created_at: String,
544    /// Metadata
545    pub metadata: HashMap<String, String>,
546}
547
548/// List summaries response
549#[derive(Debug, Clone, Serialize, Deserialize)]
550pub struct ListSummariesResponse {
551    /// List of summaries
552    pub summaries: Vec<SummaryInfo>,
553    /// Total count
554    pub total_count: usize,
555    /// Status
556    pub status: String,
557}
558
559/// Indexing progress
560#[derive(Debug, Clone, Serialize, Deserialize)]
561pub struct IndexingProgress {
562    /// Whether indexing is in progress
563    pub is_indexing: bool,
564    /// Overall status
565    pub overall_status: String,
566    /// Collections being indexed
567    pub collections: Vec<CollectionProgress>,
568}
569
570/// Collection progress
571#[derive(Debug, Clone, Serialize, Deserialize)]
572pub struct CollectionProgress {
573    /// Collection name
574    pub collection_name: String,
575    /// Status
576    pub status: String,
577    /// Progress percentage
578    pub progress: f32,
579    /// Vector count
580    pub vector_count: usize,
581    /// Error message if any
582    pub error_message: Option<String>,
583    /// Last updated timestamp
584    pub last_updated: String,
585}
586
587// ===== INTELLIGENT SEARCH MODELS =====
588
589/// Intelligent search request
590#[derive(Debug, Clone, Serialize, Deserialize)]
591pub struct IntelligentSearchRequest {
592    /// Search query
593    pub query: String,
594    /// Collections to search (optional - searches all if not specified)
595    pub collections: Option<Vec<String>>,
596    /// Maximum number of results
597    pub max_results: Option<usize>,
598    /// Enable domain expansion
599    pub domain_expansion: Option<bool>,
600    /// Enable technical focus
601    pub technical_focus: Option<bool>,
602    /// Enable MMR diversification
603    pub mmr_enabled: Option<bool>,
604    /// MMR balance parameter (0.0-1.0)
605    pub mmr_lambda: Option<f32>,
606}
607
608/// Semantic search request
609#[derive(Debug, Clone, Serialize, Deserialize)]
610pub struct SemanticSearchRequest {
611    /// Search query
612    pub query: String,
613    /// Collection to search
614    pub collection: String,
615    /// Maximum number of results
616    pub max_results: Option<usize>,
617    /// Enable semantic reranking
618    pub semantic_reranking: Option<bool>,
619    /// Enable cross-encoder reranking
620    pub cross_encoder_reranking: Option<bool>,
621    /// Minimum similarity threshold
622    pub similarity_threshold: Option<f32>,
623}
624
625/// Contextual search request
626#[derive(Debug, Clone, Serialize, Deserialize)]
627pub struct ContextualSearchRequest {
628    /// Search query
629    pub query: String,
630    /// Collection to search
631    pub collection: String,
632    /// Metadata-based context filters
633    pub context_filters: Option<HashMap<String, serde_json::Value>>,
634    /// Maximum number of results
635    pub max_results: Option<usize>,
636    /// Enable context-aware reranking
637    pub context_reranking: Option<bool>,
638    /// Weight of context factors (0.0-1.0)
639    pub context_weight: Option<f32>,
640}
641
642/// Multi-collection search request
643#[derive(Debug, Clone, Serialize, Deserialize)]
644pub struct MultiCollectionSearchRequest {
645    /// Search query
646    pub query: String,
647    /// Collections to search
648    pub collections: Vec<String>,
649    /// Maximum results per collection
650    pub max_per_collection: Option<usize>,
651    /// Maximum total results
652    pub max_total_results: Option<usize>,
653    /// Enable cross-collection reranking
654    pub cross_collection_reranking: Option<bool>,
655}
656
657/// Intelligent search result
658#[derive(Debug, Clone, Serialize, Deserialize)]
659pub struct IntelligentSearchResult {
660    /// Result ID
661    pub id: String,
662    /// Similarity score
663    pub score: f32,
664    /// Result content
665    pub content: String,
666    /// Metadata
667    pub metadata: Option<HashMap<String, serde_json::Value>>,
668    /// Collection name
669    pub collection: Option<String>,
670    /// Query used for this result
671    pub query_used: Option<String>,
672}
673
674/// Intelligent search response
675#[derive(Debug, Clone, Serialize, Deserialize)]
676pub struct IntelligentSearchResponse {
677    /// Search results
678    pub results: Vec<IntelligentSearchResult>,
679    /// Total number of results found
680    pub total_results: usize,
681    /// Search duration in milliseconds
682    pub duration_ms: u64,
683    /// Queries generated
684    pub queries_generated: Option<Vec<String>>,
685    /// Collections searched
686    pub collections_searched: Option<Vec<String>>,
687    /// Search metadata
688    pub metadata: Option<HashMap<String, serde_json::Value>>,
689}
690
691/// Semantic search response
692#[derive(Debug, Clone, Serialize, Deserialize)]
693pub struct SemanticSearchResponse {
694    /// Search results
695    pub results: Vec<IntelligentSearchResult>,
696    /// Total number of results found
697    pub total_results: usize,
698    /// Search duration in milliseconds
699    pub duration_ms: u64,
700    /// Collection searched
701    pub collection: String,
702    /// Search metadata
703    pub metadata: Option<HashMap<String, serde_json::Value>>,
704}
705
706/// Contextual search response
707#[derive(Debug, Clone, Serialize, Deserialize)]
708pub struct ContextualSearchResponse {
709    /// Search results
710    pub results: Vec<IntelligentSearchResult>,
711    /// Total number of results found
712    pub total_results: usize,
713    /// Search duration in milliseconds
714    pub duration_ms: u64,
715    /// Collection searched
716    pub collection: String,
717    /// Context filters applied
718    pub context_filters: Option<HashMap<String, serde_json::Value>>,
719    /// Search metadata
720    pub metadata: Option<HashMap<String, serde_json::Value>>,
721}
722
723/// Multi-collection search response
724#[derive(Debug, Clone, Serialize, Deserialize)]
725pub struct MultiCollectionSearchResponse {
726    /// Search results
727    pub results: Vec<IntelligentSearchResult>,
728    /// Total number of results found
729    pub total_results: usize,
730    /// Search duration in milliseconds
731    pub duration_ms: u64,
732    /// Collections searched
733    pub collections_searched: Vec<String>,
734    /// Results per collection
735    pub results_per_collection: Option<HashMap<String, usize>>,
736    /// Search metadata
737    pub metadata: Option<HashMap<String, serde_json::Value>>,
738}
739
740// ==================== REPLICATION MODELS ====================
741
742/// Status of a replica node
743#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
744#[serde(rename_all = "PascalCase")]
745pub enum ReplicaStatus {
746    /// Replica is connected and healthy
747    Connected,
748    /// Replica is syncing data
749    Syncing,
750    /// Replica is lagging behind master
751    Lagging,
752    /// Replica is disconnected
753    Disconnected,
754}
755
756/// Information about a replica node
757#[derive(Debug, Clone, Serialize, Deserialize)]
758pub struct ReplicaInfo {
759    /// Unique identifier for the replica
760    pub replica_id: String,
761    /// Hostname or IP address of the replica
762    pub host: String,
763    /// Port number of the replica
764    pub port: u16,
765    /// Current status of the replica
766    pub status: String,
767    /// Timestamp of last heartbeat
768    pub last_heartbeat: DateTime<Utc>,
769    /// Number of operations successfully synced
770    pub operations_synced: u64,
771
772    // Legacy fields (backwards compatible)
773    /// Legacy: Current offset on replica (deprecated, use operations_synced)
774    #[serde(skip_serializing_if = "Option::is_none")]
775    pub offset: Option<u64>,
776    /// Legacy: Lag in operations (deprecated, use status)
777    #[serde(skip_serializing_if = "Option::is_none")]
778    pub lag: Option<u64>,
779}
780
781/// Statistics for replication status
782#[derive(Debug, Clone, Serialize, Deserialize)]
783pub struct ReplicationStats {
784    // New fields (v1.2.0+)
785    /// Role of the node: Master or Replica
786    #[serde(skip_serializing_if = "Option::is_none")]
787    pub role: Option<String>,
788    /// Total bytes sent to replicas (Master only)
789    #[serde(skip_serializing_if = "Option::is_none")]
790    pub bytes_sent: Option<u64>,
791    /// Total bytes received from master (Replica only)
792    #[serde(skip_serializing_if = "Option::is_none")]
793    pub bytes_received: Option<u64>,
794    /// Timestamp of last synchronization
795    #[serde(skip_serializing_if = "Option::is_none")]
796    pub last_sync: Option<DateTime<Utc>>,
797    /// Number of operations pending replication
798    #[serde(skip_serializing_if = "Option::is_none")]
799    pub operations_pending: Option<usize>,
800    /// Size of snapshot data in bytes
801    #[serde(skip_serializing_if = "Option::is_none")]
802    pub snapshot_size: Option<usize>,
803    /// Number of connected replicas (Master only)
804    #[serde(skip_serializing_if = "Option::is_none")]
805    pub connected_replicas: Option<usize>,
806
807    // Legacy fields (backwards compatible - always present)
808    /// Current offset on master node
809    pub master_offset: u64,
810    /// Current offset on replica node
811    pub replica_offset: u64,
812    /// Number of operations behind
813    pub lag_operations: u64,
814    /// Total operations replicated
815    pub total_replicated: u64,
816}
817
818/// Response for replication status endpoint
819#[derive(Debug, Clone, Serialize, Deserialize)]
820pub struct ReplicationStatusResponse {
821    /// Overall status message
822    pub status: String,
823    /// Detailed replication statistics
824    pub stats: ReplicationStats,
825    /// Optional message with additional information
826    #[serde(skip_serializing_if = "Option::is_none")]
827    pub message: Option<String>,
828}
829
830/// Response for listing replicas
831#[derive(Debug, Clone, Serialize, Deserialize)]
832pub struct ReplicaListResponse {
833    /// List of replica nodes
834    pub replicas: Vec<ReplicaInfo>,
835    /// Total count of replicas
836    pub count: usize,
837    /// Status message
838    pub message: String,
839}