-
Notifications
You must be signed in to change notification settings - Fork 0
Add wipe_and_recreate method to SQLiteWasmDatabase #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Features added: StorageManager, FileSystemDirectoryHandle, FileSystemHandle, FileSystemRemoveOptions, FileSystemGetDirectoryOptions
Allows resetting the signal back to pending state for reuse after wipe_and_recreate operations.
Provides delete_opfs_sahpool_directory() to remove the .opfs-sahpool directory used by sqlite-wasm-rs for persistent storage.
Allows completely wiping and recreating the database: - Terminates current worker - Rejects pending queries - Deletes OPFS storage - Creates fresh worker - Same instance remains valid after operation Uses interior mutability (Rc<RefCell<Worker>>) to allow bound callbacks to continue working.
- 8 integration tests covering data clearing, post-wipe operations, instance validity, and error recovery - Wipe & Recreate button in demo app for manual testing
This reverts commit 1a6fa53.
WalkthroughRefactors DB worker to use shared references and store Changes
Sequence DiagramsequenceDiagram
participant App as Svelte App
participant DB as SQLiteWasmDatabase
participant OPS as opfs module
participant Worker as Embedded Worker
participant OPFS as Browser OPFS
App->>DB: wipe_and_recreate()
DB->>Worker: worker.borrow().terminate()
Worker-->>DB: terminated
DB->>DB: reject pending queries
DB->>DB: ready.reset()
DB->>OPS: delete_opfs_sahpool_directory()
OPS->>OPFS: navigator.storage.getDirectory() / get OPFS root
OPFS-->>OPS: root handle
OPS->>OPFS: get_directory_if_exists(".opfs-sahpool")
OPFS-->>OPS: sahpool handle or NotFound
OPS->>OPFS: delete_directory_contents(sahpool)
OPFS-->>OPS: contents deleted
OPS->>OPFS: removeEntry("sahpool")
OPFS-->>OPS: removed
OPS-->>DB: Ok(())
DB->>DB: spawn embedded worker (new)
DB->>Worker: install onmessage handler
Worker-->>DB: ready message
DB-->>App: Ok(())
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Code reviewFound 1 issue:
sqlite-web/packages/sqlite-web/src/ready.rs Lines 172 to 178 in cf1c2d7
🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@packages/sqlite-web/src/db.rs`:
- Around line 185-210: The wipe_and_recreate implementation resets the request
ID counter causing possible ID reuse between worker generations; instead of
setting *self.next_request_id.borrow_mut() = 1, leave the counter unchanged so
IDs remain monotonic (or advance it safely to a new high value) to avoid
collisions with stale replies from the terminated worker; update
wipe_and_recreate (and any code that initializes next_request_id) to stop
resetting next_request_id and ensure request ID generation logic in the code
that issues requests continues incrementing the existing counter (refer to
next_request_id, pending_queries, wipe_and_recreate, install_onmessage_handler,
and worker).
In `@packages/sqlite-web/src/opfs.rs`:
- Around line 60-75: The function get_directory_if_exists currently treats all
JS errors as "not found"; add the web-sys "DomException" feature in Cargo.toml
and change the error handling in get_directory_if_exists to detect DomException
and only treat a "NotFoundError" as Ok(None), while propagating other errors as
SQLiteWasmDatabaseError (preserving existing describe_js_value-based messages);
keep the creation options via FileSystemGetDirectoryOptions and return
handle.dyn_into().map(Some) on success, but on Err(e) use
e.dyn_ref::<web_sys::DomException>() to inspect .name() and return Ok(None) only
when name == "NotFoundError", otherwise convert the error into an appropriate
SQLiteWasmDatabaseError and return Err.
In `@packages/sqlite-web/src/ready.rs`:
- Around line 173-177: The test currently calls signal.mark_ready() before
retrieving the promise, but mark_ready() consumes/drops the internal promise so
signal.wait_promise() will error; fix by calling let promise =
signal.wait_promise().expect(...) before invoking signal.mark_ready(), then call
signal.mark_ready() and await the previously captured promise with
wasm_bindgen_futures::JsFuture::from(promise).await.expect(...); reference the
existing symbols signal.wait_promise(), signal.mark_ready(), and the promise
variable to locate where to reorder the operations.
- Around line 91-96: reset() currently replaces self.promise without notifying
any existing waiters; if InitializationState is Pending, call the existing
reject (or resolve) callback before dropping it so outstanding promises don't
hang. Specifically, in reset() check whether *self.state.borrow() ==
InitializationState::Pending and if so take() the stored reject (or resolve)
from self.reject/self.resolve and invoke it with a suitable JS error/message
(then drop those callbacks), then proceed to set state to Pending, replace the
promise via create_ready_promise(&self.resolve,&self.reject) and store it in
self.promise; ensure resolve/reject are cleared after invocation to avoid
double-calls.
| async fn get_directory_if_exists( | ||
| parent: &FileSystemDirectoryHandle, | ||
| name: &str, | ||
| ) -> Result<Option<FileSystemDirectoryHandle>, SQLiteWasmDatabaseError> { | ||
| let options = FileSystemGetDirectoryOptions::new(); | ||
| options.set_create(false); | ||
|
|
||
| match JsFuture::from(parent.get_directory_handle_with_options(name, &options)).await { | ||
| Ok(handle) => handle.dyn_into().map(Some).map_err(|e| { | ||
| SQLiteWasmDatabaseError::OpfsDeletionFailed(format!( | ||
| "directory handle type mismatch: {}", | ||
| describe_js_value(&e) | ||
| )) | ||
| }), | ||
| Err(_) => Ok(None), | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate and read the opfs.rs file
find . -name "opfs.rs" -type fRepository: rainlanguage/sqlite-web
Length of output: 100
🏁 Script executed:
# Check the current content of the file around lines 60-75
cat -n packages/sqlite-web/src/opfs.rs | sed -n '50,85p'Repository: rainlanguage/sqlite-web
Length of output: 1506
🏁 Script executed:
# Search for DomException usage in the codebase
rg "DomException" --type rustRepository: rainlanguage/sqlite-web
Length of output: 49
🏁 Script executed:
# Look for similar error handling patterns with NotFoundError or dyn_ref
rg "NotFoundError\|dyn_ref.*DomException" --type rust -A 3Repository: rainlanguage/sqlite-web
Length of output: 49
🏁 Script executed:
# Check the imports at the top of opfs.rs
head -30 packages/sqlite-web/src/opfs.rsRepository: rainlanguage/sqlite-web
Length of output: 1123
🏁 Script executed:
# Check how get_directory_if_exists is used in the code
rg "get_directory_if_exists" --type rust -B 2 -A 2Repository: rainlanguage/sqlite-web
Length of output: 665
🏁 Script executed:
# Look at the broader context - check if web_sys has DomException or similar
rg "web_sys::" packages/sqlite-web/src/opfs.rsRepository: rainlanguage/sqlite-web
Length of output: 273
🏁 Script executed:
# Check what web_sys exports - look for any exception/error handling
grep -r "DomException\|Exception" packages/sqlite-web/Cargo.tomlRepository: rainlanguage/sqlite-web
Length of output: 49
🏁 Script executed:
# Check Cargo.toml to understand web_sys version
cat packages/sqlite-web/Cargo.toml | head -50Repository: rainlanguage/sqlite-web
Length of output: 616
🏁 Script executed:
# Look at other error handling in the file to see patterns
rg "Err\(" packages/sqlite-web/src/opfs.rs -A 1Repository: rainlanguage/sqlite-web
Length of output: 100
🏁 Script executed:
# Check web-sys version and available exports
cat packages/Cargo.toml | grep -A 10 "web-sys"Repository: rainlanguage/sqlite-web
Length of output: 118
🏁 Script executed:
# Look for any existing error handling with js_sys or exceptions
rg "js_sys::" packages/sqlite-web/src/ -A 2Repository: rainlanguage/sqlite-web
Length of output: 16156
🏁 Script executed:
# Search the entire codebase for NotFoundError handling pattern
rg "NotFound" --type rustRepository: rainlanguage/sqlite-web
Length of output: 49
🏁 Script executed:
# Check if there's documentation or examples in the repo about error handling
find . -name "*.rs" -type f -exec grep -l "DomException\|get_directory_handle" {} \;Repository: rainlanguage/sqlite-web
Length of output: 100
🏁 Script executed:
# Let's check web-sys docs indirectly by looking at what's available
# First, check if there's a Cargo.lock file that shows actual versions
head -100 Cargo.lock | grep -A 5 "name = \"web-sys\""Repository: rainlanguage/sqlite-web
Length of output: 49
🏁 Script executed:
# Check the workspace Cargo.toml to see web-sys configuration
cat Cargo.toml | grep -A 20 "web-sys"Repository: rainlanguage/sqlite-web
Length of output: 551
🏁 Script executed:
# Look at the errors.rs file to understand error handling patterns
cat -n packages/sqlite-web/src/errors.rs | head -50Repository: rainlanguage/sqlite-web
Length of output: 1826
🏁 Script executed:
# Check if there's any error name checking pattern in the codebase
rg "name()\|\.name\|\.type" packages/sqlite-web/src/ --type rustRepository: rainlanguage/sqlite-web
Length of output: 49
🏁 Script executed:
# Search for how File System API errors are handled elsewhere
rg "get_directory_handle\|get_file_handle\|remove_entry" packages/sqlite-web/src/ --type rust -B 2 -A 5Repository: rainlanguage/sqlite-web
Length of output: 49
🏁 Script executed:
# Check web-sys documentation in a comment or see if there's information about DomException
python3 << 'EOF'
# Query web for web_sys DomException availability
import subprocess
result = subprocess.run(['rg', 'DomException', '--type', 'rust'], cwd='.', capture_output=True, text=True)
print("DomException search result (should be empty):", result.returncode)
print("stdout:", result.stdout)
print("stderr:", result.stderr)
EOFRepository: rainlanguage/sqlite-web
Length of output: 153
🏁 Script executed:
# Let's check if there's a way to check error names in web-sys
# Look for any pattern matching on error types
rg "dyn_ref\|dyn_into" packages/sqlite-web/src/ --type rust -B 1 -A 1Repository: rainlanguage/sqlite-web
Length of output: 49
🏁 Script executed:
# Check web-sys features more comprehensively
rg "DomException" --type rustRepository: rainlanguage/sqlite-web
Length of output: 49
🏁 Script executed:
# Let's verify if there's an alternative way to check error names
# Search for how errors are handled with Reflect pattern
rg "Reflect::get.*name\|error.*name" --type rust -B 2 -A 2Repository: rainlanguage/sqlite-web
Length of output: 49
🏁 Script executed:
# Check if there are any examples of checking JS error types in the codebase
cat -n packages/sqlite-web/src/opfs.rs | sed -n '1,120p'Repository: rainlanguage/sqlite-web
Length of output: 4969
🏁 Script executed:
# Verify web-sys version and check if DomException feature exists
web_sys_version=$(rg 'web-sys.*version' Cargo.toml | head -1)
echo "Web-sys configuration: $web_sys_version"Repository: rainlanguage/sqlite-web
Length of output: 131
🌐 Web query:
web-sys 0.3 DomException feature rust
💡 Result:
In web-sys 0.3, DomException is behind a Cargo feature named DomException. To use web_sys::DomException, enable that feature in your Cargo.toml:
[dependencies.web-sys]
version = "0.3"
features = ["DomException"]web-sys gates most Web API types behind per-type features, and the docs for DomException explicitly state it requires the DomException feature. [1], [2], [3]
Add DomException feature and distinguish NotFoundError from other errors.
The current implementation swallows all errors with Err(_) => Ok(None), which masks permission issues, type mismatches, and other failures. Only NotFoundError should return Ok(None); other errors must be propagated.
The suggested fix requires adding the DomException feature to web-sys in Cargo.toml since it is not currently enabled. Update the dependencies and implement the error type check in get_directory_if_exists:
🛠️ Required changes
In Cargo.toml, update web-sys features:
web-sys = { version = "0.3", features = [
"Blob",
"BlobPropertyBag",
"Url",
"Worker",
"WorkerOptions",
"WorkerType",
"BroadcastChannel",
"MessageEvent",
"DedicatedWorkerGlobalScope",
"Navigator",
"Window",
"Location",
"StorageManager",
"FileSystemDirectoryHandle",
"FileSystemHandle",
"FileSystemRemoveOptions",
"FileSystemGetDirectoryOptions",
"DomException"
]}In opfs.rs, update the import:
-use web_sys::{FileSystemDirectoryHandle, FileSystemGetDirectoryOptions, FileSystemRemoveOptions};
+use web_sys::{
+ DomException, FileSystemDirectoryHandle, FileSystemGetDirectoryOptions, FileSystemRemoveOptions,
+};Update get_directory_if_exists to check error type:
match JsFuture::from(parent.get_directory_handle_with_options(name, &options)).await {
Ok(handle) => handle.dyn_into().map(Some).map_err(|e| {
SQLiteWasmDatabaseError::OpfsDeletionFailed(format!(
"directory handle type mismatch: {}",
describe_js_value(&e)
))
}),
- Err(_) => Ok(None),
+ Err(err) => {
+ if let Some(dom) = err.dyn_ref::<DomException>() {
+ if dom.name() == "NotFoundError" {
+ return Ok(None);
+ }
+ }
+ Err(SQLiteWasmDatabaseError::OpfsDeletionFailed(format!(
+ "failed to access directory {name}: {}",
+ describe_js_value(&err)
+ )))
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async fn get_directory_if_exists( | |
| parent: &FileSystemDirectoryHandle, | |
| name: &str, | |
| ) -> Result<Option<FileSystemDirectoryHandle>, SQLiteWasmDatabaseError> { | |
| let options = FileSystemGetDirectoryOptions::new(); | |
| options.set_create(false); | |
| match JsFuture::from(parent.get_directory_handle_with_options(name, &options)).await { | |
| Ok(handle) => handle.dyn_into().map(Some).map_err(|e| { | |
| SQLiteWasmDatabaseError::OpfsDeletionFailed(format!( | |
| "directory handle type mismatch: {}", | |
| describe_js_value(&e) | |
| )) | |
| }), | |
| Err(_) => Ok(None), | |
| } | |
| async fn get_directory_if_exists( | |
| parent: &FileSystemDirectoryHandle, | |
| name: &str, | |
| ) -> Result<Option<FileSystemDirectoryHandle>, SQLiteWasmDatabaseError> { | |
| let options = FileSystemGetDirectoryOptions::new(); | |
| options.set_create(false); | |
| match JsFuture::from(parent.get_directory_handle_with_options(name, &options)).await { | |
| Ok(handle) => handle.dyn_into().map(Some).map_err(|e| { | |
| SQLiteWasmDatabaseError::OpfsDeletionFailed(format!( | |
| "directory handle type mismatch: {}", | |
| describe_js_value(&e) | |
| )) | |
| }), | |
| Err(err) => { | |
| if let Some(dom) = err.dyn_ref::<DomException>() { | |
| if dom.name() == "NotFoundError" { | |
| return Ok(None); | |
| } | |
| } | |
| Err(SQLiteWasmDatabaseError::OpfsDeletionFailed(format!( | |
| "failed to access directory {name}: {}", | |
| describe_js_value(&err) | |
| ))) | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In `@packages/sqlite-web/src/opfs.rs` around lines 60 - 75, The function
get_directory_if_exists currently treats all JS errors as "not found"; add the
web-sys "DomException" feature in Cargo.toml and change the error handling in
get_directory_if_exists to detect DomException and only treat a "NotFoundError"
as Ok(None), while propagating other errors as SQLiteWasmDatabaseError
(preserving existing describe_js_value-based messages); keep the creation
options via FileSystemGetDirectoryOptions and return handle.dyn_into().map(Some)
on success, but on Err(e) use e.dyn_ref::<web_sys::DomException>() to inspect
.name() and return Ok(None) only when name == "NotFoundError", otherwise convert
the error into an appropriate SQLiteWasmDatabaseError and return Err.
- Reject existing promise before dropping to prevent hangs - Fix test to capture promise before calling mark_ready()
- Add DomException web-sys feature - Distinguish NotFoundError from other errors in get_directory_if_exists() - Remove redundant test
- Remove request ID reset to avoid ID collisions with stale replies - Consolidate wipe tests into single test function - Add NaN/Infinity parameter validation tests - Remove redundant tests from tests.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/sqlite-web/src/db.rs`:
- Around line 186-214: wipe_and_recreate currently terminates the worker and
returns early if delete_opfs_sahpool_directory() fails, leaving the instance
without a worker; change the flow to capture the OPFS deletion error (call
delete_opfs_sahpool_directory().await and store any Err), then always proceed to
recreate the worker via create_worker_from_code, install_onmessage_handler,
replace *self.worker, and call self.wait_until_ready().await before finally
propagating the stored deletion error (if any) as the Result; keep mapping
create_worker_from_code errors to SQLiteWasmDatabaseError::JsError and ensure
any pending_queries handling and ready_signal.reset() remain unchanged.
Capture OPFS deletion error and propagate it after worker recreation to avoid leaving the database in an unusable state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/sqlite-web/src/db.rs`:
- Around line 333-404: Split the large wasm_bindgen_test function
wipe_and_recreate_tests into focused tests: keep one async test (e.g.,
wipe_and_recreate_happy_path) that exercises SQLiteWasmDatabase::new,
SQLiteWasmDatabase::wipe_and_recreate, creation/insertion/select, repeated wipes
(the t0..t2 loop) and checks on sqlite_master; move the parameter validation
checks that call db.query with NaN/Infinity into a separate async test (e.g.,
query_rejects_invalid_numbers) that only asserts errors for
JsValue::from_f64(NaN/INFINITY/NEG_INFINITY). Ensure both functions retain
#[wasm_bindgen_test(async)] and reuse the same
SQLiteWasmDatabase::new("test_wipe") setup or create distinct named DBs to avoid
interference.
| #[wasm_bindgen_test(async)] | ||
| async fn wipe_and_recreate_tests() { | ||
| let db = SQLiteWasmDatabase::new("test_wipe").await.unwrap(); | ||
| db.wipe_and_recreate().await.unwrap(); | ||
|
|
||
| db.query( | ||
| "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)", | ||
| None, | ||
| ) | ||
| .await | ||
| .unwrap(); | ||
| db.query("INSERT INTO users (name) VALUES ('Alice')", None) | ||
| .await | ||
| .unwrap(); | ||
|
|
||
| let result = db | ||
| .query("SELECT COUNT(*) as count FROM users", None) | ||
| .await | ||
| .unwrap(); | ||
| assert!(result.contains("\"count\": 1")); | ||
|
|
||
| db.wipe_and_recreate().await.unwrap(); | ||
|
|
||
| let result = db.query("SELECT * FROM users", None).await; | ||
| assert!(result.is_err() || result.unwrap().contains("no such table")); | ||
|
|
||
| let create_result = db | ||
| .query( | ||
| "CREATE TABLE new_table (id INTEGER PRIMARY KEY, value TEXT)", | ||
| None, | ||
| ) | ||
| .await; | ||
| assert!(create_result.is_ok()); | ||
|
|
||
| let insert_result = db | ||
| .query("INSERT INTO new_table (value) VALUES ('test')", None) | ||
| .await; | ||
| assert!(insert_result.is_ok()); | ||
|
|
||
| let select_result = db.query("SELECT * FROM new_table", None).await.unwrap(); | ||
| assert!(select_result.contains("test")); | ||
|
|
||
| for i in 0..3 { | ||
| db.query(&format!("CREATE TABLE t{} (id INTEGER)", i), None) | ||
| .await | ||
| .unwrap(); | ||
| db.wipe_and_recreate().await.unwrap(); | ||
| } | ||
|
|
||
| let result = db | ||
| .query("SELECT name FROM sqlite_master WHERE type='table'", None) | ||
| .await | ||
| .unwrap(); | ||
| assert!(!result.contains("t0")); | ||
| assert!(!result.contains("t1")); | ||
| assert!(!result.contains("t2")); | ||
|
|
||
| let arr = Array::new(); | ||
| arr.push(&JsValue::from_f64(f64::NAN)); | ||
| let res = db.query("SELECT ?", Some(arr)).await; | ||
| assert!(res.is_err(), "NaN should be rejected"); | ||
|
|
||
| let arr = Array::new(); | ||
| arr.push(&JsValue::from_f64(f64::INFINITY)); | ||
| let res = db.query("SELECT ?", Some(arr)).await; | ||
| assert!(res.is_err(), "+Infinity should be rejected"); | ||
|
|
||
| let arr = Array::new(); | ||
| arr.push(&JsValue::from_f64(f64::NEG_INFINITY)); | ||
| let res = db.query("SELECT ?", Some(arr)).await; | ||
| assert!(res.is_err(), "-Infinity should be rejected"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider splitting the test into focused test cases.
This test bundles wipe/recreate scenarios, consecutive wipes, and parameter validation (NaN/Infinity) into a single function. While functional, isolated tests improve debuggability and make failures easier to diagnose. The invalid parameter tests (lines 390-403) are unrelated to wipe_and_recreate and could be a separate test.
🤖 Prompt for AI Agents
In `@packages/sqlite-web/src/db.rs` around lines 333 - 404, Split the large
wasm_bindgen_test function wipe_and_recreate_tests into focused tests: keep one
async test (e.g., wipe_and_recreate_happy_path) that exercises
SQLiteWasmDatabase::new, SQLiteWasmDatabase::wipe_and_recreate,
creation/insertion/select, repeated wipes (the t0..t2 loop) and checks on
sqlite_master; move the parameter validation checks that call db.query with
NaN/Infinity into a separate async test (e.g., query_rejects_invalid_numbers)
that only asserts errors for JsValue::from_f64(NaN/INFINITY/NEG_INFINITY).
Ensure both functions retain #[wasm_bindgen_test(async)] and reuse the same
SQLiteWasmDatabase::new("test_wipe") setup or create distinct named DBs to avoid
interference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have opted to use a single test because the database persists between the tests and it was causing us issues. By doing it this way, we make sure that we have we are testing everything properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@findolor, thank you for the clarification! That makes perfect sense—if the database state persists between test functions in your WASM test environment, consolidating the related scenarios into a single test is the right approach to ensure proper isolation and test correctness. I appreciate you explaining the reasoning behind this design decision.
✏️ Learnings added
Learnt from: findolor
Repo: rainlanguage/sqlite-web PR: 27
File: packages/sqlite-web/src/db.rs:333-404
Timestamp: 2026-01-27T10:13:33.826Z
Learning: In the sqlite-web WASM test environment, database state can persist between test functions, causing test interference. To ensure proper test isolation, related test scenarios for features like wipe_and_recreate should be consolidated into a single test function rather than split into multiple independent test cases.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: CR
Repo: rainlanguage/sqlite-web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T06:55:20.178Z
Learning: Applies to packages/sqlite-web/lib.rs : Expose an async, promise-based query interface from the SQLiteWasmDatabase public API
Learnt from: findolor
Repo: rainlanguage/sqlite-web PR: 14
File: svelte-test/tests/database-functions/float-is-zero.test.ts:39-57
Timestamp: 2025-09-19T07:06:20.173Z
Learning: PRAGMA function_list is not available in the WASM SQLite test environment used by svelte-test, so availability testing should rely on direct function calls rather than PRAGMA queries.
Learnt from: CR
Repo: rainlanguage/sqlite-web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T06:55:20.178Z
Learning: Applies to packages/sqlite-web-core/src/database_functions.rs : Integrate and expose rain.math.float-backed custom database functions for SQLite queries
Learnt from: CR
Repo: rainlanguage/sqlite-web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T06:55:20.178Z
Learning: Applies to packages/sqlite-web/worker_template.rs : Ensure the worker JavaScript generated by worker_template.rs embeds the WASM (base64) and does not fetch external WASM files
Learnt from: findolor
Repo: rainlanguage/sqlite-web PR: 9
File: packages/sqlite-web-core/src/coordination.rs:52-65
Timestamp: 2025-09-15T06:11:31.781Z
Learning: In packages/sqlite-web-core/src/coordination.rs, the pattern of using `db.borrow_mut().take()` followed by async database operations and then putting the database back with `*db.borrow_mut() = Some(database)` is safe in their use case and doesn't cause concurrent access issues or "Database not initialized" errors.
Learnt from: CR
Repo: rainlanguage/sqlite-web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T06:55:20.178Z
Learning: Applies to packages/sqlite-web-core/src/worker.rs : Keep worker.rs as the main worker entry point invoked by worker_main()
Learnt from: findolor
Repo: rainlanguage/sqlite-web PR: 6
File: svelte-test/tests/database-functions/float-sum.test.ts:78-86
Timestamp: 2025-09-17T08:04:44.062Z
Learning: In svelte-test/tests/database-functions/float-sum.test.ts, the schema defines `amount TEXT NOT NULL` but the NULL value handling tests attempt to insert NULL values, creating a constraint violation that prevents the tests from passing.
Learnt from: findolor
Repo: rainlanguage/sqlite-web PR: 15
File: svelte-test/tests/integration/error-handling.test.ts:418-434
Timestamp: 2025-09-17T17:44:54.855Z
Learning: In the sqlite-web test harness, parameter binding is not available for the db.query() method, so string interpolation with manual SQL escaping using value.replace(/'/g, "''") is the necessary approach for handling special characters in test data.
Learnt from: findolor
Repo: rainlanguage/sqlite-web PR: 5
File: packages/sqlite-web-core/src/database_functions/bigint_sum.rs:76-93
Timestamp: 2025-08-27T05:55:40.481Z
Learning: In the sqlite-web-core codebase, for SQLite aggregate function context initialization, the maintainer prefers using byte-scanning to detect zero-initialized memory rather than using explicit initialization flags or Option wrappers.
Learnt from: CR
Repo: rainlanguage/sqlite-web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T06:55:20.178Z
Learning: Applies to packages/sqlite-web-core/src/messages.rs : Use structured message types for worker communication as defined in messages.rs
Learnt from: findolor
Repo: rainlanguage/sqlite-web PR: 12
File: svelte-test/tests/fixtures/test-helpers.ts:11-11
Timestamp: 2025-09-15T10:01:17.743Z
Learning: In the sqlite-web project, test database names in createTestDatabase function do not need timestamp suffixes for uniqueness. The maintainer has confirmed that test isolation via unique naming is not required.
Learnt from: CR
Repo: rainlanguage/sqlite-web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T06:55:20.178Z
Learning: Applies to packages/sqlite-web/embedded_worker.js : Do not manually edit embedded_worker.js; it is generated by the build and should be treated as read-only
Learnt from: CR
Repo: rainlanguage/sqlite-web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T06:55:20.178Z
Learning: Maintain self-contained workers with no external WASM file dependencies across the project
Motivation
This change adds the ability to completely reset an in-browser SQLite database by wiping all OPFS storage and recreating the worker. This is useful for scenarios where users need a fresh database state without reloading the page.
Solution
Added a new
wipe_and_recreate()async method toSQLiteWasmDatabasethat:Supporting changes:
opfs.rsmodule with OPFS directory deletion utilitiesReadySignal::reset()method to return signal to pending stateOpfsDeletionFailederror variantStorageManager,FileSystemDirectoryHandle, etc.)workerfield toRc<RefCell<Worker>>to allow replacementdb_namefield to store database name for worker recreationChecks
By submitting this for review, I'm confirming I've done the following:
Summary by CodeRabbit
New Features
Bug Fixes / Reliability
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.