@uwdata/mosaic-core
Version:
Scalable and extensible linked data views.
115 lines • 3.73 kB
JavaScript
import { decodeIPC } from '../util/decode-ipc.js';
/**
* Connect to a DuckDB server over a WebSocket interface.
* @param options Connector options.
* @param options.uri The URI for the DuckDB REST server.
* @param options.ipc Arrow IPC extraction options.
* @returns A connector instance.
*/
export function socketConnector(options) {
return new SocketConnector(options);
}
/**
* DuckDB socket connector.
*/
export class SocketConnector {
_uri;
_queue;
_connected;
_request;
_ws;
_events;
/**
* @param options Connector options.
* @param options.uri The URI for the DuckDB REST server.
* @param options.ipc Arrow IPC extraction options.
*/
constructor({ uri = 'ws://localhost:3000/', ipc = undefined, } = {}) {
this._uri = uri;
this._queue = [];
this._connected = false;
this._request = null;
this._ws = null;
// eslint-disable-next-line @typescript-eslint/no-this-alias
const c = this;
this._events = {
open() {
c._connected = true;
c.next();
},
close() {
c._connected = false;
c._request = null;
c._ws = null;
while (c._queue.length) {
c._queue.shift().reject('Socket closed');
}
},
error(event) {
if (c._request) {
const { reject } = c._request;
c._request = null;
c.next();
reject(event);
}
else {
console.error('WebSocket error: ', event);
}
},
message(msg) {
const { data } = msg;
if (c._request) {
const { query, resolve, reject } = c._request;
// clear state, start next request
c._request = null;
c.next();
// process result
if (typeof data === 'string') {
const json = JSON.parse(data);
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
json.error ? reject(json.error) : resolve(json);
}
else if (query.type === 'exec') {
resolve();
}
else if (query.type === 'arrow') {
resolve(decodeIPC(data, ipc));
}
else {
throw new Error(`Unexpected socket data: ${data}`);
}
}
else {
console.log('WebSocket message: ', data);
}
}
};
}
get connected() {
return this._connected;
}
init() {
this._ws = new WebSocket(this._uri);
this._ws.binaryType = 'arraybuffer';
for (const type in this._events) {
this._ws.addEventListener(type, this._events[type]);
}
}
enqueue(query, resolve, reject) {
if (this._ws == null)
this.init();
this._queue.push({ query, resolve, reject });
if (this._connected && !this._request)
this.next();
}
next() {
if (this._queue.length) {
this._request = this._queue.shift();
this._ws.send(JSON.stringify(this._request.query));
}
}
query(query) {
return new Promise((resolve, reject) => this.enqueue(query, resolve, reject));
}
}
//# sourceMappingURL=socket.js.map