1use reddb_grpc_proto::red_db_client::RedDbClient;
14use reddb_grpc_proto::*;
15use reddb_wire::auth::{bearer_authorization_value, login_payload_json, AUTHORIZATION_HEADER};
16use tonic::transport::Channel;
17use tonic::Request;
18
19#[derive(Debug, Clone)]
20pub struct HealthStatus {
21 pub healthy: bool,
22 pub state: String,
23 pub checked_at_unix_ms: u64,
24}
25
26#[derive(Debug, Clone)]
27pub struct QueryResponse {
28 pub ok: bool,
29 pub mode: String,
30 pub statement: String,
31 pub engine: String,
32 pub columns: Vec<String>,
33 pub record_count: u64,
34 pub affected_rows: u64,
37 pub result_json: String,
38}
39
40#[derive(Debug, Clone)]
41pub struct CreatedEntity {
42 pub ok: bool,
43 pub id: u64,
44 pub entity_json: String,
45}
46
47#[derive(Debug, Clone)]
48pub struct BulkCreateStatus {
49 pub ok: bool,
50 pub count: u64,
51 pub ids: Vec<u64>,
52}
53
54#[derive(Debug, Clone)]
55pub struct OperationStatus {
56 pub ok: bool,
57 pub message: String,
58}
59
60#[derive(Clone)]
61pub struct RedDBClient {
62 inner: RedDbClient<Channel>,
63 token: Option<String>,
64 pub addr: String,
65}
66
67impl RedDBClient {
68 pub async fn connect(
69 addr: &str,
70 token: Option<String>,
71 ) -> Result<Self, Box<dyn std::error::Error>> {
72 let endpoint = if addr.starts_with("http") {
73 addr.to_string()
74 } else {
75 format!("http://{}", addr)
76 };
77 let inner = RedDbClient::connect(endpoint.clone()).await?;
78 Ok(Self {
79 inner,
80 token,
81 addr: endpoint,
82 })
83 }
84
85 fn auth_request<T>(&self, inner: T) -> Request<T> {
86 let mut req = Request::new(inner);
87 if let Some(ref token) = self.token {
88 if let Ok(value) = bearer_authorization_value(token).parse() {
89 req.metadata_mut().insert(AUTHORIZATION_HEADER, value);
90 }
91 }
92 req
93 }
94
95 pub fn set_token(&mut self, token: String) {
97 self.token = Some(token);
98 }
99
100 pub async fn health_status(&mut self) -> Result<HealthStatus, Box<dyn std::error::Error>> {
101 let req = self.auth_request(Empty {});
102 let resp = self.inner.health(req).await?;
103 let reply = resp.into_inner();
104 Ok(HealthStatus {
105 healthy: reply.healthy,
106 state: reply.state,
107 checked_at_unix_ms: reply.checked_at_unix_ms,
108 })
109 }
110
111 pub async fn health(&mut self) -> Result<String, Box<dyn std::error::Error>> {
112 let reply = self.health_status().await?;
113 Ok(format!(
114 "state: {}, healthy: {}",
115 reply.state, reply.healthy
116 ))
117 }
118
119 pub async fn query_reply(
120 &mut self,
121 sql: &str,
122 ) -> Result<QueryResponse, Box<dyn std::error::Error>> {
123 self.query_reply_with_params(sql, Vec::new()).await
124 }
125
126 pub async fn query_reply_with_params(
127 &mut self,
128 sql: &str,
129 params: Vec<QueryValue>,
130 ) -> Result<QueryResponse, Box<dyn std::error::Error>> {
131 let req = self.auth_request(QueryRequest {
132 query: sql.to_string(),
133 entity_types: vec![],
134 capabilities: vec![],
135 params,
136 });
137 let resp = self.inner.query(req).await?;
138 let reply = resp.into_inner();
139 Ok(QueryResponse {
140 ok: reply.ok,
141 mode: reply.mode,
142 statement: reply.statement,
143 engine: reply.engine,
144 columns: reply.columns,
145 record_count: reply.record_count,
146 affected_rows: reply.affected_rows,
147 result_json: reply.result_json,
148 })
149 }
150
151 pub async fn query(&mut self, sql: &str) -> Result<String, Box<dyn std::error::Error>> {
152 let reply = self.query_reply(sql).await?;
153 Ok(reply.result_json)
154 }
155
156 pub async fn collections(&mut self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
157 let req = self.auth_request(Empty {});
158 let resp = self.inner.collections(req).await?;
159 Ok(resp.into_inner().collections)
160 }
161
162 pub async fn scan(
163 &mut self,
164 collection: &str,
165 limit: u64,
166 ) -> Result<String, Box<dyn std::error::Error>> {
167 let req = self.auth_request(ScanRequest {
168 collection: collection.to_string(),
169 offset: 0,
170 limit,
171 });
172 let resp = self.inner.scan(req).await?;
173 let reply = resp.into_inner();
174 let items: Vec<String> = reply.items.iter().map(|e| e.json.clone()).collect();
175 Ok(format!(
176 "total: {}, items: [{}]",
177 reply.total,
178 items.join(", ")
179 ))
180 }
181
182 pub async fn stats(&mut self) -> Result<String, Box<dyn std::error::Error>> {
183 let req = self.auth_request(Empty {});
184 let resp = self.inner.stats(req).await?;
185 let reply = resp.into_inner();
186 Ok(format!(
187 "collections: {}, entities: {}, memory: {} bytes, started_at: {}",
188 reply.collection_count,
189 reply.total_entities,
190 reply.total_memory_bytes,
191 reply.started_at_unix_ms
192 ))
193 }
194
195 pub async fn create_row(
196 &mut self,
197 collection: &str,
198 json: &str,
199 ) -> Result<String, Box<dyn std::error::Error>> {
200 let reply = self.create_row_entity(collection, json).await?;
201 Ok(format!("id: {}, entity: {}", reply.id, reply.entity_json))
202 }
203
204 pub async fn create_row_entity(
205 &mut self,
206 collection: &str,
207 json: &str,
208 ) -> Result<CreatedEntity, Box<dyn std::error::Error>> {
209 let req = self.auth_request(JsonCreateRequest {
210 collection: collection.to_string(),
211 payload_json: json.to_string(),
212 });
213 let resp = self.inner.create_row(req).await?;
214 let reply = resp.into_inner();
215 Ok(CreatedEntity {
216 ok: reply.ok,
217 id: reply.id,
218 entity_json: reply.entity_json,
219 })
220 }
221
222 pub async fn bulk_create_rows(
223 &mut self,
224 collection: &str,
225 payload_json: Vec<String>,
226 ) -> Result<BulkCreateStatus, Box<dyn std::error::Error>> {
227 let req = self.auth_request(JsonBulkCreateRequest {
228 collection: collection.to_string(),
229 payload_json,
230 });
231 let resp = self.inner.bulk_create_rows(req).await?;
232 let reply = resp.into_inner();
233 Ok(BulkCreateStatus {
234 ok: reply.ok,
235 count: reply.count,
236 ids: reply.items.into_iter().map(|item| item.id).collect(),
237 })
238 }
239
240 pub async fn explain(&mut self, sql: &str) -> Result<String, Box<dyn std::error::Error>> {
241 let req = self.auth_request(QueryRequest {
242 query: sql.to_string(),
243 entity_types: vec![],
244 capabilities: vec![],
245 params: vec![],
246 });
247 let resp = self.inner.explain_query(req).await?;
248 Ok(resp.into_inner().payload)
249 }
250
251 pub async fn login(
252 &mut self,
253 username: &str,
254 password: &str,
255 ) -> Result<String, Box<dyn std::error::Error>> {
256 let req = self.auth_request(JsonPayloadRequest {
257 payload_json: login_payload_json(username, password),
258 });
259 let resp = self.inner.auth_login(req).await?;
260 let reply = resp.into_inner();
261 Ok(reply.payload)
262 }
263
264 pub async fn replication_status(&mut self) -> Result<String, Box<dyn std::error::Error>> {
265 let req = self.auth_request(Empty {});
266 let resp = self.inner.replication_status(req).await?;
267 Ok(resp.into_inner().payload)
268 }
269
270 pub async fn topology(&mut self) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
276 let req = self.auth_request(TopologyRequest {});
277 let resp = self.inner.topology(req).await?;
278 Ok(resp.into_inner().topology_bytes)
279 }
280
281 pub async fn delete_entity(
282 &mut self,
283 collection: &str,
284 id: u64,
285 ) -> Result<OperationStatus, Box<dyn std::error::Error>> {
286 let req = self.auth_request(DeleteEntityRequest {
287 collection: collection.to_string(),
288 id,
289 });
290 let resp = self.inner.delete_entity(req).await?;
291 let reply = resp.into_inner();
292 Ok(OperationStatus {
293 ok: reply.ok,
294 message: reply.message,
295 })
296 }
297}