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