arc_vector_rust/
client.rs

1use crate::channel_pool::ChannelPool;
2use crate::arc_vector::alias_operations::Action;
3use crate::arc_vector::collections_client::CollectionsClient;
4use crate::arc_vector::point_id::PointIdOptions;
5use crate::arc_vector::points_client::PointsClient;
6use crate::arc_vector::points_selector::PointsSelectorOneOf;
7use crate::arc_vector::snapshots_client::SnapshotsClient;
8use crate::arc_vector::update_collection_cluster_setup_request::Operation;
9use crate::arc_vector::value::Kind;
10use crate::arc_vector::vectors::VectorsOptions;
11use crate::arc_vector::with_payload_selector::SelectorOptions;
12use crate::arc_vector::{
13    arc_vector_client, with_vectors_selector, AliasOperations, ChangeAliases, ClearPayloadPoints,
14    CollectionClusterInfoRequest, CollectionClusterInfoResponse, CollectionOperationResponse,
15    CountPoints, CountResponse, CreateAlias, CreateCollection, CreateFieldIndexCollection,
16    CreateFullSnapshotRequest, CreateSnapshotRequest, CreateSnapshotResponse, DeleteAlias,
17    DeleteCollection, DeleteFieldIndexCollection, DeleteFullSnapshotRequest, DeletePayloadPoints,
18    DeletePointVectors, DeletePoints, DeleteSnapshotRequest, DeleteSnapshotResponse, FieldType,
19    GetCollectionInfoRequest, GetCollectionInfoResponse, GetPoints, GetResponse, HealthCheckReply,
20    HealthCheckRequest, ListAliasesRequest, ListAliasesResponse, ListCollectionAliasesRequest,
21    ListCollectionsRequest, ListCollectionsResponse, ListFullSnapshotsRequest,
22    ListSnapshotsRequest, ListSnapshotsResponse, ListValue, NamedVectors, OptimizersConfigDiff,
23    PayloadIncludeSelector, PayloadIndexParams, PointId, PointStruct, PointVectors, PointsIdsList,
24    PointsOperationResponse, PointsSelector, ReadConsistency, RecommendBatchPoints,
25    RecommendBatchResponse, RecommendGroupsResponse, RecommendPointGroups, RecommendPoints,
26    RecommendResponse, RenameAlias, ScrollPoints, ScrollResponse, SearchBatchPoints,
27    SearchBatchResponse, SearchGroupsResponse, SearchPointGroups, SearchPoints, SearchResponse,
28    SetPayloadPoints, Struct, UpdateCollection, UpdateCollectionClusterSetupRequest,
29    UpdateCollectionClusterSetupResponse, UpdatePointVectors, UpsertPoints, Value, Vector, Vectors,
30    VectorsSelector, WithPayloadSelector, WithVectorsSelector, WriteOrdering,
31};
32use anyhow::Result;
33#[cfg(feature = "serde")]
34use serde::{Deserialize, Serialize};
35use std::collections::HashMap;
36use std::future::Future;
37#[cfg(feature = "download_snapshots")]
38use std::path::PathBuf;
39use std::time::Duration;
40use tonic::codegen::InterceptedService;
41use tonic::service::Interceptor;
42use tonic::transport::{Channel, Uri};
43use tonic::{Request, Status};
44
45pub struct ArcVectorClientConfig {
46    pub uri: String,
47    pub timeout: Duration,
48    pub connect_timeout: Duration,
49    pub keep_alive_while_idle: bool,
50    pub api_key: Option<String>,
51}
52
53/// A builder type for `ArcVectorClient`s
54pub type ArcVectorClientBuilder = ArcVectorClientConfig;
55
56/// Helper thread to allow setting an API key from various types
57pub trait MaybeApiKey {
58    fn maybe_key(self) -> Option<String>;
59}
60
61impl MaybeApiKey for &str {
62    fn maybe_key(self) -> Option<String> {
63        Some(self.to_string())
64    }
65}
66
67impl MaybeApiKey for String {
68    fn maybe_key(self) -> Option<String> {
69        Some(self)
70    }
71}
72
73impl MaybeApiKey for Option<String> {
74    fn maybe_key(self) -> Option<String> {
75        self
76    }
77}
78
79impl MaybeApiKey for Option<&String> {
80    fn maybe_key(self) -> Option<String> {
81        self.map(ToOwned::to_owned)
82    }
83}
84
85impl MaybeApiKey for Option<&str> {
86    fn maybe_key(self) -> Option<String> {
87        self.map(ToOwned::to_owned)
88    }
89}
90
91impl<E: Sized> MaybeApiKey for std::result::Result<String, E> {
92    fn maybe_key(self) -> Option<String> {
93        self.ok()
94    }
95}
96
97pub trait AsTimeout {
98    fn timeout(self) -> Duration;
99}
100
101impl AsTimeout for Duration {
102    fn timeout(self) -> Duration {
103        self
104    }
105}
106
107impl AsTimeout for u64 {
108    fn timeout(self) -> Duration {
109        Duration::from_secs(self)
110    }
111}
112
113impl ArcVectorClientConfig {
114    pub fn from_url(url: &str) -> Self {
115        ArcVectorClientConfig {
116            uri: url.to_string(),
117            ..Self::default()
118        }
119    }
120
121    pub fn set_api_key(&mut self, api_key: &str) {
122        self.api_key = Some(api_key.to_string());
123    }
124
125    pub fn set_timeout(&mut self, timeout: Duration) {
126        self.timeout = timeout;
127    }
128
129    pub fn set_connect_timeout(&mut self, connect_timeout: Duration) {
130        self.connect_timeout = connect_timeout;
131    }
132
133    pub fn set_keep_alive_while_idle(&mut self, keep_alive_while_idle: bool) {
134        self.keep_alive_while_idle = keep_alive_while_idle;
135    }
136
137    /// set the API key, builder-like. The API key argument can be any of
138    /// `&str`, `String`, `Option<&str>``, `Option<String>` or `Result<String>`.`
139    ///
140    /// # Examples:
141    ///
142    /// A typical use case might be getting the key from an env var:
143    /// ```rust, no_run
144    /// use arc_vector_rust::prelude::*;
145    ///
146    /// let client = ArcVectorClient::from_url("localhost:6334")
147    ///     .with_api_key(std::env::var("ARC_VECTOR_API_KEY"))
148    ///     .build();
149    /// ```
150    /// Another possibility might be getting it out of some config
151    /// ```rust, no_run
152    /// use arc_vector_rust::prelude::*;
153    ///# use std::collections::HashMap;
154    ///# let config: HashMap<&str, String> = HashMap::new();
155    /// let client = ArcVectorClientConfig::from_url("localhost:6334")
156    ///     .with_api_key(config.get("api_key"))
157    ///     .build();
158    /// ```
159    pub fn with_api_key(mut self, api_key: impl MaybeApiKey) -> Self {
160        self.api_key = api_key.maybe_key();
161        self
162    }
163
164    /// Configure the service to keep the connection alive while idle
165    pub fn keep_alive_while_idle(mut self) -> Self {
166        self.keep_alive_while_idle = true;
167        self
168    }
169
170    /// Set the timeout for this client
171    pub fn with_timeout(mut self, timeout: impl AsTimeout) -> Self {
172        self.timeout = timeout.timeout();
173        self
174    }
175
176    /// Set the connect timeout for this client
177    pub fn with_connect_timeout(mut self, timeout: impl AsTimeout) -> Self {
178        self.connect_timeout = timeout.timeout();
179        self
180    }
181
182    /// Build the ArcVectorClient
183    pub fn build(self) -> Result<ArcVectorClient> {
184        ArcVectorClient::new(Some(self))
185    }
186}
187
188impl From<bool> for WithPayloadSelector {
189    fn from(flag: bool) -> Self {
190        WithPayloadSelector {
191            selector_options: Some(SelectorOptions::Enable(flag)),
192        }
193    }
194}
195
196impl From<Vec<&str>> for WithPayloadSelector {
197    fn from(fields: Vec<&str>) -> Self {
198        WithPayloadSelector {
199            selector_options: Some(SelectorOptions::Include(PayloadIncludeSelector {
200                fields: fields.into_iter().map(|f| f.to_string()).collect(),
201            })),
202        }
203    }
204}
205
206impl From<Vec<PointId>> for PointsSelector {
207    fn from(point_ids: Vec<PointId>) -> Self {
208        PointsSelector {
209            points_selector_one_of: Some(PointsSelectorOneOf::Points(PointsIdsList {
210                ids: point_ids,
211            })),
212        }
213    }
214}
215
216impl From<Vec<f32>> for Vector {
217    fn from(vector: Vec<f32>) -> Self {
218        Vector { data: vector }
219    }
220}
221
222impl From<HashMap<String, Vec<f32>>> for Vectors {
223    fn from(named_vectors: HashMap<String, Vec<f32>>) -> Self {
224        Vectors {
225            vectors_options: Some(VectorsOptions::Vectors(NamedVectors {
226                vectors: named_vectors
227                    .into_iter()
228                    .map(|(k, v)| (k, v.into()))
229                    .collect(),
230            })),
231        }
232    }
233}
234
235impl From<Vec<f32>> for Vectors {
236    fn from(vector: Vec<f32>) -> Self {
237        Vectors {
238            vectors_options: Some(VectorsOptions::Vector(vector.into())),
239        }
240    }
241}
242
243impl From<Vec<&str>> for WithVectorsSelector {
244    fn from(names: Vec<&str>) -> Self {
245        WithVectorsSelector {
246            selector_options: Some(with_vectors_selector::SelectorOptions::Include(
247                VectorsSelector {
248                    names: names.into_iter().map(|name| name.to_string()).collect(),
249                },
250            )),
251        }
252    }
253}
254
255impl From<bool> for WithVectorsSelector {
256    fn from(flag: bool) -> Self {
257        WithVectorsSelector {
258            selector_options: Some(with_vectors_selector::SelectorOptions::Enable(flag)),
259        }
260    }
261}
262
263impl Default for ArcVectorClientConfig {
264    fn default() -> Self {
265        Self {
266            uri: String::from("http://localhost:6334"),
267            timeout: Duration::from_secs(5),
268            connect_timeout: Duration::from_secs(5),
269            keep_alive_while_idle: true,
270            api_key: None,
271        }
272    }
273}
274
275pub struct TokenInterceptor {
276    api_key: Option<String>,
277}
278
279impl TokenInterceptor {
280    pub fn new(api_key: Option<String>) -> Self {
281        Self { api_key }
282    }
283}
284
285impl Interceptor for TokenInterceptor {
286    fn call(&mut self, mut req: Request<()>) -> Result<Request<()>, Status> {
287        if let Some(api_key) = &self.api_key {
288            req.metadata_mut().insert(
289                "api-key",
290                api_key.parse().map_err(|_| {
291                    Status::invalid_argument(format!("Malformed API key: {}", api_key))
292                })?,
293            );
294        }
295        Ok(req)
296    }
297}
298
299pub struct ArcVectorClient {
300    pub channel: ChannelPool,
301    pub cfg: ArcVectorClientConfig,
302}
303
304impl ArcVectorClient {
305    /// Create a builder to setup the client
306    pub fn from_url(url: &str) -> ArcVectorClientBuilder {
307        ArcVectorClientBuilder::from_url(url)
308    }
309
310    /// Wraps a channel with a token interceptor
311    fn with_api_key(&self, channel: Channel) -> InterceptedService<Channel, TokenInterceptor> {
312        let interceptor = TokenInterceptor::new(self.cfg.api_key.clone());
313        InterceptedService::new(channel, interceptor)
314    }
315
316    pub async fn with_snapshot_client<T, O: Future<Output = Result<T, Status>>>(
317        &self,
318        f: impl Fn(SnapshotsClient<InterceptedService<Channel, TokenInterceptor>>) -> O,
319    ) -> Result<T, Status> {
320        self.channel
321            .with_channel(
322                |channel| {
323                    let service = self.with_api_key(channel);
324                    let client = SnapshotsClient::new(service);
325                    let client = client.max_decoding_message_size(usize::MAX);
326                    f(client)
327                },
328                false,
329            )
330            .await
331    }
332
333    // Access to raw collection API
334    pub async fn with_collections_client<T, O: Future<Output = Result<T, Status>>>(
335        &self,
336        f: impl Fn(CollectionsClient<InterceptedService<Channel, TokenInterceptor>>) -> O,
337    ) -> Result<T, Status> {
338        self.channel
339            .with_channel(
340                |channel| {
341                    let service = self.with_api_key(channel);
342                    let client = CollectionsClient::new(service);
343                    let client = client.max_decoding_message_size(usize::MAX);
344                    f(client)
345                },
346                false,
347            )
348            .await
349    }
350
351    // Access to raw points API
352    pub async fn with_points_client<T, O: Future<Output = Result<T, Status>>>(
353        &self,
354        f: impl Fn(PointsClient<InterceptedService<Channel, TokenInterceptor>>) -> O,
355    ) -> Result<T, Status> {
356        self.channel
357            .with_channel(
358                |channel| {
359                    let service = self.with_api_key(channel);
360                    let client = PointsClient::new(service);
361                    let client = client.max_decoding_message_size(usize::MAX);
362                    f(client)
363                },
364                true,
365            )
366            .await
367    }
368
369    // Access to raw root arc_vector API
370    pub async fn with_root_arc_vector_client<T, O: Future<Output = Result<T, Status>>>(
371        &self,
372        f: impl Fn(arc_vector_client::ArcVectorClient<InterceptedService<Channel, TokenInterceptor>>) -> O,
373    ) -> Result<T, Status> {
374        self.channel
375            .with_channel(
376                |channel| {
377                    let service = self.with_api_key(channel);
378                    let client = arc_vector_client::ArcVectorClient::new(service);
379                    let client = client.max_decoding_message_size(usize::MAX);
380                    f(client)
381                },
382                true,
383            )
384            .await
385    }
386
387    pub fn new(cfg: Option<ArcVectorClientConfig>) -> Result<Self> {
388        let cfg = cfg.unwrap_or_default();
389
390        let channel = ChannelPool::new(
391            cfg.uri.parse::<Uri>()?,
392            cfg.timeout,
393            cfg.connect_timeout,
394            cfg.keep_alive_while_idle,
395        );
396
397        let client = Self { channel, cfg };
398
399        Ok(client)
400    }
401
402    pub async fn health_check(&self) -> Result<HealthCheckReply> {
403        Ok(self
404            .with_root_arc_vector_client(|mut arc_vector_api| async move {
405                let result = arc_vector_api.health_check(HealthCheckRequest {}).await?;
406                Ok(result.into_inner())
407            })
408            .await?)
409    }
410
411    pub async fn list_collections(&self) -> Result<ListCollectionsResponse> {
412        Ok(self
413            .with_collections_client(|mut collection_api| async move {
414                let result = collection_api.list(ListCollectionsRequest {}).await?;
415                Ok(result.into_inner())
416            })
417            .await?)
418    }
419
420    pub async fn has_collection(&self, collection_name: impl ToString) -> Result<bool> {
421        let collection_name = collection_name.to_string();
422        let response = self.list_collections().await?;
423        let result = response
424            .collections
425            .into_iter()
426            .any(|c| c.name == collection_name);
427
428        Ok(result)
429    }
430
431    pub async fn create_collection(
432        &self,
433        details: &CreateCollection,
434    ) -> Result<CollectionOperationResponse> {
435        Ok(self
436            .with_collections_client(|mut collection_api| async move {
437                let result = collection_api.create(details.clone()).await?;
438                Ok(result.into_inner())
439            })
440            .await?)
441    }
442
443    pub async fn update_collection(
444        &self,
445        collection_name: impl ToString,
446        optimizers_config: &OptimizersConfigDiff,
447    ) -> Result<CollectionOperationResponse> {
448        let collection_name = collection_name.to_string();
449        let collection_name_ref = collection_name.as_str();
450
451        Ok(self
452            .with_collections_client(|mut collection_api| async move {
453                let result = collection_api
454                    .update(UpdateCollection {
455                        collection_name: collection_name_ref.to_string(),
456                        optimizers_config: Some(optimizers_config.clone()),
457                        timeout: None,
458                        params: None,
459                        hnsw_config: None,
460                        vectors_config: None,
461                        quantization_config: None,
462                    })
463                    .await?;
464
465                Ok(result.into_inner())
466            })
467            .await?)
468    }
469
470    pub async fn delete_collection(
471        &self,
472        collection_name: impl ToString,
473    ) -> Result<CollectionOperationResponse> {
474        let collection_name = collection_name.to_string();
475        let collection_name_ref = collection_name.as_str();
476
477        Ok(self
478            .with_collections_client(|mut collection_api| async move {
479                let result = collection_api
480                    .delete(DeleteCollection {
481                        collection_name: collection_name_ref.to_string(),
482                        ..Default::default()
483                    })
484                    .await?;
485                Ok(result.into_inner())
486            })
487            .await?)
488    }
489
490    pub async fn collection_info(
491        &self,
492        collection_name: impl ToString,
493    ) -> Result<GetCollectionInfoResponse> {
494        let collection_name = collection_name.to_string();
495        let collection_name_ref = collection_name.as_str();
496
497        Ok(self
498            .with_collections_client(|mut collection_api| async move {
499                let result = collection_api
500                    .get(GetCollectionInfoRequest {
501                        collection_name: collection_name_ref.to_string(),
502                    })
503                    .await?;
504                Ok(result.into_inner())
505            })
506            .await?)
507    }
508
509    pub async fn create_alias(
510        &self,
511        collection_name: impl ToString,
512        alias_name: impl ToString,
513    ) -> Result<CollectionOperationResponse> {
514        let create_alias = CreateAlias {
515            collection_name: collection_name.to_string(),
516            alias_name: alias_name.to_string(),
517        };
518        let change_aliases = ChangeAliases {
519            actions: vec![AliasOperations {
520                action: Some(Action::CreateAlias(create_alias)),
521            }],
522            timeout: None,
523        };
524        self.update_aliases(change_aliases).await
525    }
526
527    pub async fn delete_alias(
528        &self,
529        alias_name: impl ToString,
530    ) -> Result<CollectionOperationResponse> {
531        let delete_alias = DeleteAlias {
532            alias_name: alias_name.to_string(),
533        };
534        let change_aliases = ChangeAliases {
535            actions: vec![AliasOperations {
536                action: Some(Action::DeleteAlias(delete_alias)),
537            }],
538            timeout: None,
539        };
540        self.update_aliases(change_aliases).await
541    }
542
543    pub async fn rename_alias(
544        &self,
545        old_alias_name: impl ToString,
546        new_alias_name: impl ToString,
547    ) -> Result<CollectionOperationResponse> {
548        let rename_alias = RenameAlias {
549            old_alias_name: old_alias_name.to_string(),
550            new_alias_name: new_alias_name.to_string(),
551        };
552        let change_aliases = ChangeAliases {
553            actions: vec![AliasOperations {
554                action: Some(Action::RenameAlias(rename_alias)),
555            }],
556            timeout: None,
557        };
558        self.update_aliases(change_aliases).await
559    }
560
561    // lower level API
562    pub async fn update_aliases(
563        &self,
564        change_aliases: ChangeAliases,
565    ) -> Result<CollectionOperationResponse> {
566        let change_aliases = change_aliases.clone();
567        let chang_aliases_ref = &change_aliases;
568        Ok(self
569            .with_collections_client(|mut collection_api| async move {
570                let result = collection_api
571                    .update_aliases(chang_aliases_ref.clone())
572                    .await?;
573                Ok(result.into_inner())
574            })
575            .await?)
576    }
577
578    pub async fn list_collection_aliases(
579        &self,
580        collection_name: impl ToString,
581    ) -> Result<ListAliasesResponse> {
582        let collection_name = collection_name.to_string();
583        let collection_name_ref = collection_name.as_str();
584        Ok(self
585            .with_collections_client(|mut collection_api| async move {
586                let result = collection_api
587                    .list_collection_aliases(ListCollectionAliasesRequest {
588                        collection_name: collection_name_ref.to_string(),
589                    })
590                    .await?;
591                Ok(result.into_inner())
592            })
593            .await?)
594    }
595
596    pub async fn list_aliases(&self) -> Result<ListAliasesResponse> {
597        Ok(self
598            .with_collections_client(|mut collection_api| async move {
599                let result = collection_api.list_aliases(ListAliasesRequest {}).await?;
600                Ok(result.into_inner())
601            })
602            .await?)
603    }
604
605    pub async fn collection_cluster_info(
606        &self,
607        collection_name: impl ToString,
608    ) -> Result<CollectionClusterInfoResponse> {
609        let collection_name = collection_name.to_string();
610        let collection_name_ref = collection_name.as_str();
611
612        Ok(self
613            .with_collections_client(|mut collection_api| async move {
614                let request = CollectionClusterInfoRequest {
615                    collection_name: collection_name_ref.to_string(),
616                };
617                let result = collection_api.collection_cluster_info(request).await?;
618                Ok(result.into_inner())
619            })
620            .await?)
621    }
622
623    pub async fn update_collection_cluster_setup(
624        &self,
625        collection_name: impl ToString,
626        operation: Operation,
627    ) -> Result<UpdateCollectionClusterSetupResponse> {
628        let collection_name = collection_name.to_string();
629        let collection_name_ref = collection_name.as_str();
630        let operation_ref = &operation;
631        Ok(self
632            .with_collections_client(|mut collection_api| async move {
633                let request = UpdateCollectionClusterSetupRequest {
634                    collection_name: collection_name_ref.to_string(),
635                    timeout: None,
636                    operation: Some(operation_ref.clone()),
637                };
638                let result = collection_api
639                    .update_collection_cluster_setup(request)
640                    .await?;
641                Ok(result.into_inner())
642            })
643            .await?)
644    }
645
646    /// Update or insert points into the collection.
647    /// If points with given ID already exist, they will be overwritten.
648    /// This method does *not* wait for completion of the operation, use
649    /// [`upsert_points_blocking`] for that.
650    /// Also this method does not split the points to insert to avoid timeouts,
651    /// look at [`upsert_points_batch`] for that.
652    pub async fn upsert_points(
653        &self,
654        collection_name: impl ToString,
655        points: Vec<PointStruct>,
656        ordering: Option<WriteOrdering>,
657    ) -> Result<PointsOperationResponse> {
658        self._upsert_points(collection_name, &points, false, ordering)
659            .await
660    }
661
662    /// Update or insert points into the collection, wait for completion.
663    /// If points with given ID already exist, they will be overwritten.
664    /// This method does not split the points to insert to avoid timeouts,
665    /// look at [`upsert_points_batch`] for that.
666    pub async fn upsert_points_blocking(
667        &self,
668        collection_name: impl ToString,
669        points: Vec<PointStruct>,
670        ordering: Option<WriteOrdering>,
671    ) -> Result<PointsOperationResponse> {
672        self._upsert_points(collection_name, &points, true, ordering)
673            .await
674    }
675
676    #[inline]
677    async fn _upsert_points(
678        &self,
679        collection_name: impl ToString,
680        points: &[PointStruct],
681        block: bool,
682        ordering: Option<WriteOrdering>,
683    ) -> Result<PointsOperationResponse> {
684        let collection_name = collection_name.to_string();
685        let collection_name_ref = collection_name.as_str();
686        let ordering_ref = ordering.as_ref();
687        Ok(self
688            .with_points_client(|mut points_api| async move {
689                Ok(points_api
690                    .upsert(UpsertPoints {
691                        collection_name: collection_name_ref.to_string(),
692                        wait: Some(block),
693                        points: points.to_vec(),
694                        ordering: ordering_ref.cloned(),
695                    })
696                    .await?
697                    .into_inner())
698            })
699            .await?)
700    }
701
702    /// Update or insert points into the collection, splitting in chunks.
703    /// If points with given ID already exist, they will be overwritten.
704    /// This method does *not* wait for completion of the operation, use
705    /// [`upsert_points_batch_blocking`] for that.
706    pub async fn upsert_points_batch(
707        &self,
708        collection_name: impl ToString,
709        points: Vec<PointStruct>,
710        ordering: Option<WriteOrdering>,
711        chunk_size: usize,
712    ) -> Result<PointsOperationResponse> {
713        self._upsert_points_batch(collection_name, &points, false, ordering, chunk_size)
714            .await
715    }
716
717    /// Update or insert points into the collection, splitting in chunks and
718    /// waiting for completion of each.
719    /// If points with given ID already exist, they will be overwritten.
720    pub async fn upsert_points_batch_blocking(
721        &self,
722        collection_name: impl ToString,
723        points: Vec<PointStruct>,
724        ordering: Option<WriteOrdering>,
725        chunk_size: usize,
726    ) -> Result<PointsOperationResponse> {
727        self._upsert_points_batch(collection_name, &points, true, ordering, chunk_size)
728            .await
729    }
730
731    #[inline]
732    async fn _upsert_points_batch(
733        &self,
734        collection_name: impl ToString,
735        points: &[PointStruct],
736        block: bool,
737        ordering: Option<WriteOrdering>,
738        chunk_size: usize,
739    ) -> Result<PointsOperationResponse> {
740        if points.len() < chunk_size {
741            return self
742                ._upsert_points(collection_name, points, block, ordering)
743                .await;
744        }
745        let collection_name = collection_name.to_string();
746        let collection_name_ref = collection_name.as_str();
747        let ordering_ref = ordering.as_ref();
748        Ok(self
749            .with_points_client(|mut points_api| async move {
750                let mut resp = PointsOperationResponse {
751                    result: None,
752                    time: 0.0,
753                };
754                for chunk in points.chunks(chunk_size) {
755                    let PointsOperationResponse { result, time } = points_api
756                        .upsert(UpsertPoints {
757                            collection_name: collection_name_ref.to_string(),
758                            wait: Some(block),
759                            points: chunk.to_vec(),
760                            ordering: ordering_ref.cloned(),
761                        })
762                        .await?
763                        .into_inner();
764                    resp.result = result;
765                    resp.time += time;
766                }
767                Ok(resp)
768            })
769            .await?)
770    }
771
772    pub async fn set_payload(
773        &self,
774        collection_name: impl ToString,
775        points: &PointsSelector,
776        payload: Payload,
777        ordering: Option<WriteOrdering>,
778    ) -> Result<PointsOperationResponse> {
779        self._set_payload(collection_name, points, &payload, false, ordering)
780            .await
781    }
782
783    pub async fn set_payload_blocking(
784        &self,
785        collection_name: impl ToString,
786        points: &PointsSelector,
787        payload: Payload,
788        ordering: Option<WriteOrdering>,
789    ) -> Result<PointsOperationResponse> {
790        self._set_payload(collection_name, points, &payload, true, ordering)
791            .await
792    }
793
794    #[inline]
795    async fn _set_payload(
796        &self,
797        collection_name: impl ToString,
798        points: &PointsSelector,
799        payload: &Payload,
800        block: bool,
801        ordering: Option<WriteOrdering>,
802    ) -> Result<PointsOperationResponse> {
803        let collection_name = collection_name.to_string();
804        let collection_name_ref = collection_name.as_str();
805        let ordering_ref = ordering.as_ref();
806
807        Ok(self
808            .with_points_client(|mut points_api| async move {
809                let result = points_api
810                    .set_payload(SetPayloadPoints {
811                        collection_name: collection_name_ref.to_string(),
812                        wait: Some(block),
813                        payload: payload.0.clone(),
814                        points_selector: Some(points.clone()),
815                        ordering: ordering_ref.cloned(),
816                    })
817                    .await?;
818                Ok(result.into_inner())
819            })
820            .await?)
821    }
822
823    pub async fn overwrite_payload(
824        &self,
825        collection_name: impl ToString,
826        points: &PointsSelector,
827        payload: Payload,
828        ordering: Option<WriteOrdering>,
829    ) -> Result<PointsOperationResponse> {
830        self._overwrite_payload(collection_name, points, &payload, false, ordering)
831            .await
832    }
833
834    pub async fn overwrite_payload_blocking(
835        &self,
836        collection_name: impl ToString,
837        points: &PointsSelector,
838        payload: Payload,
839        ordering: Option<WriteOrdering>,
840    ) -> Result<PointsOperationResponse> {
841        self._overwrite_payload(collection_name, points, &payload, true, ordering)
842            .await
843    }
844
845    #[inline]
846    async fn _overwrite_payload(
847        &self,
848        collection_name: impl ToString,
849        points: &PointsSelector,
850        payload: &Payload,
851        block: bool,
852        ordering: Option<WriteOrdering>,
853    ) -> Result<PointsOperationResponse> {
854        let collection_name = collection_name.to_string();
855        let collection_name_ref = collection_name.as_str();
856        let ordering_ref = ordering.as_ref();
857
858        Ok(self
859            .with_points_client(|mut points_api| async move {
860                let result = points_api
861                    .overwrite_payload(SetPayloadPoints {
862                        collection_name: collection_name_ref.to_string(),
863                        wait: Some(block),
864                        payload: payload.0.clone(),
865                        points_selector: Some(points.clone()),
866                        ordering: ordering_ref.cloned(),
867                    })
868                    .await?;
869                Ok(result.into_inner())
870            })
871            .await?)
872    }
873
874    pub async fn delete_payload(
875        &self,
876        collection_name: impl ToString,
877        points: &PointsSelector,
878        keys: Vec<String>,
879        ordering: Option<WriteOrdering>,
880    ) -> Result<PointsOperationResponse> {
881        self._delete_payload(collection_name, points, &keys, false, ordering)
882            .await
883    }
884
885    pub async fn delete_payload_blocking(
886        &self,
887        collection_name: impl ToString,
888        points: &PointsSelector,
889        keys: Vec<String>,
890        ordering: Option<WriteOrdering>,
891    ) -> Result<PointsOperationResponse> {
892        self._delete_payload(collection_name, points, &keys, true, ordering)
893            .await
894    }
895
896    #[inline]
897    async fn _delete_payload(
898        &self,
899        collection_name: impl ToString,
900        points: &PointsSelector,
901        keys: &[String],
902        block: bool,
903        ordering: Option<WriteOrdering>,
904    ) -> Result<PointsOperationResponse> {
905        let collection_name = collection_name.to_string();
906        let collection_name_ref = collection_name.as_str();
907        let ordering_ref = ordering.as_ref();
908
909        Ok(self
910            .with_points_client(|mut points_api| async move {
911                let result = points_api
912                    .delete_payload(DeletePayloadPoints {
913                        collection_name: collection_name_ref.to_string(),
914                        wait: Some(block),
915                        keys: keys.to_owned(),
916                        points_selector: Some(points.clone()),
917                        ordering: ordering_ref.cloned(),
918                    })
919                    .await?;
920                Ok(result.into_inner())
921            })
922            .await?)
923    }
924
925    pub async fn clear_payload(
926        &self,
927        collection_name: impl ToString,
928        points_selector: Option<PointsSelector>,
929        ordering: Option<WriteOrdering>,
930    ) -> Result<PointsOperationResponse> {
931        self._clear_payload(collection_name, points_selector.as_ref(), false, ordering)
932            .await
933    }
934
935    pub async fn clear_payload_blocking(
936        &self,
937        collection_name: impl ToString,
938        points_selector: Option<PointsSelector>,
939        ordering: Option<WriteOrdering>,
940    ) -> Result<PointsOperationResponse> {
941        self._clear_payload(collection_name, points_selector.as_ref(), true, ordering)
942            .await
943    }
944
945    #[inline]
946    async fn _clear_payload(
947        &self,
948        collection_name: impl ToString,
949        points_selector: Option<&PointsSelector>,
950        block: bool,
951        ordering: Option<WriteOrdering>,
952    ) -> Result<PointsOperationResponse> {
953        let collection_name = collection_name.to_string();
954        let collection_name_ref = collection_name.as_str();
955        let ordering_ref = ordering.as_ref();
956
957        Ok(self
958            .with_points_client(|mut points_api| async move {
959                let result = points_api
960                    .clear_payload(ClearPayloadPoints {
961                        collection_name: collection_name_ref.to_string(),
962                        wait: Some(block),
963                        points: points_selector.cloned(),
964                        ordering: ordering_ref.cloned(),
965                    })
966                    .await?;
967                Ok(result.into_inner())
968            })
969            .await?)
970    }
971
972    pub async fn get_points(
973        &self,
974        collection_name: impl ToString,
975        points: &[PointId],
976        with_vectors: Option<impl Into<WithVectorsSelector>>,
977        with_payload: Option<impl Into<WithPayloadSelector>>,
978        read_consistency: Option<ReadConsistency>,
979    ) -> Result<GetResponse> {
980        let collection_name = collection_name.to_string();
981        let collection_name_ref = collection_name.as_str();
982
983        let with_vectors = with_vectors.map(|v| v.into());
984        let with_payload = with_payload.map(|v| v.into());
985
986        let with_vectors_ref = with_vectors.as_ref();
987        let with_payload_ref = with_payload.as_ref();
988        let read_consistency_ref = read_consistency.as_ref();
989
990        Ok(self
991            .with_points_client(|mut points_api| async move {
992                let result = points_api
993                    .get(GetPoints {
994                        collection_name: collection_name_ref.to_string(),
995                        ids: points.to_owned(),
996                        with_payload: with_payload_ref.cloned(),
997                        with_vectors: with_vectors_ref.cloned(),
998                        read_consistency: read_consistency_ref.cloned(),
999                    })
1000                    .await?;
1001
1002                Ok(result.into_inner())
1003            })
1004            .await?)
1005    }
1006
1007    pub async fn search_points(&self, request: &SearchPoints) -> Result<SearchResponse> {
1008        Ok(self
1009            .with_points_client(|mut points_api| async move {
1010                let result = points_api.search(request.clone()).await?;
1011                Ok(result.into_inner())
1012            })
1013            .await?)
1014    }
1015
1016    pub async fn search_batch_points(
1017        &self,
1018        request: &SearchBatchPoints,
1019    ) -> Result<SearchBatchResponse> {
1020        Ok(self
1021            .with_points_client(|mut points_api| async move {
1022                let result = points_api.search_batch(request.clone()).await?;
1023                Ok(result.into_inner())
1024            })
1025            .await?)
1026    }
1027
1028    pub async fn search_groups(&self, request: &SearchPointGroups) -> Result<SearchGroupsResponse> {
1029        Ok(self
1030            .with_points_client(|mut points_api| async move {
1031                let result = points_api.search_groups(request.clone()).await?;
1032                Ok(result.into_inner())
1033            })
1034            .await?)
1035    }
1036
1037    pub async fn delete_points(
1038        &self,
1039        collection_name: impl ToString,
1040        points: &PointsSelector,
1041        ordering: Option<WriteOrdering>,
1042    ) -> Result<PointsOperationResponse> {
1043        self._delete_points(collection_name, false, points, ordering)
1044            .await
1045    }
1046
1047    pub async fn delete_points_blocking(
1048        &self,
1049        collection_name: impl ToString,
1050        points: &PointsSelector,
1051        ordering: Option<WriteOrdering>,
1052    ) -> Result<PointsOperationResponse> {
1053        self._delete_points(collection_name, true, points, ordering)
1054            .await
1055    }
1056
1057    async fn _delete_points(
1058        &self,
1059        collection_name: impl ToString,
1060        blocking: bool,
1061        points: &PointsSelector,
1062        ordering: Option<WriteOrdering>,
1063    ) -> Result<PointsOperationResponse> {
1064        let collection_name = collection_name.to_string();
1065        let collection_name_ref = collection_name.as_str();
1066        let ordering_ref = ordering.as_ref();
1067
1068        Ok(self
1069            .with_points_client(|mut points_api| async move {
1070                let result = points_api
1071                    .delete(DeletePoints {
1072                        collection_name: collection_name_ref.to_string(),
1073                        wait: Some(blocking),
1074                        points: Some(points.clone()),
1075                        ordering: ordering_ref.cloned(),
1076                    })
1077                    .await?;
1078                Ok(result.into_inner())
1079            })
1080            .await?)
1081    }
1082
1083    pub async fn delete_vectors(
1084        &self,
1085        collection_name: impl ToString,
1086        points_selector: &PointsSelector,
1087        vector_selector: &VectorsSelector,
1088        ordering: Option<WriteOrdering>,
1089    ) -> Result<PointsOperationResponse> {
1090        self._delete_vectors(
1091            collection_name,
1092            false,
1093            points_selector,
1094            vector_selector,
1095            ordering,
1096        )
1097        .await
1098    }
1099
1100    pub async fn delete_vectors_blocking(
1101        &self,
1102        collection_name: impl ToString,
1103        points_selector: &PointsSelector,
1104        vector_selector: &VectorsSelector,
1105        ordering: Option<WriteOrdering>,
1106    ) -> Result<PointsOperationResponse> {
1107        self._delete_vectors(
1108            collection_name,
1109            true,
1110            points_selector,
1111            vector_selector,
1112            ordering,
1113        )
1114        .await
1115    }
1116
1117    async fn _delete_vectors(
1118        &self,
1119        collection_name: impl ToString,
1120        blocking: bool,
1121        points_selector: &PointsSelector,
1122        vector_selector: &VectorsSelector,
1123        ordering: Option<WriteOrdering>,
1124    ) -> Result<PointsOperationResponse> {
1125        let collection_name = collection_name.to_string();
1126        let collection_name_ref = collection_name.as_str();
1127        let ordering_ref = ordering.as_ref();
1128
1129        Ok(self
1130            .with_points_client(|mut points_api| async move {
1131                let result = points_api
1132                    .delete_vectors(DeletePointVectors {
1133                        collection_name: collection_name_ref.to_string(),
1134                        wait: Some(blocking),
1135                        points_selector: Some(points_selector.clone()),
1136                        vectors: Some(vector_selector.clone()),
1137                        ordering: ordering_ref.cloned(),
1138                    })
1139                    .await?;
1140                Ok(result.into_inner())
1141            })
1142            .await?)
1143    }
1144
1145    pub async fn update_vectors(
1146        &self,
1147        collection_name: impl ToString,
1148        points: &[PointVectors],
1149        ordering: Option<WriteOrdering>,
1150    ) -> Result<PointsOperationResponse> {
1151        self._update_vectors(collection_name, false, points, ordering)
1152            .await
1153    }
1154
1155    pub async fn update_vectors_blocking(
1156        &self,
1157        collection_name: impl ToString,
1158        points: &[PointVectors],
1159        ordering: Option<WriteOrdering>,
1160    ) -> Result<PointsOperationResponse> {
1161        self._update_vectors(collection_name, true, points, ordering)
1162            .await
1163    }
1164
1165    async fn _update_vectors(
1166        &self,
1167        collection_name: impl ToString,
1168        blocking: bool,
1169        points: &[PointVectors],
1170        ordering: Option<WriteOrdering>,
1171    ) -> Result<PointsOperationResponse> {
1172        let collection_name = collection_name.to_string();
1173        let collection_name_ref = collection_name.as_str();
1174        let ordering_ref = ordering.as_ref();
1175
1176        Ok(self
1177            .with_points_client(|mut points_api| async move {
1178                let result = points_api
1179                    .update_vectors(UpdatePointVectors {
1180                        collection_name: collection_name_ref.to_string(),
1181                        wait: Some(blocking),
1182                        points: points.to_owned(),
1183                        ordering: ordering_ref.cloned(),
1184                    })
1185                    .await?;
1186                Ok(result.into_inner())
1187            })
1188            .await?)
1189    }
1190
1191    pub async fn scroll(&self, request: &ScrollPoints) -> Result<ScrollResponse> {
1192        Ok(self
1193            .with_points_client(|mut points_api| async move {
1194                let result = points_api.scroll(request.clone()).await?;
1195                Ok(result.into_inner())
1196            })
1197            .await?)
1198    }
1199
1200    pub async fn recommend(&self, request: &RecommendPoints) -> Result<RecommendResponse> {
1201        Ok(self
1202            .with_points_client(|mut points_api| async move {
1203                let result = points_api.recommend(request.clone()).await?;
1204                Ok(result.into_inner())
1205            })
1206            .await?)
1207    }
1208
1209    pub async fn recommend_batch(
1210        &self,
1211        request: &RecommendBatchPoints,
1212    ) -> Result<RecommendBatchResponse> {
1213        Ok(self
1214            .with_points_client(|mut points_api| async move {
1215                let result = points_api.recommend_batch(request.clone()).await?;
1216                Ok(result.into_inner())
1217            })
1218            .await?)
1219    }
1220
1221    pub async fn recommend_groups(
1222        &self,
1223        request: &RecommendPointGroups,
1224    ) -> Result<RecommendGroupsResponse> {
1225        Ok(self
1226            .with_points_client(|mut points_api| async move {
1227                let result = points_api.recommend_groups(request.clone()).await?;
1228                Ok(result.into_inner())
1229            })
1230            .await?)
1231    }
1232
1233    pub async fn count(&self, request: &CountPoints) -> Result<CountResponse> {
1234        Ok(self
1235            .with_points_client(|mut points_api| async move {
1236                let result = points_api.count(request.clone()).await?;
1237                Ok(result.into_inner())
1238            })
1239            .await?)
1240    }
1241
1242    /// Create index for a payload field
1243    pub async fn _create_field_index(
1244        &self,
1245        collection_name: impl ToString,
1246        field_name: impl ToString,
1247        field_type: FieldType,
1248        field_index_params: Option<&PayloadIndexParams>,
1249        wait: bool,
1250        ordering: Option<WriteOrdering>,
1251    ) -> Result<PointsOperationResponse> {
1252        let collection_name = collection_name.to_string();
1253        let collection_name_ref = collection_name.as_str();
1254        let field_name = field_name.to_string();
1255        let field_name_ref = field_name.as_str();
1256        let ordering_ref = ordering.as_ref();
1257
1258        Ok(self
1259            .with_points_client(|mut client| async move {
1260                let result = client
1261                    .create_field_index(CreateFieldIndexCollection {
1262                        collection_name: collection_name_ref.to_string(),
1263                        wait: Some(wait),
1264                        field_name: field_name_ref.to_string(),
1265                        field_type: Some(field_type.into()),
1266                        field_index_params: field_index_params.cloned(),
1267                        ordering: ordering_ref.cloned(),
1268                    })
1269                    .await?;
1270                Ok(result.into_inner())
1271            })
1272            .await?)
1273    }
1274
1275    pub async fn create_field_index(
1276        &self,
1277        collection_name: impl ToString,
1278        field_name: impl ToString,
1279        field_type: FieldType,
1280        field_index_params: Option<&PayloadIndexParams>,
1281        ordering: Option<WriteOrdering>,
1282    ) -> Result<PointsOperationResponse> {
1283        self._create_field_index(
1284            collection_name,
1285            field_name,
1286            field_type,
1287            field_index_params,
1288            false,
1289            ordering,
1290        )
1291        .await
1292    }
1293
1294    pub async fn create_field_index_blocking(
1295        &self,
1296        collection_name: impl ToString,
1297        field_name: impl ToString,
1298        field_type: FieldType,
1299        field_index_params: Option<&PayloadIndexParams>,
1300        ordering: Option<WriteOrdering>,
1301    ) -> Result<PointsOperationResponse> {
1302        self._create_field_index(
1303            collection_name,
1304            field_name,
1305            field_type,
1306            field_index_params,
1307            true,
1308            ordering,
1309        )
1310        .await
1311    }
1312
1313    pub async fn _delete_field_index(
1314        &self,
1315        collection_name: impl ToString,
1316        field_name: impl ToString,
1317        wait: bool,
1318        ordering: Option<WriteOrdering>,
1319    ) -> Result<PointsOperationResponse> {
1320        let collection_name = collection_name.to_string();
1321        let collection_name_ref = collection_name.as_str();
1322        let field_name = field_name.to_string();
1323        let field_name_ref = field_name.as_str();
1324        let ordering_ref = ordering.as_ref();
1325
1326        Ok(self
1327            .with_points_client(|mut client| async move {
1328                let result = client
1329                    .delete_field_index(DeleteFieldIndexCollection {
1330                        collection_name: collection_name_ref.to_string(),
1331                        wait: Some(wait),
1332                        field_name: field_name_ref.to_string(),
1333                        ordering: ordering_ref.cloned(),
1334                    })
1335                    .await?;
1336                Ok(result.into_inner())
1337            })
1338            .await?)
1339    }
1340
1341    pub async fn delete_field_index(
1342        &self,
1343        collection_name: impl ToString,
1344        field_name: impl ToString,
1345        ordering: Option<WriteOrdering>,
1346    ) -> Result<PointsOperationResponse> {
1347        self._delete_field_index(collection_name, field_name, false, ordering)
1348            .await
1349    }
1350
1351    pub async fn delete_field_index_blocking(
1352        &self,
1353        collection_name: impl ToString,
1354        field_name: impl ToString,
1355        ordering: Option<WriteOrdering>,
1356    ) -> Result<PointsOperationResponse> {
1357        self._delete_field_index(collection_name, field_name, true, ordering)
1358            .await
1359    }
1360
1361    pub async fn create_snapshot(
1362        &self,
1363        collection_name: impl ToString,
1364    ) -> Result<CreateSnapshotResponse> {
1365        let collection_name = collection_name.to_string();
1366        let collection_name_ref = collection_name.as_str();
1367        Ok(self
1368            .with_snapshot_client(|mut client| async move {
1369                let result = client
1370                    .create(CreateSnapshotRequest {
1371                        collection_name: collection_name_ref.to_string(),
1372                    })
1373                    .await?;
1374
1375                Ok(result.into_inner())
1376            })
1377            .await?)
1378    }
1379
1380    pub async fn list_snapshots(
1381        &self,
1382        collection_name: impl ToString,
1383    ) -> Result<ListSnapshotsResponse> {
1384        let collection_name = collection_name.to_string();
1385        let collection_name_ref = collection_name.as_str();
1386        Ok(self
1387            .with_snapshot_client(|mut client| async move {
1388                let result = client
1389                    .list(ListSnapshotsRequest {
1390                        collection_name: collection_name_ref.to_string(),
1391                    })
1392                    .await?;
1393                Ok(result.into_inner())
1394            })
1395            .await?)
1396    }
1397
1398    pub async fn delete_snapshot(
1399        &self,
1400        collection_name: impl ToString,
1401        snapshot_name: impl ToString,
1402    ) -> Result<DeleteSnapshotResponse> {
1403        let collection_name = collection_name.to_string();
1404        let collection_name_ref = collection_name.as_str();
1405        let snapshot_name = snapshot_name.to_string();
1406        let snapshot_name_ref = snapshot_name.as_str();
1407        Ok(self
1408            .with_snapshot_client(|mut client| async move {
1409                let result = client
1410                    .delete(DeleteSnapshotRequest {
1411                        collection_name: collection_name_ref.to_string(),
1412                        snapshot_name: snapshot_name_ref.to_string(),
1413                    })
1414                    .await?;
1415                Ok(result.into_inner())
1416            })
1417            .await?)
1418    }
1419
1420    pub async fn create_full_snapshot(&self) -> Result<CreateSnapshotResponse> {
1421        Ok(self
1422            .with_snapshot_client(|mut client| async move {
1423                let result = client.create_full(CreateFullSnapshotRequest {}).await?;
1424
1425                Ok(result.into_inner())
1426            })
1427            .await?)
1428    }
1429
1430    pub async fn list_full_snapshots(&self) -> Result<ListSnapshotsResponse> {
1431        Ok(self
1432            .with_snapshot_client(|mut client| async move {
1433                let result = client.list_full(ListFullSnapshotsRequest {}).await?;
1434                Ok(result.into_inner())
1435            })
1436            .await?)
1437    }
1438
1439    pub async fn delete_full_snapshot(
1440        &self,
1441        snapshot_name: impl ToString,
1442    ) -> Result<DeleteSnapshotResponse> {
1443        let snapshot_name = snapshot_name.to_string();
1444        let snapshot_name_ref = snapshot_name.as_str();
1445        Ok(self
1446            .with_snapshot_client(|mut client| async move {
1447                let result = client
1448                    .delete_full(DeleteFullSnapshotRequest {
1449                        snapshot_name: snapshot_name_ref.to_string(),
1450                    })
1451                    .await?;
1452                Ok(result.into_inner())
1453            })
1454            .await?)
1455    }
1456
1457    #[cfg(feature = "download_snapshots")]
1458    pub async fn download_snapshot<T>(
1459        &self,
1460        out_path: impl Into<PathBuf>,
1461        collection_name: T,
1462        snapshot_name: Option<T>,
1463        rest_api_uri: Option<T>,
1464    ) -> Result<()>
1465    where
1466        T: ToString + Clone,
1467    {
1468        use futures_util::StreamExt;
1469        use std::io::Write;
1470
1471        let snapshot_name = match snapshot_name {
1472            Some(sn) => sn.to_string(),
1473            _ => match self
1474                .list_snapshots(collection_name.clone())
1475                .await?
1476                .snapshot_descriptions
1477                .first()
1478            {
1479                Some(sn) => sn.name.clone(),
1480                _ => anyhow::bail!(
1481                    "No snapshots found for collection {}",
1482                    collection_name.to_string()
1483                ),
1484            },
1485        };
1486
1487        let mut stream = reqwest::get(format!(
1488            "{}/collections/{}/snapshots/{}",
1489            rest_api_uri
1490                .map(|uri| uri.to_string())
1491                .unwrap_or_else(|| String::from("http://localhost:6333")),
1492            collection_name.to_string(),
1493            snapshot_name
1494        ))
1495        .await?
1496        .bytes_stream();
1497
1498        let out_path = out_path.into();
1499        let _ = std::fs::remove_file(&out_path);
1500        let mut file = std::fs::OpenOptions::new()
1501            .write(true)
1502            .create_new(true)
1503            .open(out_path)?;
1504
1505        while let Some(chunk) = stream.next().await {
1506            let _written = file.write(&chunk?)?;
1507        }
1508
1509        Ok(())
1510    }
1511}
1512
1513impl PointStruct {
1514    pub fn new(id: impl Into<PointId>, vectors: impl Into<Vectors>, payload: Payload) -> Self {
1515        Self {
1516            id: Some(id.into()),
1517            payload: payload.into(),
1518            vectors: Some(vectors.into()),
1519        }
1520    }
1521}
1522
1523impl From<String> for PointId {
1524    fn from(val: String) -> Self {
1525        Self {
1526            point_id_options: Some(PointIdOptions::Uuid(val)),
1527        }
1528    }
1529}
1530
1531impl From<u64> for PointId {
1532    fn from(val: u64) -> Self {
1533        Self {
1534            point_id_options: Some(PointIdOptions::Num(val)),
1535        }
1536    }
1537}
1538
1539#[derive(Clone, PartialEq, Debug, Default)]
1540#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1541pub struct Payload(HashMap<String, Value>);
1542
1543impl From<Payload> for HashMap<String, Value> {
1544    #[inline]
1545    fn from(payload: Payload) -> Self {
1546        payload.0
1547    }
1548}
1549
1550impl From<HashMap<&str, Value>> for Payload {
1551    #[inline]
1552    fn from(payload: HashMap<&str, Value>) -> Self {
1553        Self(
1554            payload
1555                .into_iter()
1556                .map(|(k, v)| (k.to_string(), v))
1557                .collect(),
1558        )
1559    }
1560}
1561
1562impl Payload {
1563    pub fn new() -> Self {
1564        Self(HashMap::new())
1565    }
1566
1567    pub fn new_from_hashmap(payload: HashMap<String, Value>) -> Self {
1568        Self(payload)
1569    }
1570
1571    pub fn insert(&mut self, key: impl ToString, val: impl Into<Value>) {
1572        self.0.insert(key.to_string(), val.into());
1573    }
1574}
1575
1576impl From<f64> for Value {
1577    fn from(val: f64) -> Self {
1578        Self {
1579            kind: Some(Kind::DoubleValue(val)),
1580        }
1581    }
1582}
1583
1584impl From<i64> for Value {
1585    fn from(val: i64) -> Self {
1586        Self {
1587            kind: Some(Kind::IntegerValue(val)),
1588        }
1589    }
1590}
1591
1592impl From<bool> for Value {
1593    fn from(val: bool) -> Self {
1594        Self {
1595            kind: Some(Kind::BoolValue(val)),
1596        }
1597    }
1598}
1599
1600impl From<String> for Value {
1601    fn from(val: String) -> Self {
1602        Self {
1603            kind: Some(Kind::StringValue(val)),
1604        }
1605    }
1606}
1607
1608impl From<&str> for Value {
1609    fn from(val: &str) -> Self {
1610        Self {
1611            kind: Some(Kind::StringValue(val.into())),
1612        }
1613    }
1614}
1615
1616impl From<Payload> for Value {
1617    fn from(val: Payload) -> Self {
1618        Self {
1619            kind: Some(Kind::StructValue(Struct { fields: val.0 })),
1620        }
1621    }
1622}
1623
1624impl<T> From<Vec<T>> for Value
1625where
1626    T: Into<Value>,
1627{
1628    fn from(val: Vec<T>) -> Self {
1629        Self {
1630            kind: Some(Kind::ListValue(ListValue {
1631                values: val.into_iter().map(|v| v.into()).collect(),
1632            })),
1633        }
1634    }
1635}
1636
1637impl<T> From<Vec<(&str, T)>> for Value
1638where
1639    T: Into<Value>,
1640{
1641    fn from(val: Vec<(&str, T)>) -> Self {
1642        Self {
1643            kind: Some(Kind::StructValue(Struct {
1644                fields: val
1645                    .into_iter()
1646                    .map(|(k, v)| (k.to_string(), v.into()))
1647                    .collect(),
1648            })),
1649        }
1650    }
1651}