Skip to main content

etcd_client/rpc/
kv.rs

1//! Etcd KV Operations.
2
3use crate::caller::{ClientCaller, ClientCallerBuilder};
4pub use crate::rpc::pb::etcdserverpb::compare::CompareResult as CompareOp;
5pub use crate::rpc::pb::etcdserverpb::range_request::{SortOrder, SortTarget};
6
7use crate::error::Result;
8use crate::intercept::InterceptedChannel;
9use crate::rpc::pb::etcdserverpb::compare::{CompareTarget, TargetUnion};
10use crate::rpc::pb::etcdserverpb::kv_client::KvClient as PbKvClient;
11use crate::rpc::pb::etcdserverpb::request_op::Request as PbTxnOp;
12use crate::rpc::pb::etcdserverpb::response_op::Response as PbTxnOpResponse;
13use crate::rpc::pb::etcdserverpb::{
14    CompactionRequest as PbCompactionRequest, CompactionRequest,
15    CompactionResponse as PbCompactionResponse, Compare as PbCompare,
16    DeleteRangeRequest as PbDeleteRequest, DeleteRangeRequest,
17    DeleteRangeResponse as PbDeleteResponse, PutRequest as PbPutRequest,
18    PutResponse as PbPutResponse, RangeRequest as PbRangeRequest, RangeResponse as PbRangeResponse,
19    RequestOp as PbTxnRequestOp, TxnRequest as PbTxnRequest, TxnResponse as PbTxnResponse,
20};
21use crate::rpc::{get_prefix, KeyRange, KeyValue, ResponseHeader};
22use crate::vec::VecExt;
23use std::mem::ManuallyDrop;
24use tonic::{IntoRequest, Request};
25
26type Client = PbKvClient<InterceptedChannel>;
27
28/// Client for KV operations.
29#[repr(transparent)]
30#[derive(Clone)]
31pub struct KvClient {
32    inner: ClientCaller<Client>,
33}
34
35impl KvClient {
36    /// Creates a kv client.
37    #[inline]
38    pub(crate) fn new(builder: ClientCallerBuilder) -> Self {
39        Self {
40            inner: builder.build(Client::new),
41        }
42    }
43
44    /// Limits the maximum size of a decoded message.
45    ///
46    /// Default: `4MB`
47    pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
48        self.inner = self
49            .inner
50            .with(|client| client.max_decoding_message_size(limit));
51        self
52    }
53
54    /// Limits the maximum size of an encoded message.
55    ///
56    /// Default: `usize::MAX`
57    pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
58        self.inner = self
59            .inner
60            .with(|client| client.max_encoding_message_size(limit));
61        self
62    }
63
64    /// Puts the given key into the key-value store.
65    /// A put request increments the revision of the key-value store
66    /// and generates one event in the event history.
67    #[inline]
68    pub async fn put(
69        &mut self,
70        key: impl Into<Vec<u8>>,
71        value: impl Into<Vec<u8>>,
72        options: Option<PutOptions>,
73    ) -> Result<PutResponse> {
74        async fn put_impl(client: &mut Client, req: PutOptions) -> Result<PutResponse> {
75            let resp = client.put(req).await?.into_inner();
76            Ok(PutResponse::new(resp))
77        }
78        self.inner
79            .do_call(options.unwrap_or_default().with_kv(key, value), put_impl)
80            .await
81    }
82
83    /// Gets the key or a range of keys from the store.
84    #[inline]
85    pub async fn get(
86        &mut self,
87        key: impl Into<Vec<u8>>,
88        options: Option<GetOptions>,
89    ) -> Result<GetResponse> {
90        async fn get_impl(client: &mut Client, req: GetOptions) -> Result<GetResponse> {
91            let resp = client.range(req).await?.into_inner();
92            Ok(GetResponse::new(resp))
93        }
94        self.inner
95            .do_call(options.unwrap_or_default().with_key(key.into()), get_impl)
96            .await
97    }
98
99    /// Deletes the given key or a range of keys from the key-value store.
100    #[inline]
101    pub async fn delete(
102        &mut self,
103        key: impl Into<Vec<u8>>,
104        options: Option<DeleteOptions>,
105    ) -> Result<DeleteResponse> {
106        async fn delete_impl(client: &mut Client, req: DeleteOptions) -> Result<DeleteResponse> {
107            let resp = client.delete_range(req).await?.into_inner();
108            Ok(DeleteResponse::new(resp))
109        }
110        self.inner
111            .do_call(
112                options.unwrap_or_default().with_key(key.into()),
113                delete_impl,
114            )
115            .await
116    }
117
118    /// Compacts the event history in the etcd key-value store. The key-value
119    /// store should be periodically compacted or the event history will continue to grow
120    /// indefinitely.
121    #[inline]
122    pub async fn compact(
123        &mut self,
124        revision: i64,
125        options: Option<CompactionOptions>,
126    ) -> Result<CompactionResponse> {
127        async fn compact_impl(
128            client: &mut Client,
129            req: CompactionOptions,
130        ) -> Result<CompactionResponse> {
131            let resp = client.compact(req).await?.into_inner();
132            Ok(CompactionResponse::new(resp))
133        }
134        self.inner
135            .do_call(
136                options.unwrap_or_default().with_revision(revision),
137                compact_impl,
138            )
139            .await
140    }
141
142    /// Processes multiple operations in a single transaction.
143    /// A txn request increments the revision of the key-value store
144    /// and generates events with the same revision for every completed operation.
145    /// It is not allowed to modify the same key several times within one txn.
146    #[inline]
147    pub async fn txn(&mut self, txn: Txn) -> Result<TxnResponse> {
148        async fn txn_impl(client: &mut Client, txn: Txn) -> Result<TxnResponse> {
149            let resp = client.txn(txn).await?.into_inner();
150            Ok(TxnResponse::new(resp))
151        }
152        self.inner.do_call(txn, txn_impl).await
153    }
154}
155
156/// Options for `Put` operation.
157#[derive(Debug, Default, Clone)]
158#[repr(transparent)]
159pub struct PutOptions(PbPutRequest);
160
161impl PutOptions {
162    /// Set key-value pair.
163    #[inline]
164    fn with_kv(mut self, key: impl Into<Vec<u8>>, value: impl Into<Vec<u8>>) -> Self {
165        self.0.key = key.into();
166        self.0.value = value.into();
167        self
168    }
169
170    /// Creates a `PutOptions`.
171    #[inline]
172    pub const fn new() -> Self {
173        Self(PbPutRequest {
174            key: Vec::new(),
175            value: Vec::new(),
176            lease: 0,
177            prev_kv: false,
178            ignore_value: false,
179            ignore_lease: false,
180        })
181    }
182
183    /// Lease is the lease ID to associate with the key in the key-value store. A lease
184    /// value of 0 indicates no lease.
185    #[inline]
186    pub const fn with_lease(mut self, lease: i64) -> Self {
187        self.0.lease = lease;
188        self
189    }
190
191    /// If prev_kv is set, etcd gets the previous key-value pair before changing it.
192    /// The previous key-value pair will be returned in the put response.
193    #[inline]
194    pub const fn with_prev_key(mut self) -> Self {
195        self.0.prev_kv = true;
196        self
197    }
198
199    /// If ignore_value is set, etcd updates the key using its current value.
200    /// Returns an error if the key does not exist.
201    #[inline]
202    pub const fn with_ignore_value(mut self) -> Self {
203        self.0.ignore_value = true;
204        self
205    }
206
207    /// If ignore_lease is set, etcd updates the key using its current lease.
208    /// Returns an error if the key does not exist.
209    #[inline]
210    pub const fn with_ignore_lease(mut self) -> Self {
211        self.0.ignore_lease = true;
212        self
213    }
214}
215
216impl From<PutOptions> for PbPutRequest {
217    #[inline]
218    fn from(options: PutOptions) -> Self {
219        options.0
220    }
221}
222
223impl IntoRequest<PbPutRequest> for PutOptions {
224    #[inline]
225    fn into_request(self) -> Request<PbPutRequest> {
226        Request::new(self.into())
227    }
228}
229
230/// Response for `Put` operation.
231#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
232#[derive(Debug, Clone)]
233#[repr(transparent)]
234pub struct PutResponse(PbPutResponse);
235
236impl PutResponse {
237    /// Create a new `PutResponse` from pb put response.
238    #[inline]
239    const fn new(resp: PbPutResponse) -> Self {
240        Self(resp)
241    }
242
243    /// Get response header.
244    #[inline]
245    pub fn header(&self) -> Option<&ResponseHeader> {
246        self.0.header.as_ref().map(From::from)
247    }
248
249    /// Takes the header out of the response, leaving a [`None`] in its place.
250    #[inline]
251    pub fn take_header(&mut self) -> Option<ResponseHeader> {
252        self.0.header.take().map(ResponseHeader::new)
253    }
254
255    /// If prev_kv is set in the request, the previous key-value pair will be returned.
256    #[inline]
257    pub fn prev_key(&self) -> Option<&KeyValue> {
258        self.0.prev_kv.as_ref().map(From::from)
259    }
260
261    /// Takes the prev_key out of the response, leaving a [`None`] in its place.
262    #[inline]
263    pub fn take_prev_key(&mut self) -> Option<KeyValue> {
264        self.0.prev_kv.take().map(KeyValue::new)
265    }
266
267    #[inline]
268    pub(crate) fn strip_prev_key_prefix(&mut self, prefix: &[u8]) {
269        if let Some(kv) = self.0.prev_kv.as_mut() {
270            kv.key.strip_key_prefix(prefix);
271        }
272    }
273}
274
275/// Options for `Get` operation.
276#[derive(Debug, Default, Clone)]
277pub struct GetOptions {
278    req: PbRangeRequest,
279    key_range: KeyRange,
280}
281
282impl GetOptions {
283    /// Sets key.
284    #[inline]
285    fn with_key(mut self, key: impl Into<Vec<u8>>) -> Self {
286        self.key_range.with_key(key);
287        self
288    }
289
290    /// Creates a `GetOptions`.
291    #[inline]
292    pub const fn new() -> Self {
293        Self {
294            req: PbRangeRequest {
295                key: Vec::new(),
296                range_end: Vec::new(),
297                limit: 0,
298                revision: 0,
299                sort_order: 0,
300                sort_target: 0,
301                serializable: false,
302                keys_only: false,
303                count_only: false,
304                min_mod_revision: 0,
305                max_mod_revision: 0,
306                min_create_revision: 0,
307                max_create_revision: 0,
308            },
309            key_range: KeyRange::new(),
310        }
311    }
312
313    /// Specifies the range of 'Get'.
314    /// Returns the keys in the range [key, end_key).
315    /// `end_key` must be lexicographically greater than start key.
316    #[inline]
317    pub fn with_range(mut self, end_key: impl Into<Vec<u8>>) -> Self {
318        self.key_range.with_range(end_key);
319        self
320    }
321
322    /// Gets all keys >= key.
323    #[inline]
324    pub fn with_from_key(mut self) -> Self {
325        self.key_range.with_from_key();
326        self
327    }
328
329    /// Gets all keys prefixed with key.
330    #[inline]
331    pub fn with_prefix(mut self) -> Self {
332        self.key_range.with_prefix();
333        self
334    }
335
336    /// Gets all keys.
337    #[inline]
338    pub fn with_all_keys(mut self) -> Self {
339        self.key_range.with_all_keys();
340        self
341    }
342
343    /// Limits the number of keys returned for the request. When limit is set to 0,
344    /// it is treated as no limit.
345    #[inline]
346    pub const fn with_limit(mut self, limit: i64) -> Self {
347        self.req.limit = limit;
348        self
349    }
350
351    /// The point-in-time of the key-value store to use for the range.
352    /// If revision is less or equal to zero, the range is over the newest key-value store.
353    /// If the revision has been compacted, ErrCompacted is returned as a response.
354    #[inline]
355    pub const fn with_revision(mut self, revision: i64) -> Self {
356        self.req.revision = revision;
357        self
358    }
359
360    /// Sets the order for returned sorted results.
361    /// It requires 'with_range' and/or 'with_prefix' to be specified too.
362    #[inline]
363    pub fn with_sort(mut self, target: SortTarget, order: SortOrder) -> Self {
364        if target == SortTarget::Key && order == SortOrder::Ascend {
365            // If order != SortOrder::None, server fetches the entire key-space,
366            // and then applies the sort and limit, if provided.
367            // Since by default the server returns results sorted by keys
368            // in lexicographically ascending order, the client should ignore
369            // SortOrder if the target is SortTarget::Key.
370            self.req.sort_order = SortOrder::None as i32;
371        } else {
372            self.req.sort_order = order as i32;
373        }
374        self.req.sort_target = target as i32;
375        self
376    }
377
378    /// Sets the get request to use serializable member-local reads.
379    /// Get requests are linearizable by default; linearizable requests have higher
380    /// latency and lower throughput than serializable requests but reflect the current
381    /// consensus of the cluster. For better performance, in exchange for possible stale reads,
382    /// a serializable get request is served locally without needing to reach consensus
383    /// with other nodes in the cluster.
384    #[inline]
385    pub const fn with_serializable(mut self) -> Self {
386        self.req.serializable = true;
387        self
388    }
389
390    /// Returns only the keys and not the values.
391    #[inline]
392    pub const fn with_keys_only(mut self) -> Self {
393        self.req.keys_only = true;
394        self
395    }
396
397    /// Returns only the count of the keys in the range.
398    #[inline]
399    pub const fn with_count_only(mut self) -> Self {
400        self.req.count_only = true;
401        self
402    }
403
404    /// Sets the lower bound for returned key mod revisions; all keys with
405    /// lesser mod revisions will be filtered away.
406    #[inline]
407    pub const fn with_min_mod_revision(mut self, revision: i64) -> Self {
408        self.req.min_mod_revision = revision;
409        self
410    }
411
412    /// Sets the upper bound for returned key mod revisions; all keys with
413    /// greater mod revisions will be filtered away.
414    #[inline]
415    pub const fn with_max_mod_revision(mut self, revision: i64) -> Self {
416        self.req.max_mod_revision = revision;
417        self
418    }
419
420    /// Sets the lower bound for returned key create revisions; all keys with
421    /// lesser create revisions will be filtered away.
422    #[inline]
423    pub const fn with_min_create_revision(mut self, revision: i64) -> Self {
424        self.req.min_create_revision = revision;
425        self
426    }
427
428    /// `max_create_revision` is the upper bound for returned key create revisions; all keys with
429    /// greater create revisions will be filtered away.
430    #[inline]
431    pub const fn with_max_create_revision(mut self, revision: i64) -> Self {
432        self.req.max_create_revision = revision;
433        self
434    }
435
436    #[inline]
437    pub(crate) fn key_range_end_mut(&mut self) -> &mut Vec<u8> {
438        &mut self.key_range.range_end
439    }
440}
441
442impl From<GetOptions> for PbRangeRequest {
443    #[inline]
444    fn from(mut options: GetOptions) -> Self {
445        let (key, rang_end) = options.key_range.build();
446        options.req.key = key;
447        options.req.range_end = rang_end;
448        options.req
449    }
450}
451
452impl IntoRequest<PbRangeRequest> for GetOptions {
453    #[inline]
454    fn into_request(self) -> Request<PbRangeRequest> {
455        Request::new(self.into())
456    }
457}
458
459/// Response for `Get` operation.
460#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
461#[derive(Debug, Clone)]
462#[repr(transparent)]
463pub struct GetResponse(PbRangeResponse);
464
465impl GetResponse {
466    /// Create a new `GetResponse` from pb get response.
467    #[inline]
468    const fn new(resp: PbRangeResponse) -> Self {
469        Self(resp)
470    }
471
472    /// Get response header.
473    #[inline]
474    pub fn header(&self) -> Option<&ResponseHeader> {
475        self.0.header.as_ref().map(From::from)
476    }
477
478    /// Takes the header out of the response, leaving a [`None`] in its place.
479    #[inline]
480    pub fn take_header(&mut self) -> Option<ResponseHeader> {
481        self.0.header.take().map(ResponseHeader::new)
482    }
483
484    /// The list of key-value pairs matched by the `Get` request.
485    /// kvs is empty when count is requested.
486    #[inline]
487    pub fn kvs(&self) -> &[KeyValue] {
488        unsafe { &*(self.0.kvs.as_slice() as *const _ as *const [KeyValue]) }
489    }
490
491    /// If `kvs` is set in the request, take the key-value pairs, leaving an empty vector in its place.
492    #[inline]
493    pub fn take_kvs(&mut self) -> Vec<KeyValue> {
494        let kvs = ManuallyDrop::new(std::mem::take(&mut self.0.kvs));
495        unsafe { Vec::from_raw_parts(kvs.as_ptr() as *mut KeyValue, kvs.len(), kvs.capacity()) }
496    }
497
498    #[inline]
499    pub(crate) fn strip_kvs_prefix(&mut self, prefix: &[u8]) {
500        for kv in self.0.kvs.iter_mut() {
501            kv.key.strip_key_prefix(prefix);
502        }
503    }
504
505    /// Indicates if there are more keys to return in the requested range.
506    #[inline]
507    pub const fn more(&self) -> bool {
508        self.0.more
509    }
510
511    /// The number of keys within the range when requested.
512    #[inline]
513    pub const fn count(&self) -> i64 {
514        self.0.count
515    }
516}
517
518/// Options for `Delete` operation.
519#[derive(Debug, Default, Clone)]
520pub struct DeleteOptions {
521    req: PbDeleteRequest,
522    key_range: KeyRange,
523}
524
525impl DeleteOptions {
526    /// Sets key.
527    #[inline]
528    fn with_key(mut self, key: impl Into<Vec<u8>>) -> Self {
529        self.key_range.with_key(key);
530        self
531    }
532
533    /// Creates a `DeleteOptions`.
534    #[inline]
535    pub const fn new() -> Self {
536        Self {
537            req: PbDeleteRequest {
538                key: Vec::new(),
539                range_end: Vec::new(),
540                prev_kv: false,
541            },
542            key_range: KeyRange::new(),
543        }
544    }
545
546    /// `end_key` is the key following the last key to delete for the range [key, end_key).
547    #[inline]
548    pub fn with_range(mut self, end_key: impl Into<Vec<u8>>) -> Self {
549        self.key_range.with_range(end_key);
550        self
551    }
552
553    /// Deletes all keys >= key.
554    #[inline]
555    pub fn with_from_key(mut self) -> Self {
556        self.key_range.with_from_key();
557        self
558    }
559
560    /// Deletes all keys prefixed with key.
561    #[inline]
562    pub fn with_prefix(mut self) -> Self {
563        self.key_range.with_prefix();
564        self
565    }
566
567    /// Deletes all keys.
568    #[inline]
569    pub fn with_all_keys(mut self) -> Self {
570        self.key_range.with_all_keys();
571        self
572    }
573
574    /// If `prev_kv` is set, etcd gets the previous key-value pairs before deleting it.
575    /// The previous key-value pairs will be returned in the delete response.
576    #[inline]
577    pub const fn with_prev_key(mut self) -> Self {
578        self.req.prev_kv = true;
579        self
580    }
581
582    #[inline]
583    pub(crate) fn key_range_end_mut(&mut self) -> &mut Vec<u8> {
584        &mut self.key_range.range_end
585    }
586}
587
588impl From<DeleteOptions> for PbDeleteRequest {
589    #[inline]
590    fn from(mut options: DeleteOptions) -> Self {
591        let (key, rang_end) = options.key_range.build();
592        options.req.key = key;
593        options.req.range_end = rang_end;
594        options.req
595    }
596}
597
598impl IntoRequest<PbDeleteRequest> for DeleteOptions {
599    #[inline]
600    fn into_request(self) -> Request<DeleteRangeRequest> {
601        Request::new(self.into())
602    }
603}
604
605/// Response for `Delete` operation.
606#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
607#[derive(Debug, Clone)]
608#[repr(transparent)]
609pub struct DeleteResponse(PbDeleteResponse);
610
611impl DeleteResponse {
612    /// Create a new `DeleteResponse` from pb delete response.
613    #[inline]
614    const fn new(resp: PbDeleteResponse) -> Self {
615        Self(resp)
616    }
617
618    /// Delete response header.
619    #[inline]
620    pub fn header(&self) -> Option<&ResponseHeader> {
621        self.0.header.as_ref().map(From::from)
622    }
623
624    /// Takes the header out of the response, leaving a [`None`] in its place.
625    #[inline]
626    pub fn take_header(&mut self) -> Option<ResponseHeader> {
627        self.0.header.take().map(ResponseHeader::new)
628    }
629
630    /// The number of keys deleted by the delete request.
631    #[inline]
632    pub const fn deleted(&self) -> i64 {
633        self.0.deleted
634    }
635
636    /// If `prev_kv` is set in the request, the previous key-value pairs will be returned.
637    #[inline]
638    pub fn prev_kvs(&self) -> &[KeyValue] {
639        unsafe { &*(self.0.prev_kvs.as_slice() as *const _ as *const [KeyValue]) }
640    }
641
642    /// If `prev_kvs` is set in the request, take the previous key-value pairs, leaving an empty vector in its place.
643    #[inline]
644    pub fn take_prev_kvs(&mut self) -> Vec<KeyValue> {
645        let kvs = ManuallyDrop::new(std::mem::take(&mut self.0.prev_kvs));
646        unsafe { Vec::from_raw_parts(kvs.as_ptr() as *mut KeyValue, kvs.len(), kvs.capacity()) }
647    }
648
649    #[inline]
650    pub(crate) fn strip_prev_kvs_prefix(&mut self, prefix: &[u8]) {
651        for kv in self.0.prev_kvs.iter_mut() {
652            kv.key.strip_key_prefix(prefix);
653        }
654    }
655}
656
657/// Options for `Compact` operation.
658#[derive(Debug, Default, Clone)]
659#[repr(transparent)]
660pub struct CompactionOptions(PbCompactionRequest);
661
662impl CompactionOptions {
663    /// Creates a `CompactionOptions`.
664    #[inline]
665    pub const fn new() -> Self {
666        Self(PbCompactionRequest {
667            revision: 0,
668            physical: false,
669        })
670    }
671
672    /// The key-value store revision for the compaction operation.
673    #[inline]
674    const fn with_revision(mut self, revision: i64) -> Self {
675        self.0.revision = revision;
676        self
677    }
678
679    /// Physical is set so the RPC will wait until the compaction is physically
680    /// applied to the local database such that compacted entries are totally
681    /// removed from the backend database.
682    #[inline]
683    pub const fn with_physical(mut self) -> Self {
684        self.0.physical = true;
685        self
686    }
687}
688
689impl IntoRequest<PbCompactionRequest> for CompactionOptions {
690    #[inline]
691    fn into_request(self) -> Request<CompactionRequest> {
692        Request::new(self.0)
693    }
694}
695
696/// Response for `Compact` operation.
697#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
698#[derive(Debug, Clone)]
699#[repr(transparent)]
700pub struct CompactionResponse(PbCompactionResponse);
701
702impl CompactionResponse {
703    /// Create a new `CompactionResponse` from pb compaction response.
704    #[inline]
705    const fn new(resp: PbCompactionResponse) -> Self {
706        Self(resp)
707    }
708
709    /// Compact response header.
710    #[inline]
711    pub fn header(&self) -> Option<&ResponseHeader> {
712        self.0.header.as_ref().map(From::from)
713    }
714
715    /// Takes the header out of the response, leaving a [`None`] in its place.
716    #[inline]
717    pub fn take_header(&mut self) -> Option<ResponseHeader> {
718        self.0.header.take().map(ResponseHeader::new)
719    }
720}
721
722/// Transaction comparison.
723#[derive(Debug, Clone)]
724#[repr(transparent)]
725pub struct Compare(PbCompare);
726
727impl Compare {
728    /// Creates a new `Compare`.
729    #[inline]
730    fn new(
731        key: impl Into<Vec<u8>>,
732        cmp: CompareOp,
733        target: CompareTarget,
734        target_union: TargetUnion,
735    ) -> Self {
736        Self(PbCompare {
737            result: cmp as i32,
738            target: target as i32,
739            key: key.into(),
740            range_end: Vec::new(),
741            target_union: Some(target_union),
742        })
743    }
744
745    /// Compares the version of the given key.
746    #[inline]
747    pub fn version(key: impl Into<Vec<u8>>, cmp: CompareOp, version: i64) -> Self {
748        Self::new(
749            key,
750            cmp,
751            CompareTarget::Version,
752            TargetUnion::Version(version),
753        )
754    }
755
756    /// Compares the creation revision of the given key.
757    #[inline]
758    pub fn create_revision(key: impl Into<Vec<u8>>, cmp: CompareOp, revision: i64) -> Self {
759        Self::new(
760            key,
761            cmp,
762            CompareTarget::Create,
763            TargetUnion::CreateRevision(revision),
764        )
765    }
766
767    /// Compares the last modified revision of the given key.
768    #[inline]
769    pub fn mod_revision(key: impl Into<Vec<u8>>, cmp: CompareOp, revision: i64) -> Self {
770        Self::new(
771            key,
772            cmp,
773            CompareTarget::Mod,
774            TargetUnion::ModRevision(revision),
775        )
776    }
777
778    /// Compares the value of the given key.
779    #[inline]
780    pub fn value(key: impl Into<Vec<u8>>, cmp: CompareOp, value: impl Into<Vec<u8>>) -> Self {
781        Self::new(
782            key,
783            cmp,
784            CompareTarget::Value,
785            TargetUnion::Value(value.into()),
786        )
787    }
788
789    /// Compares the lease id of the given key.
790    #[inline]
791    pub fn lease(key: impl Into<Vec<u8>>, cmp: CompareOp, lease: i64) -> Self {
792        Self::new(key, cmp, CompareTarget::Lease, TargetUnion::Lease(lease))
793    }
794
795    /// Sets the comparison to scan the range [key, end).
796    #[inline]
797    pub fn with_range(mut self, end: impl Into<Vec<u8>>) -> Self {
798        self.0.range_end = end.into();
799        self
800    }
801
802    /// Sets the comparison to scan all keys prefixed by the key.
803    #[inline]
804    pub fn with_prefix(mut self) -> Self {
805        self.0.range_end = get_prefix(&self.0.key);
806        self
807    }
808}
809
810/// Transaction operation.
811#[derive(Debug, Clone)]
812#[repr(transparent)]
813pub struct TxnOp(PbTxnOp);
814
815impl TxnOp {
816    /// `Put` operation.
817    #[inline]
818    pub fn put(
819        key: impl Into<Vec<u8>>,
820        value: impl Into<Vec<u8>>,
821        options: Option<PutOptions>,
822    ) -> Self {
823        TxnOp(PbTxnOp::RequestPut(
824            options.unwrap_or_default().with_kv(key, value).into(),
825        ))
826    }
827
828    /// `Get` operation.
829    #[inline]
830    pub fn get(key: impl Into<Vec<u8>>, options: Option<GetOptions>) -> Self {
831        TxnOp(PbTxnOp::RequestRange(
832            options.unwrap_or_default().with_key(key).into(),
833        ))
834    }
835
836    /// `Delete` operation.
837    #[inline]
838    pub fn delete(key: impl Into<Vec<u8>>, options: Option<DeleteOptions>) -> Self {
839        TxnOp(PbTxnOp::RequestDeleteRange(
840            options.unwrap_or_default().with_key(key).into(),
841        ))
842    }
843
844    /// `Txn` operation.
845    #[inline]
846    pub fn txn(txn: Txn) -> Self {
847        TxnOp(PbTxnOp::RequestTxn(txn.into()))
848    }
849}
850
851impl From<TxnOp> for PbTxnOp {
852    #[inline]
853    fn from(op: TxnOp) -> Self {
854        op.0
855    }
856}
857
858/// Transaction of multiple operations.
859#[derive(Debug, Default, Clone)]
860pub struct Txn {
861    req: PbTxnRequest,
862    c_when: bool,
863    c_then: bool,
864    c_else: bool,
865}
866
867impl Txn {
868    /// Creates a new transaction.
869    #[inline]
870    pub const fn new() -> Self {
871        Self {
872            req: PbTxnRequest {
873                compare: Vec::new(),
874                success: Vec::new(),
875                failure: Vec::new(),
876            },
877            c_when: false,
878            c_then: false,
879            c_else: false,
880        }
881    }
882
883    /// Takes a list of comparison. If all comparisons passed in succeed,
884    /// the operations passed into `and_then()` will be executed. Or the operations
885    /// passed into `or_else()` will be executed.
886    #[inline]
887    pub fn when(mut self, compares: impl Into<Vec<Compare>>) -> Self {
888        assert!(!self.c_when, "cannot call when twice");
889        assert!(!self.c_then, "cannot call when after and_then");
890        assert!(!self.c_else, "cannot call when after or_else");
891
892        self.c_when = true;
893
894        let compares = ManuallyDrop::new(compares.into());
895        self.req.compare = unsafe {
896            Vec::from_raw_parts(
897                compares.as_ptr() as *mut PbCompare,
898                compares.len(),
899                compares.capacity(),
900            )
901        };
902
903        self
904    }
905
906    /// Takes a list of operations. The operations list will be executed, if the
907    /// comparisons passed in `when()` succeed.
908    #[inline]
909    pub fn and_then(mut self, operations: impl Into<Vec<TxnOp>>) -> Self {
910        assert!(!self.c_then, "cannot call and_then twice");
911        assert!(!self.c_else, "cannot call and_then after or_else");
912
913        self.c_then = true;
914        self.req.success = operations
915            .into()
916            .into_iter()
917            .map(|op| PbTxnRequestOp {
918                request: Some(op.into()),
919            })
920            .collect();
921        self
922    }
923
924    /// Takes a list of operations. The operations list will be executed, if the
925    /// comparisons passed in `when()` fail.
926    #[inline]
927    pub fn or_else(mut self, operations: impl Into<Vec<TxnOp>>) -> Self {
928        assert!(!self.c_else, "cannot call or_else twice");
929
930        self.c_else = true;
931        self.req.failure = operations
932            .into()
933            .into_iter()
934            .map(|op| PbTxnRequestOp {
935                request: Some(op.into()),
936            })
937            .collect();
938        self
939    }
940
941    #[inline]
942    pub(crate) fn prefix_with(&mut self, prefix: &[u8]) {
943        self.req.prefix_with(prefix);
944    }
945}
946
947impl PbTxnRequest {
948    fn prefix_with(&mut self, prefix: &[u8]) {
949        let prefix_op = |op: &mut PbTxnRequestOp| {
950            if let Some(request) = &mut op.request {
951                match request {
952                    PbTxnOp::RequestRange(req) => {
953                        req.key.prefix_with(prefix);
954                        req.range_end.prefix_range_end_with(prefix);
955                    }
956                    PbTxnOp::RequestPut(req) => {
957                        req.key.prefix_with(prefix);
958                    }
959                    PbTxnOp::RequestDeleteRange(req) => {
960                        req.key.prefix_with(prefix);
961                        req.range_end.prefix_range_end_with(prefix);
962                    }
963                    PbTxnOp::RequestTxn(req) => {
964                        req.prefix_with(prefix);
965                    }
966                }
967            }
968        };
969
970        self.compare.iter_mut().for_each(|cmp| {
971            cmp.key.prefix_with(prefix);
972            cmp.range_end.prefix_range_end_with(prefix);
973        });
974        self.success.iter_mut().for_each(prefix_op);
975        self.failure.iter_mut().for_each(prefix_op);
976    }
977}
978
979impl From<Txn> for PbTxnRequest {
980    #[inline]
981    fn from(txn: Txn) -> Self {
982        txn.req
983    }
984}
985
986impl IntoRequest<PbTxnRequest> for Txn {
987    #[inline]
988    fn into_request(self) -> Request<PbTxnRequest> {
989        Request::new(self.into())
990    }
991}
992
993/// Transaction operation response.
994#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
995#[derive(Debug, Clone)]
996pub enum TxnOpResponse {
997    Put(PutResponse),
998    Get(GetResponse),
999    Delete(DeleteResponse),
1000    Txn(TxnResponse),
1001}
1002
1003/// Response for `Txn` operation.
1004#[cfg_attr(feature = "pub-response-field", visible::StructFields(pub))]
1005#[derive(Debug, Clone)]
1006#[repr(transparent)]
1007pub struct TxnResponse(PbTxnResponse);
1008
1009impl TxnResponse {
1010    /// Creates a new `Txn` response.
1011    #[inline]
1012    const fn new(resp: PbTxnResponse) -> Self {
1013        Self(resp)
1014    }
1015
1016    /// Transaction response header.
1017    #[inline]
1018    pub fn header(&self) -> Option<&ResponseHeader> {
1019        self.0.header.as_ref().map(From::from)
1020    }
1021
1022    /// Takes the header out of the response, leaving a [`None`] in its place.
1023    #[inline]
1024    pub fn take_header(&mut self) -> Option<ResponseHeader> {
1025        self.0.header.take().map(ResponseHeader::new)
1026    }
1027
1028    /// Returns `true` if the compare evaluated to true or `false` otherwise.
1029    #[inline]
1030    pub const fn succeeded(&self) -> bool {
1031        self.0.succeeded
1032    }
1033
1034    /// Returns responses of transaction operations.
1035    #[inline]
1036    pub fn op_responses(&self) -> Vec<TxnOpResponse> {
1037        self.0
1038            .responses
1039            .iter()
1040            .map(|resp| match resp.response.as_ref().unwrap() {
1041                PbTxnOpResponse::ResponsePut(put) => {
1042                    TxnOpResponse::Put(PutResponse::new(put.clone()))
1043                }
1044                PbTxnOpResponse::ResponseRange(get) => {
1045                    TxnOpResponse::Get(GetResponse::new(get.clone()))
1046                }
1047                PbTxnOpResponse::ResponseDeleteRange(delete) => {
1048                    TxnOpResponse::Delete(DeleteResponse::new(delete.clone()))
1049                }
1050                PbTxnOpResponse::ResponseTxn(txn) => {
1051                    TxnOpResponse::Txn(TxnResponse::new(txn.clone()))
1052                }
1053            })
1054            .collect()
1055    }
1056
1057    #[inline]
1058    pub(crate) fn strip_key_prefix(&mut self, prefix: &[u8]) {
1059        self.0.strip_key_prefix(prefix);
1060    }
1061}
1062
1063impl PbTxnResponse {
1064    fn strip_key_prefix(&mut self, prefix: &[u8]) {
1065        self.responses.iter_mut().for_each(|op| {
1066            if let Some(resp) = &mut op.response {
1067                match resp {
1068                    PbTxnOpResponse::ResponseRange(r) => {
1069                        for kv in r.kvs.iter_mut() {
1070                            kv.key.strip_key_prefix(prefix);
1071                        }
1072                    }
1073                    PbTxnOpResponse::ResponsePut(r) => {
1074                        if let Some(kv) = r.prev_kv.as_mut() {
1075                            kv.key.strip_key_prefix(prefix);
1076                        }
1077                    }
1078                    PbTxnOpResponse::ResponseDeleteRange(r) => {
1079                        for kv in r.prev_kvs.iter_mut() {
1080                            kv.key.strip_key_prefix(prefix);
1081                        }
1082                    }
1083                    PbTxnOpResponse::ResponseTxn(r) => {
1084                        r.strip_key_prefix(prefix);
1085                    }
1086                }
1087            }
1088        });
1089    }
1090}