1use crate::convert::*;
3use crate::error::Result;
4use bytes::Bytes;
5use kstone_core::Item;
6use kstone_proto::{self as proto, keystone_db_client::KeystoneDbClient};
7use tonic::transport::Channel;
8use tonic::Streaming;
9
10pub struct RemoteScan {
12 limit: Option<u32>,
13 exclusive_start_key: Option<proto::LastKey>,
14 index_name: Option<String>,
15 segment: Option<u32>,
16 total_segments: Option<u32>,
17}
18
19impl RemoteScan {
20 pub fn new() -> Self {
22 Self {
23 limit: None,
24 exclusive_start_key: None,
25 index_name: None,
26 segment: None,
27 total_segments: None,
28 }
29 }
30
31 pub fn limit(mut self, limit: usize) -> Self {
33 self.limit = Some(limit as u32);
34 self
35 }
36
37 pub fn start_after(mut self, pk: &[u8], sk: Option<&[u8]>) -> Self {
39 self.exclusive_start_key = Some(proto::LastKey {
40 partition_key: pk.to_vec(),
41 sort_key: sk.map(|s| s.to_vec()),
42 });
43 self
44 }
45
46 pub fn index(mut self, index_name: impl Into<String>) -> Self {
48 self.index_name = Some(index_name.into());
49 self
50 }
51
52 pub fn segment(mut self, segment: usize, total_segments: usize) -> Self {
54 self.segment = Some(segment as u32);
55 self.total_segments = Some(total_segments as u32);
56 self
57 }
58
59 pub async fn execute(
64 self,
65 client: &mut KeystoneDbClient<Channel>,
66 ) -> Result<RemoteScanResponse> {
67 let request = proto::ScanRequest {
68 filter_expression: None,
69 expression_values: std::collections::HashMap::new(),
70 limit: self.limit,
71 exclusive_start_key: self.exclusive_start_key,
72 index_name: self.index_name,
73 segment: self.segment,
74 total_segments: self.total_segments,
75 };
76
77 let mut stream: Streaming<proto::ScanResponse> = client
78 .scan(request)
79 .await?
80 .into_inner();
81
82 let mut all_items = Vec::new();
84 let mut total_count = 0;
85 let mut total_scanned_count = 0;
86 let mut last_key = None;
87
88 while let Some(response) = stream.message().await? {
89 let items: Vec<Item> = response
90 .items
91 .into_iter()
92 .map(|proto_item| proto_item_to_ks(proto_item).expect("Invalid item from server"))
93 .collect();
94
95 total_count += response.count as usize;
96 total_scanned_count += response.scanned_count as usize;
97
98 if let Some(key) = response.last_evaluated_key {
99 let (pk, sk) = proto_last_key_to_ks(key);
100 last_key = Some((pk, sk));
101 }
102
103 all_items.extend(items);
104 }
105
106 Ok(RemoteScanResponse {
107 items: all_items,
108 count: total_count,
109 scanned_count: total_scanned_count,
110 last_key,
111 })
112 }
113}
114
115impl Default for RemoteScan {
116 fn default() -> Self {
117 Self::new()
118 }
119}
120
121pub struct RemoteScanResponse {
123 pub items: Vec<Item>,
125 pub count: usize,
127 pub last_key: Option<(Bytes, Option<Bytes>)>,
129 pub scanned_count: usize,
131}