Skip to content

Commit 18f57d4

Browse files
feat: bundler-friendly fixes & bumped version for release (#136)
* chore: update SQLite Wasm binaries from master (e8220056842ea6f71822cbe227fc1ce973f4ad0d) (#17) Co-authored-by: jurerotar <28565137+jurerotar@users.noreply.github.com> * chore: bumped version * chore: update SQLite Wasm binaries from master (ca0b14a4906fc0e247818078f4526b90a5caa03c) (#18) Co-authored-by: jurerotar <28565137+jurerotar@users.noreply.github.com> * test: added test for bundler compatibility * chore: removed test comments * chore: expanded test suite to test blobs and sahpool pause & unpause functionality --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 557a42d commit 18f57d4

13 files changed

+223
-150
lines changed

package-lock.json

Lines changed: 2 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sqlite.org/sqlite-wasm",
3-
"version": "3.51.2-build2",
3+
"version": "3.51.2-build3",
44
"description": "SQLite Wasm conveniently wrapped as an ES Module.",
55
"type": "module",
66
"repository": {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { describe, test, expect } from 'vitest';
2+
import { execSync } from 'node:child_process';
3+
import path from 'node:path';
4+
import fs from 'node:fs';
5+
6+
describe('Vite bundler compatibility', () => {
7+
test('should rename sqlite3.wasm with a hash and update the import URL', () => {
8+
const testDir = path.resolve(__dirname, 'vite-repro');
9+
const distDir = path.resolve(testDir, 'dist');
10+
11+
// Clean up previous build
12+
if (fs.existsSync(distDir)) {
13+
fs.rmSync(distDir, { recursive: true, force: true });
14+
}
15+
16+
// Run vite build
17+
execSync('npx vite build --logLevel error', {
18+
cwd: testDir,
19+
stdio: 'inherit',
20+
});
21+
22+
// 1. Check if hashed WASM file exists in dist/assets
23+
const assetsDir = path.resolve(distDir, 'assets');
24+
const files = fs.readdirSync(assetsDir);
25+
const wasmFile = files.find(
26+
(f) => f.startsWith('sqlite3-') && f.endsWith('.wasm'),
27+
);
28+
29+
expect(wasmFile).toBeDefined();
30+
31+
// 2. Check if the JS bundle contains the hashed WASM filename
32+
const assetsDirJs = path.resolve(distDir, 'assets');
33+
const jsFiles = fs
34+
.readdirSync(assetsDirJs)
35+
.filter((f) => f.endsWith('.js'));
36+
const mainBundle = jsFiles.find((f) => f.startsWith('index-'));
37+
expect(mainBundle).toBeDefined();
38+
39+
const bundleContent = fs.readFileSync(
40+
path.resolve(assetsDirJs, mainBundle),
41+
'utf8',
42+
);
43+
44+
// It should contain something like: new URL("/assets/sqlite3-hash.wasm", import.meta.url)
45+
expect(bundleContent).toContain(wasmFile);
46+
47+
// Specifically check that it's part of a new URL call or at least correctly referenced
48+
const urlPattern = new RegExp(
49+
`new URL\\(".*${wasmFile}",\\s*import\\.meta\\.url\\)`,
50+
);
51+
expect(bundleContent).toMatch(urlPattern);
52+
});
53+
});

src/__tests__/sqlite3-node.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,30 @@ test('Node.js build sanity check', async () => {
135135
expect(
136136
typeof db.selectValue('SELECT sqlite_offset(id) FROM off_test'),
137137
).toBe('number');
138+
139+
// 13. Blobs
140+
const blobData = new Uint8Array([0x00, 0xff, 0xaa, 0x55]);
141+
db.exec({
142+
sql: 'CREATE TABLE blobs (data BLOB)',
143+
});
144+
db.exec({
145+
sql: 'INSERT INTO blobs (data) VALUES (?)',
146+
bind: [blobData],
147+
});
148+
const retrievedBlob = db.selectValue('SELECT data FROM blobs');
149+
expect(retrievedBlob).toBeInstanceOf(Uint8Array);
150+
expect(retrievedBlob).toEqual(blobData);
151+
152+
// 14. Error handling
153+
expect(() => {
154+
db.exec('INVALID SQL');
155+
}).toThrow();
156+
157+
db.exec('CREATE TABLE unique_test (id INTEGER PRIMARY KEY)');
158+
db.exec('INSERT INTO unique_test VALUES (1)');
159+
expect(() => {
160+
db.exec('INSERT INTO unique_test VALUES (1)');
161+
}).toThrow(/UNIQUE constraint failed/);
138162
} finally {
139163
// 11. Close the database
140164
db.close();

src/__tests__/sqlite3-oo1.browser.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,30 @@ test('Bundler-friendly OO1 API sanity check (browser)', async () => {
135135
expect(
136136
typeof db.selectValue('SELECT sqlite_offset(id) FROM off_test'),
137137
).toBe('number');
138+
139+
// 13. Blobs
140+
const blobData = new Uint8Array([0x00, 0xff, 0xaa, 0x55]);
141+
db.exec({
142+
sql: 'CREATE TABLE blobs (data BLOB)',
143+
});
144+
db.exec({
145+
sql: 'INSERT INTO blobs (data) VALUES (?)',
146+
bind: [blobData],
147+
});
148+
const retrievedBlob = db.selectValue('SELECT data FROM blobs');
149+
expect(retrievedBlob).toBeInstanceOf(Uint8Array);
150+
expect(retrievedBlob).toEqual(blobData);
151+
152+
// 14. Error handling
153+
expect(() => {
154+
db.exec('INVALID SQL');
155+
}).toThrow();
156+
157+
db.exec('CREATE TABLE unique_test (id INTEGER PRIMARY KEY)');
158+
db.exec('INSERT INTO unique_test VALUES (1)');
159+
expect(() => {
160+
db.exec('INSERT INTO unique_test VALUES (1)');
161+
}).toThrow(/UNIQUE constraint failed/);
138162
} finally {
139163
db.close();
140164
expect(db.isOpen()).toBe(false);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!doctype html>
2+
<html>
3+
<body>
4+
<script type="module" src="./main.js"></script>
5+
</body>
6+
</html>

src/__tests__/vite-repro/main.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import sqlite3InitModule from '../../../src/index.js';
2+
3+
await sqlite3InitModule();

src/__tests__/workers/sqlite3-sahpool.worker.js

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import sqlite3InitModule from '../../bin/sqlite3-bundler-friendly.mjs';
22

3-
self.onmessage = async (e) => {
3+
self.onmessage = async () => {
44
try {
55
const sqlite3 = await sqlite3InitModule();
66
const opfsSahPool = await sqlite3.installOpfsSAHPoolVfs();
7-
const db = new opfsSahPool.OpfsSAHPoolDb('/test-sahpool-worker.sqlite3');
7+
let db = new opfsSahPool.OpfsSAHPoolDb('/test-sahpool-worker.sqlite3');
88

99
try {
1010
// 1. Basic CRUD
@@ -29,6 +29,15 @@ self.onmessage = async (e) => {
2929
throw new Error('CRUD check failed');
3030
}
3131

32+
db.close();
33+
34+
// Reopen to check persistence
35+
db = new opfsSahPool.OpfsSAHPoolDb('/test-sahpool-worker.sqlite3');
36+
const count = db.selectValue('SELECT count(*) FROM test');
37+
if (count !== 2) {
38+
throw new Error('Persistence check failed');
39+
}
40+
3241
// 2. Joins
3342
db.exec(
3443
'CREATE TABLE orders (id INTEGER PRIMARY KEY, user_id INTEGER, product TEXT)',
@@ -42,30 +51,89 @@ self.onmessage = async (e) => {
4251
rowMode: 'object',
4352
callback: (row) => joinedRows.push(row),
4453
});
45-
if (joinedRows.length !== 2) throw new Error('Join check failed');
54+
if (joinedRows.length !== 2) {
55+
throw new Error('Join check failed');
56+
}
4657

4758
// 3. CTE
4859
const cteCount = db.selectValue(
4960
'WITH RECURSIVE cnt(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM cnt LIMIT 5) SELECT count(*) FROM cnt',
5061
);
51-
if (cteCount !== 5) throw new Error('CTE check failed');
62+
if (cteCount !== 5) {
63+
throw new Error('CTE check failed');
64+
}
5265

5366
// 4. FTS5
5467
db.exec('CREATE VIRTUAL TABLE docs USING fts5(content)');
5568
db.exec("INSERT INTO docs (content) VALUES ('sqlite is great')");
5669
const ftsResult = db.selectValue(
5770
"SELECT content FROM docs WHERE docs MATCH 'sqlite'",
5871
);
59-
if (ftsResult !== 'sqlite is great') throw new Error('FTS5 check failed');
72+
if (ftsResult !== 'sqlite is great') {
73+
throw new Error('FTS5 check failed');
74+
}
6075

6176
// 5. Math Functions
6277
const cosResult = db.selectValue('SELECT cos(0)');
63-
if (cosResult !== 1) throw new Error('Math functions check failed');
78+
if (cosResult !== 1) {
79+
throw new Error('Math functions check failed');
80+
}
6481

6582
// 6. Percentile
6683
db.exec('CREATE TABLE p(x); INSERT INTO p VALUES (1),(2),(3),(4),(5);');
6784
const perc = db.selectValue('SELECT percentile(x, 50) FROM p');
68-
if (perc !== 3) throw new Error('Percentile check failed');
85+
if (perc !== 3) {
86+
throw new Error('Percentile check failed');
87+
}
88+
89+
// 7. pauseVfs and unpauseVfs
90+
// Ensure it's not paused initially
91+
if (opfsSahPool.isPaused()) {
92+
throw new Error('VFS should not be paused initially');
93+
}
94+
95+
db.close(); // Must close DB before pausing if it's the only one using it,
96+
// or at least ensures no open file handles.
97+
// Actually, pauseVfs throws if there are open file handles.
98+
99+
opfsSahPool.pauseVfs();
100+
if (!opfsSahPool.isPaused()) {
101+
throw new Error('VFS should be paused after pauseVfs()');
102+
}
103+
104+
// Attempting to open a DB with a paused VFS should fail
105+
try {
106+
new opfsSahPool.OpfsSAHPoolDb('/test-sahpool-worker.sqlite3');
107+
throw new Error('Opening DB should have failed while VFS is paused');
108+
} catch (e) {
109+
// Expected error
110+
}
111+
112+
await opfsSahPool.unpauseVfs();
113+
if (opfsSahPool.isPaused()) {
114+
throw new Error('VFS should not be paused after unpauseVfs()');
115+
}
116+
117+
// Test that pauseVfs() throws if there are open file handles
118+
db = new opfsSahPool.OpfsSAHPoolDb('/test-sahpool-worker.sqlite3');
119+
try {
120+
opfsSahPool.pauseVfs();
121+
throw new Error('pauseVfs should have failed with open DB handles');
122+
} catch (e) {
123+
if (!e.message.includes('Cannot pause VFS')) {
124+
throw new Error(
125+
'pauseVfs failed with unexpected error: ' + e.message,
126+
);
127+
}
128+
}
129+
db.close();
130+
131+
// Now it should work again
132+
db = new opfsSahPool.OpfsSAHPoolDb('/test-sahpool-worker.sqlite3');
133+
const count2 = db.selectValue('SELECT count(*) FROM test');
134+
if (count2 !== 2) {
135+
throw new Error('Persistence check after unpause failed');
136+
}
69137

70138
self.postMessage({ type: 'success' });
71139
} finally {

0 commit comments

Comments
 (0)