diff --git a/examples/collection.rs b/examples/collection.rs index 97cbe74..49609c3 100644 --- a/examples/collection.rs +++ b/examples/collection.rs @@ -2,9 +2,7 @@ use milvus::index::{IndexParams, IndexType}; use milvus::options::LoadOptions; use milvus::query::QueryOptions; use milvus::schema::{CollectionSchema, CollectionSchemaBuilder}; -use milvus::{ - client::Client, collection::Collection, data::FieldColumn, error::Error, schema::FieldSchema, -}; +use milvus::{client::Client, data::FieldColumn, error::Error, schema::FieldSchema}; use std::collections::HashMap; use rand::prelude::*; diff --git a/milvus-proto b/milvus-proto index 02cbad3..78707a7 160000 --- a/milvus-proto +++ b/milvus-proto @@ -1 +1 @@ -Subproject commit 02cbad30332f52be598373b3f0c5968270f753f8 +Subproject commit 78707a7e3212885c8d2d219a66acd8bbececa072 diff --git a/src/client.rs b/src/client.rs index c953f25..d368e61 100644 --- a/src/client.rs +++ b/src/client.rs @@ -43,7 +43,7 @@ impl Interceptor for AuthInterceptor { mut req: Request<()>, ) -> std::result::Result, tonic::Status> { if let Some(ref token) = self.token { - let header_value = format!("{}", token); + let header_value = token; req.metadata_mut() .insert("authorization", header_value.parse().unwrap()); } @@ -92,6 +92,7 @@ where pub struct Client { pub(crate) client: MilvusServiceClient>, pub(crate) collection_cache: CollectionCache, + pub(crate) db_name: String, } impl Client { @@ -137,7 +138,8 @@ impl Client { Ok(Self { client: client.clone(), - collection_cache: CollectionCache::new(client), + collection_cache: CollectionCache::new(client, ""), + db_name: String::new(), }) } @@ -151,7 +153,7 @@ impl Client { .clone() .flush(FlushRequest { base: Some(MsgBase::new(MsgType::Flush)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_names: collections.into_iter().map(|x| x.to_string()).collect(), }) .await? @@ -190,7 +192,7 @@ impl Client { .clone() .create_alias(crate::proto::milvus::CreateAliasRequest { base: Some(MsgBase::new(MsgType::CreateAlias)), - db_name: "".to_string(), // reserved + db_name: self.db_name.clone(), collection_name, alias, }) @@ -218,7 +220,7 @@ impl Client { .clone() .drop_alias(crate::proto::milvus::DropAliasRequest { base: Some(MsgBase::new(MsgType::DropAlias)), - db_name: "".to_string(), // reserved + db_name: self.db_name.clone(), alias, }) .await? @@ -248,7 +250,7 @@ impl Client { .clone() .alter_alias(crate::proto::milvus::AlterAliasRequest { base: Some(MsgBase::new(MsgType::AlterAlias)), - db_name: "".to_string(), // reserved + db_name: self.db_name.clone(), collection_name, alias, }) diff --git a/src/collection.rs b/src/collection.rs index d70748f..021629f 100644 --- a/src/collection.rs +++ b/src/collection.rs @@ -25,7 +25,7 @@ use crate::proto::milvus::{ ReleaseCollectionRequest, ShowCollectionsRequest, }; use crate::proto::schema::DataType; -use crate::schema::CollectionSchema; +use crate::schema::{CollectionSchema, FieldSchema}; use crate::types::*; use crate::utils::status_to_result; use crate::value::Value; @@ -55,7 +55,7 @@ pub struct Collection { // pub num_partitions: usize, pub consistency_level: ConsistencyLevel, pub description: String, - pub fields: Vec, + pub fields: Vec, // pub enable_dynamic_field: bool, } @@ -64,25 +64,30 @@ pub(crate) struct CollectionCache { collections: dashmap::DashMap, timestamps: dashmap::DashMap, client: MilvusServiceClient>, + db_name: String, } impl CollectionCache { - pub fn new(client: MilvusServiceClient>) -> Self { + pub fn new( + client: MilvusServiceClient>, + db_name: &str, + ) -> Self { Self { collections: dashmap::DashMap::new(), timestamps: dashmap::DashMap::new(), - client: client, + client, + db_name: db_name.to_string(), } } - pub async fn get<'a>(&self, name: &str) -> Result { + pub async fn get(&self, name: &str) -> Result { if !self.local_exist(name) { let resp = self .client .clone() .describe_collection(DescribeCollectionRequest { base: Some(MsgBase::new(MsgType::DescribeCollection)), - db_name: "".to_owned(), + db_name: self.db_name.clone(), collection_name: name.into(), collection_id: 0, time_stamp: 0, @@ -115,7 +120,7 @@ impl CollectionCache { } pub fn get_timestamp(&self, name: &str) -> Option { - self.timestamps.get(name).map(|v| v.value().clone()) + self.timestamps.get(name).map(|v| *v.value()) } fn local_exist(&self, name: &str) -> bool { @@ -134,7 +139,7 @@ impl From for Collection { // num_partitions: value.partitions_num as usize, consistency_level: ConsistencyLevel::from_i32(value.consistency_level).unwrap(), description: schema.description, - fields: schema.fields.into_iter().map(|f| Field::from(f)).collect(), + fields: schema.fields.into_iter().map(FieldSchema::from).collect(), // enable_dynamic_field: value.enable_dynamic_field, } } @@ -182,8 +187,6 @@ impl From for CompactionState { } } -type ConcurrentHashMap = tokio::sync::RwLock>; - impl Client { /// Creates a new collection with the specified schema and options. /// @@ -211,6 +214,7 @@ impl Client { schema: buf.to_vec(), shards_num: options.shard_num, consistency_level: options.consistency_level as i32, + db_name: self.db_name.clone(), ..Default::default() }) .await? @@ -238,7 +242,7 @@ impl Client { .drop_collection(DropCollectionRequest { base: Some(MsgBase::new(MsgType::DropCollection)), collection_name: name.into(), - ..Default::default() + db_name: self.db_name.clone(), }) .await? .into_inner(), @@ -256,6 +260,7 @@ impl Client { .clone() .show_collections(ShowCollectionsRequest { base: Some(MsgBase::new(MsgType::ShowCollections)), + db_name: self.db_name.clone(), ..Default::default() }) .await? @@ -283,7 +288,7 @@ impl Client { .clone() .describe_collection(DescribeCollectionRequest { base: Some(MsgBase::new(MsgType::DescribeCollection)), - db_name: "".to_owned(), + db_name: self.db_name.clone(), collection_name: name.into(), collection_id: 0, time_stamp: 0, @@ -315,7 +320,7 @@ impl Client { .clone() .has_collection(HasCollectionRequest { base: Some(MsgBase::new(MsgType::HasCollection)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_name: name.clone(), time_stamp: 0, }) @@ -365,7 +370,7 @@ impl Client { .clone() .get_collection_statistics(proto::milvus::GetCollectionStatisticsRequest { base: Some(MsgBase::new(MsgType::GetCollectionStatistics)), - db_name: "".into(), + db_name: self.db_name.clone(), collection_name: name.to_owned(), }) .await? @@ -401,11 +406,12 @@ impl Client { .clone() .load_collection(LoadCollectionRequest { base: Some(MsgBase::new(MsgType::LoadCollection)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_name: collection_name.clone(), replica_number: options.replica_number, resource_groups: vec![], refresh: false, + ..Default::default() }) .await? .into_inner(), @@ -455,7 +461,7 @@ impl Client { .clone() .get_load_state(proto::milvus::GetLoadStateRequest { base: Some(MsgBase::new(MsgType::Undefined)), - db_name: "".into(), + db_name: self.db_name.clone(), collection_name: collection_name.into(), partition_names: options.partition_names, }) @@ -485,7 +491,7 @@ impl Client { .clone() .release_collection(ReleaseCollectionRequest { base: Some(MsgBase::new(MsgType::ReleaseCollection)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_name: collection_name.into(), }) .await? @@ -502,7 +508,7 @@ impl Client { .clone() .flush(FlushRequest { base: Some(MsgBase::new(MsgType::Flush)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_names: vec![collection_name.into()], }) .await? @@ -528,7 +534,7 @@ impl Client { .clone() .create_index(CreateIndexRequest { base: Some(MsgBase::new(MsgType::CreateIndex)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_name: collection_name.into(), field_name, extra_params: index_params.extra_kv_params(), @@ -593,7 +599,7 @@ impl Client { .clone() .describe_index(DescribeIndexRequest { base: Some(MsgBase::new(MsgType::DescribeIndex)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_name: collection_name.into(), field_name: field_name.into(), index_name: "".to_string(), @@ -615,7 +621,7 @@ impl Client { .clone() .drop_index(DropIndexRequest { base: Some(MsgBase::new(MsgType::DropIndex)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_name: collection_name.into(), field_name: field_name.into(), index_name: "".to_string(), @@ -637,6 +643,8 @@ impl Client { .manual_compaction(ManualCompactionRequest { collection_id: collection.id, timetravel: 0, + db_name: self.db_name.clone(), + ..Default::default() }) .await? .into_inner(); diff --git a/src/data.rs b/src/data.rs index 7258bf6..0d9d9e3 100644 --- a/src/data.rs +++ b/src/data.rs @@ -135,6 +135,10 @@ impl FieldColumn { self.value.len() / self.dim as usize } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn copy_with_metadata(&self) -> Self { Self { dim: self.dim, diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..e0a63f7 --- /dev/null +++ b/src/database.rs @@ -0,0 +1,156 @@ +use std::collections::HashMap; + +use crate::{ + client::Client, + collection::CollectionCache, + error::{Error, Result}, + proto::{ + common::{KeyValuePair, MsgBase, MsgType}, + milvus::{ + AlterDatabaseRequest, CreateDatabaseRequest, DescribeDatabaseRequest, + DropDatabaseRequest, ListDatabasesRequest, + }, + }, + utils::{hashmap_to_vec, status_to_result, vec_to_hashmap}, +}; + +pub struct DatabaseDescription { + pub db_id: i64, + pub db_name: String, + pub properties: HashMap, +} + +impl Client { + pub async fn create_database( + &self, + db_name: &str, + properties: HashMap, + ) -> Result<()> { + let status = self + .client + .clone() + .create_database(CreateDatabaseRequest { + base: Some(MsgBase::new(MsgType::CreateDatabase)), + db_name: db_name.to_owned(), + properties: properties + .iter() + .map(|(k, v)| KeyValuePair { + key: k.clone(), + value: v.clone(), + }) + .collect(), + }) + .await? + .into_inner(); + + status_to_result(&Some(status)) + } + + pub async fn list_databases(&self) -> Result> { + let response = self + .client + .clone() + .list_databases(ListDatabasesRequest { + base: Some(MsgBase::new(MsgType::ListDatabases)), + }) + .await? + .into_inner(); + + status_to_result(&response.status)?; + Ok(response.db_names) + } + + pub async fn describe_database(&self, db_name: &str) -> Result { + let response = self + .client + .clone() + .describe_database(DescribeDatabaseRequest { + base: Some(MsgBase::new(MsgType::DescribeDatabase)), + db_name: db_name.to_owned(), + }) + .await? + .into_inner(); + + status_to_result(&response.status)?; + Ok(DatabaseDescription { + db_id: response.db_id, + db_name: response.db_name, + properties: vec_to_hashmap(&response.properties), + }) + } + + pub async fn alter_database_properties( + &self, + db_name: &str, + properties: HashMap, + ) -> Result<()> { + let status = self + .client + .clone() + .alter_database(AlterDatabaseRequest { + base: Some(MsgBase::new(MsgType::AlterDatabase)), + db_name: db_name.to_owned(), + properties: hashmap_to_vec(&properties), + ..Default::default() + }) + .await? + .into_inner(); + + status_to_result(&Some(status)) + } + + pub async fn drop_database_properties( + &self, + db_name: &str, + property_keys: Vec, + ) -> Result<()> { + let status = self + .client + .clone() + .alter_database(AlterDatabaseRequest { + base: Some(MsgBase::new(MsgType::AlterDatabase)), + db_name: db_name.to_owned(), + delete_keys: property_keys, + ..Default::default() + }) + .await? + .into_inner(); + + status_to_result(&Some(status)) + } + + pub async fn use_database(&mut self, db_name: &str) -> Result<()> { + if self.db_name == db_name { + return Result::Ok(()); + } + + let db = db_name.to_string(); + if !db_name.is_empty() { + let dbs = self.list_databases().await?; + + if !dbs.contains(&db) { + return Result::Err(Error::Unexpected(format!( + "Database with the name '{db_name}' does not exist." + ))); + } + } + + self.db_name = db.clone(); + self.collection_cache = CollectionCache::new(self.client.clone(), db_name); + Result::Ok(()) + } + + pub async fn drop_database(&self, db_name: &str) -> Result<()> { + let status = self + .client + .clone() + .drop_database(DropDatabaseRequest { + base: Some(MsgBase::new(MsgType::DropDatabase)), + db_name: db_name.to_owned(), + }) + .await? + .into_inner(); + + status_to_result(&Some(status)) + } +} diff --git a/src/index/mod.rs b/src/index/mod.rs index 3eac2af..d9aebf6 100644 --- a/src/index/mod.rs +++ b/src/index/mod.rs @@ -40,6 +40,8 @@ pub enum IndexType { NGTPANNG, #[strum(serialize = "NGT_ONNG")] NGTONNG, + #[strum(serialize = "AUTOINDEX")] + AUTOINDEX, } #[derive(Debug, Clone, Copy, EnumString, Display)] @@ -51,6 +53,9 @@ pub enum MetricType { TANIMOTO, SUBSTRUCTURE, SUPERSTRUCTURE, + COSINE, + #[strum(serialize = "")] + None, } #[derive(Debug, Clone)] @@ -148,7 +153,10 @@ impl From for IndexInfo { let index_type = IndexType::from_str(¶ms.remove("index_type").unwrap()).unwrap(); let metric_type = MetricType::from_str(¶ms.remove("metric_type").unwrap()).unwrap(); - let params = serde_json::from_str(params.get("params").unwrap()).unwrap(); + let params = match params.get("params") { + Some(v) => serde_json::from_str(v).unwrap(), + None => HashMap::new(), + }; let params = IndexParams::new( description.index_name.clone(), @@ -159,7 +167,7 @@ impl From for IndexInfo { Self { field_name: description.field_name.clone(), id: description.index_id, - params: params, + params, state: description.state(), } } diff --git a/src/lib.rs b/src/lib.rs index bb2ef6b..17f47f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ pub mod client; pub mod collection; pub mod data; +pub mod database; pub mod error; pub mod mutate; pub mod options; diff --git a/src/mutate.rs b/src/mutate.rs index 17680f6..3e4607c 100644 --- a/src/mutate.rs +++ b/src/mutate.rs @@ -1,35 +1,22 @@ -use prost::bytes::{BufMut, BytesMut}; - use crate::error::Result; use crate::{ client::Client, - collection, data::FieldColumn, error::Error, proto::{ self, common::{MsgBase, MsgType}, milvus::{InsertRequest, UpsertRequest}, - schema::{scalar_field::Data, DataType}, + schema::DataType, }, - schema::FieldData, - utils::status_to_result, value::ValueVec, }; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct InsertOptions { pub(crate) partition_name: String, } -impl Default for InsertOptions { - fn default() -> Self { - Self { - partition_name: String::new(), - } - } -} - impl InsertOptions { pub fn new() -> Self { Self::default() @@ -98,12 +85,13 @@ impl Client { .clone() .insert(InsertRequest { base: Some(MsgBase::new(MsgType::Insert)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_name: collection_name.clone(), partition_name: options.partition_name, num_rows: row_num as u32, fields_data: fields_data.into_iter().map(|f| f.into()).collect(), hash_keys: Vec::new(), + ..Default::default() }) .await? .into_inner(); @@ -128,11 +116,12 @@ impl Client { .clone() .delete(proto::milvus::DeleteRequest { base: Some(MsgBase::new(MsgType::Delete)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_name: collection_name.clone(), - expr: expr, + expr, partition_name: options.partition_name.clone(), hash_keys: Vec::new(), + ..Default::default() }) .await? .into_inner(); @@ -148,7 +137,7 @@ impl Client { match options.filter.len() { 0 => { let collection = self.collection_cache.get(collection_name).await?; - let pk = collection.fields.iter().find(|f| f.is_primary_key).unwrap(); + let pk = collection.fields.iter().find(|f| f.is_primary).unwrap(); let mut expr = String::new(); expr.push_str(&pk.name); @@ -157,7 +146,7 @@ impl Client { (DataType::Int64, ValueVec::Long(values)) => { for (i, v) in values.iter().enumerate() { if i > 0 { - expr.push_str(","); + expr.push(','); } expr.push_str(format!("{}", v).as_str()); } @@ -167,7 +156,7 @@ impl Client { (DataType::VarChar, ValueVec::String(values)) => { for (i, v) in values.iter().enumerate() { if i > 0 { - expr.push_str(","); + expr.push(','); } expr.push_str(v.as_str()); } @@ -208,12 +197,13 @@ impl Client { .clone() .upsert(UpsertRequest { base: Some(MsgBase::new(MsgType::Upsert)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_name: collection_name.clone(), partition_name: options.partition_name, num_rows: row_num as u32, fields_data: fields_data.into_iter().map(|f| f.into()).collect(), hash_keys: Vec::new(), + ..Default::default() }) .await? .into_inner(); diff --git a/src/options.rs b/src/options.rs index 097740a..95f49c8 100644 --- a/src/options.rs +++ b/src/options.rs @@ -65,19 +65,11 @@ impl LoadOptions { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct GetLoadStateOptions { pub(crate) partition_names: Vec, } -impl Default for GetLoadStateOptions { - fn default() -> Self { - Self { - partition_names: vec![], - } - } -} - impl GetLoadStateOptions { pub fn new() -> Self { Self::default() diff --git a/src/partition.rs b/src/partition.rs index 0e13909..0db1997 100644 --- a/src/partition.rs +++ b/src/partition.rs @@ -3,10 +3,7 @@ use std::collections::HashMap; use crate::error::*; use crate::{ client::Client, - proto::{ - self, - common::{MsgBase, MsgType}, - }, + proto::common::{MsgBase, MsgType}, utils::status_to_result, }; @@ -21,7 +18,7 @@ impl Client { .clone() .create_partition(crate::proto::milvus::CreatePartitionRequest { base: Some(MsgBase::new(MsgType::CreatePartition)), - db_name: "".to_string(), // reserved + db_name: self.db_name.clone(), collection_name, partition_name, }) @@ -40,7 +37,7 @@ impl Client { .clone() .drop_partition(crate::proto::milvus::DropPartitionRequest { base: Some(MsgBase::new(MsgType::DropPartition)), - db_name: "".to_string(), // reserved + db_name: self.db_name.clone(), collection_name, partition_name, }) @@ -55,11 +52,9 @@ impl Client { .clone() .show_partitions(crate::proto::milvus::ShowPartitionsRequest { base: Some(MsgBase::new(MsgType::ShowPartitions)), - db_name: "".to_string(), // reserved + db_name: self.db_name.clone(), collection_name, - collection_id: 0, // reserved - partition_names: vec![], // reserved - r#type: 0, // reserved + ..Default::default() }) .await? .into_inner(); @@ -77,7 +72,7 @@ impl Client { .clone() .has_partition(crate::proto::milvus::HasPartitionRequest { base: Some(MsgBase::new(MsgType::HasPartition)), - db_name: "".to_string(), // reserved + db_name: self.db_name.clone(), collection_name, partition_name, }) @@ -97,7 +92,7 @@ impl Client { .clone() .get_partition_statistics(crate::proto::milvus::GetPartitionStatisticsRequest { base: Some(MsgBase::new(MsgType::GetPartitionStatistics)), - db_name: "".to_string(), // reserved + db_name: self.db_name.clone(), collection_name, partition_name, }) @@ -120,7 +115,7 @@ impl Client { // .clone() // .load_partitions(proto::milvus::LoadPartitionsRequest { // base: Some(MsgBase::new(MsgType::LoadPartitions)), - // db_name: "".to_string(), + // db_name: self.db_name.clone(), // collection_name: collection_name.into(), // replica_number, // partition_names: names.clone(), @@ -147,7 +142,7 @@ impl Client { // .clone() // .release_partitions(ReleasePartitionsRequest { // base: Some(MsgBase::new(MsgType::ReleasePartitions)), - // db_name: "".to_string(), + // db_name: self.db_name.clone(), // collection_name: self.schema().name.to_string(), // partition_names: partition_names.into_iter().map(|x| x.to_string()).collect(), // }) diff --git a/src/proto/milvus.proto.common.rs b/src/proto/milvus.proto.common.rs index 161a5bb..febd580 100644 --- a/src/proto/milvus.proto.common.rs +++ b/src/proto/milvus.proto.common.rs @@ -12,6 +12,11 @@ pub struct Status { pub retriable: bool, #[prost(string, tag = "5")] pub detail: ::prost::alloc::string::String, + #[prost(map = "string, string", tag = "6")] + pub extra_info: ::std::collections::HashMap< + ::prost::alloc::string::String, + ::prost::alloc::string::String, + >, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -42,7 +47,9 @@ pub struct PlaceholderValue { pub tag: ::prost::alloc::string::String, #[prost(enumeration = "PlaceholderType", tag = "2")] pub r#type: i32, - /// values is a 2d-array, every array contains a vector + /// values is a 2d-array of nq rows, every row contains a query vector. + /// for dense vector, all rows are of the same length; for sparse vector, + /// the length of each row may vary depending on their number of non-zeros. #[prost(bytes = "vec", repeated, tag = "3")] pub values: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, } @@ -88,6 +95,8 @@ pub struct ReplicateInfo { pub is_replicate: bool, #[prost(uint64, tag = "2")] pub msg_timestamp: u64, + #[prost(string, tag = "3")] + pub replicate_id: ::prost::alloc::string::String, } /// Don't Modify This. @czs #[allow(clippy::derive_partial_eq_without_eq)] @@ -167,6 +176,17 @@ pub struct ServerInfo { ::prost::alloc::string::String, >, } +/// NodeInfo is used to describe the node information. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NodeInfo { + #[prost(int64, tag = "1")] + pub node_id: i64, + #[prost(string, tag = "2")] + pub address: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub hostname: ::prost::alloc::string::String, +} /// Deprecated #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -229,6 +249,11 @@ pub enum ErrorCode { NotReadyServe = 56, /// Coord is switching from standby mode to active mode NotReadyCoordActivating = 57, + CreatePrivilegeGroupFailure = 58, + DropPrivilegeGroupFailure = 59, + ListPrivilegeGroupsFailure = 60, + OperatePrivilegeGroupFailure = 61, + SchemaMismatch = 62, /// Service availability. /// NA: Not Available. DataCoordNa = 100, @@ -299,6 +324,11 @@ impl ErrorCode { ErrorCode::TimeTickLongDelay => "TimeTickLongDelay", ErrorCode::NotReadyServe => "NotReadyServe", ErrorCode::NotReadyCoordActivating => "NotReadyCoordActivating", + ErrorCode::CreatePrivilegeGroupFailure => "CreatePrivilegeGroupFailure", + ErrorCode::DropPrivilegeGroupFailure => "DropPrivilegeGroupFailure", + ErrorCode::ListPrivilegeGroupsFailure => "ListPrivilegeGroupsFailure", + ErrorCode::OperatePrivilegeGroupFailure => "OperatePrivilegeGroupFailure", + ErrorCode::SchemaMismatch => "SchemaMismatch", ErrorCode::DataCoordNa => "DataCoordNA", ErrorCode::DdRequestRace => "DDRequestRace", } @@ -363,6 +393,11 @@ impl ErrorCode { "TimeTickLongDelay" => Some(Self::TimeTickLongDelay), "NotReadyServe" => Some(Self::NotReadyServe), "NotReadyCoordActivating" => Some(Self::NotReadyCoordActivating), + "CreatePrivilegeGroupFailure" => Some(Self::CreatePrivilegeGroupFailure), + "DropPrivilegeGroupFailure" => Some(Self::DropPrivilegeGroupFailure), + "ListPrivilegeGroupsFailure" => Some(Self::ListPrivilegeGroupsFailure), + "OperatePrivilegeGroupFailure" => Some(Self::OperatePrivilegeGroupFailure), + "SchemaMismatch" => Some(Self::SchemaMismatch), "DataCoordNA" => Some(Self::DataCoordNa), "DDRequestRace" => Some(Self::DdRequestRace), _ => None, @@ -453,12 +488,49 @@ impl SegmentState { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] +pub enum SegmentLevel { + /// zero value for legacy logic + Legacy = 0, + /// L0 segment, contains delta data for current channel + L0 = 1, + /// L1 segment, normal segment, with no extra compaction attribute + L1 = 2, + /// L2 segment, segment with extra data distribution info + L2 = 3, +} +impl SegmentLevel { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + SegmentLevel::Legacy => "Legacy", + SegmentLevel::L0 => "L0", + SegmentLevel::L1 => "L1", + SegmentLevel::L2 => "L2", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "Legacy" => Some(Self::Legacy), + "L0" => Some(Self::L0), + "L1" => Some(Self::L1), + "L2" => Some(Self::L2), + _ => None, + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] pub enum PlaceholderType { None = 0, BinaryVector = 100, FloatVector = 101, Float16Vector = 102, BFloat16Vector = 103, + SparseFloatVector = 104, Int64 = 5, VarChar = 21, } @@ -474,6 +546,7 @@ impl PlaceholderType { PlaceholderType::FloatVector => "FloatVector", PlaceholderType::Float16Vector => "Float16Vector", PlaceholderType::BFloat16Vector => "BFloat16Vector", + PlaceholderType::SparseFloatVector => "SparseFloatVector", PlaceholderType::Int64 => "Int64", PlaceholderType::VarChar => "VarChar", } @@ -486,6 +559,7 @@ impl PlaceholderType { "FloatVector" => Some(Self::FloatVector), "Float16Vector" => Some(Self::Float16Vector), "BFloat16Vector" => Some(Self::BFloat16Vector), + "SparseFloatVector" => Some(Self::SparseFloatVector), "Int64" => Some(Self::Int64), "VarChar" => Some(Self::VarChar), _ => None, @@ -512,6 +586,7 @@ pub enum MsgType { RenameCollection = 112, DescribeAlias = 113, ListAliases = 114, + AlterCollectionField = 115, /// DEFINITION REQUESTS: PARTITION CreatePartition = 200, DropPartition = 201, @@ -535,12 +610,19 @@ pub enum MsgType { DescribeIndex = 301, DropIndex = 302, GetIndexStatistics = 303, + AlterIndex = 304, /// MANIPULATION REQUESTS Insert = 400, Delete = 401, Flush = 402, ResendSegmentStats = 403, Upsert = 404, + /// streaming service new msg type for internal usage compatible + ManualFlush = 405, + /// streaming service new msg type for internal usage compatible + FlushSegment = 406, + /// streaming service new msg type for internal usage compatible + CreateSegment = 407, /// QUERY Search = 500, SearchResult = 501, @@ -580,6 +662,7 @@ pub enum MsgType { Connect = 1209, ListClientInfos = 1210, AllocTimestamp = 1211, + Replicate = 1212, /// Credential CreateCredential = 1500, GetCredential = 1501, @@ -597,6 +680,11 @@ pub enum MsgType { SelectGrant = 1607, RefreshPolicyInfoCache = 1608, ListPolicy = 1609, + CreatePrivilegeGroup = 1610, + DropPrivilegeGroup = 1611, + ListPrivilegeGroups = 1612, + OperatePrivilegeGroup = 1613, + OperatePrivilegeV2 = 1614, /// Resource group CreateResourceGroup = 1700, DropResourceGroup = 1701, @@ -604,10 +692,13 @@ pub enum MsgType { DescribeResourceGroup = 1703, TransferNode = 1704, TransferReplica = 1705, + UpdateResourceGroups = 1706, /// Database group CreateDatabase = 1801, DropDatabase = 1802, ListDatabases = 1803, + AlterDatabase = 1804, + DescribeDatabase = 1805, } impl MsgType { /// String value of the enum field names used in the ProtoBuf definition. @@ -632,6 +723,7 @@ impl MsgType { MsgType::RenameCollection => "RenameCollection", MsgType::DescribeAlias => "DescribeAlias", MsgType::ListAliases => "ListAliases", + MsgType::AlterCollectionField => "AlterCollectionField", MsgType::CreatePartition => "CreatePartition", MsgType::DropPartition => "DropPartition", MsgType::HasPartition => "HasPartition", @@ -652,11 +744,15 @@ impl MsgType { MsgType::DescribeIndex => "DescribeIndex", MsgType::DropIndex => "DropIndex", MsgType::GetIndexStatistics => "GetIndexStatistics", + MsgType::AlterIndex => "AlterIndex", MsgType::Insert => "Insert", MsgType::Delete => "Delete", MsgType::Flush => "Flush", MsgType::ResendSegmentStats => "ResendSegmentStats", MsgType::Upsert => "Upsert", + MsgType::ManualFlush => "ManualFlush", + MsgType::FlushSegment => "FlushSegment", + MsgType::CreateSegment => "CreateSegment", MsgType::Search => "Search", MsgType::SearchResult => "SearchResult", MsgType::GetIndexState => "GetIndexState", @@ -692,6 +788,7 @@ impl MsgType { MsgType::Connect => "Connect", MsgType::ListClientInfos => "ListClientInfos", MsgType::AllocTimestamp => "AllocTimestamp", + MsgType::Replicate => "Replicate", MsgType::CreateCredential => "CreateCredential", MsgType::GetCredential => "GetCredential", MsgType::DeleteCredential => "DeleteCredential", @@ -707,15 +804,23 @@ impl MsgType { MsgType::SelectGrant => "SelectGrant", MsgType::RefreshPolicyInfoCache => "RefreshPolicyInfoCache", MsgType::ListPolicy => "ListPolicy", + MsgType::CreatePrivilegeGroup => "CreatePrivilegeGroup", + MsgType::DropPrivilegeGroup => "DropPrivilegeGroup", + MsgType::ListPrivilegeGroups => "ListPrivilegeGroups", + MsgType::OperatePrivilegeGroup => "OperatePrivilegeGroup", + MsgType::OperatePrivilegeV2 => "OperatePrivilegeV2", MsgType::CreateResourceGroup => "CreateResourceGroup", MsgType::DropResourceGroup => "DropResourceGroup", MsgType::ListResourceGroups => "ListResourceGroups", MsgType::DescribeResourceGroup => "DescribeResourceGroup", MsgType::TransferNode => "TransferNode", MsgType::TransferReplica => "TransferReplica", + MsgType::UpdateResourceGroups => "UpdateResourceGroups", MsgType::CreateDatabase => "CreateDatabase", MsgType::DropDatabase => "DropDatabase", MsgType::ListDatabases => "ListDatabases", + MsgType::AlterDatabase => "AlterDatabase", + MsgType::DescribeDatabase => "DescribeDatabase", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -737,6 +842,7 @@ impl MsgType { "RenameCollection" => Some(Self::RenameCollection), "DescribeAlias" => Some(Self::DescribeAlias), "ListAliases" => Some(Self::ListAliases), + "AlterCollectionField" => Some(Self::AlterCollectionField), "CreatePartition" => Some(Self::CreatePartition), "DropPartition" => Some(Self::DropPartition), "HasPartition" => Some(Self::HasPartition), @@ -757,11 +863,15 @@ impl MsgType { "DescribeIndex" => Some(Self::DescribeIndex), "DropIndex" => Some(Self::DropIndex), "GetIndexStatistics" => Some(Self::GetIndexStatistics), + "AlterIndex" => Some(Self::AlterIndex), "Insert" => Some(Self::Insert), "Delete" => Some(Self::Delete), "Flush" => Some(Self::Flush), "ResendSegmentStats" => Some(Self::ResendSegmentStats), "Upsert" => Some(Self::Upsert), + "ManualFlush" => Some(Self::ManualFlush), + "FlushSegment" => Some(Self::FlushSegment), + "CreateSegment" => Some(Self::CreateSegment), "Search" => Some(Self::Search), "SearchResult" => Some(Self::SearchResult), "GetIndexState" => Some(Self::GetIndexState), @@ -797,6 +907,7 @@ impl MsgType { "Connect" => Some(Self::Connect), "ListClientInfos" => Some(Self::ListClientInfos), "AllocTimestamp" => Some(Self::AllocTimestamp), + "Replicate" => Some(Self::Replicate), "CreateCredential" => Some(Self::CreateCredential), "GetCredential" => Some(Self::GetCredential), "DeleteCredential" => Some(Self::DeleteCredential), @@ -812,15 +923,23 @@ impl MsgType { "SelectGrant" => Some(Self::SelectGrant), "RefreshPolicyInfoCache" => Some(Self::RefreshPolicyInfoCache), "ListPolicy" => Some(Self::ListPolicy), + "CreatePrivilegeGroup" => Some(Self::CreatePrivilegeGroup), + "DropPrivilegeGroup" => Some(Self::DropPrivilegeGroup), + "ListPrivilegeGroups" => Some(Self::ListPrivilegeGroups), + "OperatePrivilegeGroup" => Some(Self::OperatePrivilegeGroup), + "OperatePrivilegeV2" => Some(Self::OperatePrivilegeV2), "CreateResourceGroup" => Some(Self::CreateResourceGroup), "DropResourceGroup" => Some(Self::DropResourceGroup), "ListResourceGroups" => Some(Self::ListResourceGroups), "DescribeResourceGroup" => Some(Self::DescribeResourceGroup), "TransferNode" => Some(Self::TransferNode), "TransferReplica" => Some(Self::TransferReplica), + "UpdateResourceGroups" => Some(Self::UpdateResourceGroups), "CreateDatabase" => Some(Self::CreateDatabase), "DropDatabase" => Some(Self::DropDatabase), "ListDatabases" => Some(Self::ListDatabases), + "AlterDatabase" => Some(Self::AlterDatabase), + "DescribeDatabase" => Some(Self::DescribeDatabase), _ => None, } } @@ -1041,6 +1160,31 @@ pub enum ObjectPrivilege { PrivilegeShowPartitions = 41, PrivilegeHasPartition = 42, PrivilegeGetFlushState = 43, + PrivilegeCreateAlias = 44, + PrivilegeDropAlias = 45, + PrivilegeDescribeAlias = 46, + PrivilegeListAliases = 47, + PrivilegeUpdateResourceGroups = 48, + PrivilegeAlterDatabase = 49, + PrivilegeDescribeDatabase = 50, + PrivilegeBackupRbac = 51, + PrivilegeRestoreRbac = 52, + PrivilegeGroupReadOnly = 53, + PrivilegeGroupReadWrite = 54, + PrivilegeGroupAdmin = 55, + PrivilegeCreatePrivilegeGroup = 56, + PrivilegeDropPrivilegeGroup = 57, + PrivilegeListPrivilegeGroups = 58, + PrivilegeOperatePrivilegeGroup = 59, + PrivilegeGroupClusterReadOnly = 60, + PrivilegeGroupClusterReadWrite = 61, + PrivilegeGroupClusterAdmin = 62, + PrivilegeGroupDatabaseReadOnly = 63, + PrivilegeGroupDatabaseReadWrite = 64, + PrivilegeGroupDatabaseAdmin = 65, + PrivilegeGroupCollectionReadOnly = 66, + PrivilegeGroupCollectionReadWrite = 67, + PrivilegeGroupCollectionAdmin = 68, } impl ObjectPrivilege { /// String value of the enum field names used in the ProtoBuf definition. @@ -1097,6 +1241,53 @@ impl ObjectPrivilege { ObjectPrivilege::PrivilegeShowPartitions => "PrivilegeShowPartitions", ObjectPrivilege::PrivilegeHasPartition => "PrivilegeHasPartition", ObjectPrivilege::PrivilegeGetFlushState => "PrivilegeGetFlushState", + ObjectPrivilege::PrivilegeCreateAlias => "PrivilegeCreateAlias", + ObjectPrivilege::PrivilegeDropAlias => "PrivilegeDropAlias", + ObjectPrivilege::PrivilegeDescribeAlias => "PrivilegeDescribeAlias", + ObjectPrivilege::PrivilegeListAliases => "PrivilegeListAliases", + ObjectPrivilege::PrivilegeUpdateResourceGroups => { + "PrivilegeUpdateResourceGroups" + } + ObjectPrivilege::PrivilegeAlterDatabase => "PrivilegeAlterDatabase", + ObjectPrivilege::PrivilegeDescribeDatabase => "PrivilegeDescribeDatabase", + ObjectPrivilege::PrivilegeBackupRbac => "PrivilegeBackupRBAC", + ObjectPrivilege::PrivilegeRestoreRbac => "PrivilegeRestoreRBAC", + ObjectPrivilege::PrivilegeGroupReadOnly => "PrivilegeGroupReadOnly", + ObjectPrivilege::PrivilegeGroupReadWrite => "PrivilegeGroupReadWrite", + ObjectPrivilege::PrivilegeGroupAdmin => "PrivilegeGroupAdmin", + ObjectPrivilege::PrivilegeCreatePrivilegeGroup => { + "PrivilegeCreatePrivilegeGroup" + } + ObjectPrivilege::PrivilegeDropPrivilegeGroup => "PrivilegeDropPrivilegeGroup", + ObjectPrivilege::PrivilegeListPrivilegeGroups => { + "PrivilegeListPrivilegeGroups" + } + ObjectPrivilege::PrivilegeOperatePrivilegeGroup => { + "PrivilegeOperatePrivilegeGroup" + } + ObjectPrivilege::PrivilegeGroupClusterReadOnly => { + "PrivilegeGroupClusterReadOnly" + } + ObjectPrivilege::PrivilegeGroupClusterReadWrite => { + "PrivilegeGroupClusterReadWrite" + } + ObjectPrivilege::PrivilegeGroupClusterAdmin => "PrivilegeGroupClusterAdmin", + ObjectPrivilege::PrivilegeGroupDatabaseReadOnly => { + "PrivilegeGroupDatabaseReadOnly" + } + ObjectPrivilege::PrivilegeGroupDatabaseReadWrite => { + "PrivilegeGroupDatabaseReadWrite" + } + ObjectPrivilege::PrivilegeGroupDatabaseAdmin => "PrivilegeGroupDatabaseAdmin", + ObjectPrivilege::PrivilegeGroupCollectionReadOnly => { + "PrivilegeGroupCollectionReadOnly" + } + ObjectPrivilege::PrivilegeGroupCollectionReadWrite => { + "PrivilegeGroupCollectionReadWrite" + } + ObjectPrivilege::PrivilegeGroupCollectionAdmin => { + "PrivilegeGroupCollectionAdmin" + } } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1148,6 +1339,43 @@ impl ObjectPrivilege { "PrivilegeShowPartitions" => Some(Self::PrivilegeShowPartitions), "PrivilegeHasPartition" => Some(Self::PrivilegeHasPartition), "PrivilegeGetFlushState" => Some(Self::PrivilegeGetFlushState), + "PrivilegeCreateAlias" => Some(Self::PrivilegeCreateAlias), + "PrivilegeDropAlias" => Some(Self::PrivilegeDropAlias), + "PrivilegeDescribeAlias" => Some(Self::PrivilegeDescribeAlias), + "PrivilegeListAliases" => Some(Self::PrivilegeListAliases), + "PrivilegeUpdateResourceGroups" => Some(Self::PrivilegeUpdateResourceGroups), + "PrivilegeAlterDatabase" => Some(Self::PrivilegeAlterDatabase), + "PrivilegeDescribeDatabase" => Some(Self::PrivilegeDescribeDatabase), + "PrivilegeBackupRBAC" => Some(Self::PrivilegeBackupRbac), + "PrivilegeRestoreRBAC" => Some(Self::PrivilegeRestoreRbac), + "PrivilegeGroupReadOnly" => Some(Self::PrivilegeGroupReadOnly), + "PrivilegeGroupReadWrite" => Some(Self::PrivilegeGroupReadWrite), + "PrivilegeGroupAdmin" => Some(Self::PrivilegeGroupAdmin), + "PrivilegeCreatePrivilegeGroup" => Some(Self::PrivilegeCreatePrivilegeGroup), + "PrivilegeDropPrivilegeGroup" => Some(Self::PrivilegeDropPrivilegeGroup), + "PrivilegeListPrivilegeGroups" => Some(Self::PrivilegeListPrivilegeGroups), + "PrivilegeOperatePrivilegeGroup" => { + Some(Self::PrivilegeOperatePrivilegeGroup) + } + "PrivilegeGroupClusterReadOnly" => Some(Self::PrivilegeGroupClusterReadOnly), + "PrivilegeGroupClusterReadWrite" => { + Some(Self::PrivilegeGroupClusterReadWrite) + } + "PrivilegeGroupClusterAdmin" => Some(Self::PrivilegeGroupClusterAdmin), + "PrivilegeGroupDatabaseReadOnly" => { + Some(Self::PrivilegeGroupDatabaseReadOnly) + } + "PrivilegeGroupDatabaseReadWrite" => { + Some(Self::PrivilegeGroupDatabaseReadWrite) + } + "PrivilegeGroupDatabaseAdmin" => Some(Self::PrivilegeGroupDatabaseAdmin), + "PrivilegeGroupCollectionReadOnly" => { + Some(Self::PrivilegeGroupCollectionReadOnly) + } + "PrivilegeGroupCollectionReadWrite" => { + Some(Self::PrivilegeGroupCollectionReadWrite) + } + "PrivilegeGroupCollectionAdmin" => Some(Self::PrivilegeGroupCollectionAdmin), _ => None, } } diff --git a/src/proto/milvus.proto.milvus.rs b/src/proto/milvus.proto.milvus.rs index 9a077ab..8c5c112 100644 --- a/src/proto/milvus.proto.milvus.rs +++ b/src/proto/milvus.proto.milvus.rs @@ -142,6 +142,24 @@ pub struct AlterCollectionRequest { pub collection_id: i64, #[prost(message, repeated, tag = "5")] pub properties: ::prost::alloc::vec::Vec, + #[prost(string, repeated, tag = "6")] + pub delete_keys: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AlterCollectionFieldRequest { + /// Not useful for now + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + #[prost(string, tag = "2")] + pub db_name: ::prost::alloc::string::String, + /// The unique collection name in milvus.(Required) + #[prost(string, tag = "3")] + pub collection_name: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub field_name: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "5")] + pub properties: ::prost::alloc::vec::Vec, } /// * /// Check collection exist in milvus or not. @@ -243,6 +261,12 @@ pub struct DescribeCollectionResponse { pub db_name: ::prost::alloc::string::String, #[prost(int64, tag = "15")] pub num_partitions: i64, + #[prost(int64, tag = "16")] + pub db_id: i64, + #[prost(uint64, tag = "17")] + pub request_time: u64, + #[prost(uint64, tag = "18")] + pub update_timestamp: u64, } /// * /// Load collection data into query nodes, then you can do vector search on this collection. @@ -266,6 +290,12 @@ pub struct LoadCollectionRequest { /// Whether to enable refresh mode. #[prost(bool, tag = "6")] pub refresh: bool, + /// Field Partial Load fields list + #[prost(string, repeated, tag = "7")] + pub load_fields: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// Field Partial load skip load dynamic fields + #[prost(bool, tag = "8")] + pub skip_load_dynamic_field: bool, } /// * /// Release collection data from query nodes, then you can't do vector search on this collection. @@ -469,6 +499,12 @@ pub struct LoadPartitionsRequest { /// Whether to enable refresh mode. #[prost(bool, tag = "7")] pub refresh: bool, + /// Field Partial Load fields list + #[prost(string, repeated, tag = "8")] + pub load_fields: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// Field Partial load skip load dynamic fields + #[prost(bool, tag = "9")] + pub skip_load_dynamic_field: bool, } /// /// Release specific partitions data of one collection from query nodes. @@ -645,6 +681,8 @@ pub struct AlterIndexRequest { pub index_name: ::prost::alloc::string::String, #[prost(message, repeated, tag = "5")] pub extra_params: ::prost::alloc::vec::Vec, + #[prost(string, repeated, tag = "6")] + pub delete_keys: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } /// /// Get created index information. @@ -802,6 +840,8 @@ pub struct InsertRequest { pub hash_keys: ::prost::alloc::vec::Vec, #[prost(uint32, tag = "7")] pub num_rows: u32, + #[prost(uint64, tag = "8")] + pub schema_timestamp: u64, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -820,6 +860,8 @@ pub struct UpsertRequest { pub hash_keys: ::prost::alloc::vec::Vec, #[prost(uint32, tag = "7")] pub num_rows: u32, + #[prost(uint64, tag = "8")] + pub schema_timestamp: u64, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -861,6 +903,38 @@ pub struct DeleteRequest { pub expr: ::prost::alloc::string::String, #[prost(uint32, repeated, tag = "6")] pub hash_keys: ::prost::alloc::vec::Vec, + #[prost(enumeration = "super::common::ConsistencyLevel", tag = "7")] + pub consistency_level: i32, + #[prost(map = "string, message", tag = "8")] + pub expr_template_values: ::std::collections::HashMap< + ::prost::alloc::string::String, + super::schema::TemplateValue, + >, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SubSearchRequest { + /// must + #[prost(string, tag = "1")] + pub dsl: ::prost::alloc::string::String, + /// serialized `PlaceholderGroup` + /// + /// must + #[prost(bytes = "vec", tag = "2")] + pub placeholder_group: ::prost::alloc::vec::Vec, + /// must + #[prost(enumeration = "super::common::DslType", tag = "3")] + pub dsl_type: i32, + /// must + #[prost(message, repeated, tag = "4")] + pub search_params: ::prost::alloc::vec::Vec, + #[prost(int64, tag = "5")] + pub nq: i64, + #[prost(map = "string, message", tag = "6")] + pub expr_template_values: ::std::collections::HashMap< + ::prost::alloc::string::String, + super::schema::TemplateValue, + >, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -907,6 +981,13 @@ pub struct SearchRequest { pub use_default_consistency: bool, #[prost(bool, tag = "16")] pub search_by_primary_keys: bool, + #[prost(message, repeated, tag = "17")] + pub sub_reqs: ::prost::alloc::vec::Vec, + #[prost(map = "string, message", tag = "18")] + pub expr_template_values: ::std::collections::HashMap< + ::prost::alloc::string::String, + super::schema::TemplateValue, + >, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -930,7 +1011,7 @@ pub struct SearchResults { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct SearchRequestV2 { +pub struct HybridSearchRequest { /// must #[prost(message, optional, tag = "1")] pub base: ::core::option::Option, @@ -997,6 +1078,11 @@ pub struct FlushResponse { /// hybrid ts for geting flush tate #[prost(map = "string, uint64", tag = "6")] pub coll_flush_ts: ::std::collections::HashMap<::prost::alloc::string::String, u64>, + #[prost(map = "string, message", tag = "7")] + pub channel_cps: ::std::collections::HashMap< + ::prost::alloc::string::String, + super::msg::MsgPosition, + >, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1027,6 +1113,11 @@ pub struct QueryRequest { pub consistency_level: i32, #[prost(bool, tag = "12")] pub use_default_consistency: bool, + #[prost(map = "string, message", tag = "13")] + pub expr_template_values: ::std::collections::HashMap< + ::prost::alloc::string::String, + super::schema::TemplateValue, + >, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1039,6 +1130,11 @@ pub struct QueryResults { pub collection_name: ::prost::alloc::string::String, #[prost(string, repeated, tag = "4")] pub output_fields: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// for session-like operation like iterator + #[prost(uint64, tag = "5")] + pub session_ts: u64, + #[prost(string, tag = "6")] + pub primary_field_name: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1136,6 +1232,8 @@ pub struct PersistentSegmentInfo { pub num_rows: i64, #[prost(enumeration = "super::common::SegmentState", tag = "5")] pub state: i32, + #[prost(enumeration = "super::common::SegmentLevel", tag = "6")] + pub level: i32, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1182,6 +1280,8 @@ pub struct QuerySegmentInfo { pub state: i32, #[prost(int64, repeated, tag = "10")] pub node_ids: ::prost::alloc::vec::Vec, + #[prost(enumeration = "super::common::SegmentLevel", tag = "11")] + pub level: i32, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1297,6 +1397,12 @@ pub struct ManualCompactionRequest { pub collection_id: i64, #[prost(uint64, tag = "2")] pub timetravel: u64, + #[prost(bool, tag = "3")] + pub major_compaction: bool, + #[prost(string, tag = "4")] + pub collection_name: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub db_name: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1413,8 +1519,12 @@ pub struct ImportRequest { /// import options, bucket, etc. #[prost(message, repeated, tag = "6")] pub options: ::prost::alloc::vec::Vec, + /// target database #[prost(string, tag = "7")] pub db_name: ::prost::alloc::string::String, + /// serialized `schema.ClusteringInfo` + #[prost(bytes = "vec", tag = "8")] + pub clustering_info: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1645,6 +1755,60 @@ pub struct DropRoleRequest { /// role name #[prost(string, tag = "2")] pub role_name: ::prost::alloc::string::String, + /// force to drop the role even if there is permission binding + #[prost(bool, tag = "3")] + pub force_drop: bool, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreatePrivilegeGroupRequest { + /// Not useful for now + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + /// group name + #[prost(string, tag = "2")] + pub group_name: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DropPrivilegeGroupRequest { + /// Not useful for now + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + /// group name + #[prost(string, tag = "2")] + pub group_name: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListPrivilegeGroupsRequest { + /// Not useful for now + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListPrivilegeGroupsResponse { + #[prost(message, optional, tag = "1")] + pub status: ::core::option::Option, + #[prost(message, repeated, tag = "2")] + pub privilege_groups: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OperatePrivilegeGroupRequest { + /// Not useful for now + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + /// group name + #[prost(string, tag = "2")] + pub group_name: ::prost::alloc::string::String, + /// privileges + #[prost(message, repeated, tag = "3")] + pub privileges: ::prost::alloc::vec::Vec, + /// operation type + #[prost(enumeration = "OperatePrivilegeGroupType", tag = "4")] + pub r#type: i32, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1664,6 +1828,14 @@ pub struct OperateUserRoleRequest { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct PrivilegeGroupInfo { + #[prost(string, tag = "1")] + pub group_name: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "2")] + pub privileges: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct SelectRoleRequest { /// Not useful for now #[prost(message, optional, tag = "1")] @@ -1801,6 +1973,81 @@ pub struct OperatePrivilegeRequest { /// operation type #[prost(enumeration = "OperatePrivilegeType", tag = "3")] pub r#type: i32, + /// version + #[prost(string, tag = "4")] + pub version: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OperatePrivilegeV2Request { + /// Not useful for now + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + /// role + #[prost(message, optional, tag = "2")] + pub role: ::core::option::Option, + /// privilege + #[prost(message, optional, tag = "3")] + pub grantor: ::core::option::Option, + /// operation type + #[prost(enumeration = "OperatePrivilegeType", tag = "4")] + pub r#type: i32, + /// db name + #[prost(string, tag = "5")] + pub db_name: ::prost::alloc::string::String, + /// collection name + #[prost(string, tag = "6")] + pub collection_name: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UserInfo { + #[prost(string, tag = "1")] + pub user: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub password: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "3")] + pub roles: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RbacMeta { + /// user + #[prost(message, repeated, tag = "1")] + pub users: ::prost::alloc::vec::Vec, + /// role + #[prost(message, repeated, tag = "2")] + pub roles: ::prost::alloc::vec::Vec, + /// (role, object, previledge) + #[prost(message, repeated, tag = "3")] + pub grants: ::prost::alloc::vec::Vec, + /// privilege group info + #[prost(message, repeated, tag = "4")] + pub privilege_groups: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BackupRbacMetaRequest { + /// Not useful for now + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BackupRbacMetaResponse { + #[prost(message, optional, tag = "1")] + pub status: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub rbac_meta: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RestoreRbacMetaRequest { + /// Not useful for now + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub rbac_meta: ::core::option::Option, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1885,6 +2132,19 @@ pub struct CreateResourceGroupRequest { pub base: ::core::option::Option, #[prost(string, tag = "2")] pub resource_group: ::prost::alloc::string::String, + #[prost(message, optional, tag = "3")] + pub config: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdateResourceGroupsRequest { + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + #[prost(map = "string, message", tag = "2")] + pub resource_groups: ::std::collections::HashMap< + ::prost::alloc::string::String, + super::rg::ResourceGroupConfig, + >, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1981,6 +2241,12 @@ pub struct ResourceGroup { ::prost::alloc::string::String, i32, >, + /// resource group configuration. + #[prost(message, optional, tag = "7")] + pub config: ::core::option::Option, + /// query node belong to this resource group now. + #[prost(message, repeated, tag = "8")] + pub nodes: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -2063,6 +2329,8 @@ pub struct CreateDatabaseRequest { pub base: ::core::option::Option, #[prost(string, tag = "2")] pub db_name: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "3")] + pub properties: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -2090,6 +2358,42 @@ pub struct ListDatabasesResponse { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct AlterDatabaseRequest { + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + #[prost(string, tag = "2")] + pub db_name: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub db_id: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "4")] + pub properties: ::prost::alloc::vec::Vec, + #[prost(string, repeated, tag = "5")] + pub delete_keys: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DescribeDatabaseRequest { + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + #[prost(string, tag = "2")] + pub db_name: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DescribeDatabaseResponse { + #[prost(message, optional, tag = "1")] + pub status: ::core::option::Option, + #[prost(string, tag = "2")] + pub db_name: ::prost::alloc::string::String, + #[prost(int64, tag = "3")] + pub db_id: i64, + #[prost(uint64, tag = "4")] + pub created_timestamp: u64, + #[prost(message, repeated, tag = "5")] + pub properties: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct ReplicateMessageRequest { #[prost(message, optional, tag = "1")] pub base: ::core::option::Option, @@ -2114,6 +2418,30 @@ pub struct ReplicateMessageResponse { #[prost(string, tag = "2")] pub position: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ImportAuthPlaceholder { + #[prost(string, tag = "1")] + pub db_name: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub collection_name: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub partition_name: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetImportProgressAuthPlaceholder { + #[prost(string, tag = "1")] + pub db_name: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListImportsAuthPlaceholder { + #[prost(string, tag = "3")] + pub db_name: ::prost::alloc::string::String, + #[prost(string, tag = "1")] + pub collection_name: ::prost::alloc::string::String, +} /// Deprecated: use GetLoadingProgress rpc instead #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -2145,6 +2473,34 @@ impl ShowType { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] +pub enum OperatePrivilegeGroupType { + AddPrivilegesToGroup = 0, + RemovePrivilegesFromGroup = 1, +} +impl OperatePrivilegeGroupType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + OperatePrivilegeGroupType::AddPrivilegesToGroup => "AddPrivilegesToGroup", + OperatePrivilegeGroupType::RemovePrivilegesFromGroup => { + "RemovePrivilegesFromGroup" + } + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "AddPrivilegesToGroup" => Some(Self::AddPrivilegesToGroup), + "RemovePrivilegesFromGroup" => Some(Self::RemovePrivilegesFromGroup), + _ => None, + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] pub enum OperateUserRoleType { AddUserToRole = 0, RemoveUserFromRole = 1, @@ -2171,6 +2527,35 @@ impl OperateUserRoleType { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] +pub enum PrivilegeLevel { + Cluster = 0, + Database = 1, + Collection = 2, +} +impl PrivilegeLevel { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PrivilegeLevel::Cluster => "Cluster", + PrivilegeLevel::Database => "Database", + PrivilegeLevel::Collection => "Collection", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "Cluster" => Some(Self::Cluster), + "Database" => Some(Self::Database), + "Collection" => Some(Self::Collection), + _ => None, + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] pub enum OperatePrivilegeType { Grant = 0, Revoke = 1, @@ -2203,6 +2588,7 @@ pub enum QuotaState { WriteLimited = 3, DenyToRead = 4, DenyToWrite = 5, + DenyToDdl = 6, } impl QuotaState { /// String value of the enum field names used in the ProtoBuf definition. @@ -2216,6 +2602,7 @@ impl QuotaState { QuotaState::WriteLimited => "WriteLimited", QuotaState::DenyToRead => "DenyToRead", QuotaState::DenyToWrite => "DenyToWrite", + QuotaState::DenyToDdl => "DenyToDDL", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -2226,6 +2613,7 @@ impl QuotaState { "WriteLimited" => Some(Self::WriteLimited), "DenyToRead" => Some(Self::DenyToRead), "DenyToWrite" => Some(Self::DenyToWrite), + "DenyToDDL" => Some(Self::DenyToDdl), _ => None, } } @@ -2462,6 +2850,25 @@ pub mod milvus_service_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn alter_collection_field( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/AlterCollectionField", + ); + self.inner.unary(request.into_request(), path, codec).await + } pub async fn create_partition( &mut self, request: impl tonic::IntoRequest, @@ -2945,9 +3352,9 @@ pub mod milvus_service_client { ); self.inner.unary(request.into_request(), path, codec).await } - pub async fn search_v2( + pub async fn hybrid_search( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> Result, tonic::Status> { self.inner .ready() @@ -2960,7 +3367,7 @@ pub mod milvus_service_client { })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/milvus.proto.milvus.MilvusService/SearchV2", + "/milvus.proto.milvus.MilvusService/HybridSearch", ); self.inner.unary(request.into_request(), path, codec).await } @@ -3542,6 +3949,25 @@ pub mod milvus_service_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn operate_privilege_v2( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/OperatePrivilegeV2", + ); + self.inner.unary(request.into_request(), path, codec).await + } pub async fn select_grant( &mut self, request: impl tonic::IntoRequest, @@ -3637,6 +4063,25 @@ pub mod milvus_service_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn update_resource_groups( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/UpdateResourceGroups", + ); + self.inner.unary(request.into_request(), path, codec).await + } pub async fn transfer_node( &mut self, request: impl tonic::IntoRequest, @@ -3878,6 +4323,44 @@ pub mod milvus_service_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn alter_database( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/AlterDatabase", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn describe_database( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/DescribeDatabase", + ); + self.inner.unary(request.into_request(), path, codec).await + } pub async fn replicate_message( &mut self, request: impl tonic::IntoRequest, @@ -3897,6 +4380,120 @@ pub mod milvus_service_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn backup_rbac( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/BackupRBAC", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn restore_rbac( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/RestoreRBAC", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn create_privilege_group( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/CreatePrivilegeGroup", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn drop_privilege_group( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/DropPrivilegeGroup", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn list_privilege_groups( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/ListPrivilegeGroups", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn operate_privilege_group( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/milvus.proto.milvus.MilvusService/OperatePrivilegeGroup", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } /// Generated client implementations. diff --git a/src/proto/milvus.proto.msg.rs b/src/proto/milvus.proto.msg.rs index 1132b94..cab36ba 100644 --- a/src/proto/milvus.proto.msg.rs +++ b/src/proto/milvus.proto.msg.rs @@ -170,6 +170,20 @@ pub struct DataNodeTtMsg { #[prost(message, repeated, tag = "4")] pub segments_stats: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ReplicateMsg { + #[prost(message, optional, tag = "1")] + pub base: ::core::option::Option, + #[prost(bool, tag = "2")] + pub is_end: bool, + #[prost(bool, tag = "3")] + pub is_cluster: bool, + #[prost(string, tag = "4")] + pub database: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub collection: ::prost::alloc::string::String, +} #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum InsertDataVersion { diff --git a/src/proto/milvus.proto.rg.rs b/src/proto/milvus.proto.rg.rs new file mode 100644 index 0000000..846183c --- /dev/null +++ b/src/proto/milvus.proto.rg.rs @@ -0,0 +1,40 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResourceGroupLimit { + /// preserve for other limit. + #[prost(int32, tag = "1")] + pub node_num: i32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResourceGroupTransfer { + /// resource groups can be transfered with current resource group. + #[prost(string, tag = "1")] + pub resource_group: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResourceGroupNodeFilter { + /// node in resource group must match node labels requirements + #[prost(message, repeated, tag = "1")] + pub node_labels: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResourceGroupConfig { + /// requests node num in resource group, if node num is less than requests.nodeNum, it will be transfer from other resource group. + #[prost(message, optional, tag = "1")] + pub requests: ::core::option::Option, + /// limited node num in resource group, if node num is more than limits.nodeNum, it will be transfer to other resource group. + #[prost(message, optional, tag = "2")] + pub limits: ::core::option::Option, + /// missing node should be transfer from given resource group at high priority in repeated list. + #[prost(message, repeated, tag = "3")] + pub transfer_from: ::prost::alloc::vec::Vec, + /// redundant node should be transfer to given resource group at high priority in repeated list. + #[prost(message, repeated, tag = "4")] + pub transfer_to: ::prost::alloc::vec::Vec, + /// node in resource group must match node filters + #[prost(message, optional, tag = "5")] + pub node_filter: ::core::option::Option, +} diff --git a/src/proto/milvus.proto.schema.rs b/src/proto/milvus.proto.schema.rs index d28ba36..6c50225 100644 --- a/src/proto/milvus.proto.schema.rs +++ b/src/proto/milvus.proto.schema.rs @@ -36,6 +36,8 @@ pub struct FieldSchema { /// enable logic partitions #[prost(bool, tag = "13")] pub is_partition_key: bool, + #[prost(bool, tag = "14")] + pub is_clustering_key: bool, } /// * /// @brief Collection schema @@ -55,6 +57,10 @@ pub struct CollectionSchema { /// mark whether this table has the dynamic field function enabled. #[prost(bool, tag = "5")] pub enable_dynamic_field: bool, + #[prost(message, repeated, tag = "6")] + pub properties: ::prost::alloc::vec::Vec, + #[prost(string, tag = "8")] + pub db_name: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -171,12 +177,23 @@ pub mod scalar_field { JsonData(super::JsonArray), } } +/// beta, api may change +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SparseFloatArray { + #[prost(bytes = "vec", repeated, tag = "1")] + pub contents: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// dim is the max dimension of the current batch of vectors + #[prost(int64, tag = "2")] + pub dim: i64, +} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct VectorField { + /// For sparse vector, dim is the max dimension of the current batch of vectors #[prost(int64, tag = "1")] pub dim: i64, - #[prost(oneof = "vector_field::Data", tags = "2, 3, 4, 5")] + #[prost(oneof = "vector_field::Data", tags = "2, 3, 4, 5, 6")] pub data: ::core::option::Option, } /// Nested message and enum types in `VectorField`. @@ -192,6 +209,8 @@ pub mod vector_field { Float16Vector(::prost::alloc::vec::Vec), #[prost(bytes, tag = "5")] Bfloat16Vector(::prost::alloc::vec::Vec), + #[prost(message, tag = "6")] + SparseFloatVector(super::SparseFloatArray), } } #[allow(clippy::derive_partial_eq_without_eq)] @@ -255,6 +274,95 @@ pub struct SearchResultData { pub output_fields: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(message, optional, tag = "8")] pub group_by_field_value: ::core::option::Option, + #[prost(int64, tag = "9")] + pub all_search_count: i64, + #[prost(float, repeated, tag = "10")] + pub distances: ::prost::alloc::vec::Vec, + #[prost(float, repeated, tag = "12")] + pub recalls: ::prost::alloc::vec::Vec, + #[prost(string, tag = "13")] + pub primary_field_name: ::prost::alloc::string::String, +} +/// vector field clustering info +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct VectorClusteringInfo { + /// for multi vectors + #[prost(string, tag = "1")] + pub field: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub centroid: ::core::option::Option, +} +/// Scalar field clustering info +/// todo more definitions: min/max, etc +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ScalarClusteringInfo { + #[prost(string, tag = "1")] + pub field: ::prost::alloc::string::String, +} +/// clustering distribution info of a certain data unit, it can be segment, partition, etc. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClusteringInfo { + #[prost(message, repeated, tag = "1")] + pub vector_clustering_infos: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "2")] + pub scalar_clustering_infos: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TemplateValue { + #[prost(oneof = "template_value::Val", tags = "1, 2, 3, 4, 5")] + pub val: ::core::option::Option, +} +/// Nested message and enum types in `TemplateValue`. +pub mod template_value { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Val { + #[prost(bool, tag = "1")] + BoolVal(bool), + #[prost(int64, tag = "2")] + Int64Val(i64), + #[prost(double, tag = "3")] + FloatVal(f64), + #[prost(string, tag = "4")] + StringVal(::prost::alloc::string::String), + #[prost(message, tag = "5")] + ArrayVal(super::TemplateArrayValue), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TemplateArrayValue { + #[prost(oneof = "template_array_value::Data", tags = "1, 2, 3, 4, 5, 6")] + pub data: ::core::option::Option, +} +/// Nested message and enum types in `TemplateArrayValue`. +pub mod template_array_value { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Data { + #[prost(message, tag = "1")] + BoolData(super::BoolArray), + #[prost(message, tag = "2")] + LongData(super::LongArray), + #[prost(message, tag = "3")] + DoubleData(super::DoubleArray), + #[prost(message, tag = "4")] + StringData(super::StringArray), + #[prost(message, tag = "5")] + ArrayData(super::TemplateArrayValueArray), + #[prost(message, tag = "6")] + JsonData(super::JsonArray), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TemplateArrayValueArray { + #[prost(message, repeated, tag = "1")] + pub data: ::prost::alloc::vec::Vec, } /// * /// @brief Field data type @@ -278,6 +386,7 @@ pub enum DataType { FloatVector = 101, Float16Vector = 102, BFloat16Vector = 103, + SparseFloatVector = 104, } impl DataType { /// String value of the enum field names used in the ProtoBuf definition. @@ -302,6 +411,7 @@ impl DataType { DataType::FloatVector => "FloatVector", DataType::Float16Vector => "Float16Vector", DataType::BFloat16Vector => "BFloat16Vector", + DataType::SparseFloatVector => "SparseFloatVector", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -323,6 +433,7 @@ impl DataType { "FloatVector" => Some(Self::FloatVector), "Float16Vector" => Some(Self::Float16Vector), "BFloat16Vector" => Some(Self::BFloat16Vector), + "SparseFloatVector" => Some(Self::SparseFloatVector), _ => None, } } diff --git a/src/proto/mod.rs b/src/proto/mod.rs index 224a71b..9263981 100644 --- a/src/proto/mod.rs +++ b/src/proto/mod.rs @@ -24,6 +24,8 @@ pub mod feder; pub mod milvus; #[path = "milvus.proto.msg.rs"] pub mod msg; +#[path = "milvus.proto.rg.rs"] +pub mod rg; #[path = "milvus.proto.schema.rs"] pub mod schema; diff --git a/src/query.rs b/src/query.rs index 044e4c6..c9a12e5 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,4 +1,3 @@ -use std::borrow::Borrow; use std::collections::HashMap; use prost::bytes::BytesMut; @@ -22,21 +21,12 @@ const STRONG_TIMESTAMP: u64 = 0; const BOUNDED_TIMESTAMP: u64 = 2; const EVENTUALLY_TIMESTAMP: u64 = 1; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct QueryOptions { output_fields: Vec, partition_names: Vec, } -impl Default for QueryOptions { - fn default() -> Self { - Self { - output_fields: Vec::new(), - partition_names: Vec::new(), - } - } -} - impl QueryOptions { pub fn new() -> Self { Self::default() @@ -205,10 +195,10 @@ impl Client { .clone() .query(proto::milvus::QueryRequest { base: Some(MsgBase::new(MsgType::Retrieve)), - db_name: "".to_owned(), + db_name: self.db_name.clone(), collection_name: collection_name.to_owned(), expr: expr.as_ref().to_owned(), - output_fields: output_fields, + output_fields, partition_names: options.partition_names.clone(), travel_timestamp: 0, guarantee_timestamp: self @@ -218,17 +208,14 @@ impl Client { not_return_all_meta: false, consistency_level: ConsistencyLevel::default() as _, use_default_consistency: false, + ..Default::default() }) .await? .into_inner(); status_to_result(&res.status)?; - Ok(res - .fields_data - .into_iter() - .map(|f| FieldColumn::from(f)) - .collect()) + Ok(res.fields_data.into_iter().map(FieldColumn::from).collect()) } pub async fn search( @@ -273,19 +260,14 @@ impl Client { .clone() .search(SearchRequest { base: Some(MsgBase::new(MsgType::Search)), - db_name: "".to_string(), + db_name: self.db_name.clone(), collection_name: collection_name.clone(), partition_names: option.partitions.clone(), dsl: option.expr.clone(), nq: data.len() as _, placeholder_group: get_place_holder_group(data)?, dsl_type: DslType::BoolExprV1 as _, - output_fields: option - .output_fields - .clone() - .into_iter() - .map(|f| f.into()) - .collect(), + output_fields: option.output_fields.clone(), search_params, travel_timestamp: 0, guarantee_timestamp: self @@ -295,6 +277,7 @@ impl Client { consistency_level: ConsistencyLevel::default() as _, use_default_consistency: false, search_by_primary_keys: false, + ..Default::default() }) .await? .into_inner(); @@ -356,7 +339,7 @@ fn get_place_holder_group(vectors: Vec) -> Result> { }; let mut buf = BytesMut::new(); group.encode(&mut buf).unwrap(); - return Ok(buf.to_vec()); + Ok(buf.to_vec()) } fn get_place_holder_value(vectors: Vec) -> Result { @@ -366,7 +349,7 @@ fn get_place_holder_value(vectors: Vec) -> Result { values: Vec::new(), }; // if no vectors, return an empty one - if vectors.len() == 0 { + if vectors.is_empty() { return Ok(place_holder); }; @@ -399,5 +382,5 @@ fn get_place_holder_value(vectors: Vec) -> Result { } }; } - return Ok(place_holder); + Ok(place_holder) } diff --git a/src/schema.rs b/src/schema.rs index 73460b2..e4191ca 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -14,9 +14,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::error; +use std::collections::HashMap; + use crate::error::Result; use crate::proto::schema::FieldState; +use crate::{ + error, + utils::{hashmap_to_vec, vec_to_hashmap}, +}; use prost::alloc::vec::Vec; use prost::encoding::bool; use thiserror::Error as ThisError; @@ -410,7 +415,7 @@ impl From for schema::FieldSchema { schema::FieldSchema { field_id: 0, - name: fld.name.into(), + name: fld.name, is_primary_key: fld.is_primary, description: fld.description, data_type: fld.dtype as i32, @@ -422,6 +427,7 @@ impl From for schema::FieldSchema { default_value: None, is_dynamic: false, is_partition_key: false, + ..Default::default() } } } @@ -432,6 +438,8 @@ pub struct CollectionSchema { pub(crate) description: String, pub(crate) fields: Vec, pub(crate) enable_dynamic_field: bool, + pub(crate) db_name: String, + pub(crate) properties: HashMap, } impl CollectionSchema { @@ -449,7 +457,7 @@ impl CollectionSchema { } pub fn validate(&self) -> Result<()> { - self.primary_column().ok_or_else(|| Error::NoPrimaryKey)?; + self.primary_column().ok_or(Error::NoPrimaryKey)?; // TODO addidtional schema checks need to be added here Ok(()) } @@ -474,7 +482,7 @@ impl CollectionSchema { } } } - return Err(error::Error::from(Error::NoSuchKey(field_name.to_owned()))); + Err(error::Error::from(Error::NoSuchKey(field_name.to_owned()))) } } @@ -486,6 +494,8 @@ impl From for schema::CollectionSchema { description: col.description, fields: col.fields.into_iter().map(Into::into).collect(), enable_dynamic_field: col.enable_dynamic_field, + db_name: col.db_name, + properties: hashmap_to_vec(&col.properties), } } } @@ -497,6 +507,8 @@ impl From for CollectionSchema { name: v.name, description: v.description, enable_dynamic_field: v.enable_dynamic_field, + db_name: v.db_name, + properties: vec_to_hashmap(&v.properties), } } } @@ -507,6 +519,8 @@ pub struct CollectionSchemaBuilder { description: String, inner: Vec, enable_dynamic_field: bool, + db_name: String, + properties: HashMap, } impl CollectionSchemaBuilder { @@ -516,6 +530,8 @@ impl CollectionSchemaBuilder { description: description.to_owned(), inner: Vec::new(), enable_dynamic_field: false, + db_name: String::new(), + properties: HashMap::new(), } } @@ -554,6 +570,16 @@ impl CollectionSchemaBuilder { Err(error::Error::from(Error::NoSuchKey(n.to_string()))) } + pub fn set_database(&mut self, db_name: &str) -> &mut Self { + self.db_name = db_name.to_owned(); + self + } + + pub fn set_property(&mut self, key: &str, value: &str) -> &mut Self { + self.properties.insert(key.to_owned(), value.to_owned()); + self + } + pub fn enable_auto_id(&mut self) -> Result<&mut Self> { for f in self.inner.iter_mut() { if f.is_primary { @@ -590,13 +616,15 @@ impl CollectionSchemaBuilder { return Err(error::Error::from(Error::NoPrimaryKey)); } - let this = std::mem::replace(self, CollectionSchemaBuilder::new("".into(), "")); + let this = std::mem::replace(self, CollectionSchemaBuilder::new("", "")); Ok(CollectionSchema { - fields: this.inner.into(), + fields: this.inner, name: this.name, description: this.description, enable_dynamic_field: self.enable_dynamic_field, + db_name: self.db_name.clone(), + properties: self.properties.clone(), }) } } diff --git a/src/types.rs b/src/types.rs index 52803d1..cb418e4 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,24 +1 @@ -use crate::proto::{self, schema::DataType}; - pub(crate) type Timestamp = u64; - -#[derive(Debug, Clone)] -pub struct Field { - pub id: i64, - pub name: String, - pub description: String, - pub dtype: DataType, - pub is_primary_key: bool, -} - -impl From for Field { - fn from(value: proto::schema::FieldSchema) -> Self { - Self { - id: value.field_id, - name: value.name, - description: value.description, - dtype: DataType::from_i32(value.data_type).unwrap_or(DataType::None), - is_primary_key: value.is_primary_key, - } - } -} diff --git a/src/utils.rs b/src/utils.rs index 8382c68..65177c5 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -14,9 +14,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::collections::HashMap; + use crate::{ error::Error, - proto::common::{ErrorCode, Status}, + proto::common::{ErrorCode, KeyValuePair, Status}, }; pub fn status_to_result(status: &Option) -> Result<(), Error> { @@ -35,3 +37,16 @@ pub fn status_to_result(status: &Option) -> Result<(), Error> { ))), } } + +pub fn vec_to_hashmap(vec: &[KeyValuePair]) -> HashMap { + HashMap::from_iter(vec.iter().map(|kv| (kv.key.clone(), kv.value.clone()))) +} + +pub fn hashmap_to_vec(map: &HashMap) -> Vec { + map.iter() + .map(|(k, v)| KeyValuePair { + key: k.clone(), + value: v.clone(), + }) + .collect() +} diff --git a/src/value.rs b/src/value.rs index f2c72e1..5dd39b1 100644 --- a/src/value.rs +++ b/src/value.rs @@ -189,25 +189,26 @@ impl ValueVec { DataType::FloatVector => Self::Float(Vec::new()), DataType::Float16Vector => Self::Binary(Vec::new()), DataType::BFloat16Vector => Self::Binary(Vec::new()), + DataType::SparseFloatVector => unimplemented!(), } } pub fn check_dtype(&self, dtype: DataType) -> bool { - match (self, dtype) { + matches!( + (self, dtype), (ValueVec::Binary(..), DataType::BinaryVector) - | (ValueVec::Float(..), DataType::FloatVector) - | (ValueVec::Float(..), DataType::Float) - | (ValueVec::Int(..), DataType::Int8) - | (ValueVec::Int(..), DataType::Int16) - | (ValueVec::Int(..), DataType::Int32) - | (ValueVec::Long(..), DataType::Int64) - | (ValueVec::Bool(..), DataType::Bool) - | (ValueVec::String(..), DataType::String) - | (ValueVec::String(..), DataType::VarChar) - | (ValueVec::None, _) - | (ValueVec::Double(..), DataType::Double) => true, - _ => false, - } + | (ValueVec::Float(..), DataType::FloatVector) + | (ValueVec::Float(..), DataType::Float) + | (ValueVec::Int(..), DataType::Int8) + | (ValueVec::Int(..), DataType::Int16) + | (ValueVec::Int(..), DataType::Int32) + | (ValueVec::Long(..), DataType::Int64) + | (ValueVec::Bool(..), DataType::Bool) + | (ValueVec::String(..), DataType::String) + | (ValueVec::String(..), DataType::VarChar) + | (ValueVec::None, _) + | (ValueVec::Double(..), DataType::Double) + ) } #[inline] @@ -270,6 +271,7 @@ impl From for ValueVec { VectorData::BinaryVector(v) => Self::Binary(v), VectorData::Bfloat16Vector(v) => Self::Binary(v), VectorData::Float16Vector(v) => Self::Binary(v), + VectorData::SparseFloatVector(_) => unimplemented!(), }, None => Self::None, }, diff --git a/tests/client.rs b/tests/client.rs index 8720e4a..2943e91 100644 --- a/tests/client.rs +++ b/tests/client.rs @@ -75,6 +75,7 @@ async fn create_has_drop_collection() -> Result<()> { let schema = schema .add_field(FieldSchema::new_int64("i64_field", "")) .add_field(FieldSchema::new_bool("bool_field", "")) + .add_field(FieldSchema::new_float_vector("float_field", "", 2)) .set_primary_key("i64_field")? .enable_auto_id()? .build()?; diff --git a/tests/database.rs b/tests/database.rs new file mode 100644 index 0000000..d0bf557 --- /dev/null +++ b/tests/database.rs @@ -0,0 +1,82 @@ +use std::collections::HashMap; + +use milvus::{ + client::Client, + data::FieldColumn, + error::Result, + index::{IndexParams, IndexType, MetricType}, + proto::common::LoadState, + query::QueryOptions, + schema::{CollectionSchemaBuilder, FieldSchema}, +}; + +mod common; +use common::*; + +#[tokio::test] +async fn alternative_database() -> Result<()> { + let mut client = Client::new(URL).await?; + let db_name = format!("test_database_{}", gen_random_name()); + + client.create_database(&db_name, HashMap::new()).await?; + client.use_database(&db_name).await?; + + let collection_name = format!("test_collection_{}", gen_random_name()); + + let schema = CollectionSchemaBuilder::new(&collection_name, "") + .add_field(FieldSchema::new_primary_int64("id", "", true)) + .add_field(FieldSchema::new_float_vector("vector", "", 2)) + .build()?; + + let column = FieldColumn::new( + schema.get_field("vector").unwrap(), + gen_random_f32_vector(2), + ); + client.create_collection(schema, None).await?; + client + .create_index( + &collection_name, + "id", + IndexParams::new( + "AUTOINDEX".into(), + IndexType::AUTOINDEX, + MetricType::None, + HashMap::new(), + ), + ) + .await?; + client + .create_index( + &collection_name, + "vector", + IndexParams::new( + "AUTOINDEX_V".into(), + IndexType::AUTOINDEX, + MetricType::COSINE, + HashMap::new(), + ), + ) + .await?; + client.load_collection(&collection_name, None).await?; + let state = client.get_load_state(&collection_name, None).await?; + assert_eq!(state, LoadState::Loaded); + + client.insert(&collection_name, vec![column], None).await?; + + let result = client + .query(&collection_name, "id > 0", &QueryOptions::default()) + .await?; + assert_eq!(result.len(), 2, "{:#?}", result); + + client.release_collection(&collection_name).await?; + let state = client.get_load_state(&collection_name, None).await?; + assert_eq!(state, LoadState::NotLoad); + + client.drop_collection(&collection_name).await?; + client.drop_database(&db_name).await?; + + let dbs = client.list_databases().await?; + assert!(!dbs.contains(&db_name)); + + Ok(()) +}