Switch search runtime to vendored sqlite3 WASM
This commit is contained in:
parent
fc85729374
commit
04c8ce7005
6 changed files with 13059 additions and 10 deletions
|
@ -1,3 +1,7 @@
|
|||
# mp3-com-meta-browser
|
||||
|
||||
A self contained static website for browsing the collection of salvaged mp3.com files.
|
||||
|
||||
## Runtime Notes
|
||||
|
||||
- Uses the official `sqlite3` WASM build (vendored under `vendor/sqlite3/`) so that FTS5 is available client-side.
|
||||
|
|
|
@ -365,8 +365,8 @@
|
|||
<!-- Third-party libs loaded from CDNs (no trackers). Pinned versions. -->
|
||||
<!-- fflate: tiny ZIP library used to unzip the downloaded DB archive client-side. -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/fflate@0.8.2/umd/index.js" crossorigin="anonymous"></script>
|
||||
<!-- sql.js (WASM SQLite) loader; WASM resolved via locateFile in script.js. -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.2/sql-wasm.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<!-- SQLite WASM build (oo1 API) shipped locally to ensure FTS5 support. -->
|
||||
<script src="./vendor/sqlite3/sqlite3.js"></script>
|
||||
|
||||
<!-- App logic -->
|
||||
<script src="./script.js"></script>
|
||||
|
|
109
script.js
109
script.js
|
@ -2,13 +2,13 @@
|
|||
Application bootstrap for the static, client-side metadata browser.
|
||||
- Downloads a zipped SQLite DB (db.zip) with progress and unzips it in-memory
|
||||
- Caches the uncompressed DB bytes in IndexedDB for reuse on next load
|
||||
- Loads sql.js (WASM) and opens the database from the cached bytes
|
||||
- Loads the official sqlite3 WASM build (oo1 API) and opens the database from the cached bytes
|
||||
- Swaps interchangeable UX elements (views) in a viewport, with fade transitions
|
||||
|
||||
Assumptions:
|
||||
- A ZIP archive is hosted at `/db.zip` containing a single `.sqlite` file.
|
||||
- We use `fflate` (UMD) from a CDN to unzip after download (keeps implementation minimal).
|
||||
- We use `sql.js` from a CDN; the WASM is located via `locateFile` (see initSql()).
|
||||
- We ship the sqlite3 WASM runtime locally to guarantee FTS5 support.
|
||||
- We store raw DB bytes in IndexedDB (localStorage is too small for large DBs).
|
||||
*/
|
||||
|
||||
|
@ -297,15 +297,109 @@
|
|||
return dbBytes;
|
||||
}
|
||||
|
||||
// --- SQL.js init ---
|
||||
// --- SQLite WASM init ---
|
||||
async function initSql() {
|
||||
if (typeof initSqlJs !== 'function') throw new Error('sql.js not loaded');
|
||||
if (typeof sqlite3InitModule !== 'function') throw new Error('sqlite3.js not loaded');
|
||||
loader.setStep('Initializing SQLite…');
|
||||
loader.setDetail('Loading WASM');
|
||||
const SQL = await initSqlJs({
|
||||
locateFile: (file) => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.2/${file}`,
|
||||
const sqlite3 = await sqlite3InitModule({
|
||||
locateFile: (file) => `./vendor/sqlite3/${file}`,
|
||||
});
|
||||
return SQL;
|
||||
return createSqlCompat(sqlite3);
|
||||
}
|
||||
|
||||
function createSqlCompat(sqlite3) {
|
||||
const { capi, wasm } = sqlite3;
|
||||
const SQLITE_DESERIALIZE_FREEONCLOSE = 0x01;
|
||||
const SQLITE_DESERIALIZE_READONLY = 0x04;
|
||||
|
||||
function loadDatabaseBytes(dbHandle, bytes) {
|
||||
if (!bytes || !bytes.byteLength) return;
|
||||
const byteLength = bytes.byteLength;
|
||||
const pData = wasm.alloc(byteLength);
|
||||
try {
|
||||
wasm.heap8u().set(bytes, pData);
|
||||
const [pSchema] = wasm.allocCString('main', true);
|
||||
try {
|
||||
const rc = capi.sqlite3_deserialize(
|
||||
dbHandle.pointer,
|
||||
pSchema,
|
||||
pData,
|
||||
byteLength,
|
||||
byteLength,
|
||||
SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_READONLY
|
||||
);
|
||||
if (rc !== capi.SQLITE_OK) {
|
||||
throw new sqlite3.SQLite3Error(`sqlite3_deserialize failed with rc=${rc}`);
|
||||
}
|
||||
} finally {
|
||||
wasm.dealloc(pSchema);
|
||||
}
|
||||
} catch (err) {
|
||||
wasm.dealloc(pData);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
class Statement {
|
||||
constructor(stmt) {
|
||||
this._stmt = stmt;
|
||||
this._columnNames = null;
|
||||
}
|
||||
bind(values) {
|
||||
this._stmt.bind(values);
|
||||
return true;
|
||||
}
|
||||
step() {
|
||||
return !!this._stmt.step();
|
||||
}
|
||||
getAsObject() {
|
||||
if (!this._columnNames) this._columnNames = this._stmt.getColumnNames([]);
|
||||
const row = Object.create(null);
|
||||
const count = this._columnNames.length;
|
||||
for (let i = 0; i < count; i += 1) {
|
||||
row[this._columnNames[i]] = this._stmt.get(i);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
free() {
|
||||
this._stmt.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
class Database {
|
||||
constructor(bytes) {
|
||||
this._db = new sqlite3.oo1.DB();
|
||||
if (bytes) loadDatabaseBytes(this._db, bytes);
|
||||
}
|
||||
prepare(sql) {
|
||||
return new Statement(this._db.prepare(sql));
|
||||
}
|
||||
exec(sql) {
|
||||
return this._db.exec(sql);
|
||||
}
|
||||
close() {
|
||||
this._db.close();
|
||||
}
|
||||
get pointer() {
|
||||
return this._db.pointer;
|
||||
}
|
||||
}
|
||||
|
||||
function ensureFts5Available(dbHandle) {
|
||||
let stmt;
|
||||
try {
|
||||
stmt = dbHandle.prepare('CREATE VIRTUAL TABLE temp.__fts5_check USING fts5(content TEXT)');
|
||||
stmt.step();
|
||||
} catch (err) {
|
||||
throw new Error('SQLite build missing FTS5 support; search requires an fts5-enabled wasm');
|
||||
} finally {
|
||||
try { if (stmt) stmt.free(); } catch (_) {}
|
||||
try { dbHandle.exec('DROP TABLE IF EXISTS temp.__fts5_check'); } catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
return { Database, ensureFts5Available };
|
||||
}
|
||||
|
||||
// --- Templates & Views ---
|
||||
|
@ -2380,6 +2474,7 @@
|
|||
const SQL = await initSql();
|
||||
loader.setDetail('Opening database');
|
||||
const db = new SQL.Database(dbBytes);
|
||||
SQL.ensureFts5Available(db);
|
||||
|
||||
activeDb = db;
|
||||
window.__db = db;
|
||||
|
|
46
vendor/sqlite3/README.txt
vendored
Normal file
46
vendor/sqlite3/README.txt
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
This is the README for the sqlite3 WASM/JS distribution.
|
||||
|
||||
Main project page: https://sqlite.org
|
||||
|
||||
Documentation: https://sqlite.org/wasm
|
||||
|
||||
This archive contains the following deliverables for the WASM/JS
|
||||
build:
|
||||
|
||||
- jswasm/sqlite3.js is the canonical "vanilla JS" version.
|
||||
|
||||
- jswasm/sqlite3.mjs is the same but in ES6 module form
|
||||
|
||||
- jswasm/*-bundler-friendly.js and .mjs are variants which are
|
||||
intended to be compatible with "bundler" tools commonly seen in
|
||||
node.js-based projects. Projects using such tools should use those
|
||||
variants, where available, instead of files without the
|
||||
"-bundler-friendly" suffix. Some files do not have separate
|
||||
variants.
|
||||
|
||||
- jswasm/sqlite3.wasm is the binary WASM file imported by all of the
|
||||
above-listed JS files.
|
||||
|
||||
- The jswasm directory additionally contains a number of supplemental
|
||||
JS files which cannot be bundled directly with the main JS files
|
||||
but are necessary for certain usages.
|
||||
|
||||
- The top-level directory contains various demonstration and test
|
||||
applications for sqlite3.js and sqlite3.mjs.
|
||||
sqlite3-bundler-friendly.mjs requires client-side build tools to make
|
||||
use of and is not demonstrated here.
|
||||
|
||||
Browsers will not serve WASM files from file:// URLs, so the test and
|
||||
demonstration apps require a web server and that server must include
|
||||
the following headers in its response when serving the files:
|
||||
|
||||
Cross-Origin-Opener-Policy: same-origin
|
||||
Cross-Origin-Embedder-Policy: require-corp
|
||||
|
||||
The core library will function without those headers but certain
|
||||
features, most notably OPFS storage, will not be available.
|
||||
|
||||
One simple way to get the demo apps up and running on Unix-style
|
||||
systems is to install althttpd (https://sqlite.org/althttpd) and run:
|
||||
|
||||
althttpd --enable-sab --page index.html
|
12904
vendor/sqlite3/sqlite3.js
vendored
Normal file
12904
vendor/sqlite3/sqlite3.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
vendor/sqlite3/sqlite3.wasm
vendored
Normal file
BIN
vendor/sqlite3/sqlite3.wasm
vendored
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue