-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4432 from Spxg/wasm-example
Add a sqlite-wasm example
- Loading branch information
Showing
12 changed files
with
417 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pkg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[package] | ||
name = "sqlite-wasm-example" | ||
version = "0.1.0" | ||
edition.workspace = true | ||
publish = false | ||
|
||
[dependencies] | ||
diesel = { path = "../../../diesel", features = ["sqlite", "returning_clauses_for_sqlite_3_35"] } | ||
diesel_migrations = { path = "../../../diesel_migrations", features = ["sqlite"] } | ||
serde = { version = "1.0.217", features = ["derive"] } | ||
serde-wasm-bindgen = "0.6.5" | ||
wasm-bindgen = "0.2.99" | ||
wasm-bindgen-futures = "0.4.49" | ||
|
||
[lib] | ||
crate-type = ["cdylib"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# `rs-diesel-sqlite` | ||
|
||
Diesel's `Getting Started` guide using SQLite instead of Postgresql | ||
|
||
## Usage | ||
|
||
Compile wasm and start the web server: | ||
|
||
``` | ||
rustup target add wasm32-unknown-unknown | ||
# Add wasm32-unknown-unknown toolchain | ||
cargo install wasm-pack | ||
# Install the wasm-pack toolchain | ||
wasm-pack build --target web | ||
# Build wasm | ||
python3 server.py | ||
# Start server | ||
``` | ||
|
||
Next, try it on the web page: [on the web page](http://localhost:8000) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
|
||
<head> | ||
<meta charset="utf-8"> | ||
<title>diesel sqlite-wasm example</title> | ||
</head> | ||
|
||
<body> | ||
<label for="vfs">choose vfs:</label> | ||
<select id="vfs"> | ||
<option value="0">memory</option> | ||
<option value="1">opfs</option> | ||
<option value="2">opfs-sahpool</option> | ||
</select> | ||
<button id="SwitchVFS">Switch VFS</button> | ||
<p></p> | ||
|
||
<button id="ShowButton">Show 5 Published Posts</button> | ||
<p id="show_result"></p> | ||
|
||
<input id="create_title" type="string" placeholder="Enter title" /> | ||
<input id="create_body" type="string" placeholder="Enter body"> | ||
<button id="CreateButton">CreatePost</button> | ||
<p id="create_result"></p> | ||
|
||
<input id="get_post_id" type="number" placeholder="Enter PostId" /> | ||
<button id="GetButton">GetPost</button> | ||
<p id="get_result"></p> | ||
|
||
<input id="publish_post_id" type="number" placeholder="Enter PostId" /> | ||
<button id="PublishButton">PublishPost</button> | ||
<p id="publish_result"></p> | ||
|
||
<input id="delete_post_title" type="string" placeholder="Enter PostTitle" /> | ||
<button id="DeleteButton">DeletePost</button> | ||
<p id="delete_result"></p> | ||
|
||
<script type="module"> | ||
function call(payload) { | ||
worker.postMessage(payload); | ||
} | ||
|
||
async function run() { | ||
document.getElementById('SwitchVFS').onclick = () => { | ||
const id = parseInt(document.getElementById('vfs').value); | ||
call({ cmd: "switch_vfs", id: id }) | ||
}; | ||
|
||
document.getElementById('ShowButton').onclick = () => { | ||
call({ cmd: "show_posts" }) | ||
}; | ||
|
||
document.getElementById('CreateButton').onclick = () => { | ||
const title = document.getElementById('create_title').value; | ||
const body = document.getElementById('create_body').value; | ||
call({ cmd: "create_post", title: title, body: body }) | ||
}; | ||
|
||
document.getElementById('GetButton').onclick = () => { | ||
const post_id = parseInt(document.getElementById('get_post_id').value); | ||
call({ cmd: "get_post", post_id: post_id }) | ||
}; | ||
|
||
document.getElementById('PublishButton').onclick = () => { | ||
const post_id = parseInt(document.getElementById('publish_post_id').value); | ||
call({ cmd: "publish_post", post_id: post_id }) | ||
}; | ||
|
||
document.getElementById('DeleteButton').onclick = () => { | ||
const title = document.getElementById('delete_post_title').value; | ||
call({ cmd: "delete_post", title: title }) | ||
}; | ||
} | ||
|
||
const worker = new Worker('worker.js', { type: 'module' }); | ||
worker.onmessage = function (event) { | ||
run(); | ||
worker.onmessage = function (event) { | ||
const payload = event.data; | ||
switch (payload.cmd) { | ||
case 'show_posts': | ||
var posts = payload.posts; | ||
document.getElementById('show_result').innerText = JSON.stringify(posts); | ||
break; | ||
case 'create_post': | ||
var post = payload.post; | ||
document.getElementById('create_result').innerText = JSON.stringify(post); | ||
break; | ||
case 'get_post': | ||
var post = payload.post; | ||
document.getElementById('get_result').innerText = JSON.stringify(post); | ||
break; | ||
case 'publish_post': | ||
document.getElementById('publish_result').innerText = 'Publish done.'; | ||
break; | ||
case 'delete_post': | ||
document.getElementById('delete_result').innerText = 'Delete done.'; | ||
break; | ||
default: | ||
break; | ||
}; | ||
} | ||
} | ||
</script> | ||
</body> | ||
|
||
</html> |
1 change: 1 addition & 0 deletions
1
examples/sqlite/wasm/migrations/20170124012402_create_posts/down.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
DROP TABLE posts |
6 changes: 6 additions & 0 deletions
6
examples/sqlite/wasm/migrations/20170124012402_create_posts/up.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
CREATE TABLE posts ( | ||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, | ||
title VARCHAR NOT NULL, | ||
body TEXT NOT NULL, | ||
published BOOLEAN NOT NULL DEFAULT 0 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#!/usr/bin/env python3 | ||
from http.server import HTTPServer, SimpleHTTPRequestHandler, test | ||
import sys | ||
|
||
class RequestHandler(SimpleHTTPRequestHandler): | ||
def end_headers(self): | ||
self.send_header('Cross-Origin-Opener-Policy', 'same-origin') | ||
self.send_header('Cross-Origin-Embedder-Policy', 'require-corp') | ||
SimpleHTTPRequestHandler.end_headers(self) | ||
|
||
if __name__ == '__main__': | ||
test(RequestHandler, HTTPServer, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
pub mod models; | ||
pub mod schema; | ||
|
||
use std::sync::Mutex; | ||
use std::sync::Once; | ||
|
||
use crate::models::{NewPost, Post}; | ||
use diesel::prelude::*; | ||
use diesel_migrations::embed_migrations; | ||
use diesel_migrations::EmbeddedMigrations; | ||
use diesel_migrations::MigrationHarness; | ||
use wasm_bindgen::prelude::*; | ||
|
||
const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); | ||
|
||
#[wasm_bindgen] | ||
extern "C" { | ||
// Use `js_namespace` here to bind `console.log(..)` instead of just | ||
// `log(..)` | ||
#[wasm_bindgen(js_namespace = console)] | ||
fn log(s: &str); | ||
} | ||
|
||
// Next let's define a macro that's like `println!`, only it works for | ||
// `console.log`. Note that `println!` doesn't actually work on the Wasm target | ||
// because the standard library currently just eats all output. To get | ||
// `println!`-like behavior in your app you'll likely want a macro like this. | ||
macro_rules! console_log { | ||
// Note that this is using the `log` function imported above during | ||
// `bare_bones` | ||
($($t:tt)*) => (log(&format_args!($($t)*).to_string())) | ||
} | ||
|
||
static VFS: Mutex<(i32, Once)> = Mutex::new((0, Once::new())); | ||
|
||
pub fn establish_connection() -> SqliteConnection { | ||
let (vfs, once) = &*VFS.lock().unwrap(); | ||
let url = match vfs { | ||
0 => "post.db", | ||
1 => "file:post.db?vfs=opfs", | ||
2 => "file:post.db?vfs=opfs-sahpool", | ||
_ => unreachable!(), | ||
}; | ||
let mut conn = | ||
SqliteConnection::establish(url).unwrap_or_else(|_| panic!("Error connecting to post.db")); | ||
once.call_once(|| { | ||
conn.run_pending_migrations(MIGRATIONS).unwrap(); | ||
}); | ||
conn | ||
} | ||
|
||
#[cfg(all(target_family = "wasm", target_os = "unknown"))] | ||
#[wasm_bindgen] | ||
pub async fn init_sqlite() { | ||
let sqlite = diesel::init_sqlite().await.unwrap(); | ||
sqlite.install_opfs_sahpool(None).await.unwrap(); | ||
} | ||
|
||
#[wasm_bindgen] | ||
pub fn switch_vfs(id: i32) { | ||
*VFS.lock().unwrap() = (id, Once::new()); | ||
} | ||
|
||
#[wasm_bindgen] | ||
pub fn create_post(title: &str, body: &str) -> JsValue { | ||
use crate::schema::posts; | ||
|
||
let new_post = NewPost { title, body }; | ||
|
||
let post = diesel::insert_into(posts::table) | ||
.values(&new_post) | ||
.returning(Post::as_returning()) | ||
.get_result(&mut establish_connection()) | ||
.expect("Error saving new post"); | ||
|
||
serde_wasm_bindgen::to_value(&post).unwrap() | ||
} | ||
|
||
#[wasm_bindgen] | ||
pub fn delete_post(pattern: &str) { | ||
let connection = &mut establish_connection(); | ||
let num_deleted = diesel::delete( | ||
schema::posts::dsl::posts.filter(schema::posts::title.like(pattern.to_string())), | ||
) | ||
.execute(connection) | ||
.expect("Error deleting posts"); | ||
|
||
console_log!("Deleted {num_deleted} posts"); | ||
} | ||
|
||
#[wasm_bindgen] | ||
pub fn get_post(post_id: i32) -> JsValue { | ||
use schema::posts::dsl::posts; | ||
|
||
let connection = &mut establish_connection(); | ||
|
||
let post = posts | ||
.find(post_id) | ||
.select(Post::as_select()) | ||
.first(connection) | ||
.optional(); // This allows for returning an Option<Post>, otherwise it will throw an error | ||
|
||
match &post { | ||
Ok(Some(post)) => console_log!("Post with id: {} has a title: {}", post.id, post.title), | ||
Ok(None) => console_log!("Unable to find post {}", post_id), | ||
Err(_) => console_log!("An error occurred while fetching post {}", post_id), | ||
} | ||
serde_wasm_bindgen::to_value(&post.ok().flatten()).unwrap() | ||
} | ||
|
||
#[wasm_bindgen] | ||
pub fn publish_post(id: i32) { | ||
let connection = &mut establish_connection(); | ||
|
||
let post = diesel::update(schema::posts::dsl::posts.find(id)) | ||
.set(schema::posts::dsl::published.eq(true)) | ||
.returning(Post::as_returning()) | ||
.get_result(connection) | ||
.unwrap(); | ||
|
||
console_log!("Published post {}", post.title); | ||
} | ||
|
||
#[wasm_bindgen] | ||
pub fn show_posts() -> Vec<JsValue> { | ||
let connection = &mut establish_connection(); | ||
let results = schema::posts::dsl::posts | ||
.filter(schema::posts::dsl::published.eq(true)) | ||
.limit(5) | ||
.select(Post::as_select()) | ||
.load(connection) | ||
.expect("Error loading posts"); | ||
|
||
console_log!("Displaying {} posts", results.len()); | ||
for post in &results { | ||
console_log!("{}", post.title); | ||
console_log!("----------\n"); | ||
console_log!("{}", post.body); | ||
} | ||
|
||
results | ||
.into_iter() | ||
.map(|x| serde_wasm_bindgen::to_value(&x).unwrap()) | ||
.collect() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
use super::schema::posts; | ||
use diesel::prelude::*; | ||
use serde::Serialize; | ||
|
||
#[derive(Queryable, Selectable, Serialize)] | ||
#[diesel(table_name = posts)] | ||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))] | ||
pub struct Post { | ||
pub id: i32, | ||
pub title: String, | ||
pub body: String, | ||
pub published: bool, | ||
} | ||
|
||
#[derive(Insertable)] | ||
#[diesel(table_name = posts)] | ||
pub struct NewPost<'a> { | ||
pub title: &'a str, | ||
pub body: &'a str, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// @generated automatically by Diesel CLI. | ||
|
||
diesel::table! { | ||
posts (id) { | ||
id -> Integer, | ||
title -> Text, | ||
body -> Text, | ||
published -> Bool, | ||
} | ||
} |
Oops, something went wrong.