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