Skip to content

Commit 94b68ca

Browse files
Appempting to use directly uuid crate (failing)
1 parent 7a18927 commit 94b68ca

15 files changed

Lines changed: 436 additions & 636 deletions

File tree

.github/workflows/test.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,35 @@ jobs:
155155
cd extensions/sqlite-vec
156156
wasm-pack test --node
157157
158+
test_sqlite_wasm_uuid4:
159+
strategy:
160+
matrix:
161+
os: [ubuntu-latest]
162+
runs-on: ${{ matrix.os }}
163+
steps:
164+
- uses: actions/checkout@v4
165+
- name: Install wasm-pack
166+
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
167+
- name: Test
168+
run: |
169+
cd extensions/uuid4
170+
wasm-pack test --node
171+
172+
test_sqlite_wasm_uuid7:
173+
strategy:
174+
matrix:
175+
os: [ubuntu-latest]
176+
runs-on: ${{ matrix.os }}
177+
steps:
178+
- uses: actions/checkout@v4
179+
- name: Install wasm-pack
180+
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
181+
- name: Test
182+
run: |
183+
cd extensions/uuid7
184+
wasm-pack test --node
185+
186+
158187
test_sqlite_wasm_vfs:
159188
strategy:
160189
matrix:

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,22 @@ See [ADDING_EXTENSIONS.md](docs/ADDING_EXTENSIONS.md) for instructions on how to
9292

9393
Contributions are welcome!
9494

95+
## Testing
96+
97+
To run tests for the workspace or specific extensions, use `wasm-pack test --node`.
98+
99+
Extensions (like `extensions/uuid4` or `extensions/uuid7`) are configured to run within a NodeJS environment.
100+
101+
```bash
102+
# Test uuid4 extension
103+
cd extensions/uuid4
104+
wasm-pack test --node
105+
106+
# Test uuid7 extension
107+
cd extensions/uuid7
108+
wasm-pack test --node
109+
```
110+
95111
## Related Project
96112

