1use js_sys::{Array, ArrayBuffer, Function, Object};
14use macro_rules_attribute::apply;
15use perspective_client::{assert_view_api, OnUpdateOptions, ViewWindow};
16use wasm_bindgen::prelude::*;
17use wasm_bindgen_futures::spawn_local;
18
19#[cfg(doc)]
20use crate::table::Table;
21use crate::utils::{inherit_docs, ApiFuture, ApiResult, JsValueSerdeExt, LocalPollLoop};
22
23#[wasm_bindgen]
24unsafe extern "C" {
25 #[wasm_bindgen(typescript_type = "ViewWindow")]
26 #[derive(Clone)]
27 pub type JsViewWindow;
28
29 #[wasm_bindgen(method, setter, js_name = "formatted")]
30 pub fn set_formatted(this: &JsViewWindow, x: bool);
31
32 #[wasm_bindgen(typescript_type = "OnUpdateOptions")]
33 pub type JsOnUpdateOptions;
34
35}
36
37impl From<ViewWindow> for JsViewWindow {
38 fn from(value: ViewWindow) -> Self {
39 JsViewWindow::from_serde_ext(&value)
40 .unwrap()
41 .unchecked_into()
42 }
43}
44
45#[apply(inherit_docs)]
46#[inherit_doc = "view.md"]
47#[wasm_bindgen]
48#[derive(Clone)]
49pub struct View(pub(crate) perspective_client::View);
50
51assert_view_api!(View);
52
53impl From<perspective_client::View> for View {
54 fn from(value: perspective_client::View) -> Self {
55 View(value)
56 }
57}
58
59#[wasm_bindgen]
60impl View {
61 #[doc(hidden)]
62 pub fn __get_model(&self) -> View {
63 self.clone()
64 }
65
66 #[apply(inherit_docs)]
67 #[inherit_doc = "view/column_paths.md"]
68 #[wasm_bindgen]
69 pub async fn column_paths(&self) -> ApiResult<JsValue> {
70 let columns = self.0.column_paths().await?;
71 Ok(JsValue::from_serde_ext(&columns)?)
72 }
73
74 #[apply(inherit_docs)]
75 #[inherit_doc = "view/delete.md"]
76 #[wasm_bindgen]
77 pub async fn delete(&self) -> ApiResult<()> {
78 self.0.delete().await?;
79 Ok(())
80 }
81
82 #[apply(inherit_docs)]
83 #[inherit_doc = "view/dimensions.md"]
84 #[wasm_bindgen]
85 pub async fn dimensions(&self) -> ApiResult<JsValue> {
86 let dimensions = self.0.dimensions().await?;
87 Ok(JsValue::from_serde_ext(&dimensions)?)
88 }
89
90 #[apply(inherit_docs)]
91 #[inherit_doc = "view/expression_schema.md"]
92 #[wasm_bindgen]
93 pub async fn expression_schema(&self) -> ApiResult<JsValue> {
94 let schema = self.0.expression_schema().await?;
95 Ok(JsValue::from_serde_ext(&schema)?)
96 }
97
98 #[apply(inherit_docs)]
99 #[inherit_doc = "view/get_config.md"]
100 #[wasm_bindgen]
101 pub async fn get_config(&self) -> ApiResult<JsValue> {
102 let config = self.0.get_config().await?;
103 Ok(JsValue::from_serde_ext(&config)?)
104 }
105
106 #[apply(inherit_docs)]
107 #[inherit_doc = "view/get_min_max.md"]
108 #[wasm_bindgen]
109 pub async fn get_min_max(&self, name: String) -> ApiResult<Array> {
110 let result = self.0.get_min_max(name).await?;
111 Ok([result.0, result.1]
112 .iter()
113 .map(|x| js_sys::JSON::parse(x))
114 .collect::<Result<_, _>>()?)
115 }
116
117 #[apply(inherit_docs)]
118 #[inherit_doc = "view/num_rows.md"]
119 #[wasm_bindgen]
120 pub async fn num_rows(&self) -> ApiResult<i32> {
121 let size = self.0.num_rows().await?;
122 Ok(size as i32)
123 }
124
125 #[apply(inherit_docs)]
126 #[inherit_doc = "view/schema.md"]
127 #[wasm_bindgen]
128 pub async fn schema(&self) -> ApiResult<JsValue> {
129 let schema = self.0.schema().await?;
130 Ok(JsValue::from_serde_ext(&schema)?)
131 }
132
133 #[apply(inherit_docs)]
134 #[inherit_doc = "view/to_arrow.md"]
135 #[wasm_bindgen]
136 pub async fn to_arrow(&self, window: Option<JsViewWindow>) -> ApiResult<ArrayBuffer> {
137 let window = window.into_serde_ext::<Option<ViewWindow>>()?;
138 let arrow = self.0.to_arrow(window.unwrap_or_default()).await?;
139 Ok(js_sys::Uint8Array::from(&arrow[..])
140 .buffer()
141 .unchecked_into())
142 }
143
144 #[apply(inherit_docs)]
145 #[inherit_doc = "view/to_columns_string.md"]
146 #[wasm_bindgen]
147 pub async fn to_columns_string(&self, window: Option<JsViewWindow>) -> ApiResult<String> {
148 let window = window.into_serde_ext::<Option<ViewWindow>>()?;
149 let json = self.0.to_columns_string(window.unwrap_or_default()).await?;
150 Ok(json)
151 }
152
153 #[apply(inherit_docs)]
154 #[inherit_doc = "view/to_columns.md"]
155 #[wasm_bindgen]
156 pub async fn to_columns(&self, window: Option<JsViewWindow>) -> ApiResult<Object> {
157 let json = self.to_columns_string(window).await?;
158 Ok(js_sys::JSON::parse(&json)?.unchecked_into())
159 }
160
161 #[apply(inherit_docs)]
162 #[inherit_doc = "view/to_json_string.md"]
163 #[wasm_bindgen]
164 pub async fn to_json_string(&self, window: Option<JsViewWindow>) -> ApiResult<String> {
165 let window = window.into_serde_ext::<Option<ViewWindow>>()?;
166 let json = self.0.to_json_string(window.unwrap_or_default()).await?;
167 Ok(json)
168 }
169
170 #[apply(inherit_docs)]
171 #[inherit_doc = "view/to_json.md"]
172 #[wasm_bindgen]
173 pub async fn to_json(&self, window: Option<JsViewWindow>) -> ApiResult<Array> {
174 let json = self.to_json_string(window).await?;
175 Ok(js_sys::JSON::parse(&json)?.unchecked_into())
176 }
177
178 #[apply(inherit_docs)]
179 #[inherit_doc = "view/to_ndjson.md"]
180 #[wasm_bindgen]
181 pub async fn to_ndjson(&self, window: Option<JsViewWindow>) -> ApiResult<String> {
182 let window = window.into_serde_ext::<Option<ViewWindow>>()?;
183 let ndjson = self.0.to_ndjson(window.unwrap_or_default()).await?;
184 Ok(ndjson)
185 }
186
187 #[apply(inherit_docs)]
188 #[inherit_doc = "view/to_csv.md"]
189 #[wasm_bindgen]
190 pub async fn to_csv(&self, window: Option<JsViewWindow>) -> ApiResult<String> {
191 let window = window.into_serde_ext::<Option<ViewWindow>>()?;
192 Ok(self.0.to_csv(window.unwrap_or_default()).await?)
193 }
194
195 #[apply(inherit_docs)]
196 #[inherit_doc = "view/on_update.md"]
197 #[wasm_bindgen]
198 pub async fn on_update(
199 &self,
200 on_update_js: Function,
201 options: Option<JsOnUpdateOptions>,
202 ) -> ApiResult<u32> {
203 let poll_loop = LocalPollLoop::new(move |args| {
204 let js_obj = JsValue::from_serde_ext(&args)?;
205 on_update_js.call1(&JsValue::UNDEFINED, &js_obj)
206 });
207
208 let on_update = Box::new(move |msg| poll_loop.poll(msg));
209 let on_update_opts = options
210 .into_serde_ext::<Option<OnUpdateOptions>>()?
211 .unwrap_or_default();
212
213 let id = self.0.on_update(on_update, on_update_opts).await?;
214 Ok(id)
215 }
216
217 #[apply(inherit_docs)]
218 #[inherit_doc = "view/remove_update.md"]
219 #[wasm_bindgen]
220 pub async fn remove_update(&self, callback_id: u32) -> ApiResult<()> {
221 Ok(self.0.remove_update(callback_id).await?)
222 }
223
224 #[apply(inherit_docs)]
225 #[inherit_doc = "view/on_delete.md"]
226 #[wasm_bindgen]
227 pub async fn on_delete(&self, on_delete: Function) -> ApiResult<u32> {
228 let emit = LocalPollLoop::new(move |()| on_delete.call0(&JsValue::UNDEFINED));
229 let on_delete = Box::new(move || spawn_local(emit.poll(())));
230 Ok(self.0.on_delete(on_delete).await?)
231 }
232
233 #[apply(inherit_docs)]
234 #[inherit_doc = "view/num_columns.md"]
235 #[wasm_bindgen]
236 pub async fn num_columns(&self) -> ApiResult<u32> {
237 Ok(self.0.dimensions().await?.num_view_columns)
240 }
241
242 #[apply(inherit_docs)]
243 #[inherit_doc = "view/remove_delete.md"]
244 #[wasm_bindgen]
245 pub fn remove_delete(&self, callback_id: u32) -> ApiFuture<()> {
246 let client = self.0.clone();
247 ApiFuture::new(async move {
248 client.remove_delete(callback_id).await?;
249 Ok(())
250 })
251 }
252
253 #[apply(inherit_docs)]
254 #[inherit_doc = "view/collapse.md"]
255 #[wasm_bindgen]
256 pub async fn collapse(&self, row_index: u32) -> ApiResult<u32> {
257 Ok(self.0.collapse(row_index).await?)
258 }
259
260 #[apply(inherit_docs)]
261 #[inherit_doc = "view/expand.md"]
262 #[wasm_bindgen]
263 pub async fn expand(&self, row_index: u32) -> ApiResult<u32> {
264 Ok(self.0.expand(row_index).await?)
265 }
266
267 #[apply(inherit_docs)]
268 #[inherit_doc = "view/set_depth.md"]
269 #[wasm_bindgen]
270 pub async fn set_depth(&self, depth: u32) -> ApiResult<()> {
271 Ok(self.0.set_depth(depth).await?)
272 }
273}