/rust/registry/src/index.crates.io-1949cf8c6b5b557f/surrealdb-protocol-0.10.1/rust/rpc_methods.rs
Line | Count | Source |
1 | | use std::{collections::VecDeque, fmt::Display, pin::Pin}; |
2 | | |
3 | | use crate::{ |
4 | | convert::TryFromValue, |
5 | | proto::{ |
6 | | rpc::v1::{QueryError, QueryResponse, export_sql_request}, |
7 | | v1::Value, |
8 | | }, |
9 | | }; |
10 | | use anyhow::{Result, anyhow}; |
11 | | use futures::{Stream, StreamExt}; |
12 | | use tonic::Streaming; |
13 | | use tonic::async_trait; |
14 | | |
15 | | impl QueryResponse { |
16 | | /// Returns the first value from the query response. |
17 | 0 | pub fn first(mut self) -> Result<Value, anyhow::Error> { |
18 | 0 | if let Some(err) = self.error { |
19 | 0 | return Err(anyhow!("{}", err.message)); |
20 | 0 | } |
21 | | |
22 | 0 | if self.values.is_empty() { |
23 | 0 | return Err(anyhow!("No values returned")); |
24 | 0 | } |
25 | | |
26 | 0 | let value = self.values.remove(0); |
27 | | |
28 | 0 | Ok(value) |
29 | 0 | } |
30 | | |
31 | | /// Returns all values from the query response. |
32 | 0 | pub fn values(self) -> Result<Vec<Value>, anyhow::Error> { |
33 | 0 | if let Some(err) = self.error { |
34 | 0 | return Err(anyhow!("{}", err.message)); |
35 | 0 | } |
36 | | |
37 | 0 | Ok(self.values) |
38 | 0 | } |
39 | | } |
40 | | |
41 | | /// Consumes a stream of query responses and returns a stream of values. |
42 | | pub struct QueryResponseValueStream { |
43 | | stream: Streaming<QueryResponse>, |
44 | | current_values: VecDeque<Value>, |
45 | | } |
46 | | |
47 | | impl QueryResponseValueStream { |
48 | | /// Creates a new `QueryResponseValueStream` from a stream of query responses. |
49 | 0 | pub fn new(stream: Streaming<QueryResponse>) -> Self { |
50 | 0 | Self { |
51 | 0 | stream, |
52 | 0 | current_values: VecDeque::new(), |
53 | 0 | } |
54 | 0 | } |
55 | | } |
56 | | |
57 | | impl Stream for QueryResponseValueStream { |
58 | | type Item = Result<Value, anyhow::Error>; |
59 | | |
60 | 0 | fn poll_next( |
61 | 0 | mut self: Pin<&mut Self>, |
62 | 0 | cx: &mut std::task::Context<'_>, |
63 | 0 | ) -> std::task::Poll<Option<Self::Item>> { |
64 | | use std::task::Poll; |
65 | | |
66 | 0 | let this = self.as_mut().get_mut(); |
67 | | |
68 | | // If we have values in the current batch, yield the next one |
69 | 0 | if let Some(value) = this.current_values.pop_front() { |
70 | 0 | return Poll::Ready(Some(Ok(value))); |
71 | 0 | } |
72 | | |
73 | | // Otherwise, try to get the next batch from the stream |
74 | 0 | match this.stream.poll_next_unpin(cx) { |
75 | 0 | Poll::Ready(Some(Ok(response))) => { |
76 | | // Check for errors in the response |
77 | 0 | if let Some(err) = response.error { |
78 | 0 | return Poll::Ready(Some(Err(anyhow!("{}", err.message)))); |
79 | 0 | } |
80 | | |
81 | | // Extract values from the response and add them to the queue |
82 | 0 | this.current_values.extend(response.values); |
83 | | |
84 | | // Yield the first value from this batch |
85 | 0 | if let Some(value) = this.current_values.pop_front() { |
86 | 0 | Poll::Ready(Some(Ok(value))) |
87 | | } else { |
88 | | // Empty batch, try again |
89 | 0 | self.poll_next(cx) |
90 | | } |
91 | | } |
92 | 0 | Poll::Ready(Some(Err(e))) => { |
93 | | // Stream error |
94 | 0 | Poll::Ready(Some(Err(anyhow!("Stream error: {}", e)))) |
95 | | } |
96 | | Poll::Ready(None) => { |
97 | | // Stream ended |
98 | 0 | Poll::Ready(None) |
99 | | } |
100 | | Poll::Pending => { |
101 | | // Stream not ready yet |
102 | 0 | Poll::Pending |
103 | | } |
104 | | } |
105 | 0 | } |
106 | | } |
107 | | |
108 | | impl From<bool> for export_sql_request::Tables { |
109 | 0 | fn from(value: bool) -> Self { |
110 | 0 | if value { |
111 | 0 | export_sql_request::Tables { |
112 | 0 | selection: Some(export_sql_request::tables::Selection::All( |
113 | 0 | Default::default(), |
114 | 0 | )), |
115 | 0 | } |
116 | | } else { |
117 | 0 | export_sql_request::Tables { |
118 | 0 | selection: Some(export_sql_request::tables::Selection::None( |
119 | 0 | Default::default(), |
120 | 0 | )), |
121 | 0 | } |
122 | | } |
123 | 0 | } |
124 | | } |
125 | | |
126 | | impl QueryError { |
127 | | /// Creates a new `QueryError` with the given code and message. |
128 | 0 | pub fn new(code: i64, message: String) -> Self { |
129 | 0 | Self { code, message } |
130 | 0 | } |
131 | | } |
132 | | |
133 | | impl Display for QueryError { |
134 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
135 | 0 | write!(f, "({}): {}", self.code, self.message) |
136 | 0 | } |
137 | | } |
138 | | |
139 | | impl std::error::Error for QueryError {} |
140 | | |
141 | | /// A trait for converting a stream of query responses into a specific type. |
142 | | #[async_trait] |
143 | | pub trait TryFromQueryStream { |
144 | | /// Converts a stream of query responses into a specific type. |
145 | | async fn try_from_query_stream(stream: Streaming<QueryResponse>) -> Result<Self, anyhow::Error> |
146 | | where |
147 | | Self: Sized; |
148 | | } |
149 | | |
150 | | #[async_trait] |
151 | | impl<T> TryFromQueryStream for Option<T> |
152 | | where |
153 | | T: TryFromValue + Send, |
154 | | { |
155 | | async fn try_from_query_stream( |
156 | | stream: Streaming<QueryResponse>, |
157 | 0 | ) -> Result<Self, anyhow::Error> { |
158 | | let mut stream = QueryResponseValueStream::new(stream); |
159 | | let value = match stream.next().await { |
160 | | Some(Ok(value)) => value, |
161 | | Some(Err(e)) => return Err(e), |
162 | | None => return Ok(None), |
163 | | }; |
164 | | let value = T::try_from_value(value)?; |
165 | | Ok(Some(value)) |
166 | 0 | } |
167 | | } |
168 | | |
169 | | #[async_trait] |
170 | | impl<T> TryFromQueryStream for Vec<T> |
171 | | where |
172 | | T: TryFromValue + Send, |
173 | | { |
174 | | async fn try_from_query_stream( |
175 | | stream: Streaming<QueryResponse>, |
176 | 0 | ) -> Result<Self, anyhow::Error> { |
177 | | let mut stream = QueryResponseValueStream::new(stream); |
178 | | let mut values = Vec::new(); |
179 | | while let Some(value) = stream.next().await { |
180 | | let value = T::try_from_value(value?)?; |
181 | | values.push(value); |
182 | | } |
183 | | Ok(values) |
184 | 0 | } |
185 | | } |
186 | | |
187 | | impl From<Vec<&str>> for export_sql_request::Tables { |
188 | 0 | fn from(values: Vec<&str>) -> Self { |
189 | 0 | let mut selected_tables = export_sql_request::SelectedTables::default(); |
190 | 0 | for v in values { |
191 | 0 | selected_tables.tables.push(v.to_string()); |
192 | 0 | } |
193 | 0 | export_sql_request::Tables { |
194 | 0 | selection: Some(export_sql_request::tables::Selection::Selected( |
195 | 0 | selected_tables, |
196 | 0 | )), |
197 | 0 | } |
198 | 0 | } |
199 | | } |