97113
* [`diesel`](https://github.com/diesel-rs/diesel): A safe, extensible ORM and Query Builder for Rust.

examples/nodejs/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ sqlite-wasm-rs = { path = "../.." }
99
sqlite-wasm-uuid4 = { path = "../../extensions/uuid4" }
1010
sqlite-wasm-uuid7 = { path = "../../extensions/uuid7" }
1111
wasm-bindgen-futures = "0.4.54"
12+
uuid = { version = "1.20.0", features = ["js"] }
13+
getrandom = { version = "0.2", features = ["js"] }
14+
console_error_panic_hook = "0.1.7"
1215

1316
[lib]
14-
crate-type = ["cdylib"]
17+
crate-type = ["cdylib", "rlib"]

examples/nodejs/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
if (!globalThis.crypto) {
2+
globalThis.crypto = require("node:crypto").webcrypto;
3+
}
4+
5+
const wasm = require('./pkg/nodejs.js');
6+
// wasm.main(); // main is executed automatically due to #[wasm_bindgen(start)]

examples/nodejs/src/lib.rs

Lines changed: 98 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use std::ffi::CStr;
2+
use std::collections::HashSet;
23

34
use sqlite_wasm_rs::{
45
sqlite3, sqlite3_close, sqlite3_column_text, sqlite3_finalize, sqlite3_open_v2,
56
sqlite3_prepare_v3, sqlite3_step, SQLITE_OK, SQLITE_OPEN_CREATE, SQLITE_OPEN_READWRITE,
67
SQLITE_ROW,
78
};
89
use wasm_bindgen::prelude::wasm_bindgen;
10+
use uuid::{Uuid, Version};
911

1012
#[wasm_bindgen]
1113
extern "C" {
@@ -17,8 +19,36 @@ macro_rules! console_log {
1719
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
1820
}
1921

22+
unsafe fn query_uuid(db: *mut sqlite3, sql_stmt: *const std::ffi::c_char) -> String {
23+
let mut stmt = std::ptr::null_mut();
24+
let rc = sqlite3_prepare_v3(
25+
db,
26+
sql_stmt,
27+
-1,
28+
0,
29+
&mut stmt,
30+
std::ptr::null_mut(),
31+
);
32+
assert_eq!(SQLITE_OK, rc, "Failed to prepare statement");
33+
34+
let mut res = String::new();
35+
if sqlite3_step(stmt) == SQLITE_ROW {
36+
let val_ptr = sqlite3_column_text(stmt, 0);
37+
if !val_ptr.is_null() {
38+
res = CStr::from_ptr(val_ptr.cast()).to_str().unwrap().to_string();
39+
} else {
40+
panic!("Returned NULL for UUID query");
41+
}
42+
} else {
43+
panic!("No row returned for UUID query");
44+
}
45+
sqlite3_finalize(stmt);
46+
res
47+
}
48+
2049
#[wasm_bindgen(start)]
2150
async fn main() {
51+
console_error_panic_hook::set_once();
2252
let mut db: *mut sqlite3 = std::ptr::null_mut();
2353
// Open in-memory DB
2454
let ret = unsafe {
@@ -30,112 +60,94 @@ async fn main() {
3060
)
3161
};
3262
assert_eq!(SQLITE_OK, ret);
33-
console_log!("db opened: {db:?}");
63+
console_log!("db opened");
3464

3565
unsafe {
36-
// Register uuid4 extension
66+
// Register extensions
3767
let rc = sqlite_wasm_uuid4::register(db.cast());
3868
assert_eq!(SQLITE_OK, rc);
3969
console_log!("UUID4 extension registered");
4070

41-
// Register uuid7 extension
4271
let rc = sqlite_wasm_uuid7::register(db.cast());
4372
assert_eq!(SQLITE_OK, rc);
4473
console_log!("UUID7 extension registered");
4574

46-
// Test uuid()
47-
console_log!("Testing SELECT uuid();");
75+
// --- UUID4 Test ---
76+
console_log!("Generating 1000 UUIDv4...");
77+
let mut v4_results = Vec::with_capacity(1000);
4878
let sql = c"SELECT uuid();";
49-
let mut stmt = std::ptr::null_mut();
50-
let rc = sqlite3_prepare_v3(
51-
db,
52-
sql.as_ptr().cast(),
53-
-1,
54-
0,
55-
&mut stmt,
56-
std::ptr::null_mut(),
57-
);
58-
assert_eq!(SQLITE_OK, rc);
59-
60-
if sqlite3_step(stmt) == SQLITE_ROW {
61-
let val_ptr = sqlite3_column_text(stmt, 0);
62-
if !val_ptr.is_null() {
63-
let s = CStr::from_ptr(val_ptr.cast()).to_str().unwrap();
64-
console_log!("uuid() result: {}", s);
65-
66-
// Validate format: 8-4-4-4-12 hex digits
67-
assert_eq!(s.len(), 36);
68-
assert_eq!(s.chars().nth(8), Some('-'));
69-
assert_eq!(s.chars().nth(13), Some('-'));
70-
assert_eq!(s.chars().nth(18), Some('-'));
71-
assert_eq!(s.chars().nth(23), Some('-'));
72-
} else {
73-
console_log!("uuid() returned NULL");
74-
}
75-
} else {
76-
console_log!("Error: No row returned for uuid()");
79+
80+
for _ in 0..1000 {
81+
v4_results.push(query_uuid(db, sql.as_ptr()));
7782
}
78-
sqlite3_finalize(stmt);
79-
80-
// Test uuid_str()
81-
console_log!("Testing SELECT uuid_str(uuid_blob('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'));");
82-
// We know 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11' is a valid uuid
83-
let sql = c"SELECT uuid_str(uuid_blob('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'));";
84-
let rc = sqlite3_prepare_v3(
85-
db,
86-
sql.as_ptr().cast(),
87-
-1,
88-
0,
89-
&mut stmt,
90-
std::ptr::null_mut(),
91-
);
92-
assert_eq!(SQLITE_OK, rc);
9383

94-
if sqlite3_step(stmt) == SQLITE_ROW {
95-
let val_ptr = sqlite3_column_text(stmt, 0);
96-
if !val_ptr.is_null() {
97-
let s = CStr::from_ptr(val_ptr.cast()).to_str().unwrap();
98-
console_log!("uuid_str(...) result: {}", s);
99-
assert_eq!(s, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11");
100-
} else {
101-
console_log!("uuid_str(...) returned NULL");
102-
}
103-
} else {
104-
console_log!("Error: No row returned for uuid_str()");
84+
// Check uniqueness
85+
let set: HashSet<_> = v4_results.iter().cloned().collect();
86+
assert_eq!(set.len(), 1000, "All UUIDv4 must be unique");
87+
console_log!("Unique check passed for UUIDv4");
88+
89+
// Check version & parsing
90+
for (i, s) in v4_results.iter().enumerate() {
91+
let u = Uuid::parse_str(s).unwrap_or_else(|e| panic!("Failed to parse UUIDv4 at index {}: {} - {}", i, s, e));
92+
assert_eq!(u.get_version(), Some(Version::Random), "UUID at index {} is not v4: {}", i, s);
10593
}
106-
sqlite3_finalize(stmt);
94+
console_log!("Version check passed for UUIDv4");
10795

108-
// Test uuid7()
109-
console_log!("Testing SELECT uuid7();");
96+
// --- UUID7 Test ---
97+
console_log!("Generating 1000 UUIDv7...");
98+
let mut v7_results = Vec::with_capacity(1000);
11099
let sql = c"SELECT uuid7();";
111-
let mut stmt = std::ptr::null_mut();
112-
let rc = sqlite3_prepare_v3(
113-
db,
114-
sql.as_ptr().cast(),
115-
-1,
116-
0,
117-
&mut stmt,
118-
std::ptr::null_mut(),
119-
);
120-
assert_eq!(SQLITE_OK, rc);
121100

122-
if sqlite3_step(stmt) == SQLITE_ROW {
123-
let val_ptr = sqlite3_column_text(stmt, 0);
124-
if !val_ptr.is_null() {
125-
let s = CStr::from_ptr(val_ptr.cast()).to_str().unwrap();
126-
console_log!("uuid7() result: {}", s);
127-
assert_eq!(s.len(), 36);
128-
assert_eq!(s.chars().nth(14), Some('7'));
129-
} else {
130-
console_log!("uuid7() returned NULL");
131-
}
132-
} else {
133-
console_log!("Error: No row returned for uuid7()");
101+
for _ in 0..1000 {
102+
v7_results.push(query_uuid(db, sql.as_ptr()));
134103
}
135-
sqlite3_finalize(stmt);
136104

105+
// Check uniqueness
106+
let set: HashSet<_> = v7_results.iter().cloned().collect();
107+
assert_eq!(set.len(), 1000, "All UUIDv7 must be unique");
108+
console_log!("Unique check passed for UUIDv7");
109+
110+
// Check sorting (Monotonicity)
111+
// Since UUIDv7 is time-ordered, later generations should generally be greater than previous ones.
112+
// However, if generated in the same millisecond, the random component decides order.
113+
// Strict monotonicity isn't guaranteed across all implementations unless they share state,
114+
// but uuid::Uuid::now_v7() generally attempts internally to be monotonic if called rapidly.
115+
// Wait, the Rust `uuid` crate documentation says `now_v7` guarantees monotonicity for same-process calls if the feature is enabled?
116+
// Actually `Uuid::now_v7()` uses `context::Context` thread-locally if available, or just random.
117+
// The implementation in extensions/uuid7 uses `Uuid::now_v7()`.
118+
// Let's check if the list is sorted.
119+
120+
let mut sorted_v7 = v7_results.clone();
121+
sorted_v7.sort();
122+
123+
// This assertion might be flaky if the clock goes backwards or multiple threads (not in WASM mostly).
124+
// But for a single thread tight loop, it should be strictly monotonic or at least non-decreasing.
125+
// Since we assert uniqueness, non-decreasing + unique = strictly increasing.
126+
127+
if v7_results != sorted_v7 {
128+
console_log!("Warning: UUIDv7 results were not strictly monotonic.");
129+
// Find first violation
130+
for i in 0..999 {
131+
if v7_results[i] > v7_results[i+1] {
132+
console_log!("Violation at index {}: {} > {}", i, v7_results[i], v7_results[i+1]);
133+
// Allow slight harmless reordering if any, but UUIDv7 SHOULD be monotonic.
134+
// The user asked to "check they are unique and sorted".
135+
// So I will assert it.
136+
}
137+
}
138+
panic!("UUIDv7 results are not sorted!");
139+
}
140+
console_log!("Sort order check passed for UUIDv7");
141+
142+
// Check version
143+
for (i, s) in v7_results.iter().enumerate() {
144+
let u = Uuid::parse_str(s).unwrap_or_else(|e| panic!("Failed to parse UUIDv7 at index {}: {} - {}", i, s, e));
145+
assert_eq!(u.get_version(), Some(Version::SortRand), "UUID at index {} is not v7: {}", i, s);
146+
}
147+
console_log!("Version check passed for UUIDv7");
148+
137149
sqlite3_close(db);
138150
}
139-
151+
140152
console_log!("All tests passed!");
141153
}

extensions/uuid4/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ license = "MIT"
88
description = "`wasm32-unknown-unknown` bindings to the `uuid4` extension."
99
categories = ["development-tools::ffi", "wasm", "database"]
1010
keywords = ["sqlite", "sqlite-wasm", "wasm", "webassembly", "uuid4"]
11-
links = "sqlite_uuid4"
1211

1312
[dependencies]
13+
uuid = { version = "1.20.0", features = ["v4", "v7", "js", "macro-diagnostics"] }
14+
getrandom = { version = "0.2", features = ["js"] }
1415
wasm-bindgen = "0.2.104"
15-
16-
[build-dependencies]
17-
cc = "1.2.44"
16+
sqlite-wasm-rs = { path = "../../" }
1817

1918
[dev-dependencies]
2019
wasm-bindgen-test = "0.3.55"
2120
sqlite-wasm-rs = { path = "../../" }
2221
js-sys = "0.3.81"
22+
rusqlite = "0.38.0"
2323

2424
[package.metadata.docs.rs]
2525
targets = ["wasm32-unknown-unknown"]

extensions/uuid4/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,12 @@
33
`wasm32-unknown-unknown` bindings to the SQLite `uuid` extension (v4).
44

55
Exports `sqlite3_uuid4_init` for usage with `sqlite3_auto_extension`.
6+
7+
## Testing
8+
9+
This crate is configured to run tests in a NodeJS environment using `wasm-pack`.
10+
11+
```bash
12+
wasm-pack test --node
13+
```
14+

extensions/uuid4/build.rs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,3 @@
11
fn main() {
2-
println!("cargo:rerun-if-changed=c/uuid4.c");
3-
println!("cargo:rerun-if-changed=../../shim/wasm-shim.h");
4-
5-
let mut cc = cc::Build::new();
6-
7-
cc.warnings(false)
8-
.file("c/uuid4.c")
9-
.include("../../include") // fallback or general include if any
10-
.include("../../shim/musl/include")
11-
.include("../../shim/musl/arch/generic")
12-
.include("../../sqlite3") // where sqlite3ext.h is
13-
.flag("-include")
14-
.flag("../../shim/wasm-shim.h")
15-
.flag("-DSQLITE_CORE")
16-
.flag("-DSQLITE_WASM")
17-
.flag("-DNDEBUG")
18-
.compile("sqlite_uuid4");
2+
// No C compilation needed anymore
193
}

0 commit comments

Comments
 (0)