@uwdata/mosaic-core 0.4.0 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uwdata/mosaic-core",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Scalable and extensible linked data views.",
5
5
  "keywords": [
6
6
  "mosaic",
@@ -28,9 +28,9 @@
28
28
  "prepublishOnly": "npm run test && npm run lint && npm run build"
29
29
  },
30
30
  "dependencies": {
31
- "@duckdb/duckdb-wasm": "^1.28.0",
32
- "@uwdata/mosaic-sql": "^0.4.0",
33
- "apache-arrow": "^13.0.0"
31
+ "@duckdb/duckdb-wasm": "^1.28.1-dev106.0",
32
+ "@uwdata/mosaic-sql": "^0.5.0",
33
+ "apache-arrow": "^14.0.1"
34
34
  },
35
- "gitHead": "4114465543a21b25d6d14647db7d95af875d2519"
35
+ "gitHead": "92886dddfb126c1439924c5a0189e4639c3519a7"
36
36
  }
package/src/Catalog.js CHANGED
@@ -6,6 +6,7 @@ const object = () => Object.create(null);
6
6
 
7
7
  export class Catalog {
8
8
  constructor(coordinator) {
9
+ /** @type {import('@uwdata/mosaic-core').Coordinator} */
9
10
  this.mc = coordinator;
10
11
  this.clear();
11
12
  }
@@ -23,9 +23,13 @@ export function coordinator(instance) {
23
23
 
24
24
  export class Coordinator {
25
25
  constructor(db = socketConnector(), options = {}) {
26
+ const {
27
+ logger = console,
28
+ manager = QueryManager()
29
+ } = options;
26
30
  this.catalog = new Catalog(this);
27
- this.manager = options.manager || QueryManager();
28
- this.logger(options.logger || console);
31
+ this.manager = manager;
32
+ this.logger(logger);
29
33
  this.configure(options);
30
34
  this.databaseConnector(db);
31
35
  this.clear();
@@ -68,6 +72,7 @@ export class Coordinator {
68
72
  }
69
73
 
70
74
  exec(query, { priority = Priority.Normal } = {}) {
75
+ query = Array.isArray(query) ? query.join(';\n') : query;
71
76
  return this.manager.request({ type: 'exec', query }, priority);
72
77
  }
73
78
 
@@ -123,6 +128,7 @@ export class Coordinator {
123
128
  throw new Error('Client already connected.');
124
129
  }
125
130
  clients.add(client); // mark as connected
131
+ client.coordinator = this;
126
132
 
127
133
  // retrieve field statistics
128
134
  const fields = client.fields();
@@ -154,5 +160,6 @@ export class Coordinator {
154
160
  if (!clients.has(client)) return;
155
161
  clients.delete(client);
156
162
  filterGroups.get(client.filterBy)?.remove(client);
163
+ client.coordinator = null;
157
164
  }
158
165
  }
@@ -1,4 +1,3 @@
1
- import { coordinator } from './Coordinator.js';
2
1
  import { throttle } from './util/throttle.js';
3
2
 
4
3
  /**
@@ -14,6 +13,21 @@ export class MosaicClient {
14
13
  constructor(filterSelection) {
15
14
  this._filterBy = filterSelection;
16
15
  this._requestUpdate = throttle(() => this.requestQuery(), true);
16
+ this._coordinator = null;
17
+ }
18
+
19
+ /**
20
+ * Return this client's connected coordinator.
21
+ */
22
+ get coordinator() {
23
+ return this._coordinator;
24
+ }
25
+
26
+ /**
27
+ * Set this client's connected coordinator.
28
+ */
29
+ set coordinator(coordinator) {
30
+ this._coordinator = coordinator;
17
31
  }
18
32
 
19
33
  /**
@@ -63,7 +77,7 @@ export class MosaicClient {
63
77
 
64
78
  /**
65
79
  * Called by the coordinator to return a query result.
66
- *
80
+ *
67
81
  * @param {*} data the query result
68
82
  * @returns {this}
69
83
  */
@@ -86,7 +100,7 @@ export class MosaicClient {
86
100
  */
87
101
  requestQuery(query) {
88
102
  const q = query || this.query(this.filterBy?.predicate(this));
89
- return coordinator().requestQuery(this, q);
103
+ return this._coordinator.requestQuery(this, q);
90
104
  }
91
105
 
92
106
  /**
@@ -1,6 +1,13 @@
1
1
  import { Query, Ref } from '@uwdata/mosaic-sql';
2
2
  import { queryResult } from './util/query-result.js';
3
3
 
4
+ function wait(callback) {
5
+ const method = typeof requestAnimationFrame !== 'undefined'
6
+ ? requestAnimationFrame
7
+ : typeof setImmediate !== 'undefined' ? setImmediate : setTimeout;
8
+ return method(callback);
9
+ }
10
+
4
11
  /**
5
12
  * Create a consolidator to combine structurally compatible queries.
6
13
  * @param {*} enqueue Query manager enqueue method
@@ -30,7 +37,7 @@ export function consolidator(enqueue, cache, record) {
30
37
  if (entry.request.type === 'arrow') {
31
38
  // wait one frame, gather an ordered list of queries
32
39
  // only Apache Arrow is supported, so we can project efficiently
33
- id = id || requestAnimationFrame(() => run());
40
+ id = id || wait(() => run());
34
41
  pending.push({ entry, priority, index: pending.length });
35
42
  } else {
36
43
  enqueue(entry, priority);
@@ -1,14 +1,57 @@
1
1
  import * as duckdb from '@duckdb/duckdb-wasm';
2
2
 
3
- export async function wasmConnector(options) {
4
- const db = await initDatabase(options);
5
- const con = await db.connect();
3
+ export function wasmConnector(options = {}) {
4
+ const { duckdb, connection, ...opts } = options;
5
+ let db = duckdb;
6
+ let con = connection;
7
+ let loadPromise;
8
+
9
+ function load() {
10
+ if (!loadPromise) {
11
+ // use a loading promise to avoid race conditions
12
+ // synchronizes multiple callees on the same load
13
+ loadPromise = (db
14
+ ? Promise.resolve(db)
15
+ : initDatabase(opts).then(result => db = result))
16
+ .then(db => db.connect())
17
+ .then(result => con = result);
18
+ }
19
+ return loadPromise;
20
+ }
21
+
22
+ /**
23
+ * Get the backing DuckDB-WASM instance.
24
+ * Will lazily initialize DuckDB-WASM if not already loaded.
25
+ * @returns {duckdb.AsyncDuckDB} The DuckDB-WASM instance.
26
+ */
27
+ async function getDuckDB() {
28
+ if (!db) await load();
29
+ return db;
30
+ }
31
+
32
+ /**
33
+ * Get the backing DuckDB-WASM connection.
34
+ * Will lazily initialize DuckDB-WASM if not already loaded.
35
+ * @returns {duckdb.AsyncDuckDBConnection} The DuckDB-WASM connection.
36
+ */
37
+ async function getConnection() {
38
+ if (!con) await load();
39
+ return con;
40
+ }
6
41
 
7
42
  return {
8
- db,
9
- con,
43
+ getDuckDB,
44
+ getConnection,
45
+ /**
46
+ * Query the DuckDB-WASM instance.
47
+ * @param {object} query
48
+ * @param {string} [query.type] The query type: 'exec', 'arrow', or 'json'.
49
+ * @param {string} query.sql A SQL query string.
50
+ * @returns the query result
51
+ */
10
52
  query: async query => {
11
53
  const { type, sql } = query;
54
+ const con = await getConnection();
12
55
  const result = await con.query(sql);
13
56
  return type === 'exec' ? undefined
14
57
  : type === 'arrow' ? result