Skip to main content

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    /// Optional ECC public key for payload encryption (PEM, base64, or hex format)
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub public_key: Option<String>,
77}
78
79/// Collection representation
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct Collection {
82    /// Collection name
83    pub name: String,
84    /// Vector dimension
85    pub dimension: usize,
86    /// Similarity metric used for search (API may return as 'metric')
87    #[serde(alias = "similarity_metric")]
88    pub metric: Option<String>,
89    /// Optional description
90    #[serde(default)]
91    pub description: Option<String>,
92    /// Creation timestamp
93    #[serde(default)]
94    pub created_at: Option<String>,
95    /// Last update timestamp
96    #[serde(default)]
97    pub updated_at: Option<String>,
98    /// Vector count
99    #[serde(default)]
100    pub vector_count: usize,
101    /// Document count
102    #[serde(default)]
103    pub document_count: usize,
104    /// Embedding provider
105    #[serde(default)]
106    pub embedding_provider: Option<String>,
107    /// Indexing status
108    #[serde(default)]
109    pub indexing_status: Option<serde_json::Value>,
110    /// Normalization config
111    #[serde(default)]
112    pub normalization: Option<serde_json::Value>,
113    /// Quantization config
114    #[serde(default)]
115    pub quantization: Option<serde_json::Value>,
116    /// Size info
117    #[serde(default)]
118    pub size: Option<serde_json::Value>,
119}
120
121/// Collection information.
122///
123/// The v3.0.0 REST surface returns `metric` in Rust-Debug form
124/// (e.g. `"Cosine"`), plus new top-level blocks (`size`, `quantization`,
125/// `normalization`, `status`). Every field beyond `name` + `dimension`
126/// carries `#[serde(default)]` so the model tolerates pre-v3 servers
127/// and future additions (request models keep the strict posture; this
128/// is a response-only struct).
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct CollectionInfo {
131    /// Collection name
132    pub name: String,
133    /// Vector dimension
134    pub dimension: usize,
135    /// Similarity metric used for search. The v3 server emits this in
136    /// Rust-Debug form (`"Cosine"` / `"Euclidean"` / `"DotProduct"`);
137    /// callers that compare against `"cosine"` etc. should go through
138    /// `.to_lowercase()`.
139    #[serde(default, alias = "similarity_metric")]
140    pub metric: String,
141    /// Number of vectors in the collection
142    #[serde(default)]
143    pub vector_count: usize,
144    /// Number of documents in the collection
145    #[serde(default)]
146    pub document_count: usize,
147    /// Creation timestamp (RFC3339). Optional — pre-v3 servers may omit.
148    #[serde(default)]
149    pub created_at: String,
150    /// Last update timestamp (RFC3339). Optional — pre-v3 servers may omit.
151    #[serde(default)]
152    pub updated_at: String,
153    /// Indexing status. Absent on the v3 server; some legacy servers send it.
154    #[serde(default)]
155    pub indexing_status: Option<IndexingStatus>,
156    /// Size block emitted by v3 (`{total, total_bytes, index, index_bytes,
157    /// payload, payload_bytes}`).
158    #[serde(default)]
159    pub size: Option<serde_json::Value>,
160    /// Quantization block emitted by v3 (`{enabled, type, bits}`).
161    #[serde(default)]
162    pub quantization: Option<serde_json::Value>,
163    /// Normalization block emitted by v3.
164    #[serde(default)]
165    pub normalization: Option<serde_json::Value>,
166    /// Ready/indexing/error state emitted by v3.
167    #[serde(default)]
168    pub status: Option<String>,
169}
170
171/// Indexing status
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct IndexingStatus {
174    /// Status
175    pub status: String,
176    /// Progress percentage
177    pub progress: f32,
178    /// Total documents
179    pub total_documents: usize,
180    /// Processed documents
181    pub processed_documents: usize,
182    /// Vector count
183    pub vector_count: usize,
184    /// Estimated time remaining
185    pub estimated_time_remaining: Option<String>,
186    /// Last updated timestamp
187    pub last_updated: String,
188}
189
190/// Search result
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct SearchResult {
193    /// Vector ID
194    pub id: String,
195    /// Similarity score
196    pub score: f32,
197    /// Vector content (if available)
198    pub content: Option<String>,
199    /// Optional metadata
200    pub metadata: Option<HashMap<String, serde_json::Value>>,
201}
202
203/// Search response.
204///
205/// `query_time_ms` defaults to `0.0` because the v3.0.x server's text
206/// search handler doesn't emit it — callers that need elapsed timing
207/// should measure client-side. Same tolerance applies to the
208/// additional diagnostic fields the server may add in later versions.
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct SearchResponse {
211    /// Search results.
212    #[serde(default)]
213    pub results: Vec<SearchResult>,
214    /// Query time in milliseconds (server-reported; 0.0 when the
215    /// server omits it).
216    #[serde(default)]
217    pub query_time_ms: f64,
218    /// Echo of the original query string, if the server returned one.
219    #[serde(default)]
220    pub query: Option<String>,
221    /// Echo of the requested result limit, if the server returned one.
222    #[serde(default)]
223    pub limit: Option<usize>,
224    /// Echo of the collection name, if the server returned one.
225    #[serde(default)]
226    pub collection: Option<String>,
227}
228
229/// Embedding request
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct EmbeddingRequest {
232    /// Text to embed
233    pub text: String,
234    /// Optional model to use for embedding
235    pub model: Option<String>,
236    /// Optional parameters for embedding generation
237    pub parameters: Option<EmbeddingParameters>,
238}
239
240/// Embedding parameters
241#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct EmbeddingParameters {
243    /// Maximum sequence length
244    pub max_length: Option<usize>,
245    /// Whether to normalize the embedding
246    pub normalize: Option<bool>,
247    /// Optional prefix for the text
248    pub prefix: Option<String>,
249}
250
251/// Embedding response
252#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct EmbeddingResponse {
254    /// Generated embedding vector
255    pub embedding: Vec<f32>,
256    /// Model used for embedding
257    pub model: String,
258    /// Text that was embedded
259    pub text: String,
260    /// Embedding dimension
261    pub dimension: usize,
262    /// Provider used
263    pub provider: String,
264}
265
266/// Health status
267#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct HealthStatus {
269    /// Service status
270    pub status: String,
271    /// Service version
272    pub version: String,
273    /// Timestamp
274    pub timestamp: String,
275    /// Uptime in seconds
276    pub uptime: Option<u64>,
277    /// Number of collections
278    pub collections: Option<usize>,
279    /// Total number of vectors
280    pub total_vectors: Option<usize>,
281}
282
283/// Collections list response
284#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct CollectionsResponse {
286    /// List of collections
287    pub collections: Vec<Collection>,
288}
289
290/// Create collection response
291#[derive(Debug, Clone, Serialize, Deserialize)]
292pub struct CreateCollectionResponse {
293    /// Success message
294    pub message: String,
295    /// Collection name
296    pub collection: String,
297}
298
299/// Database statistics
300#[derive(Debug, Clone, Serialize, Deserialize)]
301pub struct DatabaseStats {
302    /// Total number of collections
303    pub total_collections: usize,
304    /// Total number of vectors
305    pub total_vectors: usize,
306    /// Total memory estimate in bytes
307    pub total_memory_estimate_bytes: usize,
308    /// Collections information
309    pub collections: Vec<CollectionStats>,
310}
311
312/// Collection statistics
313#[derive(Debug, Clone, Serialize, Deserialize)]
314pub struct CollectionStats {
315    /// Collection name
316    pub name: String,
317    /// Number of vectors
318    pub vector_count: usize,
319    /// Vector dimension
320    pub dimension: usize,
321    /// Memory estimate in bytes
322    pub memory_estimate_bytes: usize,
323}
324
325/// Batch text request
326#[derive(Debug, Clone, Serialize, Deserialize)]
327pub struct BatchTextRequest {
328    /// Text ID
329    pub id: String,
330    /// Text content
331    pub text: String,
332    /// Optional metadata
333    pub metadata: Option<HashMap<String, String>>,
334}
335
336/// Batch configuration
337#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct BatchConfig {
339    /// Maximum batch size
340    pub max_batch_size: Option<usize>,
341    /// Number of parallel workers
342    pub parallel_workers: Option<usize>,
343    /// Whether operations should be atomic
344    pub atomic: Option<bool>,
345}
346
347/// Batch insert request
348#[derive(Debug, Clone, Serialize, Deserialize)]
349pub struct BatchInsertRequest {
350    /// Texts to insert
351    pub texts: Vec<BatchTextRequest>,
352    /// Batch configuration
353    pub config: Option<BatchConfig>,
354}
355
356/// Batch response.
357///
358/// Tolerant of both the old (pre-v3) `{success, operation, total_operations,
359/// successful_operations, failed_operations, duration_ms, errors}` shape
360/// and the v3.0.x server's `/insert_texts` response
361/// `{collection, count, inserted, failed, results}`. All fields default to
362/// empty/zero/false when absent so callers can match on whichever pair the
363/// running server emits without branching on version.
364#[derive(Debug, Clone, Serialize, Deserialize)]
365pub struct BatchResponse {
366    /// Whether the operation was successful (pre-v3 shape; v3 emits
367    /// `inserted`/`failed` instead — left `false` and the caller
368    /// should inspect `successful_operations > 0 && failed_operations == 0`).
369    #[serde(default)]
370    pub success: bool,
371    /// Collection name (both shapes emit this).
372    #[serde(default)]
373    pub collection: String,
374    /// Operation type (pre-v3 only; v3 omits).
375    #[serde(default)]
376    pub operation: String,
377    /// Total number of operations (pre-v3 shape). v3 emits `count` —
378    /// normalised into this field via the alias.
379    #[serde(default, alias = "count")]
380    pub total_operations: usize,
381    /// Number of successful operations (pre-v3 shape). v3 emits
382    /// `inserted` — aliased so either maps onto this field.
383    #[serde(default, alias = "inserted")]
384    pub successful_operations: usize,
385    /// Number of failed operations. Same field name in both shapes.
386    #[serde(default, alias = "failed")]
387    pub failed_operations: usize,
388    /// Duration in milliseconds (pre-v3 only).
389    #[serde(default)]
390    pub duration_ms: u64,
391    /// Error messages (pre-v3 shape).
392    #[serde(default)]
393    pub errors: Vec<String>,
394    /// Per-entry result records emitted by v3 `/insert_texts`. Each
395    /// record carries the client-sent id (`client_id`) and the
396    /// server-assigned UUIDs under `vector_ids`; use this when the
397    /// server reassigns ids on insert.
398    #[serde(default)]
399    pub results: Vec<BatchResultEntry>,
400}
401
402/// One entry in `BatchResponse::results` as emitted by the v3
403/// `/insert_texts` handler. Carries the client-provided id alongside
404/// the server-assigned vector UUID(s) so callers can round-trip the
405/// mapping when they need idempotency by client id.
406#[derive(Debug, Clone, Serialize, Deserialize)]
407pub struct BatchResultEntry {
408    /// Original `id` the caller sent in `BatchTextRequest`.
409    #[serde(default)]
410    pub client_id: String,
411    /// Zero-based index of the entry in the original batch.
412    #[serde(default)]
413    pub index: usize,
414    /// `"ok"` or `"error"`.
415    #[serde(default)]
416    pub status: String,
417    /// Whether the server chunked the input (long text → multiple
418    /// vectors).
419    #[serde(default)]
420    pub chunked: bool,
421    /// Server-assigned UUID(s) — one element unless `chunked` is true.
422    #[serde(default)]
423    pub vector_ids: Vec<String>,
424    /// Count of vectors created for this entry (≥1 if `chunked`).
425    #[serde(default)]
426    pub vectors_created: usize,
427    /// Populated only on `status == "error"`.
428    #[serde(default)]
429    pub error: Option<String>,
430}
431
432/// Batch search query
433#[derive(Debug, Clone, Serialize, Deserialize)]
434pub struct BatchSearchQuery {
435    /// Query text
436    pub query: String,
437    /// Maximum number of results
438    pub limit: Option<usize>,
439    /// Minimum score threshold
440    pub score_threshold: Option<f32>,
441}
442
443/// Batch search request
444#[derive(Debug, Clone, Serialize, Deserialize)]
445pub struct BatchSearchRequest {
446    /// Search queries
447    pub queries: Vec<BatchSearchQuery>,
448    /// Batch configuration
449    pub config: Option<BatchConfig>,
450}
451
452/// Batch search response
453#[derive(Debug, Clone, Serialize, Deserialize)]
454pub struct BatchSearchResponse {
455    /// Whether the operation was successful
456    pub success: bool,
457    /// Collection name
458    pub collection: String,
459    /// Total number of queries
460    pub total_queries: usize,
461    /// Number of successful queries
462    pub successful_queries: usize,
463    /// Number of failed queries
464    pub failed_queries: usize,
465    /// Duration in milliseconds
466    pub duration_ms: u64,
467    /// Search results
468    pub results: Vec<Vec<SearchResult>>,
469    /// Error messages
470    pub errors: Vec<String>,
471}
472
473/// Batch vector update
474#[derive(Debug, Clone, Serialize, Deserialize)]
475pub struct BatchVectorUpdate {
476    /// Vector ID
477    pub id: String,
478    /// New vector data (optional)
479    pub data: Option<Vec<f32>>,
480    /// New metadata (optional)
481    pub metadata: Option<HashMap<String, serde_json::Value>>,
482}
483
484/// Batch update request
485#[derive(Debug, Clone, Serialize, Deserialize)]
486pub struct BatchUpdateRequest {
487    /// Vector updates
488    pub updates: Vec<BatchVectorUpdate>,
489    /// Batch configuration
490    pub config: Option<BatchConfig>,
491}
492
493/// Batch delete request
494#[derive(Debug, Clone, Serialize, Deserialize)]
495pub struct BatchDeleteRequest {
496    /// Vector IDs to delete
497    pub vector_ids: Vec<String>,
498    /// Batch configuration
499    pub config: Option<BatchConfig>,
500}
501
502/// Summarization methods
503#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
504#[serde(rename_all = "snake_case")]
505pub enum SummarizationMethod {
506    /// Extractive summarization
507    #[default]
508    Extractive,
509    /// Keyword summarization
510    Keyword,
511    /// Sentence summarization
512    Sentence,
513    /// Abstractive summarization
514    Abstractive,
515}
516
517/// Summarize text request
518#[derive(Debug, Clone, Serialize, Deserialize)]
519pub struct SummarizeTextRequest {
520    /// Text to summarize
521    pub text: String,
522    /// Summarization method
523    pub method: Option<SummarizationMethod>,
524    /// Maximum summary length
525    pub max_length: Option<usize>,
526    /// Compression ratio
527    pub compression_ratio: Option<f32>,
528    /// Language code
529    pub language: Option<String>,
530}
531
532/// Summarize text response
533#[derive(Debug, Clone, Serialize, Deserialize)]
534pub struct SummarizeTextResponse {
535    /// Summary ID
536    pub summary_id: String,
537    /// Original text
538    pub original_text: String,
539    /// Generated summary
540    pub summary: String,
541    /// Method used
542    pub method: String,
543    /// Original text length
544    pub original_length: usize,
545    /// Summary length
546    pub summary_length: usize,
547    /// Compression ratio
548    pub compression_ratio: f32,
549    /// Language
550    pub language: String,
551    /// Status
552    pub status: String,
553    /// Message
554    pub message: String,
555    /// Metadata
556    pub metadata: HashMap<String, String>,
557}
558
559/// Summarize context request
560#[derive(Debug, Clone, Serialize, Deserialize)]
561pub struct SummarizeContextRequest {
562    /// Context to summarize
563    pub context: String,
564    /// Summarization method
565    pub method: Option<SummarizationMethod>,
566    /// Maximum summary length
567    pub max_length: Option<usize>,
568    /// Compression ratio
569    pub compression_ratio: Option<f32>,
570    /// Language code
571    pub language: Option<String>,
572}
573
574/// Summarize context response
575#[derive(Debug, Clone, Serialize, Deserialize)]
576pub struct SummarizeContextResponse {
577    /// Summary ID
578    pub summary_id: String,
579    /// Original context
580    pub original_context: String,
581    /// Generated summary
582    pub summary: String,
583    /// Method used
584    pub method: String,
585    /// Original context length
586    pub original_length: usize,
587    /// Summary length
588    pub summary_length: usize,
589    /// Compression ratio
590    pub compression_ratio: f32,
591    /// Language
592    pub language: String,
593    /// Status
594    pub status: String,
595    /// Message
596    pub message: String,
597    /// Metadata
598    pub metadata: HashMap<String, String>,
599}
600
601/// Get summary response
602#[derive(Debug, Clone, Serialize, Deserialize)]
603pub struct GetSummaryResponse {
604    /// Summary ID
605    pub summary_id: String,
606    /// Original text
607    pub original_text: String,
608    /// Generated summary
609    pub summary: String,
610    /// Method used
611    pub method: String,
612    /// Original text length
613    pub original_length: usize,
614    /// Summary length
615    pub summary_length: usize,
616    /// Compression ratio
617    pub compression_ratio: f32,
618    /// Language
619    pub language: String,
620    /// Creation timestamp
621    pub created_at: String,
622    /// Metadata
623    pub metadata: HashMap<String, String>,
624    /// Status
625    pub status: String,
626}
627
628/// Summary info
629#[derive(Debug, Clone, Serialize, Deserialize)]
630pub struct SummaryInfo {
631    /// Summary ID
632    pub summary_id: String,
633    /// Method used
634    pub method: String,
635    /// Language
636    pub language: String,
637    /// Original text length
638    pub original_length: usize,
639    /// Summary length
640    pub summary_length: usize,
641    /// Compression ratio
642    pub compression_ratio: f32,
643    /// Creation timestamp
644    pub created_at: String,
645    /// Metadata
646    pub metadata: HashMap<String, String>,
647}
648
649/// List summaries response
650#[derive(Debug, Clone, Serialize, Deserialize)]
651pub struct ListSummariesResponse {
652    /// List of summaries
653    pub summaries: Vec<SummaryInfo>,
654    /// Total count
655    pub total_count: usize,
656    /// Status
657    pub status: String,
658}
659
660/// Indexing progress
661#[derive(Debug, Clone, Serialize, Deserialize)]
662pub struct IndexingProgress {
663    /// Whether indexing is in progress
664    pub is_indexing: bool,
665    /// Overall status
666    pub overall_status: String,
667    /// Collections being indexed
668    pub collections: Vec<CollectionProgress>,
669}
670
671/// Collection progress
672#[derive(Debug, Clone, Serialize, Deserialize)]
673pub struct CollectionProgress {
674    /// Collection name
675    pub collection_name: String,
676    /// Status
677    pub status: String,
678    /// Progress percentage
679    pub progress: f32,
680    /// Vector count
681    pub vector_count: usize,
682    /// Error message if any
683    pub error_message: Option<String>,
684    /// Last updated timestamp
685    pub last_updated: String,
686}
687
688// ===== INTELLIGENT SEARCH MODELS =====
689
690/// Intelligent search request
691#[derive(Debug, Clone, Serialize, Deserialize)]
692pub struct IntelligentSearchRequest {
693    /// Search query
694    pub query: String,
695    /// Collections to search (optional - searches all if not specified)
696    pub collections: Option<Vec<String>>,
697    /// Maximum number of results
698    pub max_results: Option<usize>,
699    /// Enable domain expansion
700    pub domain_expansion: Option<bool>,
701    /// Enable technical focus
702    pub technical_focus: Option<bool>,
703    /// Enable MMR diversification
704    pub mmr_enabled: Option<bool>,
705    /// MMR balance parameter (0.0-1.0)
706    pub mmr_lambda: Option<f32>,
707}
708
709/// Semantic search request
710#[derive(Debug, Clone, Serialize, Deserialize)]
711pub struct SemanticSearchRequest {
712    /// Search query
713    pub query: String,
714    /// Collection to search
715    pub collection: String,
716    /// Maximum number of results
717    pub max_results: Option<usize>,
718    /// Enable semantic reranking
719    pub semantic_reranking: Option<bool>,
720    /// Enable cross-encoder reranking
721    pub cross_encoder_reranking: Option<bool>,
722    /// Minimum similarity threshold
723    pub similarity_threshold: Option<f32>,
724}
725
726/// Contextual search request
727#[derive(Debug, Clone, Serialize, Deserialize)]
728pub struct ContextualSearchRequest {
729    /// Search query
730    pub query: String,
731    /// Collection to search
732    pub collection: String,
733    /// Metadata-based context filters
734    pub context_filters: Option<HashMap<String, serde_json::Value>>,
735    /// Maximum number of results
736    pub max_results: Option<usize>,
737    /// Enable context-aware reranking
738    pub context_reranking: Option<bool>,
739    /// Weight of context factors (0.0-1.0)
740    pub context_weight: Option<f32>,
741}
742
743/// Multi-collection search request
744#[derive(Debug, Clone, Serialize, Deserialize)]
745pub struct MultiCollectionSearchRequest {
746    /// Search query
747    pub query: String,
748    /// Collections to search
749    pub collections: Vec<String>,
750    /// Maximum results per collection
751    pub max_per_collection: Option<usize>,
752    /// Maximum total results
753    pub max_total_results: Option<usize>,
754    /// Enable cross-collection reranking
755    pub cross_collection_reranking: Option<bool>,
756}
757
758/// Intelligent search result
759#[derive(Debug, Clone, Serialize, Deserialize)]
760pub struct IntelligentSearchResult {
761    /// Result ID
762    pub id: String,
763    /// Similarity score
764    pub score: f32,
765    /// Result content
766    pub content: String,
767    /// Metadata
768    pub metadata: Option<HashMap<String, serde_json::Value>>,
769    /// Collection name
770    pub collection: Option<String>,
771    /// Query used for this result
772    pub query_used: Option<String>,
773}
774
775/// Intelligent search response
776#[derive(Debug, Clone, Serialize, Deserialize)]
777pub struct IntelligentSearchResponse {
778    /// Search results
779    pub results: Vec<IntelligentSearchResult>,
780    /// Total number of results found
781    pub total_results: usize,
782    /// Search duration in milliseconds
783    pub duration_ms: u64,
784    /// Queries generated
785    pub queries_generated: Option<Vec<String>>,
786    /// Collections searched
787    pub collections_searched: Option<Vec<String>>,
788    /// Search metadata
789    pub metadata: Option<HashMap<String, serde_json::Value>>,
790}
791
792/// Semantic search response
793#[derive(Debug, Clone, Serialize, Deserialize)]
794pub struct SemanticSearchResponse {
795    /// Search results
796    pub results: Vec<IntelligentSearchResult>,
797    /// Total number of results found
798    pub total_results: usize,
799    /// Search duration in milliseconds
800    pub duration_ms: u64,
801    /// Collection searched
802    pub collection: String,
803    /// Search metadata
804    pub metadata: Option<HashMap<String, serde_json::Value>>,
805}
806
807/// Contextual search response
808#[derive(Debug, Clone, Serialize, Deserialize)]
809pub struct ContextualSearchResponse {
810    /// Search results
811    pub results: Vec<IntelligentSearchResult>,
812    /// Total number of results found
813    pub total_results: usize,
814    /// Search duration in milliseconds
815    pub duration_ms: u64,
816    /// Collection searched
817    pub collection: String,
818    /// Context filters applied
819    pub context_filters: Option<HashMap<String, serde_json::Value>>,
820    /// Search metadata
821    pub metadata: Option<HashMap<String, serde_json::Value>>,
822}
823
824/// Multi-collection search response
825#[derive(Debug, Clone, Serialize, Deserialize)]
826pub struct MultiCollectionSearchResponse {
827    /// Search results
828    pub results: Vec<IntelligentSearchResult>,
829    /// Total number of results found
830    pub total_results: usize,
831    /// Search duration in milliseconds
832    pub duration_ms: u64,
833    /// Collections searched
834    pub collections_searched: Vec<String>,
835    /// Results per collection
836    pub results_per_collection: Option<HashMap<String, usize>>,
837    /// Search metadata
838    pub metadata: Option<HashMap<String, serde_json::Value>>,
839}
840
841// ==================== REPLICATION MODELS ====================
842
843/// Status of a replica node
844#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
845#[serde(rename_all = "PascalCase")]
846pub enum ReplicaStatus {
847    /// Replica is connected and healthy
848    Connected,
849    /// Replica is syncing data
850    Syncing,
851    /// Replica is lagging behind master
852    Lagging,
853    /// Replica is disconnected
854    Disconnected,
855}
856
857/// Information about a replica node
858#[derive(Debug, Clone, Serialize, Deserialize)]
859pub struct ReplicaInfo {
860    /// Unique identifier for the replica
861    pub replica_id: String,
862    /// Hostname or IP address of the replica
863    pub host: String,
864    /// Port number of the replica
865    pub port: u16,
866    /// Current status of the replica
867    pub status: String,
868    /// Timestamp of last heartbeat
869    pub last_heartbeat: DateTime<Utc>,
870    /// Number of operations successfully synced
871    pub operations_synced: u64,
872
873    // Legacy fields (backwards compatible)
874    /// Legacy: Current offset on replica (deprecated, use operations_synced)
875    #[serde(skip_serializing_if = "Option::is_none")]
876    pub offset: Option<u64>,
877    /// Legacy: Lag in operations (deprecated, use status)
878    #[serde(skip_serializing_if = "Option::is_none")]
879    pub lag: Option<u64>,
880}
881
882/// Statistics for replication status
883#[derive(Debug, Clone, Serialize, Deserialize)]
884pub struct ReplicationStats {
885    // New fields (v1.2.0+)
886    /// Role of the node: Master or Replica
887    #[serde(skip_serializing_if = "Option::is_none")]
888    pub role: Option<String>,
889    /// Total bytes sent to replicas (Master only)
890    #[serde(skip_serializing_if = "Option::is_none")]
891    pub bytes_sent: Option<u64>,
892    /// Total bytes received from master (Replica only)
893    #[serde(skip_serializing_if = "Option::is_none")]
894    pub bytes_received: Option<u64>,
895    /// Timestamp of last synchronization
896    #[serde(skip_serializing_if = "Option::is_none")]
897    pub last_sync: Option<DateTime<Utc>>,
898    /// Number of operations pending replication
899    #[serde(skip_serializing_if = "Option::is_none")]
900    pub operations_pending: Option<usize>,
901    /// Size of snapshot data in bytes
902    #[serde(skip_serializing_if = "Option::is_none")]
903    pub snapshot_size: Option<usize>,
904    /// Number of connected replicas (Master only)
905    #[serde(skip_serializing_if = "Option::is_none")]
906    pub connected_replicas: Option<usize>,
907
908    // Legacy fields (backwards compatible - always present)
909    /// Current offset on master node
910    pub master_offset: u64,
911    /// Current offset on replica node
912    pub replica_offset: u64,
913    /// Number of operations behind
914    pub lag_operations: u64,
915    /// Total operations replicated
916    pub total_replicated: u64,
917}
918
919/// Response for replication status endpoint
920#[derive(Debug, Clone, Serialize, Deserialize)]
921pub struct ReplicationStatusResponse {
922    /// Overall status message
923    pub status: String,
924    /// Detailed replication statistics
925    pub stats: ReplicationStats,
926    /// Optional message with additional information
927    #[serde(skip_serializing_if = "Option::is_none")]
928    pub message: Option<String>,
929}
930
931/// Response for listing replicas
932#[derive(Debug, Clone, Serialize, Deserialize)]
933pub struct ReplicaListResponse {
934    /// List of replica nodes
935    pub replicas: Vec<ReplicaInfo>,
936    /// Total count of replicas
937    pub count: usize,
938    /// Status message
939    pub message: String,
940}