@perspective-dev/client 4.1.0 → 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/utils/futures.rs +7 -1
- 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 +119 -292
|
@@ -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
|
|
|
@@ -13,13 +13,23 @@
|
|
|
13
13
|
export type * from "../../dist/wasm/perspective-js.d.ts";
|
|
14
14
|
import type * as psp from "../../dist/wasm/perspective-js.d.ts";
|
|
15
15
|
export type * from "./virtual_server.ts";
|
|
16
|
-
|
|
17
16
|
import * as psp_virtual from "./virtual_server.ts";
|
|
18
|
-
|
|
19
17
|
import * as wasm_module from "../../dist/wasm/perspective-js.js";
|
|
20
18
|
import * as api from "./wasm/browser.ts";
|
|
21
19
|
import { load_wasm_stage_0 } from "./wasm/decompress.ts";
|
|
22
20
|
|
|
21
|
+
export {
|
|
22
|
+
GenericSQLVirtualServerModel,
|
|
23
|
+
VirtualDataSlice,
|
|
24
|
+
VirtualServer,
|
|
25
|
+
} from "../../dist/wasm/perspective-js.js";
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
GenericSQLVirtualServerModel,
|
|
29
|
+
VirtualDataSlice,
|
|
30
|
+
VirtualServer,
|
|
31
|
+
} from "../../dist/wasm/perspective-js.js";
|
|
32
|
+
|
|
23
33
|
let GLOBAL_SERVER_WASM: Promise<ArrayBuffer | WebAssembly.Module>;
|
|
24
34
|
|
|
25
35
|
export async function createMessageHandler(
|
|
@@ -144,4 +154,7 @@ export default {
|
|
|
144
154
|
init_client,
|
|
145
155
|
init_server,
|
|
146
156
|
createMessageHandler,
|
|
157
|
+
GenericSQLVirtualServerModel,
|
|
158
|
+
VirtualDataSlice,
|
|
159
|
+
VirtualServer,
|
|
147
160
|
};
|
|
@@ -29,9 +29,20 @@ import * as engine from "./wasm/engine.ts";
|
|
|
29
29
|
import { compile_perspective } from "./wasm/emscripten_api.ts";
|
|
30
30
|
import * as psp_websocket from "./websocket.ts";
|
|
31
31
|
import * as api from "./wasm/browser.ts";
|
|
32
|
-
|
|
33
32
|
import * as virtual_server from "./virtual_server.ts";
|
|
34
33
|
|
|
34
|
+
export {
|
|
35
|
+
GenericSQLVirtualServerModel,
|
|
36
|
+
VirtualDataSlice,
|
|
37
|
+
VirtualServer,
|
|
38
|
+
} from "../../dist/wasm/perspective-js.js";
|
|
39
|
+
|
|
40
|
+
import {
|
|
41
|
+
GenericSQLVirtualServerModel,
|
|
42
|
+
VirtualDataSlice,
|
|
43
|
+
VirtualServer,
|
|
44
|
+
} from "../../dist/wasm/perspective-js.js";
|
|
45
|
+
|
|
35
46
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
36
47
|
|
|
37
48
|
const { resolve } = createRequire(import.meta.url);
|
|
@@ -337,6 +348,12 @@ export function createMessageHandler(
|
|
|
337
348
|
return virtual_server.createMessageHandler(perspective_client, handler);
|
|
338
349
|
}
|
|
339
350
|
|
|
351
|
+
/**
|
|
352
|
+
* The initialized WASM module. Use this when you need to pass the module
|
|
353
|
+
* to components that require it, such as `DuckDBHandler`.
|
|
354
|
+
*/
|
|
355
|
+
export { perspective_client as wasmModule };
|
|
356
|
+
|
|
340
357
|
export default {
|
|
341
358
|
table,
|
|
342
359
|
websocket,
|
|
@@ -347,4 +364,7 @@ export default {
|
|
|
347
364
|
on_error,
|
|
348
365
|
system_info,
|
|
349
366
|
WebSocketServer,
|
|
367
|
+
GenericSQLVirtualServerModel,
|
|
368
|
+
VirtualDataSlice,
|
|
369
|
+
VirtualServer,
|
|
350
370
|
};
|
package/src/ts/virtual_server.ts
CHANGED
|
@@ -55,8 +55,9 @@ export interface VirtualServerHandler {
|
|
|
55
55
|
viewGetData(
|
|
56
56
|
viewId: string,
|
|
57
57
|
config: ViewConfig,
|
|
58
|
+
schema: Record<string, ColumnType>,
|
|
58
59
|
viewport: ViewWindow,
|
|
59
|
-
dataSlice: perspective.
|
|
60
|
+
dataSlice: perspective.VirtualDataSlice,
|
|
60
61
|
): void | Promise<void>;
|
|
61
62
|
viewSchema?(
|
|
62
63
|
viewId: string,
|
|
@@ -78,11 +79,11 @@ export function createMessageHandler(
|
|
|
78
79
|
mod: typeof perspective,
|
|
79
80
|
handler: VirtualServerHandler,
|
|
80
81
|
) {
|
|
81
|
-
let virtualServer: perspective.
|
|
82
|
+
let virtualServer: perspective.VirtualServer;
|
|
82
83
|
async function postMessage(port: MessagePort, msg: MessageEvent) {
|
|
83
84
|
if (msg.data.cmd === "init") {
|
|
84
85
|
try {
|
|
85
|
-
virtualServer = new mod.
|
|
86
|
+
virtualServer = new mod.VirtualServer(handler);
|
|
86
87
|
if (msg.data.id !== undefined) {
|
|
87
88
|
port.postMessage({ id: msg.data.id });
|
|
88
89
|
} else {
|
|
@@ -113,14 +114,3 @@ export function createMessageHandler(
|
|
|
113
114
|
|
|
114
115
|
return channel.port2;
|
|
115
116
|
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Re-export the WASM VirtualServer and VirtualDataSlice classes with better names.
|
|
119
|
-
*
|
|
120
|
-
* VirtualServer: Handles Perspective protocol messages using your custom handler
|
|
121
|
-
* VirtualDataSlice: Used to fill data in viewGetData callbacks
|
|
122
|
-
*/
|
|
123
|
-
export {
|
|
124
|
-
JsVirtualServer as VirtualServer,
|
|
125
|
-
JsVirtualDataSlice as VirtualDataSlice,
|
|
126
|
-
} from "../../dist/wasm/perspective-js.js";
|