@@ -20,7 +20,7 @@ use js_sys::{Function, Uint8Array};
2020#[ cfg( doc) ]
2121use perspective_client:: SystemInfo ;
2222use perspective_client:: {
23- ClientError , ReconnectCallback , Session , TableData , TableInitOptions , asyncfn,
23+ ClientError , ReconnectCallback , Session , TableData , TableInitOptions , TableRef , asyncfn,
2424} ;
2525use wasm_bindgen:: prelude:: * ;
2626use wasm_bindgen_derive:: TryFromJsValue ;
@@ -35,6 +35,35 @@ extern "C" {
3535 #[ derive( Clone ) ]
3636 #[ wasm_bindgen( typescript_type = "TableInitOptions" ) ]
3737 pub type JsTableInitOptions ;
38+
39+ #[ derive( Clone ) ]
40+ #[ wasm_bindgen( typescript_type = "JoinOptions" ) ]
41+ pub type JsJoinOptions ;
42+ }
43+
44+ async fn js_to_table_ref ( val : & JsValue ) -> ApiResult < TableRef > {
45+ if let Some ( name) = val. as_string ( ) {
46+ Ok ( TableRef :: from ( name) )
47+ } else {
48+ let get_name = js_sys:: Reflect :: get ( val, & wasm_bindgen:: intern ( "get_name" ) . into ( ) )
49+ . map_err ( |_| apierror ! ( TableRefError ) ) ?
50+ . dyn_into :: < js_sys:: Function > ( )
51+ . map_err ( |_| apierror ! ( TableRefError ) ) ?;
52+
53+ let promise = get_name
54+ . call0 ( val)
55+ . map_err ( |_| apierror ! ( TableRefError ) ) ?
56+ . dyn_into :: < js_sys:: Promise > ( )
57+ . map_err ( |_| apierror ! ( TableRefError ) ) ?;
58+
59+ let name = wasm_bindgen_futures:: JsFuture :: from ( promise)
60+ . await
61+ . map_err ( |_| apierror ! ( TableRefError ) ) ?
62+ . as_string ( )
63+ . ok_or_else ( || apierror ! ( TableRefError ) ) ?;
64+
65+ Ok ( TableRef :: from ( name) )
66+ }
3867}
3968
4069#[ wasm_bindgen]
@@ -388,26 +417,38 @@ impl Client {
388417 ///
389418 /// # Arguments
390419 ///
391- /// - `left` - The left source table.
392- /// - `right` - The right source table.
420+ /// - `left` - The left source table (a [`Table`] instance or a table name
421+ /// string).
422+ /// - `right` - The right source table (a [`Table`] instance or a table name
423+ /// string).
393424 /// - `on` - The column name to join on. Must exist in both tables with the
394425 /// same type.
395- /// - `name` - Optional name for the resulting table.
426+ /// - `options` - Optional join configuration: `{ join_type?: "inner" |
427+ /// "left" | "outer", name?: string }`.
396428 ///
397429 /// # JavaScript Examples
398430 ///
399431 /// ```javascript
400- /// const joined = await client.join(orders_table, products_table, "Product ID");
432+ /// const joined = await client.join(orders_table, products_table, "Product ID", { join_type: "left" });
433+ /// const joined = await client.join("orders", "products", "Product ID", { join_type: "left" });
401434 /// ```
402435 #[ wasm_bindgen]
403436 pub async fn join (
404437 & self ,
405- left : & Table ,
406- right : & Table ,
438+ left : JsValue ,
439+ right : JsValue ,
407440 on : & str ,
408- name : Option < String > ,
441+ options : Option < JsJoinOptions > ,
409442 ) -> ApiResult < Table > {
410- Ok ( Table ( self . client . join ( & left. 0 , & right. 0 , on, name) . await ?) )
443+ let options = options
444+ . into_serde_ext :: < Option < perspective_client:: JoinOptions > > ( ) ?
445+ . unwrap_or_default ( ) ;
446+
447+ let left_ref = js_to_table_ref ( & left) . await ?;
448+ let right_ref = js_to_table_ref ( & right) . await ?;
449+ Ok ( Table (
450+ self . client . join ( left_ref, right_ref, on, options) . await ?,
451+ ) )
411452 }
412453
413454 /// Terminates this [`Client`], cleaning up any [`crate::View`] handles the
0 commit comments