From 48b57a2e91b42d7e872f09dabd9e63221da023e4 Mon Sep 17 00:00:00 2001 From: Jeffrey Heer Date: Tue, 30 Jan 2024 15:31:51 -0800 Subject: [PATCH] Update WASM connector. (#279) * feat!: Make WASM constructor sync, add existing db/con options. * test: Update dev tests to use updated wasm connector. * docs: Update docs with updated wasm connector. --- dev/index.html | 6 +++--- dev/setup.js | 2 +- docs/.vitepress/theme/Example.vue | 9 ++++----- docs/api/core/connectors.md | 6 ++++-- docs/get-started/index.md | 7 +++---- packages/core/src/connectors/wasm.js | 24 +++++++++++++++++++----- 6 files changed, 34 insertions(+), 20 deletions(-) diff --git a/dev/index.html b/dev/index.html index 66ddf3ff..c339612b 100644 --- a/dev/index.html +++ b/dev/index.html @@ -45,9 +45,9 @@ Connector: @@ -113,7 +113,7 @@ const code = await specToModule(spec, { ...options, imports }); const blob = new Blob([code], { type: 'text/javascript' }); const url = URL.createObjectURL(blob); - return (await import(url /* @vite-ignore */)).default; + return (await import(/* @vite-ignore */ url)).default; } diff --git a/dev/setup.js b/dev/setup.js index 137f464c..66e81efa 100644 --- a/dev/setup.js +++ b/dev/setup.js @@ -16,7 +16,7 @@ export async function setDatabaseConnector(type, options) { connector = restConnector(options); break; case 'wasm': - connector = (wasm || (wasm = await wasmConnector(options))); + connector = wasm || (wasm = wasmConnector(options)); break; default: throw new Error(`Unrecognized connector type: ${type}`); diff --git a/docs/.vitepress/theme/Example.vue b/docs/.vitepress/theme/Example.vue index b58e78d0..f9f9b3aa 100644 --- a/docs/.vitepress/theme/Example.vue +++ b/docs/.vitepress/theme/Example.vue @@ -7,10 +7,9 @@ let ready; function init() { if (!ready) { - ready = wasmConnector().then(wasm => { - coordinator().logger(null); - coordinator().databaseConnector(wasm); - }); + coordinator().logger(null); + coordinator().databaseConnector(wasmConnector()); + ready = true; } return ready; } @@ -18,7 +17,7 @@ function init() { export default { async mounted() { try { - await init(); + init(); const spec = yaml.parse(await fetch(withBase(this.spec)).then(r => r.text())); const view = await parseSpec(spec, { baseURL: location.origin + import.meta.env.BASE_URL }); this.$refs.view.replaceChildren(view); diff --git a/docs/api/core/connectors.md b/docs/api/core/connectors.md index b5b69443..10017553 100644 --- a/docs/api/core/connectors.md +++ b/docs/api/core/connectors.md @@ -28,8 +28,10 @@ Create a new HTTP rest connector to a DuckDB [data server](../duckdb/data-server `wasmConnector(options)` Create a new DuckDB-WASM connector with the given _options_. -This method will instantiate a new DuckDB instance in-browser using Web Assembly. +This method will instantiate a new DuckDB instance in-browser using Web Assembly. If no existing DuckDB-WASM instance provided as an option, a new instance is created lazily upon first access. The supported options are: -- _log_: A Boolean flag (default `false`) that indicates if DuckDB-WASM logs should be written to the browser console. +- _duckdb_: An existing DuckDB-WASM instance to query. If unspecified, a new instance is created. +- _connection_: An existing connection to a DuckDB-WASM instance to use. If unspecified, a new connection is created. +- _log_: A Boolean flag (default `false`) that indicates if DuckDB-WASM logs should be written to the browser console. This option is ignored when an existing _duckdb_ instance option is provided. diff --git a/docs/get-started/index.md b/docs/get-started/index.md index 14eabdbb..1cd596ae 100644 --- a/docs/get-started/index.md +++ b/docs/get-started/index.md @@ -15,8 +15,7 @@ import * as vg from "@uwdata/vgplot"; // configure the coordinator to use DuckDB-WASM // creates a new database instance running in-browser -const wasm = await vg.wasmConnector(); -vg.coordinator().databaseConnector(wasm); +vg.coordinator().databaseConnector(vg.wasmConnector()); // load data into the database // executes a query generated by the loadCSV helper @@ -48,8 +47,8 @@ For local installation you should have `npm` and `node` version 18 or higher. ### Run Examples -After installation, you can run examples locally from a DuckDB server. +After installation, you can run examples locally, using either DuckDB-WASM or a DuckDB server. -- Run `npm run server` to launch a local DuckDB server. - Run `npm run dev` to start a dev web server with examples. The `socket` and `rest` connectors will only work if a local DuckDB server is running. +- Run `npm run server` to launch a local DuckDB server. diff --git a/packages/core/src/connectors/wasm.js b/packages/core/src/connectors/wasm.js index 853c20ca..52071e6c 100644 --- a/packages/core/src/connectors/wasm.js +++ b/packages/core/src/connectors/wasm.js @@ -1,14 +1,28 @@ import * as duckdb from '@duckdb/duckdb-wasm'; -export async function wasmConnector(options) { - const db = await initDatabase(options); - const con = await db.connect(); +export function wasmConnector(options = {}) { + const { duckdb, connection, ...opts } = options; + let db = duckdb; + let con = connection; + + async function getDuckDB() { + if (!db) db = await initDatabase(opts); + return db; + } + + async function getConnection() { + if (!con) { + con = await (await getDuckDB()).connect(); + } + return con; + } return { - db, - con, + getDuckDB, + getConnection, query: async query => { const { type, sql } = query; + const con = await getConnection(); const result = await con.query(sql); return type === 'exec' ? undefined : type === 'arrow' ? result