sqlite_wasm_example/
lib.rs

1pub mod models;
2pub mod schema;
3
4use std::sync::Mutex;
5use std::sync::Once;
6
7use crate::models::{NewPost, Post};
8use diesel::prelude::*;
9use diesel_migrations::embed_migrations;
10use diesel_migrations::EmbeddedMigrations;
11use diesel_migrations::MigrationHarness;
12use wasm_bindgen::prelude::*;
13
14const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
15
16#[wasm_bindgen]
17extern "C" {
18    // Use `js_namespace` here to bind `console.log(..)` instead of just
19    // `log(..)`
20    #[wasm_bindgen(js_namespace = console)]
21    fn log(s: &str);
22}
23
24// Next let's define a macro that's like `println!`, only it works for
25// `console.log`. Note that `println!` doesn't actually work on the Wasm target
26// because the standard library currently just eats all output. To get
27// `println!`-like behavior in your app you'll likely want a macro like this.
28macro_rules! console_log {
29    // Note that this is using the `log` function imported above during
30    // `bare_bones`
31    ($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
32}
33
34static VFS: Mutex<(i32, Once)> = Mutex::new((0, Once::new()));
35
36pub fn establish_connection() -> SqliteConnection {
37    let (vfs, once) = &*VFS.lock().unwrap();
38    let url = match vfs {
39        0 => "post.db",
40        1 => "file:post.db?vfs=opfs-sahpool",
41        2 => "file:post.db?vfs=relaxed-idb",
42        _ => unreachable!(),
43    };
44    let mut conn =
45        SqliteConnection::establish(url).unwrap_or_else(|_| panic!("Error connecting to post.db"));
46    once.call_once(|| {
47        conn.run_pending_migrations(MIGRATIONS).unwrap();
48    });
49    conn
50}
51
52#[cfg(all(target_family = "wasm", target_os = "unknown"))]
53#[wasm_bindgen(js_name = installOpfsSahpool)]
54pub async fn install_opfs_sahpool() {
55    use sqlite_wasm_rs::sahpool_vfs::{install, OpfsSAHPoolCfg};
56    install(&OpfsSAHPoolCfg::default(), false).await.unwrap();
57}
58
59#[cfg(all(target_family = "wasm", target_os = "unknown"))]
60#[wasm_bindgen(js_name = installRelaxedIdb)]
61pub async fn install_relaxed_idb() {
62    use sqlite_wasm_rs::relaxed_idb_vfs::{install, RelaxedIdbCfg};
63    install(&RelaxedIdbCfg::default(), false).await.unwrap();
64}
65
66#[wasm_bindgen(js_name = switchVfs)]
67pub fn switch_vfs(id: i32) {
68    *VFS.lock().unwrap() = (id, Once::new());
69}
70
71#[wasm_bindgen(js_name = createPost)]
72pub fn create_post(title: &str, body: &str) -> JsValue {
73    use crate::schema::posts;
74
75    let new_post = NewPost { title, body };
76
77    let post = diesel::insert_into(posts::table)
78        .values(&new_post)
79        .returning(Post::as_returning())
80        .get_result(&mut establish_connection())
81        .expect("Error saving new post");
82
83    serde_wasm_bindgen::to_value(&post).unwrap()
84}
85
86#[wasm_bindgen(js_name = deletePost)]
87pub fn delete_post(pattern: &str) {
88    let connection = &mut establish_connection();
89    let num_deleted = diesel::delete(
90        schema::posts::dsl::posts.filter(schema::posts::title.like(pattern.to_string())),
91    )
92    .execute(connection)
93    .expect("Error deleting posts");
94
95    console_log!("Deleted {num_deleted} posts");
96}
97
98#[wasm_bindgen(js_name = getPost)]
99pub fn get_post(post_id: i32) -> JsValue {
100    use schema::posts::dsl::posts;
101
102    let connection = &mut establish_connection();
103
104    let post = posts
105        .find(post_id)
106        .select(Post::as_select())
107        .first(connection)
108        .optional(); // This allows for returning an Option<Post>, otherwise it will throw an error
109
110    match &post {
111        Ok(Some(post)) => console_log!("Post with id: {} has a title: {}", post.id, post.title),
112        Ok(None) => console_log!("Unable to find post {}", post_id),
113        Err(_) => console_log!("An error occurred while fetching post {}", post_id),
114    }
115    serde_wasm_bindgen::to_value(&post.ok().flatten()).unwrap()
116}
117
118#[wasm_bindgen(js_name = publishPost)]
119pub fn publish_post(id: i32) {
120    let connection = &mut establish_connection();
121
122    let post = diesel::update(schema::posts::dsl::posts.find(id))
123        .set(schema::posts::dsl::published.eq(true))
124        .returning(Post::as_returning())
125        .get_result(connection)
126        .unwrap();
127
128    console_log!("Published post {}", post.title);
129}
130
131#[wasm_bindgen(js_name = showPosts)]
132pub fn show_posts() -> Vec<JsValue> {
133    let connection = &mut establish_connection();
134    let results = schema::posts::dsl::posts
135        .filter(schema::posts::dsl::published.eq(true))
136        .limit(5)
137        .select(Post::as_select())
138        .load(connection)
139        .expect("Error loading posts");
140
141    console_log!("Displaying {} posts", results.len());
142    for post in &results {
143        console_log!("{}", post.title);
144        console_log!("----------\n");
145        console_log!("{}", post.body);
146    }
147
148    results
149        .into_iter()
150        .map(|x| serde_wasm_bindgen::to_value(&x).unwrap())
151        .collect()
152}