aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api/sqlite3-worker1-promiser.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/wasm/api/sqlite3-worker1-promiser.js')
-rw-r--r--ext/wasm/api/sqlite3-worker1-promiser.js263
1 files changed, 0 insertions, 263 deletions
diff --git a/ext/wasm/api/sqlite3-worker1-promiser.js b/ext/wasm/api/sqlite3-worker1-promiser.js
deleted file mode 100644
index 1689d3480..000000000
--- a/ext/wasm/api/sqlite3-worker1-promiser.js
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- 2022-08-24
-
- The author disclaims copyright to this source code. In place of a
- legal notice, here is a blessing:
-
- * May you do good and not evil.
- * May you find forgiveness for yourself and forgive others.
- * May you share freely, never taking more than you give.
-
- ***********************************************************************
-
- This file implements a Promise-based proxy for the sqlite3 Worker
- API #1. It is intended to be included either from the main thread or
- a Worker, but only if (A) the environment supports nested Workers
- and (B) it's _not_ a Worker which loads the sqlite3 WASM/JS
- module. This file's features will load that module and provide a
- slightly simpler client-side interface than the slightly-lower-level
- Worker API does.
-
- This script necessarily exposes one global symbol, but clients may
- freely `delete` that symbol after calling it.
-*/
-'use strict';
-/**
- Configures an sqlite3 Worker API #1 Worker such that it can be
- manipulated via a Promise-based interface and returns a factory
- function which returns Promises for communicating with the worker.
- This proxy has an _almost_ identical interface to the normal
- worker API, with any exceptions documented below.
-
- It requires a configuration object with the following properties:
-
- - `worker` (required): a Worker instance which loads
- `sqlite3-worker1.js` or a functional equivalent. Note that the
- promiser factory replaces the worker.onmessage property. This
- config option may alternately be a function, in which case this
- function re-assigns this property with the result of calling that
- function, enabling delayed instantiation of a Worker.
-
- - `onready` (optional, but...): this callback is called with no
- arguments when the worker fires its initial
- 'sqlite3-api'/'worker1-ready' message, which it does when
- sqlite3.initWorker1API() completes its initialization. This is
- the simplest way to tell the worker to kick off work at the
- earliest opportunity.
-
- - `onunhandled` (optional): a callback which gets passed the
- message event object for any worker.onmessage() events which
- are not handled by this proxy. Ideally that "should" never
- happen, as this proxy aims to handle all known message types.
-
- - `generateMessageId` (optional): a function which, when passed an
- about-to-be-posted message object, generates a _unique_ message ID
- for the message, which this API then assigns as the messageId
- property of the message. It _must_ generate unique IDs on each call
- so that dispatching can work. If not defined, a default generator
- is used (which should be sufficient for most or all cases).
-
- - `debug` (optional): a console.debug()-style function for logging
- information about messages.
-
- This function returns a stateful factory function with the
- following interfaces:
-
- - Promise function(messageType, messageArgs)
- - Promise function({message object})
-
- The first form expects the "type" and "args" values for a Worker
- message. The second expects an object in the form {type:...,
- args:...} plus any other properties the client cares to set. This
- function will always set the `messageId` property on the object,
- even if it's already set, and will set the `dbId` property to the
- current database ID if it is _not_ set in the message object.
-
- The function throws on error.
-
- The function installs a temporary message listener, posts a
- message to the configured Worker, and handles the message's
- response via the temporary message listener. The then() callback
- of the returned Promise is passed the `message.data` property from
- the resulting message, i.e. the payload from the worker, stripped
- of the lower-level event state which the onmessage() handler
- receives.
-
- Example usage:
-
- ```
- const config = {...};
- const sq3Promiser = sqlite3Worker1Promiser(config);
- sq3Promiser('open', {filename:"/foo.db"}).then(function(msg){
- console.log("open response",msg); // => {type:'open', result: {filename:'/foo.db'}, ...}
- });
- sq3Promiser({type:'close'}).then((msg)=>{
- console.log("close response",msg); // => {type:'close', result: {filename:'/foo.db'}, ...}
- });
- ```
-
- Differences from Worker API #1:
-
- - exec's {callback: STRING} option does not work via this
- interface (it triggers an exception), but {callback: function}
- does and works exactly like the STRING form does in the Worker:
- the callback is called one time for each row of the result set,
- passed the same worker message format as the worker API emits:
-
- {type:typeString,
- row:VALUE,
- rowNumber:1-based-#,
- columnNames: array}
-
- Where `typeString` is an internally-synthesized message type string
- used temporarily for worker message dispatching. It can be ignored
- by all client code except that which tests this API. The `row`
- property contains the row result in the form implied by the
- `rowMode` option (defaulting to `'array'`). The `rowNumber` is a
- 1-based integer value incremented by 1 on each call into th
- callback.
-
- At the end of the result set, the same event is fired with
- (row=undefined, rowNumber=null) to indicate that
- the end of the result set has been reached. Note that the rows
- arrive via worker-posted messages, with all the implications
- of that.
-*/
-self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){
- // Inspired by: https://stackoverflow.com/a/52439530
- if(1===arguments.length && 'function'===typeof arguments[0]){
- const f = config;
- config = Object.assign(Object.create(null), callee.defaultConfig);
- config.onready = f;
- }else{
- config = Object.assign(Object.create(null), callee.defaultConfig, config);
- }
- const handlerMap = Object.create(null);
- const noop = function(){};
- const err = config.onerror
- || noop /* config.onerror is intentionally undocumented
- pending finding a less ambiguous name */;
- const debug = config.debug || noop;
- const idTypeMap = config.generateMessageId ? undefined : Object.create(null);
- const genMsgId = config.generateMessageId || function(msg){
- return msg.type+'#'+(idTypeMap[msg.type] = (idTypeMap[msg.type]||0) + 1);
- };
- const toss = (...args)=>{throw new Error(args.join(' '))};
- if(!config.worker) config.worker = callee.defaultConfig.worker;
- if('function'===typeof config.worker) config.worker = config.worker();
- let dbId;
- config.worker.onmessage = function(ev){
- ev = ev.data;
- debug('worker1.onmessage',ev);
- let msgHandler = handlerMap[ev.messageId];
- if(!msgHandler){
- if(ev && 'sqlite3-api'===ev.type && 'worker1-ready'===ev.result) {
- /*fired one time when the Worker1 API initializes*/
- if(config.onready) config.onready();
- return;
- }
- msgHandler = handlerMap[ev.type] /* check for exec per-row callback */;
- if(msgHandler && msgHandler.onrow){
- msgHandler.onrow(ev);
- return;
- }
- if(config.onunhandled) config.onunhandled(arguments[0]);
- else err("sqlite3Worker1Promiser() unhandled worker message:",ev);
- return;
- }
- delete handlerMap[ev.messageId];
- switch(ev.type){
- case 'error':
- msgHandler.reject(ev);
- return;
- case 'open':
- if(!dbId) dbId = ev.dbId;
- break;
- case 'close':
- if(ev.dbId===dbId) dbId = undefined;
- break;
- default:
- break;
- }
- try {msgHandler.resolve(ev)}
- catch(e){msgHandler.reject(e)}
- }/*worker.onmessage()*/;
- return function(/*(msgType, msgArgs) || (msgEnvelope)*/){
- let msg;
- if(1===arguments.length){
- msg = arguments[0];
- }else if(2===arguments.length){
- msg = {
- type: arguments[0],
- args: arguments[1]
- };
- }else{
- toss("Invalid arugments for sqlite3Worker1Promiser()-created factory.");
- }
- if(!msg.dbId) msg.dbId = dbId;
- msg.messageId = genMsgId(msg);
- msg.departureTime = performance.now();
- const proxy = Object.create(null);
- proxy.message = msg;
- let rowCallbackId /* message handler ID for exec on-row callback proxy */;
- if('exec'===msg.type && msg.args){
- if('function'===typeof msg.args.callback){
- rowCallbackId = msg.messageId+':row';
- proxy.onrow = msg.args.callback;
- msg.args.callback = rowCallbackId;
- handlerMap[rowCallbackId] = proxy;
- }else if('string' === typeof msg.args.callback){
- toss("exec callback may not be a string when using the Promise interface.");
- /**
- Design note: the reason for this limitation is that this
- API takes over worker.onmessage() and the client has no way
- of adding their own message-type handlers to it. Per-row
- callbacks are implemented as short-lived message.type
- mappings for worker.onmessage().
-
- We "could" work around this by providing a new
- config.fallbackMessageHandler (or some such) which contains
- a map of event type names to callbacks. Seems like overkill
- for now, seeing as the client can pass callback functions
- to this interface (whereas the string-form "callback" is
- needed for the over-the-Worker interface).
- */
- }
- }
- //debug("requestWork", msg);
- let p = new Promise(function(resolve, reject){
- proxy.resolve = resolve;
- proxy.reject = reject;
- handlerMap[msg.messageId] = proxy;
- debug("Posting",msg.type,"message to Worker dbId="+(dbId||'default')+':',msg);
- config.worker.postMessage(msg);
- });
- if(rowCallbackId) p = p.finally(()=>delete handlerMap[rowCallbackId]);
- return p;
- };
-}/*sqlite3Worker1Promiser()*/;
-self.sqlite3Worker1Promiser.defaultConfig = {
- worker: function(){
-//#if target=es6-bundler-friendly
- return new Worker("sqlite3-worker1.js");
-//#else
- let theJs = "sqlite3-worker1.js";
- if(this.currentScript){
- const src = this.currentScript.src.split('/');
- src.pop();
- theJs = src.join('/')+'/' + theJs;
- //console.warn("promiser currentScript, theJs =",this.currentScript,theJs);
- }else{
- //console.warn("promiser self.location =",self.location);
- const urlParams = new URL(self.location.href).searchParams;
- if(urlParams.has('sqlite3.dir')){
- theJs = urlParams.get('sqlite3.dir') + '/' + theJs;
- }
- }
- return new Worker(theJs + self.location.search);
-//#endif
- }.bind({
- currentScript: self?.document?.currentScript
- }),
- onerror: (...args)=>console.error('worker1 promiser error',...args)
-};