perspective_js/
generic_sql_model.rs1use std::str::FromStr;
16
17use indexmap::IndexMap;
18use js_sys::Object;
19use perspective_client::config::ViewConfig;
20use perspective_client::proto::{ColumnType, ViewPort};
21use perspective_client::virtual_server;
22use wasm_bindgen::prelude::*;
23
24use crate::utils::*;
25
26#[wasm_bindgen]
31pub struct GenericSQLVirtualServerModel {
32 inner: virtual_server::GenericSQLVirtualServerModel,
33}
34
35#[wasm_bindgen]
36extern "C" {
37 pub type JsGenericSQLVirtualServerModelArgs;
38}
39
40#[wasm_bindgen]
41impl GenericSQLVirtualServerModel {
42 #[wasm_bindgen(constructor)]
44 pub fn new(args: Option<JsGenericSQLVirtualServerModelArgs>) -> Result<Self, JsValue> {
45 Ok(Self {
46 inner: virtual_server::GenericSQLVirtualServerModel::new(
47 args.map(|x| x.into_serde_ext())
48 .transpose()?
49 .unwrap_or_default(),
50 ),
51 })
52 }
53
54 #[wasm_bindgen(js_name = "getHostedTables")]
56 pub fn get_hosted_tables(&self) -> Result<String, JsValue> {
57 self.inner
58 .get_hosted_tables()
59 .map_err(|e| JsValue::from_str(&e.to_string()))
60 }
61
62 #[wasm_bindgen(js_name = "tableSchema")]
64 pub fn table_schema(&self, table_id: &str) -> Result<String, JsValue> {
65 self.inner
66 .table_schema(table_id)
67 .map_err(|e| JsValue::from_str(&e.to_string()))
68 }
69
70 #[wasm_bindgen(js_name = "tableSize")]
72 pub fn table_size(&self, table_id: &str) -> Result<String, JsValue> {
73 self.inner
74 .table_size(table_id)
75 .map_err(|e| JsValue::from_str(&e.to_string()))
76 }
77
78 #[wasm_bindgen(js_name = "viewColumnSize")]
80 pub fn view_column_size(&self, view_id: &str) -> Result<String, JsValue> {
81 self.inner
82 .view_column_size(view_id)
83 .map_err(|e| JsValue::from_str(&e.to_string()))
84 }
85
86 #[wasm_bindgen(js_name = "tableValidateExpression")]
88 pub fn table_validate_expression(
89 &self,
90 table_id: &str,
91 expression: &str,
92 ) -> Result<String, JsValue> {
93 self.inner
94 .table_validate_expression(table_id, expression)
95 .map_err(|e| JsValue::from_str(&e.to_string()))
96 }
97
98 #[wasm_bindgen(js_name = "viewDelete")]
100 pub fn view_delete(&self, view_id: &str) -> Result<String, JsValue> {
101 self.inner
102 .view_delete(view_id)
103 .map_err(|e| JsValue::from_str(&e.to_string()))
104 }
105
106 #[wasm_bindgen(js_name = "tableMakeView")]
109 pub fn table_make_view(
110 &self,
111 table_id: &str,
112 view_id: &str,
113 config: JsValue,
114 ) -> Result<String, JsValue> {
115 let config: ViewConfig = serde_wasm_bindgen::from_value(config)
116 .map_err(|e| JsValue::from_str(&e.to_string()))?;
117
118 self.inner
119 .table_make_view(table_id, view_id, &config)
120 .map_err(|e| JsValue::from_str(&e.to_string()))
121 }
122
123 #[wasm_bindgen(js_name = "viewGetData")]
125 pub fn view_get_data(
126 &self,
127 view_id: &str,
128 config: JsValue,
129 viewport: JsValue,
130 schema: JsValue,
131 ) -> Result<String, JsValue> {
132 let config: ViewConfig = serde_wasm_bindgen::from_value(config)
133 .map_err(|e| JsValue::from_str(&e.to_string()))?;
134
135 let viewport: ViewPort = serde_wasm_bindgen::from_value(viewport)
136 .map_err(|e| JsValue::from_str(&e.to_string()))?;
137
138 let schema = self.parse_schema(schema)?;
139
140 self.inner
141 .view_get_data(view_id, &config, &viewport, &schema)
142 .map_err(|e| JsValue::from_str(&e.to_string()))
143 }
144
145 #[wasm_bindgen(js_name = "viewSchema")]
147 pub fn view_schema(&self, view_id: &str) -> Result<String, JsValue> {
148 self.inner
149 .view_schema(view_id)
150 .map_err(|e| JsValue::from_str(&e.to_string()))
151 }
152
153 #[wasm_bindgen(js_name = "viewSize")]
155 pub fn view_size(&self, view_id: &str) -> Result<String, JsValue> {
156 self.inner
157 .view_size(view_id)
158 .map_err(|e| JsValue::from_str(&e.to_string()))
159 }
160}
161
162impl GenericSQLVirtualServerModel {
163 fn parse_schema(&self, schema: JsValue) -> Result<IndexMap<String, ColumnType>, JsValue> {
164 let obj = schema.dyn_ref::<Object>().ok_or_else(|| {
165 JsValue::from_str("Schema must be an object mapping column names to types")
166 })?;
167
168 let mut result = IndexMap::new();
169 let entries = Object::entries(obj);
170 for i in 0..entries.length() {
171 let entry = entries.get(i);
172 let entry_array = entry
173 .dyn_ref::<js_sys::Array>()
174 .ok_or_else(|| JsValue::from_str("Invalid schema entry"))?;
175 let key = entry_array
176 .get(0)
177 .as_string()
178 .ok_or_else(|| JsValue::from_str("Column name must be a string"))?;
179 let value = entry_array
180 .get(1)
181 .as_string()
182 .ok_or_else(|| JsValue::from_str("Column type must be a string"))?;
183 let column_type = ColumnType::from_str(&value)
184 .map_err(|_| JsValue::from_str(&format!("Unknown column type: {}", value)))?;
185 result.insert(key, column_type);
186 }
187 Ok(result)
188 }
189}