perspective_client/virtual_server/
handler.rs1use std::future::Future;
14use std::pin::Pin;
15
16use indexmap::IndexMap;
17
18use super::data::VirtualDataSlice;
19use super::features::Features;
20use super::generic_sql_model::column_path_source;
21use crate::config::{ViewConfig, ViewConfigUpdate};
22use crate::proto::{ColumnType, HostedTable, TableMakePortReq, ViewPort};
23use crate::table::{DescribeError, Description};
24
25#[cfg(feature = "sendable")]
26pub type VirtualServerFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
27
28#[cfg(not(feature = "sendable"))]
34pub type VirtualServerFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
35
36pub trait VirtualServerHandler {
43 #[cfg(not(feature = "sendable"))]
47 type Error: std::error::Error + Send + Sync + 'static;
48
49 #[cfg(feature = "sendable")]
50 type Error: std::error::Error + 'static;
51
52 fn get_hosted_tables(&self) -> VirtualServerFuture<'_, Result<Vec<HostedTable>, Self::Error>>;
54
55 fn table_schema(
57 &self,
58 table_id: &str,
59 ) -> VirtualServerFuture<'_, Result<IndexMap<String, ColumnType>, Self::Error>>;
60
61 fn table_size(&self, table_id: &str) -> VirtualServerFuture<'_, Result<u32, Self::Error>>;
63
64 fn table_make_view(
69 &mut self,
70 view_id: &str,
71 view_id: &str,
72 config: &mut ViewConfigUpdate,
73 ) -> VirtualServerFuture<'_, Result<String, Self::Error>>;
74
75 fn table_describe(
78 &mut self,
79 table_id: &str,
80 config: &ViewConfig,
81 ) -> VirtualServerFuture<'_, Result<Result<Description, DescribeError>, Self::Error>>;
82
83 fn view_delete(&self, view_id: &str) -> VirtualServerFuture<'_, Result<(), Self::Error>>;
85
86 fn view_get_data(
88 &self,
89 view_id: &str,
90 config: &ViewConfig,
91 schema: &IndexMap<String, ColumnType>,
92 viewport: &ViewPort,
93 ) -> VirtualServerFuture<'_, Result<VirtualDataSlice, Self::Error>>;
94
95 fn table_column_size(
99 &self,
100 table_id: &str,
101 ) -> VirtualServerFuture<'_, Result<u32, Self::Error>> {
102 let fut = self.table_schema(table_id);
103 Box::pin(async move { Ok(fut.await?.len() as u32) })
104 }
105
106 fn view_size(&self, view_id: &str) -> VirtualServerFuture<'_, Result<u32, Self::Error>> {
108 Box::pin(self.table_size(view_id))
109 }
110
111 fn view_column_size(
113 &self,
114 view_id: &str,
115 config: &ViewConfig,
116 ) -> VirtualServerFuture<'_, Result<u32, Self::Error>> {
117 let fut = self.view_schema(view_id, config);
118 Box::pin(async move { Ok(fut.await?.len() as u32) })
119 }
120
121 fn view_schema(
123 &self,
124 view_id: &str,
125 _config: &ViewConfig,
126 ) -> VirtualServerFuture<'_, Result<IndexMap<String, ColumnType>, Self::Error>> {
127 Box::pin(self.table_schema(view_id))
128 }
129
130 fn get_features(&self) -> VirtualServerFuture<'_, Result<Features<'_>, Self::Error>> {
134 Box::pin(async { Ok(Features::default()) })
135 }
136
137 fn table_make_port(
141 &self,
142 _req: &TableMakePortReq,
143 ) -> VirtualServerFuture<'_, Result<u32, Self::Error>> {
144 Box::pin(async { Ok(0) })
145 }
146
147 fn view_get_min_max(
151 &self,
152 _view_id: &str,
153 _column_name: &str,
154 _config: &crate::config::ViewConfig,
155 ) -> VirtualServerFuture<'_, Result<(crate::config::Scalar, crate::config::Scalar), Self::Error>>
156 {
157 Box::pin(async { unimplemented!("view_get_min_max not implemented") })
158 }
159
160 fn view_expand(
163 &mut self,
164 _view_id: &str,
165 _config: &ViewConfig,
166 _row_index: u32,
167 ) -> VirtualServerFuture<'_, Result<u32, Self::Error>> {
168 Box::pin(async { unimplemented!("view_expand not implemented") })
169 }
170
171 fn view_collapse(
175 &mut self,
176 _view_id: &str,
177 _config: &ViewConfig,
178 _row_index: u32,
179 ) -> VirtualServerFuture<'_, Result<u32, Self::Error>> {
180 Box::pin(async { unimplemented!("view_collapse not implemented") })
181 }
182
183 fn view_set_depth(
186 &mut self,
187 _view_id: &str,
188 _config: &ViewConfig,
189 _depth: u32,
190 ) -> VirtualServerFuture<'_, Result<(), Self::Error>> {
191 Box::pin(async { unimplemented!("view_set_depth not implemented") })
192 }
193
194 fn view_make_table(
201 &mut self,
202 _view_id: &str,
203 _table_id: &str,
204 _config: &ViewConfig,
205 _schema: Option<&IndexMap<String, ColumnType>>,
206 ) -> VirtualServerFuture<'_, Result<(), Self::Error>> {
207 Box::pin(async { unimplemented!("view_make_table not implemented") })
208 }
209
210 fn make_table(
214 &mut self,
215 _table_id: &str,
216 _data: &crate::proto::MakeTableData,
217 ) -> VirtualServerFuture<'_, Result<(), Self::Error>> {
218 Box::pin(async { unimplemented!("make_table not implemented") })
219 }
220}
221
222pub async fn describe_via_make_view<H: VirtualServerHandler + ?Sized>(
226 handler: &mut H,
227 table_id: &str,
228 config: &ViewConfig,
229) -> Result<Result<Description, DescribeError>, H::Error> {
230 static COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
231 let view_id = format!(
232 "__psp_describe_{}__",
233 COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
234 );
235
236 let mut update: ViewConfigUpdate = config.clone().into();
237 let view_id = match handler
238 .table_make_view(table_id, &view_id, &mut update)
239 .await
240 {
241 Ok(view_id) => view_id,
242 Err(e) => return Ok(Err(DescribeError::Config(e.to_string()))),
243 };
244
245 let config: ViewConfig = update.into();
246 let schema = handler.view_schema(&view_id, &config).await;
247 let deleted = handler.view_delete(&view_id).await;
248 let schema = schema?;
249 deleted?;
250 let view_schema = schema
251 .iter()
252 .map(|(name, ty)| {
253 let source = column_path_source(name, &config)
254 .map(|(_, col)| col.to_string())
255 .unwrap_or_else(|| name.clone());
256
257 (source, *ty)
258 })
259 .collect::<std::collections::HashMap<_, _>>();
260
261 let expression_schema = config
262 .expressions
263 .keys()
264 .filter_map(|name| view_schema.get(name).map(|ty| (name.clone(), *ty)))
265 .collect();
266
267 Ok(Ok(Description {
268 expression_schema,
269 view_schema,
270 }))
271}