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
53pub type ArcVectorClientBuilder = ArcVectorClientConfig;
55
56pub 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 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 pub fn keep_alive_while_idle(mut self) -> Self {
166 self.keep_alive_while_idle = true;
167 self
168 }
169
170 pub fn with_timeout(mut self, timeout: impl AsTimeout) -> Self {
172 self.timeout = timeout.timeout();
173 self
174 }
175
176 pub fn with_connect_timeout(mut self, timeout: impl AsTimeout) -> Self {
178 self.connect_timeout = timeout.timeout();
179 self
180 }
181
182 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 pub fn from_url(url: &str) -> ArcVectorClientBuilder {
307 ArcVectorClientBuilder::from_url(url)
308 }
309
310 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 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 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 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 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 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 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 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 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 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}