Skip to main content

vearch_sdk_rs/
models.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4/// Document representation for Vearch
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Document {
7    #[serde(skip_serializing_if = "Option::is_none")]
8    pub _id: Option<String>,
9    #[serde(flatten)]
10    pub fields: HashMap<String, FieldValue>,
11}
12
13impl Document {
14    /// Create a new empty document
15    pub fn new() -> Self {
16        Self {
17            _id: None,
18            fields: HashMap::new(),
19        }
20    }
21
22    /// Create a new document with a specific ID
23    pub fn with_id(id: impl Into<String>) -> Self {
24        Self {
25            _id: Some(id.into()),
26            fields: HashMap::new(),
27        }
28    }
29
30    /// Add a field to the document
31    pub fn with_field(mut self, key: impl Into<String>, value: impl Into<FieldValue>) -> Self {
32        self.fields.insert(key.into(), value.into());
33        self
34    }
35
36    /// Add a vector field to the document
37    pub fn with_vector(mut self, key: impl Into<String>, vector: Vec<f32>) -> Self {
38        self.fields.insert(key.into(), FieldValue::Vector(vector));
39        self
40    }
41
42    /// Get a field value
43    pub fn get_field(&self, key: &str) -> Option<&FieldValue> {
44        self.fields.get(key)
45    }
46
47    /// Get a vector field value
48    pub fn get_vector(&self, key: &str) -> Option<&Vec<f32>> {
49        if let Some(FieldValue::Vector(vector)) = self.fields.get(key) {
50            Some(vector)
51        } else {
52            None
53        }
54    }
55}
56
57impl Default for Document {
58    fn default() -> Self {
59        Self::new()
60    }
61}
62
63/// Field value types supported by Vearch
64#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(untagged)]
66pub enum FieldValue {
67    String(String),
68    Integer(i64),
69    Float(f64),
70    Boolean(bool),
71    Vector(Vec<f32>),
72    StringArray(Vec<String>),
73    IntegerArray(Vec<i64>),
74    FloatArray(Vec<f64>),
75}
76
77impl From<String> for FieldValue {
78    fn from(value: String) -> Self {
79        FieldValue::String(value)
80    }
81}
82
83impl From<&str> for FieldValue {
84    fn from(value: &str) -> Self {
85        FieldValue::String(value.to_string())
86    }
87}
88
89impl From<i32> for FieldValue {
90    fn from(value: i32) -> Self {
91        FieldValue::Integer(value as i64)
92    }
93}
94
95impl From<i64> for FieldValue {
96    fn from(value: i64) -> Self {
97        FieldValue::Integer(value)
98    }
99}
100
101impl From<f32> for FieldValue {
102    fn from(value: f32) -> Self {
103        FieldValue::Float(value as f64)
104    }
105}
106
107impl From<f64> for FieldValue {
108    fn from(value: f64) -> Self {
109        FieldValue::Float(value)
110    }
111}
112
113impl From<bool> for FieldValue {
114    fn from(value: bool) -> Self {
115        FieldValue::Boolean(value)
116    }
117}
118
119impl From<Vec<f32>> for FieldValue {
120    fn from(value: Vec<f32>) -> Self {
121        FieldValue::Vector(value)
122    }
123}
124
125impl From<Vec<String>> for FieldValue {
126    fn from(value: Vec<String>) -> Self {
127        FieldValue::StringArray(value)
128    }
129}
130
131impl From<Vec<i64>> for FieldValue {
132    fn from(value: Vec<i64>) -> Self {
133        FieldValue::IntegerArray(value)
134    }
135}
136
137impl From<Vec<f64>> for FieldValue {
138    fn from(value: Vec<f64>) -> Self {
139        FieldValue::FloatArray(value)
140    }
141}
142
143/// Vector field for search operations
144#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct VectorField {
146    pub field: String,
147    pub feature: Vec<f32>,
148    #[serde(skip_serializing_if = "Option::is_none")]
149    pub min_score: Option<f64>,
150    #[serde(skip_serializing_if = "Option::is_none")]
151    pub max_score: Option<f64>,
152}
153
154impl VectorField {
155    /// Create a new vector field
156    pub fn new(field: impl Into<String>, feature: Vec<f32>) -> Self {
157        Self {
158            field: field.into(),
159            feature,
160            min_score: None,
161            max_score: None,
162        }
163    }
164
165    /// Set minimum score threshold
166    pub fn with_min_score(mut self, min_score: f64) -> Self {
167        self.min_score = Some(min_score);
168        self
169    }
170
171    /// Set maximum score threshold
172    pub fn with_max_score(mut self, max_score: f64) -> Self {
173        self.max_score = Some(max_score);
174        self
175    }
176}
177
178/// Filter condition for queries
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct FilterCondition {
181    pub field: String,
182    pub operator: FilterOperator,
183    pub value: serde_json::Value,
184}
185
186/// Filter operators supported by Vearch
187#[derive(Debug, Clone, Serialize, Deserialize)]
188#[serde(rename_all = "UPPERCASE")]
189pub enum FilterOperator {
190    #[serde(rename = ">")]
191    GreaterThan,
192    #[serde(rename = ">=")]
193    GreaterThanOrEqual,
194    #[serde(rename = "<")]
195    LessThan,
196    #[serde(rename = "<=")]
197    LessThanOrEqual,
198    #[serde(rename = "IN")]
199    In,
200    #[serde(rename = "NOT IN")]
201    NotIn,
202}
203
204/// Filter structure for complex queries
205#[derive(Debug, Clone, Serialize, Deserialize)]
206pub struct Filter {
207    pub operator: String, // Currently only supports "AND"
208    pub conditions: Vec<FilterCondition>,
209}
210
211impl Filter {
212    /// Create a new AND filter
213    pub fn and(conditions: Vec<FilterCondition>) -> Self {
214        Self {
215            operator: "AND".to_string(),
216            conditions,
217        }
218    }
219
220    /// Add a condition to the filter
221    pub fn with_condition(mut self, condition: FilterCondition) -> Self {
222        self.conditions.push(condition);
223        self
224    }
225}
226
227/// Index parameters for search operations
228#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct IndexParams {
230    #[serde(skip_serializing_if = "Option::is_none")]
231    pub metric_type: Option<String>,
232    #[serde(skip_serializing_if = "Option::is_none")]
233    pub ef_search: Option<i32>,
234    #[serde(skip_serializing_if = "Option::is_none")]
235    pub nprobe: Option<i32>,
236    #[serde(skip_serializing_if = "Option::is_none")]
237    pub parallel_on_queries: Option<i32>,
238}
239
240impl IndexParams {
241    /// Create new index parameters
242    pub fn new() -> Self {
243        Self {
244            metric_type: None,
245            ef_search: None,
246            nprobe: None,
247            parallel_on_queries: None,
248        }
249    }
250
251    /// Set metric type (L2, IP, COSINE)
252    pub fn with_metric_type(mut self, metric_type: impl Into<String>) -> Self {
253        self.metric_type = Some(metric_type.into());
254        self
255    }
256
257    /// Set ef_search for HNSW index
258    pub fn with_ef_search(mut self, ef_search: i32) -> Self {
259        self.ef_search = Some(ef_search);
260        self
261    }
262
263    /// Set nprobe for IVFFLAT index
264    pub fn with_nprobe(mut self, nprobe: i32) -> Self {
265        self.nprobe = Some(nprobe);
266        self
267    }
268}
269
270impl Default for IndexParams {
271    fn default() -> Self {
272        Self::new()
273    }
274}
275
276/// Ranker for multi-vector search
277#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct Ranker {
279    #[serde(rename = "type")]
280    pub ranker_type: String,
281    pub params: Vec<f64>,
282}
283
284impl Ranker {
285    /// Create a weighted ranker
286    pub fn weighted_ranker(weights: Vec<f64>) -> Self {
287        Self {
288            ranker_type: "WeightedRanker".to_string(),
289            params: weights,
290        }
291    }
292}
293
294/// Upsert request payload
295#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct UpsertRequest {
297    pub db_name: String,
298    pub space_name: String,
299    pub documents: Vec<Document>,
300}
301
302/// Upsert response
303#[derive(Debug, Clone, Serialize, Deserialize)]
304pub struct UpsertResponse {
305    pub total: i32,
306    pub document_ids: Vec<DocumentId>,
307}
308
309/// Document ID in response
310#[derive(Debug, Clone, Serialize, Deserialize)]
311pub struct DocumentId {
312    pub _id: String,
313}
314
315/// Query request payload
316#[derive(Debug, Clone, Serialize, Deserialize)]
317pub struct QueryRequest {
318    pub db_name: String,
319    pub space_name: String,
320    #[serde(skip_serializing_if = "Option::is_none")]
321    pub document_ids: Option<Vec<String>>,
322    #[serde(skip_serializing_if = "Option::is_none")]
323    pub partition_id: Option<i32>,
324    #[serde(skip_serializing_if = "Option::is_none")]
325    pub filters: Option<Filter>,
326    #[serde(skip_serializing_if = "Option::is_none")]
327    pub fields: Option<Vec<String>>,
328    #[serde(skip_serializing_if = "Option::is_none")]
329    pub vector_value: Option<bool>,
330    #[serde(skip_serializing_if = "Option::is_none")]
331    pub limit: Option<i32>,
332}
333
334/// Search request payload
335#[derive(Debug, Clone, Serialize, Deserialize)]
336pub struct SearchRequest {
337    pub db_name: String,
338    pub space_name: String,
339    pub vectors: Vec<VectorField>,
340    #[serde(skip_serializing_if = "Option::is_none")]
341    pub filters: Option<Filter>,
342    #[serde(skip_serializing_if = "Option::is_none")]
343    pub index_params: Option<IndexParams>,
344    #[serde(skip_serializing_if = "Option::is_none")]
345    pub ranker: Option<Ranker>,
346    #[serde(skip_serializing_if = "Option::is_none")]
347    pub is_brute_search: Option<i32>,
348    #[serde(skip_serializing_if = "Option::is_none")]
349    pub vector_value: Option<bool>,
350    #[serde(skip_serializing_if = "Option::is_none")]
351    pub load_balance: Option<String>,
352    #[serde(skip_serializing_if = "Option::is_none")]
353    pub limit: Option<i32>,
354}
355
356/// Search response
357#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct SearchResponse {
359    pub documents: Vec<Vec<SearchResult>>,
360}
361
362/// Search result document
363#[derive(Debug, Clone, Serialize, Deserialize)]
364pub struct SearchResult {
365    pub _id: String,
366    pub _score: f64,
367    #[serde(flatten)]
368    pub fields: HashMap<String, serde_json::Value>,
369}
370
371/// Delete request payload
372#[derive(Debug, Clone, Serialize, Deserialize)]
373pub struct DeleteRequest {
374    pub db_name: String,
375    pub space_name: String,
376    #[serde(skip_serializing_if = "Option::is_none")]
377    pub document_ids: Option<Vec<String>>,
378    #[serde(skip_serializing_if = "Option::is_none")]
379    pub filters: Option<Filter>,
380    #[serde(skip_serializing_if = "Option::is_none")]
381    pub limit: Option<i32>,
382}
383
384/// Delete response
385#[derive(Debug, Clone, Serialize, Deserialize)]
386pub struct DeleteResponse {
387    pub total: i32,
388    pub document_ids: Vec<String>,
389}
390
391// ===== 库操作相关结构 =====
392
393/// 创建库请求
394#[derive(Debug, Clone, Serialize, Deserialize)]
395pub struct CreateDatabaseRequest {
396    pub name: String,
397    #[serde(skip_serializing_if = "Option::is_none")]
398    pub description: Option<String>,
399}
400
401/// 库信息
402#[derive(Debug, Clone, Serialize, Deserialize)]
403pub struct DatabaseInfo {
404    pub name: String,
405    #[serde(skip_serializing_if = "Option::is_none")]
406    pub description: Option<String>,
407    #[serde(skip_serializing_if = "Option::is_none")]
408    pub space_count: Option<i32>,
409    #[serde(skip_serializing_if = "Option::is_none")]
410    pub document_count: Option<i64>,
411}
412
413/// 库列表响应
414#[derive(Debug, Clone, Serialize, Deserialize)]
415pub struct ListDatabasesResponse {
416    pub databases: Vec<DatabaseInfo>,
417}
418
419/// 库操作响应
420#[derive(Debug, Clone, Serialize, Deserialize)]
421pub struct DatabaseResponse {
422    pub code: i32,
423    pub msg: String,
424    #[serde(skip_serializing_if = "Option::is_none")]
425    pub data: Option<serde_json::Value>,
426}
427
428// ===== 表空间操作相关结构 =====
429
430/// 字段类型定义
431#[derive(Debug, Clone, Serialize, Deserialize)]
432#[serde(rename_all = "lowercase")]
433pub enum FieldType {
434    String,
435    Integer,
436    Float,
437    Double,
438    Boolean,
439    Vector,
440    Array,
441    Date,
442    Geo,
443}
444
445/// 向量字段配置
446#[derive(Debug, Clone, Serialize, Deserialize)]
447pub struct VectorFieldConfig {
448    pub dimension: usize,
449    #[serde(skip_serializing_if = "Option::is_none")]
450    pub model_id: Option<String>,
451    #[serde(skip_serializing_if = "Option::is_none")]
452    pub format: Option<String>,
453}
454
455/// 数组字段配置
456#[derive(Debug, Clone, Serialize, Deserialize)]
457pub struct ArrayFieldConfig {
458    pub element_type: FieldType,
459    #[serde(skip_serializing_if = "Option::is_none")]
460    pub max_length: Option<usize>,
461}
462
463/// 字段定义
464#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct FieldDefinition {
466    #[serde(rename = "type")]
467    pub field_type: FieldType,
468    #[serde(skip_serializing_if = "Option::is_none")]
469    pub dimension: Option<usize>,
470    #[serde(skip_serializing_if = "Option::is_none")]
471    pub model_id: Option<String>,
472    #[serde(skip_serializing_if = "Option::is_none")]
473    pub format: Option<String>,
474    #[serde(skip_serializing_if = "Option::is_none")]
475    pub element_type: Option<FieldType>,
476    #[serde(skip_serializing_if = "Option::is_none")]
477    pub max_length: Option<usize>,
478    #[serde(skip_serializing_if = "Option::is_none")]
479    pub index: Option<bool>,
480    #[serde(skip_serializing_if = "Option::is_none")]
481    pub store: Option<bool>,
482}
483
484/// 索引配置
485#[derive(Debug, Clone, Serialize, Deserialize)]
486pub struct IndexConfig {
487    #[serde(rename = "type")]
488    pub index_type: String,
489    #[serde(skip_serializing_if = "Option::is_none")]
490    pub nlist: Option<i32>,
491    #[serde(skip_serializing_if = "Option::is_none")]
492    pub m: Option<i32>,
493    #[serde(skip_serializing_if = "Option::is_none")]
494    pub ef_construction: Option<i32>,
495    #[serde(skip_serializing_if = "Option::is_none")]
496    pub ef_search: Option<i32>,
497    #[serde(skip_serializing_if = "Option::is_none")]
498    pub metric_type: Option<String>,
499    #[serde(skip_serializing_if = "Option::is_none")]
500    pub nprobe: Option<i32>,
501    #[serde(skip_serializing_if = "Option::is_none")]
502    pub parallel_on_queries: Option<i32>,
503}
504
505/// 创建表空间请求
506#[derive(Debug, Clone, Serialize, Deserialize)]
507pub struct CreateSpaceRequest {
508    pub name: String,
509    pub fields: HashMap<String, FieldDefinition>,
510    #[serde(skip_serializing_if = "Option::is_none")]
511    pub index: Option<IndexConfig>,
512    #[serde(skip_serializing_if = "Option::is_none")]
513    pub partition_num: Option<i32>,
514    #[serde(skip_serializing_if = "Option::is_none")]
515    pub replica_num: Option<i32>,
516    #[serde(skip_serializing_if = "Option::is_none")]
517    pub description: Option<String>,
518}
519
520/// 表空间信息
521#[derive(Debug, Clone, Serialize, Deserialize)]
522pub struct SpaceInfo {
523    pub name: String,
524    #[serde(skip_serializing_if = "Option::is_none")]
525    pub description: Option<String>,
526    pub fields: HashMap<String, FieldDefinition>,
527    #[serde(skip_serializing_if = "Option::is_none")]
528    pub index: Option<IndexConfig>,
529    #[serde(skip_serializing_if = "Option::is_none")]
530    pub partition_num: Option<i32>,
531    #[serde(skip_serializing_if = "Option::is_none")]
532    pub replica_num: Option<i32>,
533    #[serde(skip_serializing_if = "Option::is_none")]
534    pub document_count: Option<i64>,
535    #[serde(skip_serializing_if = "Option::is_none")]
536    pub status: Option<String>,
537}
538
539/// 表空间列表响应
540#[derive(Debug, Clone, Serialize, Deserialize)]
541pub struct ListSpacesResponse {
542    pub spaces: Vec<SpaceInfo>,
543}
544
545/// 表空间操作响应
546#[derive(Debug, Clone, Serialize, Deserialize)]
547pub struct SpaceResponse {
548    pub code: i32,
549    pub msg: String,
550    #[serde(skip_serializing_if = "Option::is_none")]
551    pub data: Option<serde_json::Value>,
552}
553
554/// 表空间统计信息
555#[derive(Debug, Clone, Serialize, Deserialize)]
556pub struct SpaceStats {
557    pub name: String,
558    #[serde(skip_serializing_if = "Option::is_none")]
559    pub document_count: Option<i64>,
560    #[serde(skip_serializing_if = "Option::is_none")]
561    pub index_size: Option<i64>,
562    #[serde(skip_serializing_if = "Option::is_none")]
563    pub storage_size: Option<i64>,
564    #[serde(skip_serializing_if = "Option::is_none")]
565    pub partition_stats: Option<Vec<PartitionStats>>,
566}
567
568/// 分区统计信息
569#[derive(Debug, Clone, Serialize, Deserialize)]
570pub struct PartitionStats {
571    pub partition_id: i32,
572    #[serde(skip_serializing_if = "Option::is_none")]
573    pub document_count: Option<i64>,
574    #[serde(skip_serializing_if = "Option::is_none")]
575    pub index_size: Option<i64>,
576    #[serde(skip_serializing_if = "Option::is_none")]
577    pub storage_size: Option<i64>,
578}
579
580// ===== 鉴权相关结构 =====
581
582/// 权限类型
583#[derive(Debug, Clone, Serialize, Deserialize)]
584#[serde(rename_all = "PascalCase")]
585pub enum PrivilegeType {
586    WriteOnly,
587    ReadOnly,
588    WriteRead,
589}
590
591/// 资源类型
592#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
593#[serde(rename_all = "PascalCase")]
594pub enum ResourceType {
595    ResourceAll,
596    ResourceCluster,
597    ResourceServer,
598    ResourcePartition,
599    ResourceDB,
600    ResourceSpace,
601    ResourceDocument,
602    ResourceIndex,
603    ResourceAlias,
604    ResourceUser,
605    ResourceRole,
606    ResourceConfig,
607    ResourceCache,
608}
609
610/// 权限映射
611pub type Privileges = HashMap<ResourceType, PrivilegeType>;
612
613/// 操作类型
614#[derive(Debug, Clone, Serialize, Deserialize)]
615#[serde(rename_all = "PascalCase")]
616pub enum Operator {
617    Grant,
618    Revoke,
619}
620
621/// 创建角色请求
622#[derive(Debug, Clone, Serialize, Deserialize)]
623pub struct CreateRoleRequest {
624    pub name: String,
625    pub privileges: Privileges,
626}
627
628/// 修改角色权限请求
629#[derive(Debug, Clone, Serialize, Deserialize)]
630pub struct ModifyRoleRequest {
631    pub name: String,
632    pub operator: Operator,
633    pub privileges: Privileges,
634}
635
636/// 角色信息
637#[derive(Debug, Clone, Serialize, Deserialize)]
638pub struct RoleInfo {
639    pub name: String,
640    pub privileges: Privileges,
641}
642
643/// 角色列表响应
644#[derive(Debug, Clone, Serialize, Deserialize)]
645pub struct ListRolesResponse {
646    pub roles: Vec<RoleInfo>,
647}
648
649/// 创建用户请求
650#[derive(Debug, Clone, Serialize, Deserialize)]
651pub struct CreateUserRequest {
652    pub name: String,
653    pub password: String,
654    pub role_name: String,
655}
656
657/// 修改用户请求
658#[derive(Debug, Clone, Serialize, Deserialize)]
659pub struct ModifyUserRequest {
660    pub name: String,
661    #[serde(skip_serializing_if = "Option::is_none")]
662    pub role_name: Option<String>,
663    #[serde(skip_serializing_if = "Option::is_none")]
664    pub password: Option<String>,
665    #[serde(skip_serializing_if = "Option::is_none")]
666    pub old_password: Option<String>,
667}
668
669/// 用户信息
670#[derive(Debug, Clone, Serialize, Deserialize)]
671pub struct UserInfo {
672    pub name: String,
673    pub role_name: String,
674}
675
676/// 用户列表响应
677#[derive(Debug, Clone, Serialize, Deserialize)]
678pub struct ListUsersResponse {
679    pub users: Vec<UserInfo>,
680}
681
682/// 鉴权响应
683#[derive(Debug, Clone, Serialize, Deserialize)]
684pub struct AuthResponse {
685    pub code: i32,
686    pub msg: String,
687    #[serde(skip_serializing_if = "Option::is_none")]
688    pub data: Option<serde_json::Value>,
689}
690
691/// 鉴权配置
692#[derive(Debug, Clone)]
693pub struct AuthConfig {
694    pub username: String,
695    pub password: String,
696    pub role_name: Option<String>,
697}
698
699/// 登录响应
700#[derive(Debug, Clone, Serialize, Deserialize)]
701pub struct LoginResponse {
702    pub code: i32,
703    pub msg: String,
704    #[serde(skip_serializing_if = "Option::is_none")]
705    pub data: Option<serde_json::Value>,
706    #[serde(skip_serializing_if = "Option::is_none")]
707    pub token: Option<String>,
708}