@perspective-dev/client 4.1.1 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdn/perspective.js +2 -2
- package/dist/cdn/perspective.js.map +4 -4
- package/dist/esm/perspective.browser.d.ts +4 -0
- package/dist/esm/perspective.inline.js +2 -2
- package/dist/esm/perspective.inline.js.map +4 -4
- package/dist/esm/perspective.js +2 -2
- package/dist/esm/perspective.js.map +4 -4
- package/dist/esm/perspective.node.d.ts +9 -0
- package/dist/esm/perspective.node.js +1629 -1291
- package/dist/esm/perspective.node.js.map +3 -3
- package/dist/esm/virtual_server.d.ts +1 -8
- package/dist/esm/virtual_servers/clickhouse.js +2 -0
- package/dist/esm/virtual_servers/clickhouse.js.map +7 -0
- package/dist/esm/virtual_servers/duckdb.d.ts +21 -7
- package/dist/esm/virtual_servers/duckdb.js +1 -11
- package/dist/esm/virtual_servers/duckdb.js.map +3 -3
- package/dist/wasm/perspective-js.d.ts +723 -647
- package/dist/wasm/perspective-js.js +2115 -1841
- package/dist/wasm/perspective-js.wasm +0 -0
- package/dist/wasm/perspective-js.wasm.d.ts +61 -49
- package/package.json +2 -1
- package/src/rust/generic_sql_model.rs +189 -0
- package/src/rust/lib.rs +2 -2
- package/src/rust/utils/console_logger.rs +4 -4
- package/src/rust/virtual_server.rs +50 -46
- package/src/ts/perspective.browser.ts +15 -2
- package/src/ts/perspective.node.ts +21 -1
- package/src/ts/virtual_server.ts +4 -14
- package/src/ts/virtual_servers/clickhouse.ts +362 -0
- package/src/ts/virtual_servers/duckdb.ts +114 -292
|
Binary file
|
|
@@ -1,85 +1,97 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
|
-
export const __wbg_proxysession_free: (a: number, b: number) => void;
|
|
5
|
-
export const proxysession_handle_request: (a: number, b: number) => number;
|
|
6
|
-
export const proxysession_close: (a: number) => number;
|
|
7
4
|
export const __wbg_client_free: (a: number, b: number) => void;
|
|
5
|
+
export const __wbg_genericsqlvirtualservermodel_free: (a: number, b: number) => void;
|
|
6
|
+
export const __wbg_proxysession_free: (a: number, b: number) => void;
|
|
7
|
+
export const __wbg_table_free: (a: number, b: number) => void;
|
|
8
|
+
export const __wbg_view_free: (a: number, b: number) => void;
|
|
9
|
+
export const __wbg_virtualdataslice_free: (a: number, b: number) => void;
|
|
10
|
+
export const __wbg_virtualserver_free: (a: number, b: number) => void;
|
|
8
11
|
export const client___getClassname: (a: number, b: number) => void;
|
|
12
|
+
export const client_get_hosted_table_names: (a: number) => number;
|
|
13
|
+
export const client_handle_error: (a: number, b: number, c: number, d: number) => number;
|
|
14
|
+
export const client_handle_response: (a: number, b: number) => number;
|
|
9
15
|
export const client_new: (a: number, b: number, c: number) => void;
|
|
10
16
|
export const client_new_proxy_session: (a: number, b: number) => number;
|
|
11
|
-
export const client_handle_response: (a: number, b: number) => number;
|
|
12
|
-
export const client_handle_error: (a: number, b: number, c: number, d: number) => number;
|
|
13
17
|
export const client_on_error: (a: number, b: number) => number;
|
|
14
|
-
export const client_table: (a: number, b: number, c: number) => number;
|
|
15
|
-
export const client_terminate: (a: number, b: number) => void;
|
|
16
|
-
export const client_open_table: (a: number, b: number, c: number) => number;
|
|
17
|
-
export const client_get_hosted_table_names: (a: number) => number;
|
|
18
18
|
export const client_on_hosted_tables_update: (a: number, b: number) => number;
|
|
19
|
+
export const client_open_table: (a: number, b: number, c: number) => number;
|
|
19
20
|
export const client_remove_hosted_tables_update: (a: number, b: number) => number;
|
|
20
21
|
export const client_system_info: (a: number) => number;
|
|
22
|
+
export const client_table: (a: number, b: number, c: number) => number;
|
|
23
|
+
export const client_terminate: (a: number, b: number) => void;
|
|
24
|
+
export const genericsqlvirtualservermodel_getHostedTables: (a: number, b: number) => void;
|
|
25
|
+
export const genericsqlvirtualservermodel_new: (a: number, b: number) => void;
|
|
26
|
+
export const genericsqlvirtualservermodel_tableMakeView: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
27
|
+
export const genericsqlvirtualservermodel_tableSchema: (a: number, b: number, c: number, d: number) => void;
|
|
28
|
+
export const genericsqlvirtualservermodel_tableSize: (a: number, b: number, c: number, d: number) => void;
|
|
29
|
+
export const genericsqlvirtualservermodel_tableValidateExpression: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
30
|
+
export const genericsqlvirtualservermodel_viewColumnSize: (a: number, b: number, c: number, d: number) => void;
|
|
31
|
+
export const genericsqlvirtualservermodel_viewDelete: (a: number, b: number, c: number, d: number) => void;
|
|
32
|
+
export const genericsqlvirtualservermodel_viewGetData: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
33
|
+
export const genericsqlvirtualservermodel_viewSchema: (a: number, b: number, c: number, d: number) => void;
|
|
34
|
+
export const genericsqlvirtualservermodel_viewSize: (a: number, b: number, c: number, d: number) => void;
|
|
35
|
+
export const init: () => void;
|
|
36
|
+
export const proxysession_close: (a: number) => number;
|
|
37
|
+
export const proxysession_handle_request: (a: number, b: number) => number;
|
|
38
|
+
export const proxysession_new: (a: number, b: number) => number;
|
|
21
39
|
export const table___getClassname: (a: number, b: number) => void;
|
|
22
|
-
export const __wbg_table_free: (a: number, b: number) => void;
|
|
23
|
-
export const table_get_index: (a: number) => number;
|
|
24
|
-
export const table_get_client: (a: number) => number;
|
|
25
|
-
export const table_get_name: (a: number) => number;
|
|
26
|
-
export const table_get_limit: (a: number) => number;
|
|
27
40
|
export const table_clear: (a: number) => number;
|
|
28
|
-
export const table_delete: (a: number, b: number) => number;
|
|
29
|
-
export const table_size: (a: number) => number;
|
|
30
|
-
export const table_schema: (a: number) => number;
|
|
31
41
|
export const table_columns: (a: number) => number;
|
|
42
|
+
export const table_delete: (a: number, b: number) => number;
|
|
43
|
+
export const table_get_client: (a: number) => number;
|
|
44
|
+
export const table_get_index: (a: number) => number;
|
|
45
|
+
export const table_get_limit: (a: number) => number;
|
|
46
|
+
export const table_get_name: (a: number) => number;
|
|
32
47
|
export const table_make_port: (a: number) => number;
|
|
33
48
|
export const table_on_delete: (a: number, b: number) => number;
|
|
34
|
-
export const table_remove_delete: (a: number, b: number) => number;
|
|
35
49
|
export const table_remove: (a: number, b: number, c: number) => number;
|
|
50
|
+
export const table_remove_delete: (a: number, b: number) => number;
|
|
36
51
|
export const table_replace: (a: number, b: number, c: number) => number;
|
|
52
|
+
export const table_schema: (a: number) => number;
|
|
53
|
+
export const table_size: (a: number) => number;
|
|
37
54
|
export const table_update: (a: number, b: number, c: number) => number;
|
|
38
|
-
export const table_view: (a: number, b: number) => number;
|
|
39
55
|
export const table_validate_expressions: (a: number, b: number) => number;
|
|
40
|
-
export const
|
|
56
|
+
export const table_view: (a: number, b: number) => number;
|
|
41
57
|
export const view___get_model: (a: number) => number;
|
|
58
|
+
export const view_collapse: (a: number, b: number) => number;
|
|
42
59
|
export const view_column_paths: (a: number, b: number) => number;
|
|
43
60
|
export const view_delete: (a: number) => number;
|
|
44
61
|
export const view_dimensions: (a: number) => number;
|
|
62
|
+
export const view_expand: (a: number, b: number) => number;
|
|
45
63
|
export const view_expression_schema: (a: number) => number;
|
|
46
64
|
export const view_get_config: (a: number) => number;
|
|
47
65
|
export const view_get_min_max: (a: number, b: number, c: number) => number;
|
|
66
|
+
export const view_num_columns: (a: number) => number;
|
|
48
67
|
export const view_num_rows: (a: number) => number;
|
|
68
|
+
export const view_on_delete: (a: number, b: number) => number;
|
|
69
|
+
export const view_on_update: (a: number, b: number, c: number) => number;
|
|
70
|
+
export const view_remove_delete: (a: number, b: number) => number;
|
|
71
|
+
export const view_remove_update: (a: number, b: number) => number;
|
|
49
72
|
export const view_schema: (a: number) => number;
|
|
73
|
+
export const view_set_depth: (a: number, b: number) => number;
|
|
50
74
|
export const view_to_arrow: (a: number, b: number) => number;
|
|
51
|
-
export const view_to_columns_string: (a: number, b: number) => number;
|
|
52
75
|
export const view_to_columns: (a: number, b: number) => number;
|
|
53
|
-
export const
|
|
76
|
+
export const view_to_columns_string: (a: number, b: number) => number;
|
|
77
|
+
export const view_to_csv: (a: number, b: number) => number;
|
|
54
78
|
export const view_to_json: (a: number, b: number) => number;
|
|
79
|
+
export const view_to_json_string: (a: number, b: number) => number;
|
|
55
80
|
export const view_to_ndjson: (a: number, b: number) => number;
|
|
56
|
-
export const
|
|
57
|
-
export const
|
|
58
|
-
export const
|
|
59
|
-
export const
|
|
60
|
-
export const
|
|
61
|
-
export const
|
|
62
|
-
export const
|
|
63
|
-
export const
|
|
64
|
-
export const
|
|
65
|
-
export const
|
|
66
|
-
export const
|
|
67
|
-
export const
|
|
68
|
-
export const
|
|
69
|
-
export const
|
|
70
|
-
export const jsvirtualdataslice_setFloatCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
71
|
-
export const jsvirtualdataslice_setBooleanCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
72
|
-
export const jsvirtualdataslice_setDatetimeCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
73
|
-
export const __wbg_jsvirtualserver_free: (a: number, b: number) => void;
|
|
74
|
-
export const jsvirtualserver_new: (a: number, b: number) => void;
|
|
75
|
-
export const jsvirtualserver_handleRequest: (a: number, b: number, c: number) => number;
|
|
76
|
-
export const init: () => void;
|
|
77
|
-
export const proxysession_new: (a: number, b: number) => number;
|
|
78
|
-
export const __wasm_bindgen_func_elem_553: (a: number, b: number) => number;
|
|
79
|
-
export const __wasm_bindgen_func_elem_123: (a: number, b: number) => void;
|
|
80
|
-
export const __wasm_bindgen_func_elem_3515: (a: number, b: number, c: number) => void;
|
|
81
|
-
export const __wasm_bindgen_func_elem_3500: (a: number, b: number) => void;
|
|
82
|
-
export const __wasm_bindgen_func_elem_5070: (a: number, b: number, c: number, d: number) => void;
|
|
81
|
+
export const virtualdataslice_new: (a: number) => number;
|
|
82
|
+
export const virtualdataslice_setBooleanCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
83
|
+
export const virtualdataslice_setCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
|
|
84
|
+
export const virtualdataslice_setDatetimeCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
85
|
+
export const virtualdataslice_setFloatCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
86
|
+
export const virtualdataslice_setIntegerCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
87
|
+
export const virtualdataslice_setStringCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
88
|
+
export const virtualserver_handleRequest: (a: number, b: number, c: number) => number;
|
|
89
|
+
export const virtualserver_new: (a: number, b: number) => void;
|
|
90
|
+
export const __wasm_bindgen_func_elem_1421: (a: number, b: number) => void;
|
|
91
|
+
export const __wasm_bindgen_func_elem_3793: (a: number, b: number) => void;
|
|
92
|
+
export const __wasm_bindgen_func_elem_5384: (a: number, b: number, c: number, d: number) => void;
|
|
93
|
+
export const __wasm_bindgen_func_elem_3795: (a: number, b: number, c: number) => void;
|
|
94
|
+
export const __wasm_bindgen_func_elem_1668: (a: number, b: number) => number;
|
|
83
95
|
export const __wbindgen_export: (a: number, b: number) => number;
|
|
84
96
|
export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
85
97
|
export const __wbindgen_export3: (a: number) => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@perspective-dev/client",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"@perspective-dev/esbuild-plugin": "",
|
|
49
49
|
"@perspective-dev/metadata": "",
|
|
50
50
|
"@perspective-dev/test": "",
|
|
51
|
+
"@clickhouse/client-web": "^1.12.0",
|
|
51
52
|
"@duckdb/duckdb-wasm": "^1.30.0",
|
|
52
53
|
"@playwright/experimental-ct-react": "=1.52.0",
|
|
53
54
|
"@playwright/test": "=1.52.0",
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
//! WASM bindings for the DuckDB SQL query builder.
|
|
14
|
+
|
|
15
|
+
use std::str::FromStr;
|
|
16
|
+
|
|
17
|
+
use indexmap::IndexMap;
|
|
18
|
+
use js_sys::Object;
|
|
19
|
+
use perspective_client::config::ViewConfig;
|
|
20
|
+
use perspective_client::proto::{ColumnType, ViewPort};
|
|
21
|
+
use perspective_client::virtual_server;
|
|
22
|
+
use wasm_bindgen::prelude::*;
|
|
23
|
+
|
|
24
|
+
use crate::utils::*;
|
|
25
|
+
|
|
26
|
+
/// JavaScript-facing DuckDB SQL query builder.
|
|
27
|
+
///
|
|
28
|
+
/// This struct wraps the Rust `DuckDBSqlBuilder` and exposes it to JavaScript
|
|
29
|
+
/// via wasm_bindgen.
|
|
30
|
+
#[wasm_bindgen]
|
|
31
|
+
pub struct GenericSQLVirtualServerModel {
|
|
32
|
+
inner: virtual_server::GenericSQLVirtualServerModel,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[wasm_bindgen]
|
|
36
|
+
extern "C" {
|
|
37
|
+
pub type JsGenericSQLVirtualServerModelArgs;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#[wasm_bindgen]
|
|
41
|
+
impl GenericSQLVirtualServerModel {
|
|
42
|
+
/// Creates a new `JsDuckDBSqlBuilder` instance.
|
|
43
|
+
#[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
|
+
/// Returns the SQL query to list all hosted tables.
|
|
55
|
+
#[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
|
+
/// Returns the SQL query to describe a table's schema.
|
|
63
|
+
#[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
|
+
/// Returns the SQL query to get the row count of a table.
|
|
71
|
+
#[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
|
+
/// Returns the SQL query to get the column count of a view.
|
|
79
|
+
#[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
|
+
/// Returns the SQL query to validate an expression against a table.
|
|
87
|
+
#[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
|
+
/// Returns the SQL query to delete a view.
|
|
99
|
+
#[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
|
+
/// Returns the SQL query to create a view from a table with the given
|
|
107
|
+
/// configuration.
|
|
108
|
+
#[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
|
+
/// Returns the SQL query to fetch data from a view with the given viewport.
|
|
124
|
+
#[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
|
+
/// Returns the SQL query to describe a view's schema.
|
|
146
|
+
#[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
|
+
/// Returns the SQL query to get the row count of a view.
|
|
154
|
+
#[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
|
+
|
|
162
|
+
impl 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
|
+
}
|
package/src/rust/lib.rs
CHANGED
|
@@ -26,20 +26,20 @@
|
|
|
26
26
|
extern crate alloc;
|
|
27
27
|
|
|
28
28
|
mod client;
|
|
29
|
+
mod generic_sql_model;
|
|
29
30
|
mod table;
|
|
30
31
|
mod table_data;
|
|
31
32
|
pub mod utils;
|
|
32
33
|
mod view;
|
|
33
|
-
#[cfg(target_arch = "wasm32")]
|
|
34
34
|
mod virtual_server;
|
|
35
35
|
|
|
36
36
|
#[cfg(feature = "export-init")]
|
|
37
37
|
use wasm_bindgen::prelude::*;
|
|
38
38
|
|
|
39
39
|
pub use crate::client::Client;
|
|
40
|
+
pub use crate::generic_sql_model::*;
|
|
40
41
|
pub use crate::table::*;
|
|
41
42
|
pub use crate::table_data::*;
|
|
42
|
-
#[cfg(target_arch = "wasm32")]
|
|
43
43
|
pub use crate::virtual_server::*;
|
|
44
44
|
|
|
45
45
|
#[cfg(feature = "export-init")]
|
|
@@ -170,10 +170,10 @@ impl<S: Subscriber + for<'a> LookupSpan<'a>> Layer<S> for WasmLogger {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
fn on_record(&self, id: &tracing::Id, values: &tracing::span::Record<'_>, ctx: Context<'_, S>) {
|
|
173
|
-
if let Some(span_ref) = ctx.span(id)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
173
|
+
if let Some(span_ref) = ctx.span(id)
|
|
174
|
+
&& let Some(debug_record) = span_ref.extensions_mut().get_mut::<LogLineBuffer>()
|
|
175
|
+
{
|
|
176
|
+
values.record(debug_record);
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
|
|
@@ -20,22 +20,17 @@ use std::sync::{Arc, Mutex};
|
|
|
20
20
|
use indexmap::IndexMap;
|
|
21
21
|
use js_sys::{Array, Date, Object, Reflect};
|
|
22
22
|
use perspective_client::proto::{ColumnType, HostedTable};
|
|
23
|
-
use perspective_client::virtual_server
|
|
24
|
-
|
|
25
|
-
};
|
|
23
|
+
use perspective_client::virtual_server;
|
|
24
|
+
use perspective_client::virtual_server::{Features, ResultExt, VirtualServerHandler};
|
|
26
25
|
use serde::Serialize;
|
|
27
26
|
use wasm_bindgen::prelude::*;
|
|
28
27
|
use wasm_bindgen_futures::JsFuture;
|
|
29
28
|
|
|
29
|
+
use crate::JsViewConfig;
|
|
30
30
|
use crate::utils::{ApiError, ApiFuture, *};
|
|
31
31
|
|
|
32
|
-
// Conditional type alias matching the trait definition
|
|
33
|
-
#[cfg(target_arch = "wasm32")]
|
|
34
32
|
type HandlerFuture<T> = Pin<Box<dyn Future<Output = T>>>;
|
|
35
33
|
|
|
36
|
-
#[cfg(not(target_arch = "wasm32"))]
|
|
37
|
-
type HandlerFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
|
|
38
|
-
|
|
39
34
|
#[derive(Debug)]
|
|
40
35
|
pub struct JsError(JsValue);
|
|
41
36
|
|
|
@@ -65,16 +60,8 @@ impl From<serde_wasm_bindgen::Error> for JsError {
|
|
|
65
60
|
}
|
|
66
61
|
}
|
|
67
62
|
|
|
68
|
-
// SAFETY: In WASM, we're always single-threaded, so JsError can safely be Send
|
|
69
|
-
// + Sync
|
|
70
|
-
unsafe impl Send for JsError {}
|
|
71
|
-
unsafe impl Sync for JsError {}
|
|
72
|
-
|
|
73
63
|
pub struct JsServerHandler(Object);
|
|
74
64
|
|
|
75
|
-
unsafe impl Send for JsServerHandler {}
|
|
76
|
-
unsafe impl Sync for JsServerHandler {}
|
|
77
|
-
|
|
78
65
|
impl JsServerHandler {
|
|
79
66
|
fn call_method_js(&self, method: &str, args: &Array) -> Result<JsValue, JsError> {
|
|
80
67
|
let func = Reflect::get(&self.0, &JsValue::from_str(method))?;
|
|
@@ -90,7 +77,7 @@ impl JsServerHandler {
|
|
|
90
77
|
// Check if result is a Promise
|
|
91
78
|
if result.is_instance_of::<js_sys::Promise>() {
|
|
92
79
|
let promise = js_sys::Promise::from(result);
|
|
93
|
-
JsFuture::from(promise).await.map_err(
|
|
80
|
+
JsFuture::from(promise).await.map_err(JsError)
|
|
94
81
|
} else {
|
|
95
82
|
Ok(result)
|
|
96
83
|
}
|
|
@@ -293,11 +280,7 @@ impl VirtualServerHandler for JsServerHandler {
|
|
|
293
280
|
|
|
294
281
|
let handler = self.0.clone();
|
|
295
282
|
let view_id = view_id.to_string();
|
|
296
|
-
let config_value =
|
|
297
|
-
serde_wasm_bindgen::to_value(config).ok()
|
|
298
|
-
} else {
|
|
299
|
-
None
|
|
300
|
-
};
|
|
283
|
+
let config_value = JsValue::from_serde_ext(config).ok();
|
|
301
284
|
|
|
302
285
|
Box::pin(async move {
|
|
303
286
|
let this = JsServerHandler(handler);
|
|
@@ -446,7 +429,6 @@ impl VirtualServerHandler for JsServerHandler {
|
|
|
446
429
|
|
|
447
430
|
let handler = self.0.clone();
|
|
448
431
|
let table_id = table_id.to_string();
|
|
449
|
-
|
|
450
432
|
use perspective_client::proto::make_table_data::Data;
|
|
451
433
|
let data_value = match &data.data {
|
|
452
434
|
Some(Data::FromCsv(csv)) => JsValue::from_str(csv),
|
|
@@ -474,22 +456,25 @@ impl VirtualServerHandler for JsServerHandler {
|
|
|
474
456
|
&self,
|
|
475
457
|
view_id: &str,
|
|
476
458
|
config: &perspective_client::config::ViewConfig,
|
|
459
|
+
schema: &IndexMap<String, ColumnType>,
|
|
477
460
|
viewport: &perspective_client::proto::ViewPort,
|
|
478
|
-
) -> HandlerFuture<Result<VirtualDataSlice, Self::Error>> {
|
|
461
|
+
) -> HandlerFuture<Result<virtual_server::VirtualDataSlice, Self::Error>> {
|
|
479
462
|
let handler = self.0.clone();
|
|
480
463
|
let view_id = view_id.to_string();
|
|
481
464
|
let window: JsViewPort = viewport.clone().into();
|
|
482
465
|
let config_value = serde_wasm_bindgen::to_value(config).unwrap();
|
|
483
466
|
let window_value = serde_wasm_bindgen::to_value(&window).unwrap();
|
|
467
|
+
let schema_value = JsValue::from_serde_ext(&schema).unwrap();
|
|
484
468
|
|
|
485
469
|
Box::pin(async move {
|
|
486
470
|
let this = JsServerHandler(handler);
|
|
487
|
-
let data =
|
|
471
|
+
let data = VirtualDataSlice::new(config_value.clone().unchecked_into());
|
|
488
472
|
|
|
489
473
|
{
|
|
490
474
|
let args = Array::new();
|
|
491
475
|
args.push(&JsValue::from_str(&view_id));
|
|
492
476
|
args.push(&config_value);
|
|
477
|
+
args.push(&schema_value);
|
|
493
478
|
args.push(&window_value);
|
|
494
479
|
args.push(&JsValue::from(data.clone()));
|
|
495
480
|
this.call_method_js_async("viewGetData", &args).await?;
|
|
@@ -497,8 +482,8 @@ impl VirtualServerHandler for JsServerHandler {
|
|
|
497
482
|
|
|
498
483
|
// Lock the mutex and take ownership of the inner data
|
|
499
484
|
// We can't unwrap the Arc because the JsValue might still hold a reference
|
|
500
|
-
let
|
|
501
|
-
let slice = std::mem::take(&mut *arc.lock().unwrap());
|
|
485
|
+
let VirtualDataSlice(_obj, arc) = data;
|
|
486
|
+
let slice = std::mem::take(&mut *arc.lock().unwrap()).unwrap();
|
|
502
487
|
Ok(slice)
|
|
503
488
|
})
|
|
504
489
|
}
|
|
@@ -530,24 +515,20 @@ impl From<perspective_client::proto::ViewPort> for JsViewPort {
|
|
|
530
515
|
}
|
|
531
516
|
}
|
|
532
517
|
|
|
533
|
-
#[wasm_bindgen]
|
|
518
|
+
#[wasm_bindgen(js_name = "VirtualDataSlice")]
|
|
534
519
|
#[derive(Clone)]
|
|
535
|
-
pub struct
|
|
536
|
-
|
|
537
|
-
impl Default for JsVirtualDataSlice {
|
|
538
|
-
fn default() -> Self {
|
|
539
|
-
JsVirtualDataSlice(
|
|
540
|
-
Object::new(),
|
|
541
|
-
Arc::new(Mutex::new(VirtualDataSlice::default())),
|
|
542
|
-
)
|
|
543
|
-
}
|
|
544
|
-
}
|
|
520
|
+
pub struct VirtualDataSlice(Object, Arc<Mutex<Option<virtual_server::VirtualDataSlice>>>);
|
|
545
521
|
|
|
546
522
|
#[wasm_bindgen]
|
|
547
|
-
impl
|
|
523
|
+
impl VirtualDataSlice {
|
|
548
524
|
#[wasm_bindgen(constructor)]
|
|
549
|
-
pub fn new() -> Self {
|
|
550
|
-
|
|
525
|
+
pub fn new(config: JsViewConfig) -> Self {
|
|
526
|
+
VirtualDataSlice(
|
|
527
|
+
Object::new(),
|
|
528
|
+
Arc::new(Mutex::new(Some(virtual_server::VirtualDataSlice::new(
|
|
529
|
+
config.into_serde_ext().unwrap(),
|
|
530
|
+
)))),
|
|
531
|
+
)
|
|
551
532
|
}
|
|
552
533
|
|
|
553
534
|
#[wasm_bindgen(js_name = "setCol")]
|
|
@@ -582,12 +563,16 @@ impl JsVirtualDataSlice {
|
|
|
582
563
|
self.1
|
|
583
564
|
.lock()
|
|
584
565
|
.unwrap()
|
|
566
|
+
.as_mut()
|
|
567
|
+
.unwrap()
|
|
585
568
|
.set_col(name, group_by_index, index as usize, None as Option<String>)
|
|
586
569
|
.unwrap();
|
|
587
570
|
} else if let Some(s) = val.as_string() {
|
|
588
571
|
self.1
|
|
589
572
|
.lock()
|
|
590
573
|
.unwrap()
|
|
574
|
+
.as_mut()
|
|
575
|
+
.unwrap()
|
|
591
576
|
.set_col(name, group_by_index, index as usize, Some(s))
|
|
592
577
|
.unwrap();
|
|
593
578
|
} else {
|
|
@@ -608,12 +593,16 @@ impl JsVirtualDataSlice {
|
|
|
608
593
|
self.1
|
|
609
594
|
.lock()
|
|
610
595
|
.unwrap()
|
|
596
|
+
.as_mut()
|
|
597
|
+
.unwrap()
|
|
611
598
|
.set_col(name, group_by_index, index as usize, None as Option<i32>)
|
|
612
599
|
.unwrap();
|
|
613
600
|
} else if let Some(n) = val.as_f64() {
|
|
614
601
|
self.1
|
|
615
602
|
.lock()
|
|
616
603
|
.unwrap()
|
|
604
|
+
.as_mut()
|
|
605
|
+
.unwrap()
|
|
617
606
|
.set_col(name, group_by_index, index as usize, Some(n as i32))
|
|
618
607
|
.unwrap();
|
|
619
608
|
} else {
|
|
@@ -634,12 +623,16 @@ impl JsVirtualDataSlice {
|
|
|
634
623
|
self.1
|
|
635
624
|
.lock()
|
|
636
625
|
.unwrap()
|
|
626
|
+
.as_mut()
|
|
627
|
+
.unwrap()
|
|
637
628
|
.set_col(name, group_by_index, index as usize, None as Option<f64>)
|
|
638
629
|
.unwrap();
|
|
639
630
|
} else if let Some(n) = val.as_f64() {
|
|
640
631
|
self.1
|
|
641
632
|
.lock()
|
|
642
633
|
.unwrap()
|
|
634
|
+
.as_mut()
|
|
635
|
+
.unwrap()
|
|
643
636
|
.set_col(name, group_by_index, index as usize, Some(n))
|
|
644
637
|
.unwrap();
|
|
645
638
|
} else {
|
|
@@ -660,12 +653,16 @@ impl JsVirtualDataSlice {
|
|
|
660
653
|
self.1
|
|
661
654
|
.lock()
|
|
662
655
|
.unwrap()
|
|
656
|
+
.as_mut()
|
|
657
|
+
.unwrap()
|
|
663
658
|
.set_col(name, group_by_index, index as usize, None as Option<bool>)
|
|
664
659
|
.unwrap();
|
|
665
660
|
} else if let Some(b) = val.as_bool() {
|
|
666
661
|
self.1
|
|
667
662
|
.lock()
|
|
668
663
|
.unwrap()
|
|
664
|
+
.as_mut()
|
|
665
|
+
.unwrap()
|
|
669
666
|
.set_col(name, group_by_index, index as usize, Some(b))
|
|
670
667
|
.unwrap();
|
|
671
668
|
} else {
|
|
@@ -686,6 +683,8 @@ impl JsVirtualDataSlice {
|
|
|
686
683
|
self.1
|
|
687
684
|
.lock()
|
|
688
685
|
.unwrap()
|
|
686
|
+
.as_mut()
|
|
687
|
+
.unwrap()
|
|
689
688
|
.set_col(name, group_by_index, index as usize, None as Option<i64>)
|
|
690
689
|
.unwrap();
|
|
691
690
|
} else if let Some(date) = val.dyn_ref::<Date>() {
|
|
@@ -693,30 +692,35 @@ impl JsVirtualDataSlice {
|
|
|
693
692
|
self.1
|
|
694
693
|
.lock()
|
|
695
694
|
.unwrap()
|
|
695
|
+
.as_mut()
|
|
696
|
+
.unwrap()
|
|
696
697
|
.set_col(name, group_by_index, index as usize, Some(timestamp))
|
|
697
698
|
.unwrap();
|
|
698
699
|
} else if let Some(n) = val.as_f64() {
|
|
699
700
|
self.1
|
|
700
701
|
.lock()
|
|
701
702
|
.unwrap()
|
|
703
|
+
.as_mut()
|
|
704
|
+
.unwrap()
|
|
702
705
|
.set_col(name, group_by_index, index as usize, Some(n as i64))
|
|
703
706
|
.unwrap();
|
|
704
707
|
} else {
|
|
705
708
|
tracing::error!("Unhandled datetime value");
|
|
706
709
|
}
|
|
710
|
+
|
|
707
711
|
Ok(())
|
|
708
712
|
}
|
|
709
713
|
}
|
|
710
714
|
|
|
711
715
|
#[wasm_bindgen]
|
|
712
|
-
pub struct
|
|
716
|
+
pub struct VirtualServer(Rc<UnsafeCell<virtual_server::VirtualServer<JsServerHandler>>>);
|
|
713
717
|
|
|
714
718
|
#[wasm_bindgen]
|
|
715
|
-
impl
|
|
719
|
+
impl VirtualServer {
|
|
716
720
|
#[wasm_bindgen(constructor)]
|
|
717
|
-
pub fn new(handler: Object) -> Result<
|
|
718
|
-
Ok(
|
|
719
|
-
VirtualServer::new(JsServerHandler(handler)),
|
|
721
|
+
pub fn new(handler: Object) -> Result<VirtualServer, JsValue> {
|
|
722
|
+
Ok(VirtualServer(Rc::new(UnsafeCell::new(
|
|
723
|
+
virtual_server::VirtualServer::new(JsServerHandler(handler)),
|
|
720
724
|
))))
|
|
721
725
|
}
|
|
722
726
|
|