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_make_table(
167 &mut self,
168 _view_id: &str,
169 _table_id: &str,
170 _config: &ViewConfig,
171 _schema: Option<&IndexMap<String, ColumnType>>,
172 ) -> VirtualServerFuture<'_, Result<(), Self::Error>> {
173 Box::pin(async { unimplemented!("view_make_table not implemented") })
174 }
175
176 fn make_table(
180 &mut self,
181 _table_id: &str,
182 _data: &crate::proto::MakeTableData,
183 ) -> VirtualServerFuture<'_, Result<(), Self::Error>> {
184 Box::pin(async { unimplemented!("make_table not implemented") })
185 }
186}
187
188pub async fn describe_via_make_view<H: VirtualServerHandler + ?Sized>(
192 handler: &mut H,
193 table_id: &str,
194 config: &ViewConfig,
195) -> Result<Result<Description, DescribeError>, H::Error> {
196 static COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
197 let view_id = format!(
198 "__psp_describe_{}__",
199 COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
200 );
201
202 let mut update: ViewConfigUpdate = config.clone().into();
203 let view_id = match handler
204 .table_make_view(table_id, &view_id, &mut update)
205 .await
206 {
207 Ok(view_id) => view_id,
208 Err(e) => return Ok(Err(DescribeError::Config(e.to_string()))),
209 };
210
211 let config: ViewConfig = update.into();
212 let schema = handler.view_schema(&view_id, &config).await;
213 let deleted = handler.view_delete(&view_id).await;
214 let schema = schema?;
215 deleted?;
216 let view_schema = schema
217 .iter()
218 .map(|(name, ty)| {
219 let source = column_path_source(name, &config)
220 .map(|(_, col)| col.to_string())
221 .unwrap_or_else(|| name.clone());
222
223 (source, *ty)
224 })
225 .collect::<std::collections::HashMap<_, _>>();
226
227 let expression_schema = config
228 .expressions
229 .keys()
230 .filter_map(|name| view_schema.get(name).map(|ty| (name.clone(), *ty)))
231 .collect();
232
233 Ok(Ok(Description {
234 expression_schema,
235 view_schema,
236 }))
237}