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        _ => unreachable!(),
42    };
43    let mut conn =
44        SqliteConnection::establish(url).unwrap_or_else(|_| panic!("Error connecting to post.db"));
45    once.call_once(|| {
46        conn.run_pending_migrations(MIGRATIONS).unwrap();
47    });
48    conn
49}
50
51#[cfg(all(target_family = "wasm", target_os = "unknown"))]
52#[wasm_bindgen]
53pub async fn install_opfs_sahpool() {
54    sqlite_wasm_rs::export::install_opfs_sahpool(None, false)
55        .await
56        .unwrap();
57}
58
59#[wasm_bindgen]
60pub fn switch_vfs(id: i32) {
61    *VFS.lock().unwrap() = (id, Once::new());
62}
63
64#[wasm_bindgen]
65pub fn create_post(title: &str, body: &str) -> JsValue {
66    use crate::schema::posts;
67
68    let new_post = NewPost { title, body };
69
70    let post = diesel::insert_into(posts::table)
71        .values(&new_post)
72        .returning(Post::as_returning())
73        .get_result(&mut establish_connection())
74        .expect("Error saving new post");
75
76    serde_wasm_bindgen::to_value(&post).unwrap()
77}
78
79#[wasm_bindgen]
80pub fn delete_post(pattern: &str) {
81    let connection = &mut establish_connection();
82    let num_deleted = diesel::delete(
83        schema::posts::dsl::posts.filter(schema::posts::title.like(pattern.to_string())),
84    )
85    .execute(connection)
86    .expect("Error deleting posts");
87
88    console_log!("Deleted {num_deleted} posts");
89}
90
91#[wasm_bindgen]
92pub fn get_post(post_id: i32) -> JsValue {
93    use schema::posts::dsl::posts;
94
95    let connection = &mut establish_connection();
96
97    let post = posts
98        .find(post_id)
99        .select(Post::as_select())
100        .first(connection)
101        .optional(); // This allows for returning an Option<Post>, otherwise it will throw an error
102
103    match &post {
104        Ok(Some(post)) => console_log!("Post with id: {} has a title: {}", post.id, post.title),
105        Ok(None) => console_log!("Unable to find post {}", post_id),
106        Err(_) => console_log!("An error occurred while fetching post {}", post_id),
107    }
108    serde_wasm_bindgen::to_value(&post.ok().flatten()).unwrap()
109}
110
111#[wasm_bindgen]
112pub fn publish_post(id: i32) {
113    let connection = &mut establish_connection();
114
115    let post = diesel::update(schema::posts::dsl::posts.find(id))
116        .set(schema::posts::dsl::published.eq(true))
117        .returning(Post::as_returning())
118        .get_result(connection)
119        .unwrap();
120
121    console_log!("Published post {}", post.title);
122}
123
124#[wasm_bindgen]
125pub fn show_posts() -> Vec<JsValue> {
126    let connection = &mut establish_connection();
127    let results = schema::posts::dsl::posts
128        .filter(schema::posts::dsl::published.eq(true))
129        .limit(5)
130        .select(Post::as_select())
131        .load(connection)
132        .expect("Error loading posts");
133
134    console_log!("Displaying {} posts", results.len());
135    for post in &results {
136        console_log!("{}", post.title);
137        console_log!("----------\n");
138        console_log!("{}", post.body);
139    }
140
141    results
142        .into_iter()
143        .map(|x| serde_wasm_bindgen::to_value(&x).unwrap())
144        .collect()
145}