diff --git a/demo/index.html b/demo/index.html index 814a7ce..6a57a0e 100644 --- a/demo/index.html +++ b/demo/index.html @@ -5,6 +5,7 @@ SQLite Wasm Demo +

SQLite Wasm Demo

@@ -12,5 +13,7 @@

Main thread

Worker

+

Built-in SQLite Client

+
diff --git a/demo/sqlite-client.js b/demo/sqlite-client.js new file mode 100644 index 0000000..5130ff7 --- /dev/null +++ b/demo/sqlite-client.js @@ -0,0 +1,28 @@ +import SqliteClient from '/src/sqlite.client.mjs'; + +const sqliteClient = new SqliteClient('/db.sqlite3', '/src/sqlite.worker.mjs'); + +await sqliteClient.init(); + +await sqliteClient.executeSql('CREATE TABLE IF NOT EXISTS t(a,b)'); + +for (let i = 20; i <= 25; ++i) { + await sqliteClient.executeSql('INSERT INTO t(a,b) VALUES (?,?)', [i, i * 2]); +} + +const rows = await sqliteClient.executeSql( + 'SELECT a FROM t ORDER BY a LIMIT 3', +); + +console.log(rows); + +document.getElementById('sqlite-client').innerHTML = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + rows.map((row) => '').concat(); +'' + '
a
' + row[0] + '
'; diff --git a/package-lock.json b/package-lock.json index 9369f53..6720503 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "@sqlite.org/sqlite-wasm", "version": "3.42.0-build1", "license": "Apache-2.0", + "dependencies": { + "comlink": "^4.4.1" + }, "bin": { "sqlite-wasm": "bin/index.js" }, @@ -249,6 +252,11 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/comlink": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.1.tgz", + "integrity": "sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q==" + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", diff --git a/package.json b/package.json index 937c6a0..eb54ea8 100644 --- a/package.json +++ b/package.json @@ -58,5 +58,8 @@ "prettier": "^2.8.8", "publint": "^0.1.12", "shx": "^0.3.4" + }, + "dependencies": { + "comlink": "^4.4.1" } } diff --git a/src/sqlite-client.mjs b/src/sqlite-client.mjs new file mode 100644 index 0000000..a30ad13 --- /dev/null +++ b/src/sqlite-client.mjs @@ -0,0 +1,70 @@ +const log = (...args) => console.log(...args); +const error = (...args) => console.error(...args); + +export default class SqliteClient { + sqliteWorker; + + dbFile = ''; + sqliteWorkerPath = ''; + + constructor(dbFile, sqliteWorkerPath) { + if (typeof dbFile !== 'string') { + return error( + "The 'dbFile' parameter passed to the SqliteClient constructor must be of type 'string'. Instead, you passed: '" + + typeof dbFile + + "'", + ); + } + + if (typeof sqliteWorkerPath !== 'string') { + return error( + "The 'sqliteWorkerPath' parameter passed to the SqliteClient constructor must be of type 'string'. Instead, you passed: '" + + typeof sqliteWorkerPath + + "'", + ); + } + + this.dbFile = dbFile; + this.sqliteWorkerPath = sqliteWorkerPath; + } + + async init() { + const SqliteWorker = Comlink.wrap( + new Worker(this.sqliteWorkerPath, { + type: 'module', + }), + ); + + this.sqliteWorker = await new SqliteWorker(); + + await this.sqliteWorker.init(this.dbFile); + } + + async executeSql(sqlStatement, bindParameters = []) { + if (typeof sqlStatement !== 'string') { + return error( + "The 'sqlStatement' parameter passed to the 'executeSql' method of the SqliteClient must be of type 'string'. Instead, you passed: '" + + typeof sqlStatement + + "'", + ); + } + + if (!Array.isArray(bindParameters)) { + return error( + "The 'bindParameters' parameter passed to the 'executeSql' method of the SqliteClient must be of type 'array'. Instead, you passed: '" + + typeof bindParameters + + "'", + ); + } + + return new Promise(async (resolve) => { + await this.sqliteWorker.executeSql( + sqlStatement, + bindParameters, + Comlink.proxy((rows) => { + return resolve(rows); + }), + ); + }); + } +} diff --git a/src/sqlite-worker.mjs b/src/sqlite-worker.mjs new file mode 100644 index 0000000..62150a2 --- /dev/null +++ b/src/sqlite-worker.mjs @@ -0,0 +1,38 @@ +import * as Comlink from 'https://unpkg.com/comlink/dist/esm/comlink.mjs'; +import { default as sqlite3InitModule } from '../index.mjs'; + +const log = (...args) => console.log(...args); +const error = (...args) => console.error(...args); + +class SqliteWorker { + db; + init(dbFile) { + return new Promise((resolve) => { + sqlite3InitModule({ + print: log, + printErr: error, + }).then((sqlite3) => { + try { + this.db = new sqlite3.oo1.OpfsDb(dbFile); + } catch (err) { + error(err.name, err.message); + } + + return resolve(); + }); + }); + } + + executeSql(sqlStatement, bindParameters, callback) { + return callback( + this.db.exec({ + sql: sqlStatement, + bind: bindParameters, + returnValue: 'resultRows', + rowMode: 'array', + }), + ); + } +} + +Comlink.expose(SqliteWorker);